diff --git a/swift/container/sharder.py b/swift/container/sharder.py index a2d811f376..5abfb9f8eb 100644 --- a/swift/container/sharder.py +++ b/swift/container/sharder.py @@ -108,12 +108,13 @@ def find_overlapping_ranges(shard_ranges): each other. """ result = set() - for shard_range in shard_ranges: - overlapping = [sr for sr in shard_ranges - if shard_range != sr and shard_range.overlaps(sr)] + for i, shard_range in enumerate(shard_ranges): + overlapping = [ + sr for sr in shard_ranges[i + 1:] + if shard_range.name != sr.name and shard_range.overlaps(sr)] if overlapping: overlapping.append(shard_range) - overlapping.sort() + overlapping.sort(key=ShardRange.sort_key) result.add(tuple(overlapping)) return result @@ -994,12 +995,14 @@ class ContainerSharder(ContainerReplicator): continue shard_ranges = broker.get_shard_ranges(states=state) overlaps = find_overlapping_ranges(shard_ranges) - for overlapping_ranges in overlaps: + if overlaps: + all_overlaps = ', '.join( + [' '.join(['%s-%s' % (sr.lower, sr.upper) + for sr in overlapping_ranges]) + for overlapping_ranges in sorted(list(overlaps))]) warnings.append( - 'overlapping ranges in state %s: %s' % - (ShardRange.STATES[state], - ' '.join(['%s-%s' % (sr.lower, sr.upper) - for sr in overlapping_ranges]))) + 'overlapping ranges in state %r: %s' % + (ShardRange.STATES[state], all_overlaps)) if warnings: self.logger.warning( diff --git a/test/unit/container/test_sharder.py b/test/unit/container/test_sharder.py index a3cc933d08..ae7c3e5aa8 100644 --- a/test/unit/container/test_sharder.py +++ b/test/unit/container/test_sharder.py @@ -117,10 +117,10 @@ class BaseTestSharder(unittest.TestCase): if not isinstance(state, (tuple, list)): state = [state] * len(bounds) state_iter = iter(state) - return [ShardRange('.shards_a/c_%s' % upper, timestamp, + return [ShardRange('.shards_a/c_%s_%s' % (upper, index), timestamp, lower, upper, state=next(state_iter), object_count=object_count, **kwargs) - for lower, upper in bounds] + for index, (lower, upper) in enumerate(bounds)] def ts_encoded(self): # make a unique timestamp string with multiple timestamps encoded; @@ -4859,11 +4859,14 @@ class TestSharder(BaseTestSharder): self.assertIn( 'Audit failed for root %s' % broker.db_file, line) self.assertIn( - 'overlapping ranges in state %s: k-t s-z' % state_text, - line) + 'overlapping ranges in state %r: k-t s-y, y-z y-z' + % state_text, line) + # check for no duplicates in reversed order + self.assertNotIn('s-z k-t', line) expected_stats = {'attempted': 1, 'success': 0, 'failure': 1} - shard_bounds = (('a', 'j'), ('k', 't'), ('s', 'z')) + shard_bounds = (('a', 'j'), ('k', 't'), ('s', 'y'), + ('y', 'z'), ('y', 'z')) for state, state_text in ShardRange.STATES.items(): if state in (ShardRange.SHRINKING, ShardRange.SHARDED,