From 5f3b0e5826049499148086b91d8139b8679e1a01 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Sun, 26 Sep 2021 15:55:12 -0500 Subject: [PATCH] MetaStoreWriter.__del__: replace with context management Signed-off-by: Rob Browning Tested-by: Rob Browning --- lib/bup/cmd/index.py | 8 +- lib/bup/cmd/save.py | 1 - lib/bup/index.py | 9 ++- test/int/test_index.py | 179 +++++++++++++++++++++-------------------- 4 files changed, 100 insertions(+), 97 deletions(-) diff --git a/lib/bup/cmd/index.py b/lib/bup/cmd/index.py index d4d9cae..d79cb21 100755 --- a/lib/bup/cmd/index.py +++ b/lib/bup/cmd/index.py @@ -74,11 +74,12 @@ def update_index(top, excluded_paths, exclude_rxs, indexfile, # tmax must be epoch nanoseconds. tmax = (time.time() - 1) * 10**9 ri = index.Reader(indexfile) - msw = index.MetaStoreWriter(indexfile + b'.meta') - wi = index.Writer(indexfile, msw, tmax) rig = IterHelper(ri.iter(name=top)) - with hlinkdb.HLinkDB(indexfile + b'.hlink') as hlinks: + with index.MetaStoreWriter(indexfile + b'.meta') as msw, \ + hlinkdb.HLinkDB(indexfile + b'.hlink') as hlinks: + + wi = index.Writer(indexfile, msw, tmax) fake_hash = None if fake_valid: @@ -199,7 +200,6 @@ def update_index(top, excluded_paths, exclude_rxs, indexfile, else: wi.close() - msw.close() hlinks.commit_save() diff --git a/lib/bup/cmd/save.py b/lib/bup/cmd/save.py index 3c889e2..1153cd5 100755 --- a/lib/bup/cmd/save.py +++ b/lib/bup/cmd/save.py @@ -459,7 +459,6 @@ def save_tree(opt, indexfile, hlink_db, msr, w): # When there's a collision, use empty metadata for the root. tree = _pop(dir_metadata = metadata.Metadata() if root_collision else None) - msr.close() return tree diff --git a/lib/bup/index.py b/lib/bup/index.py index dd24d93..d0df52a 100644 --- a/lib/bup/index.py +++ b/lib/bup/index.py @@ -105,9 +105,12 @@ class MetaStoreWriter: self._file.close() self._file = None - def __del__(self): - # Be optimistic. - self.close() + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + with pending_raise(value, rethrow=False): + self.close() def store(self, metadata): meta_encoded = metadata.encode(include_path=False) diff --git a/test/int/test_index.py b/test/int/test_index.py index f24b719..c71b90f 100644 --- a/test/int/test_index.py +++ b/test/int/test_index.py @@ -31,14 +31,13 @@ def test_index_writer(tmpdir): os.chdir(tmpdir) ds = xstat.stat(b'.') fs = xstat.stat(lib_t_dir + b'/test_index.py') - ms = index.MetaStoreWriter(b'index.meta.tmp'); - tmax = (time.time() - 1) * 10**9 - w = index.Writer(b'index.tmp', ms, tmax) - w.add(b'/var/tmp/sporky', fs, 0) - w.add(b'/etc/passwd', fs, 0) - w.add(b'/etc/', ds, 0) - w.add(b'/', ds, 0) - ms.close() + with index.MetaStoreWriter(b'index.meta.tmp') as ms: + tmax = (time.time() - 1) * 10**9 + w = index.Writer(b'index.tmp', ms, tmax) + w.add(b'/var/tmp/sporky', fs, 0) + w.add(b'/etc/passwd', fs, 0) + w.add(b'/etc/', ds, 0) + w.add(b'/', ds, 0) w.close() finally: os.chdir(orig_cwd) @@ -88,86 +87,88 @@ def test_index_dirty(tmpdir): try: os.chdir(tmpdir) default_meta = metadata.Metadata() - ms1 = index.MetaStoreWriter(b'index.meta.tmp') - ms2 = index.MetaStoreWriter(b'index2.meta.tmp') - ms3 = index.MetaStoreWriter(b'index3.meta.tmp') - meta_ofs1 = ms1.store(default_meta) - meta_ofs2 = ms2.store(default_meta) - meta_ofs3 = ms3.store(default_meta) - - ds = xstat.stat(lib_t_dir) - fs = xstat.stat(lib_t_dir + b'/test_index.py') - tmax = (time.time() - 1) * 10**9 - - w1 = index.Writer(b'index.tmp', ms1, tmax) - w1.add(b'/a/b/x', fs, meta_ofs1) - w1.add(b'/a/b/c', fs, meta_ofs1) - w1.add(b'/a/b/', ds, meta_ofs1) - w1.add(b'/a/', ds, meta_ofs1) - #w1.close() - WVPASS() - - w2 = index.Writer(b'index2.tmp', ms2, tmax) - w2.add(b'/a/b/n/2', fs, meta_ofs2) - #w2.close() - WVPASS() - - w3 = index.Writer(b'index3.tmp', ms3, tmax) - w3.add(b'/a/c/n/3', fs, meta_ofs3) - #w3.close() - WVPASS() - - r1 = w1.new_reader() - r2 = w2.new_reader() - r3 = w3.new_reader() - WVPASS() - - r1all = [e.name for e in r1] - WVPASSEQ(r1all, - [b'/a/b/x', b'/a/b/c', b'/a/b/', b'/a/', b'/']) - r2all = [e.name for e in r2] - WVPASSEQ(r2all, - [b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) - r3all = [e.name for e in r3] - WVPASSEQ(r3all, - [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', b'/a/', b'/']) - all = [e.name for e in index.merge(r2, r1, r3)] - WVPASSEQ(all, - [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', - b'/a/b/x', b'/a/b/n/2', b'/a/b/n/', b'/a/b/c', - b'/a/b/', b'/a/', b'/']) - fake_validate(r1) - dump(r1) - - print([hex(e.flags) for e in r1]) - WVPASSEQ([e.name for e in r1 if e.is_valid()], r1all) - WVPASSEQ([e.name for e in r1 if not e.is_valid()], []) - WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], - [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', - b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) - - expect_invalid = [b'/'] + r2all + r3all - expect_real = (set(r1all) - set(r2all) - set(r3all)) \ - | set([b'/a/b/n/2', b'/a/c/n/3']) - dump(index.merge(r2, r1, r3)) - for e in index.merge(r2, r1, r3): - print(e.name, hex(e.flags), e.ctime) - eiv = e.name in expect_invalid - er = e.name in expect_real - WVPASSEQ(eiv, not e.is_valid()) - WVPASSEQ(er, e.is_real()) - fake_validate(r2, r3) - dump(index.merge(r2, r1, r3)) - WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], []) - - e = eget(index.merge(r2, r1, r3), b'/a/b/c') - e.invalidate() - e.repack() - dump(index.merge(r2, r1, r3)) - WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], - [b'/a/b/c', b'/a/b/', b'/a/', b'/']) - w1.close() - w2.close() - w3.close() + + with index.MetaStoreWriter(b'index.meta.tmp') as ms1, \ + index.MetaStoreWriter(b'index2.meta.tmp') as ms2, \ + index.MetaStoreWriter(b'index3.meta.tmp') as ms3: + + meta_ofs1 = ms1.store(default_meta) + meta_ofs2 = ms2.store(default_meta) + meta_ofs3 = ms3.store(default_meta) + + ds = xstat.stat(lib_t_dir) + fs = xstat.stat(lib_t_dir + b'/test_index.py') + tmax = (time.time() - 1) * 10**9 + + w1 = index.Writer(b'index.tmp', ms1, tmax) + w1.add(b'/a/b/x', fs, meta_ofs1) + w1.add(b'/a/b/c', fs, meta_ofs1) + w1.add(b'/a/b/', ds, meta_ofs1) + w1.add(b'/a/', ds, meta_ofs1) + #w1.close() + WVPASS() + + w2 = index.Writer(b'index2.tmp', ms2, tmax) + w2.add(b'/a/b/n/2', fs, meta_ofs2) + #w2.close() + WVPASS() + + w3 = index.Writer(b'index3.tmp', ms3, tmax) + w3.add(b'/a/c/n/3', fs, meta_ofs3) + #w3.close() + WVPASS() + + r1 = w1.new_reader() + r2 = w2.new_reader() + r3 = w3.new_reader() + WVPASS() + + r1all = [e.name for e in r1] + WVPASSEQ(r1all, + [b'/a/b/x', b'/a/b/c', b'/a/b/', b'/a/', b'/']) + r2all = [e.name for e in r2] + WVPASSEQ(r2all, + [b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) + r3all = [e.name for e in r3] + WVPASSEQ(r3all, + [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', b'/a/', b'/']) + all = [e.name for e in index.merge(r2, r1, r3)] + WVPASSEQ(all, + [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', + b'/a/b/x', b'/a/b/n/2', b'/a/b/n/', b'/a/b/c', + b'/a/b/', b'/a/', b'/']) + fake_validate(r1) + dump(r1) + + print([hex(e.flags) for e in r1]) + WVPASSEQ([e.name for e in r1 if e.is_valid()], r1all) + WVPASSEQ([e.name for e in r1 if not e.is_valid()], []) + WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], + [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', + b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) + + expect_invalid = [b'/'] + r2all + r3all + expect_real = (set(r1all) - set(r2all) - set(r3all)) \ + | set([b'/a/b/n/2', b'/a/c/n/3']) + dump(index.merge(r2, r1, r3)) + for e in index.merge(r2, r1, r3): + print(e.name, hex(e.flags), e.ctime) + eiv = e.name in expect_invalid + er = e.name in expect_real + WVPASSEQ(eiv, not e.is_valid()) + WVPASSEQ(er, e.is_real()) + fake_validate(r2, r3) + dump(index.merge(r2, r1, r3)) + WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], []) + + e = eget(index.merge(r2, r1, r3), b'/a/b/c') + e.invalidate() + e.repack() + dump(index.merge(r2, r1, r3)) + WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], + [b'/a/b/c', b'/a/b/', b'/a/', b'/']) + w1.close() + w2.close() + w3.close() finally: os.chdir(orig_cwd) -- 2.39.2