Commit 791d4425 authored by bescoto's avatar bescoto

Fixed selection bug, renamed metadata files to ".snapshot"


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@278 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent 02f71b86
...@@ -6,6 +6,10 @@ to Dave Steinberg for giving me an account on his system for testing. ...@@ -6,6 +6,10 @@ to Dave Steinberg for giving me an account on his system for testing.
Re-enabled --windows-mode and filename quoting. Re-enabled --windows-mode and filename quoting.
Fixed selection bug: In 0.11.1, files which were included in one
backup would be automatically included in the next. Now you can
include/exclude files session-by-session.
New in v0.11.1 (2002/12/31) New in v0.11.1 (2002/12/31)
--------------------------- ---------------------------
......
...@@ -16,12 +16,12 @@ have changed between two times ...@@ -16,12 +16,12 @@ have changed between two times
---------[ Medium term ]--------------------------------------- ---------[ Medium term ]---------------------------------------
Add ACL support
Add --dry-run option (target for v1.1.x) Add --dry-run option (target for v1.1.x)
Add # of increments option to --remove-older-than Add # of increments option to --remove-older-than
Restore only changed files
Make argument shortcut for cstream Make argument shortcut for cstream
Make --calculate-averages work with directory_statistics file. Make --calculate-averages work with directory_statistics file.
......
...@@ -37,6 +37,11 @@ blocksize = 32768 ...@@ -37,6 +37,11 @@ blocksize = 32768
# values may save on connection overhead and latency. # values may save on connection overhead and latency.
conn_bufsize = 98304 conn_bufsize = 98304
# This is used in rorpiter.CacheIndexable. The number represents the
# number of rpaths which may be stuck in buffers when moving over a
# remote connection.
pipeline_max_length = int(conn_bufsize / 150)
# True if script is running as a server # True if script is running as a server
server = None server = None
......
...@@ -31,7 +31,7 @@ def Mirror(src_rpath, dest_rpath): ...@@ -31,7 +31,7 @@ def Mirror(src_rpath, dest_rpath):
DestS.init_statistics() DestS.init_statistics()
source_rpiter = SourceS.get_source_select() source_rpiter = SourceS.get_source_select()
dest_sigiter = DestS.process_source_get_sigs(dest_rpath, source_rpiter, 0) dest_sigiter = DestS.process_source_get_sigs(dest_rpath, source_rpiter, 0)
source_diffiter = SourceS.get_diffs(src_rpath, dest_sigiter) source_diffiter = SourceS.get_diffs(dest_sigiter)
DestS.patch(dest_rpath, source_diffiter) DestS.patch(dest_rpath, source_diffiter)
DestS.write_statistics() DestS.write_statistics()
...@@ -43,7 +43,7 @@ def Mirror_and_increment(src_rpath, dest_rpath, inc_rpath): ...@@ -43,7 +43,7 @@ def Mirror_and_increment(src_rpath, dest_rpath, inc_rpath):
DestS.init_statistics() DestS.init_statistics()
source_rpiter = SourceS.get_source_select() source_rpiter = SourceS.get_source_select()
dest_sigiter = DestS.process_source_get_sigs(dest_rpath, source_rpiter, 1) dest_sigiter = DestS.process_source_get_sigs(dest_rpath, source_rpiter, 1)
source_diffiter = SourceS.get_diffs(src_rpath, dest_sigiter) source_diffiter = SourceS.get_diffs(dest_sigiter)
DestS.patch_and_increment(dest_rpath, source_diffiter, inc_rpath) DestS.patch_and_increment(dest_rpath, source_diffiter, inc_rpath)
DestS.write_statistics() DestS.write_statistics()
...@@ -59,19 +59,26 @@ class SourceStruct: ...@@ -59,19 +59,26 @@ class SourceStruct:
connection. Otherwise we will get an error because a list connection. Otherwise we will get an error because a list
containing files can't be pickled. containing files can't be pickled.
Also, cls.source_select needs to be cached so get_diffs below
can retrieve the necessary rps.
""" """
sel = selection.Select(rpath) sel = selection.Select(rpath)
sel.ParseArgs(tuplelist, filelists) sel.ParseArgs(tuplelist, filelists)
cls.source_select = sel.set_iter() sel.set_iter()
cache_size = Globals.pipeline_max_length * 2 # 2 because to and from
cls.source_select = rorpiter.CacheIndexable(sel, cache_size)
def get_source_select(cls): def get_source_select(cls):
"""Return source select iterator, set by set_source_select""" """Return source select iterator, set by set_source_select"""
return cls.source_select return cls.source_select
def get_diffs(cls, baserp, dest_sigiter): def get_diffs(cls, dest_sigiter):
"""Return diffs of any files with signature in dest_sigiter""" """Return diffs of any files with signature in dest_sigiter"""
source_rps = cls.source_select
def get_one_diff(dest_sig): def get_one_diff(dest_sig):
src_rp = baserp.new_index(dest_sig.index) src_rp = (source_rps.get(dest_sig.index) or
rpath.RORPath(dest_sig.index))
diff_rorp = src_rp.getRORPath() diff_rorp = src_rp.getRORPath()
if dest_sig.isflaglinked(): if dest_sig.isflaglinked():
diff_rorp.flaglinked(dest_sig.get_link_flag()) diff_rorp.flaglinked(dest_sig.get_link_flag())
......
...@@ -266,8 +266,8 @@ def OpenMetadata(rp = None, compress = 1): ...@@ -266,8 +266,8 @@ def OpenMetadata(rp = None, compress = 1):
assert not metadata_fileobj, "Metadata file already open" assert not metadata_fileobj, "Metadata file already open"
if rp: metadata_rp = rp if rp: metadata_rp = rp
else: else:
if compress: typestr = 'data.gz' if compress: typestr = 'snapshot.gz'
else: typestr = 'data' else: typestr = 'snapshot'
metadata_rp = Globals.rbdir.append("mirror_metadata.%s.%s" % metadata_rp = Globals.rbdir.append("mirror_metadata.%s.%s" %
(Time.curtimestr, typestr)) (Time.curtimestr, typestr))
metadata_fileobj = metadata_rp.open("wb", compress = compress) metadata_fileobj = metadata_rp.open("wb", compress = compress)
...@@ -293,7 +293,7 @@ def GetMetadata(rp, restrict_index = None, compressed = None): ...@@ -293,7 +293,7 @@ def GetMetadata(rp, restrict_index = None, compressed = None):
if compressed is None: if compressed is None:
if rp.isincfile(): if rp.isincfile():
compressed = rp.inc_compressed compressed = rp.inc_compressed
assert rp.inc_type == "data", rp.inc_type assert rp.inc_type == "data" or rp.inc_type == "snapshot"
else: compressed = rp.get_indexpath().endswith(".gz") else: compressed = rp.get_indexpath().endswith(".gz")
fileobj = rp.open("rb", compress = compressed) fileobj = rp.open("rb", compress = compressed)
...@@ -311,7 +311,8 @@ def GetMetadata_at_time(rbdir, time, restrict_index = None, rblist = None): ...@@ -311,7 +311,8 @@ def GetMetadata_at_time(rbdir, time, restrict_index = None, rblist = None):
if rblist is None: rblist = map(lambda x: rbdir.append(x), if rblist is None: rblist = map(lambda x: rbdir.append(x),
robust.listrp(rbdir)) robust.listrp(rbdir))
for rp in rblist: for rp in rblist:
if (rp.isincfile() and rp.getinctype() == "data" and if (rp.isincfile() and
(rp.getinctype() == "data" or rp.getinctype() == "snapshot") and
rp.getincbase_str() == "mirror_metadata"): rp.getincbase_str() == "mirror_metadata"):
if rp.getinctime() == time: return GetMetadata(rp, restrict_index) if rp.getinctime() == time: return GetMetadata(rp, restrict_index)
return None return None
......
...@@ -403,3 +403,42 @@ class ITRBranch: ...@@ -403,3 +403,42 @@ class ITRBranch:
(index and os.path.join(*index) or '()',), 2) (index and os.path.join(*index) or '()',), 2)
class CacheIndexable:
"""Cache last few indexed elements in iterator
This class should be initialized with an iterator yielding
.index'd objects. It looks like it is just the same iterator as
the one that initialized it. Luckily, it does more, caching the
last few elements iterated, which can be retrieved using the
.get() method.
If the index is not in the cache, return None.
"""
def __init__(self, indexed_iter, cache_size = None):
"""Make new CacheIndexable. Cache_size is max cache length"""
self.cache_size = cache_size
self.iter = indexed_iter
self.cache_dict = {}
self.cache_indicies = []
def next(self):
"""Return next elem, add to cache. StopIteration passed upwards"""
next_elem = self.iter.next()
next_index = next_elem.index
self.cache_dict[next_index] = next_elem
self.cache_indicies.append(next_index)
if len(self.cache_indicies) > self.cache_size:
del self.cache_dict[self.cache_indicies[0]]
del self.cache_indicies[0]
return next_elem
def __iter__(self): return self
def get(self, index):
"""Return element with index index from cache"""
try: return self.cache_dict[index]
except KeyError: return None
...@@ -157,7 +157,7 @@ def get_increment_rp(mirror_rp, time): ...@@ -157,7 +157,7 @@ def get_increment_rp(mirror_rp, time):
for filename in data_rp.listdir(): for filename in data_rp.listdir():
rp = data_rp.append(filename) rp = data_rp.append(filename)
if rp.isincfile() and rp.getincbase_str() == "increments": if rp.isincfile() and rp.getincbase_str() == "increments":
if Time.stringtotime(rp.getinctime()) == time: return rp if rp.getinctime() == time: return rp
return None # Couldn't find appropriate increment return None # Couldn't find appropriate increment
def _reset_connections(src_rp, dest_rp): def _reset_connections(src_rp, dest_rp):
......
...@@ -249,7 +249,7 @@ class Final(PathSetter): ...@@ -249,7 +249,7 @@ class Final(PathSetter):
class FinalSelection(PathSetter): class FinalSelection(PathSetter):
"""Test selection options""" """Test selection options"""
def run(cmd): def run(self, cmd):
print "Executing: ", cmd print "Executing: ", cmd
assert not os.system(cmd) assert not os.system(cmd)
......
...@@ -254,6 +254,41 @@ class TreeReducerTest(unittest.TestCase): ...@@ -254,6 +254,41 @@ class TreeReducerTest(unittest.TestCase):
assert itm2c.root_branch.total == 12, itm2c.root_branch.total assert itm2c.root_branch.total == 12, itm2c.root_branch.total
class CacheIndexableTest(unittest.TestCase):
def get_iter(self):
"""Return iterator yielding indexed objects, add to dict d"""
for i in range(100):
it = rorpiter.IndexedTuple((i,), range(i))
self.d[(i,)] = it
yield it
def testCaching(self):
"""Test basic properties of CacheIndexable object"""
self.d = {}
ci = rorpiter.CacheIndexable(self.get_iter(), 3)
val0 = ci.next()
val1 = ci.next()
val2 = ci.next()
assert ci.get((1,)) == self.d[(1,)]
assert ci.get((3,)) is None
val3 = ci.next()
val4 = ci.next()
val5 = ci.next()
assert ci.get((3,)) == self.d[(3,)]
assert ci.get((4,)) == self.d[(4,)]
assert ci.get((1,)) is None
def testEqual(self):
"""Make sure CI doesn't alter properties of underlying iter"""
self.d = {}
l1 = list(self.get_iter())
l2 = list(rorpiter.CacheIndexable(iter(l1), 10))
assert l1 == l2, (l1, l2)
if __name__ == "__main__": unittest.main() if __name__ == "__main__": unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment