From f4adb2f28f5517772174aac18e3fe9ab1d08c913 Mon Sep 17 00:00:00 2001 From: Clay Gerrard Date: Mon, 7 Nov 2016 18:06:44 -0800 Subject: [PATCH] Fix ZeroDivisionError in reconstructor.stats_line Despite a check to prevent zero values in the denominator python integer division could result in ZeroDivisionError in the compute_eta helper function. Make sure we always have a non-zero value even if it is small. NotImplemented: * stats calculation is still not great, see lp bug #1488608 Closes-Bug: #1549110 Change-Id: I54f2081c92c2a0b8f02c31e82f44f4250043d837 --- swift/obj/reconstructor.py | 2 +- test/unit/__init__.py | 1 + test/unit/obj/test_reconstructor.py | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/swift/obj/reconstructor.py b/swift/obj/reconstructor.py index f5aad1e9b1..3758906ef4 100644 --- a/swift/obj/reconstructor.py +++ b/swift/obj/reconstructor.py @@ -354,7 +354,7 @@ class ObjectReconstructor(Daemon): self.reconstruction_device_count): elapsed = (time.time() - self.start) or 0.000001 rate = self.reconstruction_part_count / elapsed - total_part_count = (self.part_count * + total_part_count = (1.0 * self.part_count * self.device_count / self.reconstruction_device_count) self.logger.info( diff --git a/test/unit/__init__.py b/test/unit/__init__.py index ee2a262bf2..90f2539074 100644 --- a/test/unit/__init__.py +++ b/test/unit/__init__.py @@ -200,6 +200,7 @@ class PatchPolicies(object): def __enter__(self): self._orig_POLICIES = storage_policy._POLICIES storage_policy._POLICIES = self.policies + self._setup_rings() def __exit__(self, *args): storage_policy._POLICIES = self._orig_POLICIES diff --git a/test/unit/obj/test_reconstructor.py b/test/unit/obj/test_reconstructor.py index 3693d54880..cec08ce506 100644 --- a/test/unit/obj/test_reconstructor.py +++ b/test/unit/obj/test_reconstructor.py @@ -1145,6 +1145,9 @@ class TestObjectReconstructor(unittest.TestCase): # directly, so you end up with a /0 when you try to show the # percentage of complete jobs as ratio of the total job count self.reconstructor.job_count = 1 + # if we ever let a test through without properly patching the + # REPLICATE and SSYNC calls - let's fail sort fast-ish + self.reconstructor.lockup_timeout = 3 def tearDown(self): self.reconstructor._reset_stats() @@ -1154,6 +1157,29 @@ class TestObjectReconstructor(unittest.TestCase): def ts(self): return next(self.ts_iter) + def test_two_ec_policies(self): + with patch_policies([ + StoragePolicy(0, name='zero', is_deprecated=True), + ECStoragePolicy(1, name='one', is_default=True, + ec_type=DEFAULT_TEST_EC_TYPE, + ec_ndata=4, ec_nparity=3), + ECStoragePolicy(2, name='two', + ec_type=DEFAULT_TEST_EC_TYPE, + ec_ndata=8, ec_nparity=2)], + fake_ring_args=[ + {}, {'replicas': 7}, {'replicas': 10}]): + self._configure_reconstructor() + jobs = [] + + def process_job(job): + jobs.append(job) + + self.reconstructor.process_job = process_job + + os.makedirs(os.path.join(self.devices, 'sda', 'objects-1', '0')) + self.reconstructor.run_once() + self.assertEqual(1, len(jobs)) + def test_collect_parts_skips_non_ec_policy_and_device(self): stub_parts = (371, 78, 419, 834) for policy in POLICIES: