Snapshot format change: extend the slice syntax with a length-only form.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 12 Dec 2007 18:16:39 +0000 (10:16 -0800)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Wed, 12 Dec 2007 18:16:39 +0000 (10:16 -0800)
Change slice format so that in addition to <start>+<length>, it is possible
to specify just <length>.  This isn't needed (0+<length>) could be used
instead, but looks more pleasing if lengths are specified more frequently
on objects.  Also update the various tools to correctly parse the new
syntax.

This is part of the new v0.6 format.

contrib/restore.pl
doc/format.txt
lbs.py
ref.cc
ref.h

index 96cf4b4..f9c55ce 100755 (executable)
@@ -88,8 +88,8 @@ sub load_ref {
     my $ref_str = shift;
 
     # Check for special objects before attempting general parsing.
-    if ($ref_str =~ m/^zero\[(\d+)\+(\d+)\]$/) {
-        return "\0" x ($2 + 0);
+    if ($ref_str =~ m/^zero\[((\d+)\+)?(\d+)\]$/) {
+        return "\0" x ($3 + 0);
     }
 
     # Try to parse the object reference string into constituent pieces.  The
@@ -122,12 +122,17 @@ sub load_ref {
     # If a range was specified, then only a subset of the bytes of the object
     # are desired.  Extract just the desired bytes.
     if ($range) {
-        if ($range !~ m/^\[(\d+)\+(\d+)\]$/) {
+        if ($range !~ m/^\[((\d+)\+)?(\d+)\]$/) {
             die "Malformed object range: $range";
         }
 
         my $object_size = length $contents;
-        my ($start, $length) = ($1 + 0, $2 + 0);
+        my ($start, $length);
+        if ($1 ne "") {
+            ($start, $length) = ($2 + 0, $3 + 0);
+        } else {
+            ($start, $length) = (0, $3 + 0);
+        }
         if ($start >= $object_size || $start + $length > $object_size) {
             die "Object range $range falls outside object bounds "
                 . "(actual size $object_size)";
index 7449681..5072981 100644 (file)
@@ -116,7 +116,11 @@ is invalid to select using the slice syntax a range of bytes that does
 not fall within the original object.  The slice specification should be
 appended to an object name, for example:
     a704eeae-97f2-4f30-91a4-d4473956366b/000001ad[264+1000]
-selects only bytes 264..1263 from the original object.
+selects only bytes 264..1263 from the original object.  As an
+abbreviation, the slice syntax
+    [<length>]
+is shorthand for
+    [0+<length>]
 
 Both a checksum and a slice can be used.  In this case, the checksum is
 given first, followed by the slice.  The checksum is computed over the
@@ -130,9 +134,9 @@ special name "zero" may be used instead of segment/sequence number.
 This represents an object consisting entirely of zeroes.  The zero
 object must have a slice specification appended to indicate the size of
 the object.  For example
-    zero[0+1024]
+    zero[1024]
 represents a block consisting of 1024 null bytes.  A checksum should not
-be given.
+be given.  The slice syntax should use the abbreviated length-only form.
 
 
 FILE METADATA LISTING
diff --git a/lbs.py b/lbs.py
index 3108998..80240e7 100644 (file)
--- a/lbs.py
+++ b/lbs.py
@@ -139,11 +139,11 @@ class ObjectStore:
 
     @staticmethod
     def parse_ref(refstr):
-        m = re.match(r"^zero\[(\d+)\+(\d+)\]$", refstr)
+        m = re.match(r"^zero\[(\d+)\]$", refstr)
         if m:
-            return ("zero", None, None, (int(m.group(1)), int(m.group(2))))
+            return ("zero", None, None, (0, int(m.group(1))))
 
-        m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[(\d+)\+(\d+)\])?$", refstr)
+        m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[((\d+)\+)?(\d+)\])?$", refstr)
         if not m: return
 
         segment = m.group(1)
@@ -155,7 +155,11 @@ class ObjectStore:
             checksum = checksum.lstrip("(").rstrip(")")
 
         if slice is not None:
-            slice = (int(m.group(5)), int(m.group(6)))
+            if m.group(5) is None:
+                # Abbreviated slice
+                slice = (0, int(m.group(7)))
+            else:
+                slice = (int(m.group(6)), int(m.group(7)))
 
         return (segment, object, checksum, slice)
 
diff --git a/ref.cc b/ref.cc
index 80f4d1d..8ed747d 100644 (file)
--- a/ref.cc
+++ b/ref.cc
@@ -78,7 +78,11 @@ string ObjectReference::to_string() const
 
     if (range_valid) {
         char buf[64];
-        sprintf(buf, "[%zu+%zu]", range_start, range_length);
+        if (range_start == 0) {
+            sprintf(buf, "[%zu]", range_length);
+        } else {
+            sprintf(buf, "[%zu+%zu]", range_start, range_length);
+        }
         result += buf;
     }
 
@@ -143,21 +147,28 @@ ObjectReference ObjectReference::parse(const std::string& str)
         s = t;
         while (*t >= '0' && *t <= '9')
             t++;
-        if (*t != '+')
-            return ObjectReference();
 
-        string val(s, t - s);
-        range1 = atoll(val.c_str());
+        // Abbreviated-length only range?
+        if (*t == ']') {
+            string val(s, t - s);
+            range2 = atoll(val.c_str());
+        } else {
+            if (*t != '+')
+                return ObjectReference();
 
-        t++;
-        s = t;
-        while (*t >= '0' && *t <= '9')
-            t++;
-        if (*t != ']')
-            return ObjectReference();
+            string val(s, t - s);
+            range1 = atoll(val.c_str());
 
-        val = string(s, t - s);
-        range2 = atoll(val.c_str());
+            t++;
+            s = t;
+            while (*t >= '0' && *t <= '9')
+                t++;
+            if (*t != ']')
+                return ObjectReference();
+
+            val = string(s, t - s);
+            range2 = atoll(val.c_str());
+        }
 
         have_range = true;
     }
diff --git a/ref.h b/ref.h
index e499e6e..9a565ee 100644 (file)
--- a/ref.h
+++ b/ref.h
@@ -39,7 +39,8 @@
  * range specifier is given, then by default the entire object is used.
  *    <range> ::= <start> "+" <length>
  * Both <start> and <length> are decimal values.  If included, the range is
- * enclosed in brackets.
+ * enclosed in brackets.  As an abbreviation, if <start> is 0 then the range
+ * can be given as just <length> (no "+" needed).
  *
  * When both a checksum and a range are included, note that the checksum is
  * taken over the entire original object, before the range is taken into