zfec: loosen the interface of the cmdline tool to allow m < 3, and to allow k ==...
authorzooko <zooko@zooko.com>
Mon, 1 Oct 2007 03:09:45 +0000 (08:39 +0530)
committerzooko <zooko@zooko.com>
Mon, 1 Oct 2007 03:09:45 +0000 (08:39 +0530)
darcs-hash:27c79434d568611d832c31a345377bf97d143105

zfec/zfec/cmdline_zfec.py
zfec/zfec/filefec.py
zfec/zfec/test/test_zfec.py

index b62d8264a0e6278236a4a7e8a446fd1cff1948e5..accc6b4c4509a355035cb2c35aaddf450e9c64db 100755 (executable)
@@ -28,6 +28,7 @@ def main():
     parser.add_argument('-k', '--requiredshares', help='the number of share files required to reconstruct (default 4)', default=4, type=int, metavar='K')
     parser.add_argument('-f', '--force', help='overwrite any file which already in place an output file (share file)', action='store_true')
     parser.add_argument('-v', '--verbose', help='print out messages about progress', action='store_true')
+    parser.add_argument('-q', '--quiet', help='quiet progress indications and warnings about silly choices of K and M', action='store_true')
     parser.add_argument('-V', '--version', help='print out version number and exit', action='store_true')
     args = parser.parse_args()
 
@@ -36,19 +37,23 @@ def main():
         if args.prefix == "<stdin>":
             args.prefix = ""
 
-    if args.totalshares < 3:
-        print "Invalid parameters, totalshares is required to be >= 3\nPlease see the accompanying documentation."
+    if args.verbose and args.quiet:
+        print "Please choose only one of --verbose and --quiet."
         sys.exit(1)
-    if args.totalshares > 256:
-        print "Invalid parameters, totalshares is required to be <= 256\nPlease see the accompanying documentation."
+        
+    if args.totalshares > 256 or args.totalshares < 1:
+        print "Invalid parameters, totalshares is required to be <= 256 and >= 1\nPlease see the accompanying documentation."
         sys.exit(1)
-    if args.requiredshares < 2:
-        print "Invalid parameters, requiredshares is required to be >= 2\nPlease see the accompanying documentation."
-        sys.exit(1)
-    if args.requiredshares >= args.totalshares:
-        print "Invalid parameters, requiredshares is required to be < totalshares\nPlease see the accompanying documentation."
+    if args.requiredshares > args.totalshares or args.requiredshares < 1:
+        print "Invalid parameters, requiredshares is required to be <= totalshares and >= 1\nPlease see the accompanying documentation."
         sys.exit(1)
 
+    if not args.quiet:
+        if args.requiredshares == 1:
+            print "warning: silly parameters: requiredshares == 1, which means that every share will be a complete copy of the file.  You could use \"cp\" for the same effect.  But proceeding to do it anyway..."
+        if args.requiredshares == args.totalshares:
+            print "warning: silly parameters: requiredshares == totalshares, which means that all shares will be required in order to reconstruct the file.  You could use \"split\" for the same effect.  But proceeding to do it anyway..."
+
     args.inputfile.seek(0, 2)
     fsize = args.inputfile.tell()
     args.inputfile.seek(0, 0)
index 30985a918895750cd4077818e050741bec2cf03f..35d64c5cb6c2a5e366efbb492a059a6c4f3d3dcf 100644 (file)
@@ -23,17 +23,17 @@ class CorruptedShareFilesError(zfec.Error):
 
 def _build_header(m, k, pad, sh):
     """
-    @param m: the total number of shares; 3 <= m <= 256
-    @param k: the number of shares required to reconstruct; 2 <= k < m
+    @param m: the total number of shares; 1 <= m <= 256
+    @param k: the number of shares required to reconstruct; 1 <= k <= m
     @param pad: the number of bytes of padding added to the file before encoding; 0 <= pad < k
     @param sh: the shnum of this share; 0 <= k < m
 
     @return: a string (which is hopefully short) encoding m, k, sh, and pad
     """
-    assert m >= 3
+    assert m >= 1
     assert m <= 2**8
-    assert k >= 2
-    assert k < m
+    assert k >= 1
+    assert k <= m
     assert pad >= 0
     assert pad < k
 
@@ -43,14 +43,14 @@ def _build_header(m, k, pad, sh):
     bitsused = 0
     val = 0
 
-    val |= (m - 3)
+    val |= (m - 1)
     bitsused += 8 # the first 8 bits always encode m
 
-    kbits = log_ceil(m-2, 2) # num bits needed to store all possible values of k
+    kbits = log_ceil(m, 2) # num bits needed to store all possible values of k
     val <<= kbits
     bitsused += kbits
 
-    val |= (k - 2)
+    val |= (k - 1)
 
     padbits = log_ceil(k, 2) # num bits needed to store all possible values of pad
     val <<= padbits
@@ -64,8 +64,8 @@ def _build_header(m, k, pad, sh):
 
     val |= sh
 
-    assert bitsused >= 11
-    assert bitsused <= 32
+    assert bitsused >= 8, bitsused
+    assert bitsused <= 32, bitsused
 
     if bitsused <= 16:
         val <<= (16-bitsused)
@@ -98,17 +98,17 @@ def _parse_header(inf):
     if not ch:
         raise CorruptedShareFilesError("Share files were corrupted -- share file %r didn't have a complete metadata header at the front.  Perhaps the file was truncated." % (inf.name,))
     byte = ord(ch)
-    m = byte + 3
+    m = byte + 1
 
     # The next few bits encode k.
-    kbits = log_ceil(m-2, 2) # num bits needed to store all possible values of k
+    kbits = log_ceil(m, 2) # num bits needed to store all possible values of k
     b2_bits_left = 8-kbits
     kbitmask = MASK(kbits) << b2_bits_left
     ch = inf.read(1)
     if not ch:
         raise CorruptedShareFilesError("Share files were corrupted -- share file %r didn't have a complete metadata header at the front.  Perhaps the file was truncated." % (inf.name,))
     byte = ord(ch)
-    k = ((byte & kbitmask) >> b2_bits_left) + 2
+    k = ((byte & kbitmask) >> b2_bits_left) + 1
 
     shbits = log_ceil(m, 2) # num bits needed to store all possible values of shnum
     padbits = log_ceil(k, 2) # num bits needed to store all possible values of pad
index d87d91d9c84498a0fda33eed59b0691190e45220..150b7d995600b5c5b4d1aa8bd25a881f25f49523 100755 (executable)
@@ -98,8 +98,8 @@ class ZFec(unittest.TestCase):
 
 class FileFec(unittest.TestCase):
     def test_filefec_header(self):
-        for m in [3, 5, 7, 9, 11, 17, 19, 33, 35, 65, 66, 67, 129, 130, 131, 254, 255, 256,]:
-            for k in [2, 3, 5, 9, 17, 33, 65, 129, 255,]:
+        for m in [1, 2, 3, 5, 7, 9, 11, 17, 19, 33, 35, 65, 66, 67, 129, 130, 131, 254, 255, 256,]:
+            for k in [1, 2, 3, 5, 9, 17, 33, 65, 129, 255, 256,]:
                 if k >= m:
                     continue
                 for pad in [0, 1, k-1,]: