From 6dbef907ac515e3982e8652b36bbdac4a7410e6f Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Thu, 23 Oct 2008 21:00:24 -0700 Subject: [PATCH] mutable/servermap.py: fix needs_merge(), it was incorrectly claiming that mixed shares with distinct seqnums needed a merge, causing repair(force=False) to fail --- src/allmydata/mutable/servermap.py | 7 ++++++- src/allmydata/test/test_mutable.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/allmydata/mutable/servermap.py b/src/allmydata/mutable/servermap.py index 8c219616..ad174bd2 100644 --- a/src/allmydata/mutable/servermap.py +++ b/src/allmydata/mutable/servermap.py @@ -329,7 +329,12 @@ class ServerMap: # same seqnum, meaning that MutableFileNode.read_best_version is not # giving you the whole story, and that using its data to do a # subsequent publish will lose information. - return bool(len(self.recoverable_versions()) > 1) + recoverable_seqnums = [verinfo[0] + for verinfo in self.recoverable_versions()] + for seqnum in recoverable_seqnums: + if recoverable_seqnums.count(seqnum) > 1: + return True + return False class ServermapUpdater: diff --git a/src/allmydata/test/test_mutable.py b/src/allmydata/test/test_mutable.py index 409bc930..c34509ad 100644 --- a/src/allmydata/test/test_mutable.py +++ b/src/allmydata/test/test_mutable.py @@ -1399,6 +1399,36 @@ class Repair(unittest.TestCase, PublishMixin, ShouldFailMixin): d.addCallback(_check_smap) return d + def test_non_merge(self): + self.old_shares = [] + d = self.publish_multiple() + # repair should not refuse a repair that doesn't need to merge. In + # this case, we combine v2 with v3. The repair should ignore v2 and + # copy v3 into a new v5. + d.addCallback(lambda res: + self._set_versions({0:2,2:2,4:2,6:2,8:2, + 1:3,3:3,5:3,7:3,9:3})) + d.addCallback(lambda res: self._fn.check(Monitor())) + d.addCallback(lambda check_results: self._fn.repair(check_results)) + # this should give us 10 shares of v3 + def _check_repair_results(rres): + pass # TODO + d.addCallback(_check_repair_results) + d.addCallback(lambda res: self._fn.get_servermap(MODE_CHECK)) + def _check_smap(smap): + self.failUnlessEqual(len(smap.recoverable_versions()), 1) + self.failIf(smap.unrecoverable_versions()) + # now, which should have won? + roothash_s4a = self.get_roothash_for(3) + expected_contents = self.CONTENTS[3] + new_versionid = smap.best_recoverable_version() + self.failUnlessEqual(new_versionid[0], 5) # seqnum 5 + d2 = self._fn.download_version(smap, new_versionid) + d2.addCallback(self.failUnlessEqual, expected_contents) + return d2 + d.addCallback(_check_smap) + return d + def get_roothash_for(self, index): # return the roothash for the first share we see in the saved set shares = self._copied_shares[index] -- 2.45.2