Merge "Put part-replicas where they go"

This commit is contained in:
Jenkins 2015-12-10 00:51:52 +00:00 committed by Gerrit Code Review
commit 0553d9333e
5 changed files with 2542 additions and 912 deletions

View File

@ -448,29 +448,19 @@ swift-ring-builder <builder_file>
print('The overload factor is %0.2f%% (%.6f)' % ( print('The overload factor is %0.2f%% (%.6f)' % (
builder.overload * 100, builder.overload)) builder.overload * 100, builder.overload))
if builder.devs: if builder.devs:
balance_per_dev = builder._build_balance_per_dev()
print('Devices: id region zone ip address port ' print('Devices: id region zone ip address port '
'replication ip replication port name ' 'replication ip replication port name '
'weight partitions balance flags meta') 'weight partitions balance flags meta')
weighted_parts = builder.parts * builder.replicas / \ for dev in builder._iter_devs():
sum(d['weight'] for d in builder.devs if d is not None)
for dev in builder.devs:
if dev is None:
continue
if not dev['weight']:
if dev['parts']:
balance = MAX_BALANCE
else:
balance = 0
else:
balance = 100.0 * dev['parts'] / \
(dev['weight'] * weighted_parts) - 100.0
flags = 'DEL' if dev in builder._remove_devs else '' flags = 'DEL' if dev in builder._remove_devs else ''
print(' %5d %7d %5d %15s %5d %15s %17d %9s %6.02f ' print(' %5d %7d %5d %15s %5d %15s %17d %9s %6.02f '
'%10s %7.02f %5s %s' % '%10s %7.02f %5s %s' %
(dev['id'], dev['region'], dev['zone'], dev['ip'], (dev['id'], dev['region'], dev['zone'], dev['ip'],
dev['port'], dev['replication_ip'], dev['port'], dev['replication_ip'],
dev['replication_port'], dev['device'], dev['weight'], dev['replication_port'], dev['device'], dev['weight'],
dev['parts'], balance, flags, dev['meta'])) dev['parts'], balance_per_dev[dev['id']], flags,
dev['meta']))
exit(EXIT_SUCCESS) exit(EXIT_SUCCESS)
def search(): def search():
@ -924,6 +914,8 @@ swift-ring-builder <builder_file> dispersion <search_filter> [options]
verbose=options.verbose) verbose=options.verbose)
print('Dispersion is %.06f, Balance is %.06f, Overload is %0.2f%%' % ( print('Dispersion is %.06f, Balance is %.06f, Overload is %0.2f%%' % (
builder.dispersion, builder.get_balance(), builder.overload * 100)) builder.dispersion, builder.get_balance(), builder.overload * 100))
print('Required overload is %.6f%%' % (
builder.get_required_overload() * 100))
if report['worst_tier']: if report['worst_tier']:
status = EXIT_WARNING status = EXIT_WARNING
print('Worst tier is %.06f (%s)' % (report['max_dispersion'], print('Worst tier is %.06f (%s)' % (report['max_dispersion'],
@ -1034,7 +1026,6 @@ swift-ring-builder <ring_file> write_builder [min_part_hours]
for parts in builder._replica2part2dev: for parts in builder._replica2part2dev:
for dev_id in parts: for dev_id in parts:
builder.devs[dev_id]['parts'] += 1 builder.devs[dev_id]['parts'] += 1
builder._set_parts_wanted()
builder.save(builder_file) builder.save(builder_file)
def pretend_min_part_hours_passed(): def pretend_min_part_hours_passed():

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -457,39 +457,42 @@ class TestRing(TestRingBase):
# Yes, these tests are deliberately very fragile. We want to make sure # Yes, these tests are deliberately very fragile. We want to make sure
# that if someone changes the results the ring produces, they know it. # that if someone changes the results the ring produces, they know it.
exp_part = 6 exp_part = 6
exp_devs = [48, 93, 96] exp_devs = [71, 77, 30]
exp_zones = set([5, 8, 9]) exp_zones = set([6, 3, 7])
exp_handoffs = [99, 43, 94, 13, 1, 49, 60, 72, 27, 68, 78, 26, 21, 9,
51, 105, 47, 89, 65, 82, 34, 98, 38, 85, 16, 4, 59,
102, 40, 90, 20, 8, 54, 66, 80, 25, 14, 2, 50, 12, 0,
48, 70, 76, 32, 107, 45, 87, 101, 44, 93, 100, 42, 95,
106, 46, 88, 97, 37, 86, 96, 36, 84, 17, 5, 57, 63,
81, 33, 67, 79, 24, 15, 3, 58, 69, 75, 31, 61, 74, 29,
23, 10, 52, 22, 11, 53, 64, 83, 35, 62, 73, 28, 18, 6,
56, 104, 39, 91, 103, 41, 92, 19, 7, 55]
exp_first_handoffs = [23, 64, 105, 102, 67, 17, 99, 65, 69, 97, 15,
17, 24, 98, 66, 65, 69, 18, 104, 105, 16, 107,
100, 15, 14, 19, 102, 105, 63, 104, 99, 12, 107,
99, 16, 105, 71, 15, 15, 63, 63, 99, 21, 68, 20,
64, 96, 21, 98, 19, 68, 99, 15, 69, 62, 100, 96,
102, 17, 62, 13, 61, 102, 105, 22, 16, 21, 18,
21, 100, 20, 16, 21, 106, 66, 106, 16, 99, 16,
22, 62, 60, 99, 69, 18, 23, 104, 98, 106, 61,
21, 23, 23, 16, 67, 71, 101, 16, 64, 66, 70, 15,
102, 63, 19, 98, 18, 106, 101, 100, 62, 63, 98,
18, 13, 97, 23, 22, 100, 13, 14, 67, 96, 14,
105, 97, 71, 64, 96, 22, 65, 66, 98, 19, 105,
98, 97, 21, 15, 69, 100, 98, 106, 65, 66, 97,
62, 22, 68, 63, 61, 67, 67, 20, 105, 106, 105,
18, 71, 100, 17, 62, 60, 13, 103, 99, 101, 96,
97, 16, 60, 21, 14, 20, 12, 60, 69, 104, 65, 65,
17, 16, 67, 13, 64, 15, 16, 68, 96, 21, 104, 66,
96, 105, 58, 105, 103, 21, 96, 60, 16, 96, 21,
71, 16, 99, 101, 63, 62, 103, 18, 102, 60, 17,
19, 106, 97, 14, 99, 68, 102, 13, 70, 103, 21,
22, 19, 61, 103, 23, 104, 65, 62, 68, 16, 65,
15, 102, 102, 71, 99, 63, 67, 19, 23, 15, 69,
107, 14, 13, 64, 13, 105, 15, 98, 69]
exp_handoffs = [11, 47, 25, 76, 69, 23, 99, 59, 106, 64, 43, 34, 88, 3,
30, 83, 16, 27, 103, 39, 60, 0, 8, 72, 56, 19, 91, 13,
84, 38, 66, 52, 78, 107, 50, 57, 31, 32, 77, 24, 42,
100, 71, 26, 9, 20, 35, 5, 14, 94, 28, 41, 18, 102,
101, 61, 95, 21, 81, 1, 105, 58, 74, 90, 86, 46, 4, 68,
40, 80, 54, 75, 45, 79, 44, 49, 62, 29, 7, 15, 70, 87,
65, 12, 82, 17, 104, 97, 55, 22, 6, 89, 2, 67, 37, 63,
53, 92, 33, 85, 73, 51, 98, 36, 10]
exp_first_handoffs = [1, 37, 48, 68, 84, 75, 11, 101, 14, 73, 100, 75,
29, 19, 18, 101, 15, 99, 95, 24, 46, 82, 73, 62,
24, 89, 9, 22, 107, 74, 54, 63, 40, 106, 99, 83,
64, 73, 73, 106, 106, 80, 6, 25, 20, 33, 6, 79,
59, 42, 62, 24, 14, 107, 28, 0, 85, 5, 4, 12, 58,
11, 92, 18, 36, 56, 86, 1, 21, 33, 80, 97, 4, 81,
79, 76, 89, 50, 75, 27, 7, 96, 47, 55, 81, 104,
12, 5, 18, 106, 27, 93, 39, 92, 42, 30, 20, 88,
58, 105, 65, 29, 17, 52, 11, 106, 7, 24, 21, 91,
62, 52, 50, 31, 77, 102, 19, 11, 8, 58, 53, 20,
26, 8, 18, 82, 48, 68, 82, 89, 101, 50, 3, 52,
46, 11, 2, 30, 79, 66, 4, 61, 3, 56, 45, 102, 73,
84, 36, 19, 34, 84, 49, 40, 103, 66, 31, 33, 93,
33, 4, 52, 26, 58, 30, 47, 100, 57, 40, 79, 33,
107, 24, 20, 44, 4, 7, 59, 83, 101, 1, 56, 20,
61, 33, 16, 5, 74, 98, 4, 80, 15, 104, 52, 73,
18, 67, 75, 98, 73, 79, 68, 75, 27, 91, 36, 100,
52, 95, 37, 46, 70, 14, 47, 3, 70, 23, 40, 105,
62, 86, 48, 22, 54, 4, 72, 81, 13, 0, 18, 98,
101, 36, 29, 24, 39, 79, 97, 105, 28, 107, 47,
52, 101, 20, 22, 29, 65, 27, 7, 33, 64, 101, 60,
19, 55]
rb = ring.RingBuilder(8, 3, 1) rb = ring.RingBuilder(8, 3, 1)
next_dev_id = 0 next_dev_id = 0
for zone in range(1, 10): for zone in range(1, 10):
@ -501,16 +504,27 @@ class TestRing(TestRingBase):
'zone': zone, 'region': 0, 'zone': zone, 'region': 0,
'weight': 1.0}) 'weight': 1.0})
next_dev_id += 1 next_dev_id += 1
rb.rebalance(seed=1) rb.rebalance(seed=2)
rb.get_ring().save(self.testgz) rb.get_ring().save(self.testgz)
r = ring.Ring(self.testdir, ring_name='whatever') r = ring.Ring(self.testdir, ring_name='whatever')
# every part has the same number of handoffs
part_handoff_counts = set()
for part in range(r.partition_count):
part_handoff_counts.add(len(list(r.get_more_nodes(part))))
self.assertEqual(part_handoff_counts, {105})
# which less the primaries - is every device in the ring
self.assertEqual(len(list(rb._iter_devs())) - rb.replicas, 105)
part, devs = r.get_nodes('a', 'c', 'o') part, devs = r.get_nodes('a', 'c', 'o')
primary_zones = set([d['zone'] for d in devs]) primary_zones = set([d['zone'] for d in devs])
self.assertEqual(part, exp_part) self.assertEqual(part, exp_part)
self.assertEqual([d['id'] for d in devs], exp_devs) self.assertEqual([d['id'] for d in devs], exp_devs)
self.assertEqual(primary_zones, exp_zones) self.assertEqual(primary_zones, exp_zones)
devs = list(r.get_more_nodes(part)) devs = list(r.get_more_nodes(part))
self.assertEqual([d['id'] for d in devs], exp_handoffs) self.assertEqual(len(devs), len(exp_handoffs))
dev_ids = [d['id'] for d in devs]
self.assertEqual(dev_ids, exp_handoffs)
# The first 6 replicas plus the 3 primary nodes should cover all 9 # The first 6 replicas plus the 3 primary nodes should cover all 9
# zones in this test # zones in this test
@ -531,11 +545,22 @@ class TestRing(TestRingBase):
'ip': '1.2.%d.%d' % (zone, server), 'ip': '1.2.%d.%d' % (zone, server),
'port': 1234, 'zone': zone, 'region': 0, 'weight': 1.0}) 'port': 1234, 'zone': zone, 'region': 0, 'weight': 1.0})
next_dev_id += 1 next_dev_id += 1
rb.rebalance(seed=1) rb.pretend_min_part_hours_passed()
num_parts_changed, _balance, _removed_dev = rb.rebalance(seed=2)
rb.get_ring().save(self.testgz) rb.get_ring().save(self.testgz)
r = ring.Ring(self.testdir, ring_name='whatever') r = ring.Ring(self.testdir, ring_name='whatever')
# We would change expectations here, but in this test no handoffs
# changed at all. # so now we expect the device list to be longer by one device
part_handoff_counts = set()
for part in range(r.partition_count):
part_handoff_counts.add(len(list(r.get_more_nodes(part))))
self.assertEqual(part_handoff_counts, {106})
self.assertEqual(len(list(rb._iter_devs())) - rb.replicas, 106)
# I don't think there's any special reason this dev goes at this index
exp_handoffs.insert(27, rb.devs[-1]['id'])
# We would change expectations here, but in this part only the added
# device changed at all.
part, devs = r.get_nodes('a', 'c', 'o') part, devs = r.get_nodes('a', 'c', 'o')
primary_zones = set([d['zone'] for d in devs]) primary_zones = set([d['zone'] for d in devs])
self.assertEqual(part, exp_part) self.assertEqual(part, exp_part)
@ -555,36 +580,60 @@ class TestRing(TestRingBase):
seen_zones.update([d['zone'] for d in devs[:6]]) seen_zones.update([d['zone'] for d in devs[:6]])
self.assertEqual(seen_zones, set(range(1, 10))) self.assertEqual(seen_zones, set(range(1, 10)))
# Change expectations for the rest of the parts
devs = [] devs = []
for part in range(r.partition_count): for part in range(r.partition_count):
devs.append(next(r.get_more_nodes(part))['id']) devs.append(next(r.get_more_nodes(part))['id'])
changed_first_handoff = 0
for part in range(r.partition_count): for part in range(r.partition_count):
self.assertEqual( if devs[part] != exp_first_handoffs[part]:
devs[part], exp_first_handoffs[part], changed_first_handoff += 1
'handoff for partitition %d is now device id %d' % ( exp_first_handoffs[part] = devs[part]
part, devs[part])) self.assertEqual(devs, exp_first_handoffs)
self.assertEqual(changed_first_handoff, num_parts_changed)
# Remove a device. # Remove a device - no need to fluff min_part_hours.
rb.remove_dev(0) rb.remove_dev(0)
rb.rebalance(seed=1) num_parts_changed, _balance, _removed_dev = rb.rebalance(seed=1)
rb.get_ring().save(self.testgz) rb.get_ring().save(self.testgz)
r = ring.Ring(self.testdir, ring_name='whatever') r = ring.Ring(self.testdir, ring_name='whatever')
# Change expectations
# The long string of handoff nodes for the partition were the same for # so now we expect the device list to be shorter by one device
# the first 20, which is pretty good. part_handoff_counts = set()
exp_handoffs[20:] = [60, 108, 8, 72, 56, 19, 91, 13, 84, 38, 66, 52, for part in range(r.partition_count):
1, 78, 107, 50, 57, 31, 32, 77, 24, 42, 100, 71, part_handoff_counts.add(len(list(r.get_more_nodes(part))))
26, 9, 20, 35, 5, 14, 94, 28, 41, 18, 102, 101, self.assertEqual(part_handoff_counts, {105})
61, 95, 21, 81, 105, 58, 74, 90, 86, 46, 4, 68, self.assertEqual(len(list(rb._iter_devs())) - rb.replicas, 105)
40, 80, 54, 75, 45, 79, 44, 49, 62, 29, 7, 15, 70,
87, 65, 12, 82, 17, 104, 97, 55, 22, 6, 89, 2, 67, # Change expectations for our part
37, 63, 53, 92, 33, 85, 73, 51, 98, 36, 10] exp_handoffs.remove(0)
# Just a few of the first handoffs changed first_matches = 0
exp_first_handoffs[3] = 68 total_changed = 0
exp_first_handoffs[55] = 104 devs = list(d['id'] for d in r.get_more_nodes(exp_part))
exp_first_handoffs[116] = 6 for i, part in enumerate(devs):
exp_first_handoffs[181] = 15 if exp_handoffs[i] != devs[i]:
exp_first_handoffs[228] = 38 total_changed += 1
exp_handoffs[i] = devs[i]
if not total_changed:
first_matches += 1
self.assertEqual(devs, exp_handoffs)
# the first 21 handoffs were the same across the rebalance
self.assertEqual(first_matches, 21)
# but as you dig deeper some of the differences show up
self.assertEqual(total_changed, 41)
# Change expectations for the rest of the parts
devs = []
for part in range(r.partition_count):
devs.append(next(r.get_more_nodes(part))['id'])
changed_first_handoff = 0
for part in range(r.partition_count):
if devs[part] != exp_first_handoffs[part]:
changed_first_handoff += 1
exp_first_handoffs[part] = devs[part]
self.assertEqual(devs, exp_first_handoffs)
self.assertEqual(changed_first_handoff, num_parts_changed)
# Test # Test
part, devs = r.get_nodes('a', 'c', 'o') part, devs = r.get_nodes('a', 'c', 'o')
primary_zones = set([d['zone'] for d in devs]) primary_zones = set([d['zone'] for d in devs])
@ -615,56 +664,48 @@ class TestRing(TestRingBase):
# Add a partial replica # Add a partial replica
rb.set_replicas(3.5) rb.set_replicas(3.5)
rb.rebalance(seed=1) num_parts_changed, _balance, _removed_dev = rb.rebalance(seed=164)
rb.get_ring().save(self.testgz) rb.get_ring().save(self.testgz)
r = ring.Ring(self.testdir, ring_name='whatever') r = ring.Ring(self.testdir, ring_name='whatever')
# Change expectations # Change expectations
# We have another replica now # We have another replica now
exp_devs.append(47) exp_devs.append(90)
exp_zones.add(4) exp_zones.add(8)
# and therefore one less handoff
exp_handoffs = exp_handoffs[:-1]
# Caused some major changes in the sequence of handoffs for our test # Caused some major changes in the sequence of handoffs for our test
# partition, but at least the first stayed the same. # partition, but at least the first stayed the same.
exp_handoffs[1:] = [81, 25, 69, 23, 99, 59, 76, 3, 106, 64, 43, 13, 34, devs = list(d['id'] for d in r.get_more_nodes(exp_part))
88, 30, 16, 27, 103, 39, 74, 60, 108, 8, 56, 19, first_matches = 0
91, 52, 84, 38, 66, 1, 78, 45, 107, 50, 57, 83, 31, total_changed = 0
46, 32, 77, 24, 42, 63, 100, 72, 71, 7, 26, 9, 20, for i, part in enumerate(devs):
35, 5, 87, 14, 94, 62, 28, 41, 90, 18, 82, 102, 22, if exp_handoffs[i] != devs[i]:
101, 61, 85, 95, 21, 98, 67, 105, 58, 86, 4, 79, total_changed += 1
68, 40, 80, 54, 75, 44, 49, 6, 29, 15, 70, 65, 12, exp_handoffs[i] = devs[i]
17, 104, 97, 55, 89, 2, 37, 53, 92, 33, 73, 51, 36, if not total_changed:
10] first_matches += 1
# most seeds seem to throw out first handoff stabilization with
# replica_count change
self.assertEqual(first_matches, 2)
# and lots of other handoff changes...
self.assertEqual(total_changed, 95)
self.assertEqual(devs, exp_handoffs)
# Change expectations for the rest of the parts
devs = []
for part in range(r.partition_count):
devs.append(next(r.get_more_nodes(part))['id'])
changed_first_handoff = 0
for part in range(r.partition_count):
if devs[part] != exp_first_handoffs[part]:
changed_first_handoff += 1
exp_first_handoffs[part] = devs[part]
self.assertEqual(devs, exp_first_handoffs)
self.assertLessEqual(changed_first_handoff, num_parts_changed)
# Lots of first handoffs changed, but 30 of 256 is still just 11.72%.
exp_first_handoffs[1] = 6
exp_first_handoffs[4] = 104
exp_first_handoffs[11] = 106
exp_first_handoffs[17] = 13
exp_first_handoffs[21] = 77
exp_first_handoffs[22] = 95
exp_first_handoffs[27] = 46
exp_first_handoffs[29] = 65
exp_first_handoffs[30] = 3
exp_first_handoffs[31] = 20
exp_first_handoffs[51] = 50
exp_first_handoffs[53] = 8
exp_first_handoffs[54] = 2
exp_first_handoffs[72] = 107
exp_first_handoffs[79] = 72
exp_first_handoffs[85] = 71
exp_first_handoffs[88] = 66
exp_first_handoffs[92] = 29
exp_first_handoffs[93] = 46
exp_first_handoffs[96] = 38
exp_first_handoffs[101] = 57
exp_first_handoffs[103] = 87
exp_first_handoffs[104] = 28
exp_first_handoffs[107] = 1
exp_first_handoffs[109] = 69
exp_first_handoffs[110] = 50
exp_first_handoffs[111] = 76
exp_first_handoffs[115] = 47
exp_first_handoffs[117] = 48
exp_first_handoffs[119] = 7
# Test # Test
part, devs = r.get_nodes('a', 'c', 'o') part, devs = r.get_nodes('a', 'c', 'o')
primary_zones = set([d['zone'] for d in devs]) primary_zones = set([d['zone'] for d in devs])
@ -696,17 +737,16 @@ class TestRing(TestRingBase):
# One last test of a partial replica partition # One last test of a partial replica partition
exp_part2 = 136 exp_part2 = 136
exp_devs2 = [52, 76, 97] exp_devs2 = [70, 76, 32]
exp_zones2 = set([9, 5, 7]) exp_zones2 = set([3, 6, 7])
exp_handoffs2 = [2, 67, 37, 92, 33, 23, 107, 63, 44, 103, 108, 85, exp_handoffs2 = [89, 97, 37, 53, 20, 1, 86, 64, 102, 40, 90, 60, 72,
73, 10, 89, 80, 4, 17, 49, 32, 12, 41, 58, 20, 25, 27, 99, 68, 78, 26, 105, 45, 42, 95, 22, 13, 49, 55,
61, 94, 47, 69, 56, 101, 28, 83, 8, 96, 53, 51, 42, 11, 8, 83, 16, 4, 59, 33, 108, 61, 74, 29, 88, 66,
98, 35, 36, 84, 43, 104, 31, 65, 1, 40, 9, 74, 95, 80, 25, 100, 39, 67, 79, 24, 65, 96, 36, 84, 54, 21,
45, 5, 71, 86, 78, 30, 93, 48, 91, 15, 88, 39, 18, 63, 81, 56, 71, 77, 30, 48, 23, 10, 52, 82, 34, 17,
57, 72, 70, 27, 54, 16, 24, 21, 14, 11, 77, 62, 50, 107, 87, 104, 5, 35, 2, 50, 43, 62, 73, 28, 18, 14,
6, 105, 26, 55, 29, 60, 34, 13, 87, 59, 38, 99, 75, 98, 38, 85, 15, 57, 9, 51, 12, 6, 91, 3, 103, 41, 92,
106, 3, 82, 66, 79, 7, 46, 64, 81, 22, 68, 19, 102, 47, 75, 44, 69, 101, 93, 106, 46, 94, 31, 19, 7, 58]
90, 100]
part2, devs2 = r.get_nodes('a', 'c', 'o2') part2, devs2 = r.get_nodes('a', 'c', 'o2')
primary_zones2 = set([d['zone'] for d in devs2]) primary_zones2 = set([d['zone'] for d in devs2])
@ -764,14 +804,15 @@ class TestRing(TestRingBase):
# Here's a brittle canary-in-the-coalmine test to make sure the region # Here's a brittle canary-in-the-coalmine test to make sure the region
# handoff computation didn't change accidentally # handoff computation didn't change accidentally
exp_handoffs = [111, 112, 74, 54, 93, 31, 2, 43, 100, 22, 71, 92, 35, exp_handoffs = [111, 112, 35, 58, 62, 74, 20, 105, 41, 90, 53, 6, 3,
9, 50, 41, 76, 80, 84, 88, 17, 96, 6, 102, 37, 29, 67, 55, 76, 108, 32, 12, 80, 38, 85, 94, 42, 27, 99,
105, 5, 47, 20, 13, 108, 66, 81, 53, 65, 25, 58, 32, 50, 47, 70, 87, 26, 9, 15, 97, 102, 81, 23, 65, 33,
94, 101, 1, 10, 44, 73, 75, 21, 97, 28, 106, 30, 16, 77, 34, 4, 75, 8, 5, 30, 13, 73, 36, 92, 54, 51, 72,
39, 77, 42, 72, 34, 99, 14, 61, 90, 4, 40, 3, 45, 62, 78, 66, 1, 48, 14, 93, 95, 88, 86, 84, 106, 60, 101,
7, 15, 87, 12, 83, 89, 33, 98, 49, 107, 56, 86, 48, 57, 43, 89, 59, 79, 46, 61, 52, 44, 45, 37, 68, 25,
57, 24, 11, 23, 26, 46, 64, 69, 38, 36, 79, 63, 104, 100, 49, 24, 16, 71, 96, 21, 107, 98, 64, 39, 18, 29,
51, 70, 82, 67, 68, 8, 95, 91, 55, 59, 85] 103, 91, 22, 63, 69, 28, 56, 11, 82, 10, 17, 19, 7,
40, 83, 104, 31]
dev_ids = [d['id'] for d in more_devs] dev_ids = [d['id'] for d in more_devs]
self.assertEqual(len(dev_ids), len(exp_handoffs)) self.assertEqual(len(dev_ids), len(exp_handoffs))

