0.11 [???]
- SNAPSHOT FORMAT CHANGES:
+ - The object slice syntax has been simplified; backup restores
+ are still possible but rebuilding the local database from
+ snapshots before v0.8 will require translation.
- Timestamps encoded into the top-level snapshot file name are
now UTC instead of the local time zone. This should avoid
ambiguity and ensure sorted order is chronological order in
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. As an
-abbreviation, the slice syntax
+selects only bytes 264..1263 from the original object.
+
+The slice syntax
[<length>]
-is shorthand for
- [0+<length>]
-In place of a traditional slice, the annotation
- [=<length>]
-may be used. This is somewhat similar to specifying [<length>], but
+indicates that all bytes of the object are to be used, but
additionally asserts that the referenced object is exactly <length>
-bytes long--that is, this slice syntax does not change the bytes
-returned at all, but can be used to provide information about the
-underlying object store.
+bytes long. Older versions of Cumulus can also use the syntax
+ [=<length>]
+as a synonym for length assertions, but this notation is deprecated.
+
+(In older versions of the format, the syntax [<length>] was a shorthand
+for [0+<length>]: that is, select the first <length> bytes of the object
+but make no assertions about the overall size. The backup tool has not
+generated such slices since v0.8.)
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
the object. For example
zero[1024]
represents a block consisting of 1024 null bytes. A checksum should not
-be given. The slice syntax should use the abbreviated length-only form.
+be given.
FILE METADATA LISTING
if m:
return ("zero", None, None, (0, int(m.group(1)), False))
- m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[(((\d+)\+)?(\d+)|=(\d+))\])?$", refstr)
+ m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[(=?(\d+)|(\d+)\+(\d+))\])?$", refstr)
if not m: return
segment = m.group(1)
checksum = checksum.lstrip("(").rstrip(")")
if slice is not None:
- if m.group(9) is not None:
+ if m.group(6) is not None:
# Size-assertion slice
- slice = (0, int(m.group(9)), True)
- elif m.group(6) is None:
- # Abbreviated slice
- slice = (0, int(m.group(8)), False)
+ slice = (0, int(m.group(6)), True)
else:
slice = (int(m.group(7)), int(m.group(8)), False)
if slice is not None:
(start, length, exact) = slice
+ # Note: The following assertion check may need to be commented out
+ # to restore from pre-v0.8 snapshots, as the syntax for
+ # size-assertion slices has changed.
if exact and len(data) != length: raise ValueError
data = data[start:start+length]
if len(data) != length: raise IndexError
if (range_valid) {
char buf[64];
- if (range_exact) {
- sprintf(buf, "[=%zu]", range_length);
- } else if (type == REF_ZERO) {
+ if (range_exact || type == REF_ZERO) {
sprintf(buf, "[%zu]", range_length);
} else {
sprintf(buf, "[%zu+%zu]", range_start, range_length);
if (*t == '[') {
t++;
+ // An equal sign was once used for a length assertion but is now
+ // deprecated. Skip it if present, and mark that we are expecting a
+ // length-only reference.
if (*t == '=') {
range_exact = true;
t++;
if (*t == ']') {
string val(s, t - s);
range2 = atoll(val.c_str());
+ range_exact = true;
} else {
if (*t != '+')
return ObjectReference();