sharder: report perfectly overlapping shard ranges

Previously, shard ranges that overlapped perfectly (i.e. their bounds
were equal) were erroneously excluded from overlapping shard reports.
With this patch they will be reported in logs and cause shard audit
failures.

Also, the format of the audit log line is simplified to avoid
unnecessary duplication of information.

Change-Id: Ie15c9f40a132374c89337f0009fb5cf5a8e62c51
Closes-Bug: #1928459
Related-Bug: #1913332
This commit is contained in:
Alistair Coles 2021-05-14 13:59:37 +01:00
parent 9edcfad22f
commit 1b183f221d
2 changed files with 20 additions and 14 deletions

View File

@ -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(

View File

@ -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,