View File

@ -692,10 +692,10 @@ class TestUtils(unittest.TestCase):
rb.rebalance(seed=100) rb.rebalance(seed=100)
rb.validate() rb.validate()
self.assertEqual(rb.dispersion, 39.0625) self.assertEqual(rb.dispersion, 39.84375)
report = dispersion_report(rb) report = dispersion_report(rb)
self.assertEqual(report['worst_tier'], 'r1z1') self.assertEqual(report['worst_tier'], 'r1z1')
self.assertEqual(report['max_dispersion'], 39.0625) self.assertEqual(report['max_dispersion'], 39.84375)
def build_tier_report(max_replicas, placed_parts, dispersion, def build_tier_report(max_replicas, placed_parts, dispersion,
replicas): replicas):
@ -711,11 +711,11 @@ class TestUtils(unittest.TestCase):
# zone 1 are stored at least twice on the nodes # zone 1 are stored at least twice on the nodes
expected = [ expected = [
['r1z1', build_tier_report( ['r1z1', build_tier_report(
2, 256, 39.0625, [0, 0, 156, 100])], 2, 256, 39.84375, [0, 0, 154, 102])],
['r1z1-127.0.0.1', build_tier_report( ['r1z1-127.0.0.1', build_tier_report(
1, 256, 19.53125, [0, 206, 50, 0])], 1, 256, 19.921875, [0, 205, 51, 0])],
['r1z1-127.0.0.2', build_tier_report( ['r1z1-127.0.0.2', build_tier_report(
1, 256, 19.53125, [0, 206, 50, 0])], 1, 256, 19.921875, [0, 205, 51, 0])],
] ]
report = dispersion_report(rb, 'r1z1[^/]*$', verbose=True) report = dispersion_report(rb, 'r1z1[^/]*$', verbose=True)
graph = report['graph'] graph = report['graph']
@ -735,12 +735,18 @@ class TestUtils(unittest.TestCase):
'ip': '127.0.0.3', 'port': 10003, 'device': 'sdc1'}) 'ip': '127.0.0.3', 'port': 10003, 'device': 'sdc1'})
rb.add_dev({'id': 15, 'region': 1, 'zone': 0, 'weight': 500, rb.add_dev({'id': 15, 'region': 1, 'zone': 0, 'weight': 500,
'ip': '127.0.0.3', 'port': 10003, 'device': 'sdd1'}) 'ip': '127.0.0.3', 'port': 10003, 'device': 'sdd1'})
rb.rebalance(seed=10)
report = dispersion_report(rb) # when the biggest tier has the smallest devices things get ugly
self.assertEqual(rb.dispersion, 44.53125) rb.rebalance(seed=100)
report = dispersion_report(rb, verbose=True)
self.assertEqual(rb.dispersion, 70.3125)
self.assertEqual(report['worst_tier'], 'r1z0-127.0.0.3') self.assertEqual(report['worst_tier'], 'r1z0-127.0.0.3')
self.assertEqual(report['max_dispersion'], 32.520325203252035) self.assertEqual(report['max_dispersion'], 88.23529411764706)
# ... but overload can square it
rb.set_overload(rb.get_required_overload())
rb.rebalance()
self.assertEqual(rb.dispersion, 0.0)
def test_parse_address_old_format(self): def test_parse_address_old_format(self):
# Test old format # Test old format