]> git.rkrishnan.org Git - tahoe-lafs/zfec.git/blob - zfec/README.rst
e09d8f3449b64b9a6c87fda1036d50a9cf4d4787
[tahoe-lafs/zfec.git] / zfec / README.rst
1 zfec -- efficient, portable erasure coding tool
2 ===============================================
3
4 Generate redundant blocks of information such that if some of the
5 blocks are lost then the original data can be recovered from the
6 remaining blocks. This package includes command-line tools, C API,
7 Python API, and Haskell API.
8
9
10 Intro and Licence
11 -----------------
12
13 This package implements an "erasure code", or "forward error correction code".
14
15 You may use this package under the GNU General Public License, version 2 or, at
16 your option, any later version.  You may use this package under the Transitive
17 Grace Period Public Licence, version 1.0 or, at your option, any later version.
18 (You may choose to use this package under the terms of either licence, at your
19 option.)  See the file COPYING.GPL for the terms of the GNU General Public
20 License, version 2.  See the file COPYING.TGPPL.html for the terms of the
21 Transitive Grace Period Public Licence, version 1.0.
22
23 The most widely known example of an erasure code is the RAID-5 algorithm which
24 makes it so that in the event of the loss of any one hard drive, the stored data
25 can be completely recovered.  The algorithm in the zfec package has a similar
26 effect, but instead of recovering from the loss of only a single element, it can
27 be parameterized to choose in advance the number of elements whose loss it can
28 tolerate.
29
30 This package is largely based on the old "fec" library by Luigi Rizzo et al.,
31 which is a mature and optimized implementation of erasure coding.  The zfec
32 package makes several changes from the original "fec" package, including
33 addition of the Python API, refactoring of the C API to support zero-copy
34 operation, a few clean-ups and optimizations of the core code itself, and the
35 addition of a command-line tool named "zfec".
36
37
38 Installation
39 ------------
40
41 This package is managed with the "setuptools" package management tool.  To build
42 and install the package directly into your system, just run ``python ./setup.py install``.  If you prefer to keep the package limited to a specific directory so
43 that you can manage it yourself (perhaps by using the "GNU stow") tool, then
44 give it these arguments: ``python ./setup.py install --single-version-externally-managed --record=${specificdirectory}/zfec-install.log --prefix=${specificdirectory}``
45
46 To run the self-tests, execute ``python ./setup.py test`` (or if you have Twisted
47 Python installed, you can run ``trial zfec`` for nicer output and test options.)
48 This will run the tests of the C API, the Python API, and the command-line
49 tools.
50
51 To run the tests of the Haskell API: ``runhaskell haskell/test/FECTest.hs``
52
53 Note that in order to run the Haskell API tests you must have installed the
54 library first due to the fact that the interpreter cannot process FEC.hs as it
55 takes a reference to an FFI function.
56
57
58 Community
59 ---------
60
61 The source is currently available via darcs on the web with the command:
62
63 darcs get http://tahoe-lafs.org/source/zfec/trunk
64
65 More information on darcs is available at http://darcs.net
66
67 Please join the zfec mailing list and submit patches:
68
69 <http://tahoe-lafs.org/cgi-bin/mailman/listinfo/zfec-dev>
70
71
72 Overview
73 --------
74
75 This package performs two operations, encoding and decoding.  Encoding takes
76 some input data and expands its size by producing extra "check blocks", also
77 called "secondary blocks".  Decoding takes some data -- any combination of
78 blocks of the original data (called "primary blocks") and "secondary blocks",
79 and produces the original data.
80
81 The encoding is parameterized by two integers, k and m.  m is the total number
82 of blocks produced, and k is how many of those blocks are necessary to
83 reconstruct the original data.  m is required to be at least 1 and at most 256,
84 and k is required to be at least 1 and at most m.
85
86 (Note that when k == m then there is no point in doing erasure coding -- it
87 degenerates to the equivalent of the Unix "split" utility which simply splits
88 the input into successive segments.  Similarly, when k == 1 it degenerates to
89 the equivalent of the unix "cp" utility -- each block is a complete copy of the
90 input data.)
91
92 Note that each "primary block" is a segment of the original data, so its size is
93 1/k'th of the size of original data, and each "secondary block" is of the same
94 size, so the total space used by all the blocks is m/k times the size of the
95 original data (plus some padding to fill out the last primary block to be the
96 same size as all the others).  In addition to the data contained in the blocks
97 themselves there are also a few pieces of metadata which are necessary for later
98 reconstruction.  Those pieces are: 1.  the value of K, 2.  the value of M, 3.
99 the sharenum of each block, 4.  the number of bytes of padding that were used.
100 The "zfec" command-line tool compresses these pieces of data and prepends them
101 to the beginning of each share, so each the sharefile produced by the "zfec"
102 command-line tool is between one and four bytes larger than the share data
103 alone.
104
105 The decoding step requires as input k of the blocks which were produced by the
106 encoding step.  The decoding step produces as output the data that was earlier
107 input to the encoding step.
108
109
110 Command-Line Tool
111 -----------------
112
113 The bin/ directory contains two Unix-style, command-line tools "zfec"
114 and "zunfec".  Execute ``zfec --help`` or ``zunfec --help`` for usage
115 instructions.
116
117 Note: a Unix-style tool like "zfec" does only one thing -- in this
118 case erasure coding -- and leaves other tasks to other tools.  Other
119 Unix-style tools that go well with zfec include `GNU tar`_ for
120 archiving multiple files and directories into one file, `lzip`_ for
121 compression, and `GNU Privacy Guard`_ for encryption or `sha256sum`_
122 for integrity.  It is important to do things in order: first archive,
123 then compress, then either encrypt or integrity-check, then erasure
124 code.  Note that if GNU Privacy Guard is used for privacy, then it
125 will also ensure integrity, so the use of sha256sum is unnecessary in
126 that case. Note also that you also need to do integrity checking (such
127 as with sha256sum) on the blocks that result from the erasure coding
128 in *addition* to doing it on the file contents! (There are two
129 different subtle failure modes -- see "more than one file can match an
130 immutable file cap" on the `Hack Tahoe-LAFS!`_ Hall of Fame.)
131
132 The `Tahoe-LAFS`_ project uses zfec as part of a complete distributed
133 filesystem with integrated encryption, integrity, remote distribution
134 of the blocks, directory structure, backup of changed files or
135 directories, access control, immutable files and directories,
136 proof-of-retrievability, and repair of damaged files and directories.
137
138 .. _GNU tar: http://directory.fsf.org/project/tar/
139 .. _lzip: http://www.nongnu.org/lzip/lzip.html
140 .. _GNU Privacy Guard: http://www.gnupg.org/
141 .. _sha256sum: http://www.gnu.org/software/coreutils/
142 .. _Tahoe-LAFS: http://tahoe-lafs.org
143 .. _Hack Tahoe-LAFS!: http://tahoe-lafs.org/hacktahoelafs/
144
145
146 Performance
147 -----------
148
149 On my Athlon 64 2.4 GHz workstation (running Linux), the "zfec" command-line
150 tool encoded a 160 MB file with m=100, k=94 (about 6% redundancy) in 3.9
151 seconds, where the "par2" tool encoded the file with about 6% redundancy in 27
152 seconds.  zfec encoded the same file with m=12, k=6 (100% redundancy) in 4.1
153 seconds, where par2 encoded it with about 100% redundancy in 7 minutes and 56
154 seconds.
155
156 The underlying C library in benchmark mode encoded from a file at about 4.9
157 million bytes per second and decoded at about 5.8 million bytes per second.
158
159 On Peter's fancy Intel Mac laptop (2.16 GHz Core Duo), it encoded from a file at
160 about 6.2 million bytes per second.
161
162 On my even fancier Intel Mac laptop (2.33 GHz Core Duo), it encoded from a file
163 at about 6.8 million bytes per second.
164
165 On my old PowerPC G4 867 MHz Mac laptop, it encoded from a file at about 1.3
166 million bytes per second.
167
168 Here is a paper analyzing the performance of various erasure codes and their
169 implementations, including zfec:
170
171 http://www.usenix.org/events/fast09/tech/full_papers/plank/plank.pdf
172
173 Zfec shows good performance on different machines and with different values of
174 K and M. It also has a nice small memory footprint.
175
176
177 API
178 ---
179
180 Each block is associated with "blocknum".  The blocknum of each primary block is
181 its index (starting from zero), so the 0'th block is the first primary block,
182 which is the first few bytes of the file, the 1'st block is the next primary
183 block, which is the next few bytes of the file, and so on.  The last primary
184 block has blocknum k-1.  The blocknum of each secondary block is an arbitrary
185 integer between k and 255 inclusive.  (When using the Python API, if you don't
186 specify which secondary blocks you want when invoking encode(), then it will by
187 default provide the blocks with ids from k to m-1 inclusive.)
188
189 - C API
190
191   fec_encode() takes as input an array of k pointers, where each
192   pointer points to a memory buffer containing the input data (i.e.,
193   the i'th buffer contains the i'th primary block).  There is also a
194   second parameter which is an array of the blocknums of the secondary
195   blocks which are to be produced.  (Each element in that array is
196   required to be the blocknum of a secondary block, i.e. it is
197   required to be >= k and < m.)
198
199   The output from fec_encode() is the requested set of secondary
200   blocks which are written into output buffers provided by the caller.
201
202   Note that this fec_encode() is a "low-level" API in that it requires
203   the input data to be provided in a set of memory buffers of exactly
204   the right sizes.  If you are starting instead with a single buffer
205   containing all of the data then please see easyfec.py's "class
206   Encoder" as an example of how to split a single large buffer into
207   the appropriate set of input buffers for fec_encode().  If you are
208   starting with a file on disk, then please see filefec.py's
209   encode_file_stringy_easyfec() for an example of how to read the data
210   from a file and pass it to "class Encoder".  The Python interface
211   provides these higher-level operations, as does the Haskell
212   interface.  If you implement functions to do these higher-level
213   tasks in other languages than Python or Haskell, then please send a
214   patch to zfec-dev@tahoe-lafs.org so that your API can be included in
215   future releases of zfec.
216
217   fec_decode() takes as input an array of k pointers, where each
218   pointer points to a buffer containing a block.  There is also a
219   separate input parameter which is an array of blocknums, indicating
220   the blocknum of each of the blocks which is being passed in.
221
222   The output from fec_decode() is the set of primary blocks which were
223   missing from the input and had to be reconstructed.  These
224   reconstructed blocks are written into output buffers provided by the
225   caller.
226
227
228 - Python API
229
230   encode() and decode() take as input a sequence of k buffers, where a
231   "sequence" is any object that implements the Python sequence
232   protocol (such as a list or tuple) and a "buffer" is any object that
233   implements the Python buffer protocol (such as a string or array).
234   The contents that are required to be present in these buffers are
235   the same as for the C API.
236
237   encode() also takes a list of desired blocknums.  Unlike the C API,
238   the Python API accepts blocknums of primary blocks as well as
239   secondary blocks in its list of desired blocknums.  encode() returns
240   a list of buffer objects which contain the blocks requested.  For
241   each requested block which is a primary block, the resulting list
242   contains a reference to the apppropriate primary block from the
243   input list.  For each requested block which is a secondary block,
244   the list contains a newly created string object containing that
245   block.
246
247   decode() also takes a list of integers indicating the blocknums of
248   the blocks being passed int.  decode() returns a list of buffer
249   objects which contain all of the primary blocks of the original data
250   (in order).  For each primary block which was present in the input
251   list, then the result list simply contains a reference to the object
252   that was passed in the input list.  For each primary block which was
253   not present in the input, the result list contains a newly created
254   string object containing that primary block.
255
256   Beware of a "gotcha" that can result from the combination of mutable
257   data and the fact that the Python API returns references to inputs
258   when possible.
259
260   Returning references to its inputs is efficient since it avoids
261   making an unnecessary copy of the data, but if the object which was
262   passed as input is mutable and if that object is mutated after the
263   call to zfec returns, then the result from zfec -- which is just a
264   reference to that same object -- will also be mutated.  This
265   subtlety is the price you pay for avoiding data copying.  If you
266   don't want to have to worry about this then you can simply use
267   immutable objects (e.g. Python strings) to hold the data that you
268   pass to zfec.
269
270 - Haskell API
271
272   The Haskell code is fully Haddocked, to generate the documentation, run ``runhaskell Setup.lhs haddock``.
273
274
275 Utilities
276 ---------
277
278 The filefec.py module has a utility function for efficiently reading a file and
279 encoding it piece by piece.  This module is used by the "zfec" and "zunfec"
280 command-line tools from the bin/ directory.
281
282
283 Dependencies
284 ------------
285
286 A C compiler is required.  To use the Python API or the command-line
287 tools a Python interpreter is also required.  We have tested it with
288 Python v2.4, v2.5, v2.6, and v2.7.  For the Haskell interface, GHC >=
289 6.8.1 is required.
290
291
292 Acknowledgements
293 ----------------
294
295 Thanks to the author of the original fec lib, Luigi Rizzo, and the folks that
296 contributed to it: Phil Karn, Robert Morelos-Zaragoza, Hari Thirumoorthy, and
297 Dan Rubenstein.  Thanks to the Mnet hackers who wrote an earlier Python wrapper,
298 especially Myers Carpenter and Hauke Johannknecht.  Thanks to Brian Warner and
299 Amber O'Whielacronx for help with the API, documentation, debugging,
300 compression, and unit tests.  Thanks to Adam Langley for improving the C API and
301 contributing the Haskell API.  Thanks to the creators of GCC (starting with
302 Richard M. Stallman) and Valgrind (starting with Julian Seward) for a pair of
303 excellent tools.  Thanks to my coworkers at Allmydata -- http://allmydata.com --
304 Fabrice Grinda, Peter Secor, Rob Kinninmont, Brian Warner, Zandr Milewski,
305 Justin Boreta, Mark Meras for sponsoring this work and releasing it under a Free
306 Software licence. Thanks to Jack Lloyd, Samuel Neves, and David-Sarah Hopwood.
307
308
309 Enjoy!
310
311 Zooko Wilcox-O'Hearn
312
313 2010-12-04
314
315 Boulder, Colorado