Skip to content

Commit

Permalink
Merge "add swift-ring-builder option to recalculate dispersion"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and openstack-gerrit committed Jan 3, 2018
2 parents 507a4fa + 49de7db commit 3aa17e6
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 4 deletions.
10 changes: 9 additions & 1 deletion swift/cli/ringbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,7 @@ def dispersion():
Output report on dispersion.
--recalculate option will rebuild cached dispersion info and save builder
--verbose option will display dispersion graph broken down by tier
You can filter which tiers are evaluated to drill down using a regex
Expand Down Expand Up @@ -1042,15 +1043,22 @@ def dispersion():
exit(EXIT_ERROR)
usage = Commands.dispersion.__doc__.strip()
parser = optparse.OptionParser(usage)
parser.add_option('--recalculate', action='store_true',
help='Rebuild cached dispersion info and save')
parser.add_option('-v', '--verbose', action='store_true',
help='Display dispersion report for tiers')
options, args = parser.parse_args(argv)
if args[3:]:
search_filter = args[3]
else:
search_filter = None
orig_version = builder.version
report = dispersion_report(builder, search_filter=search_filter,
verbose=options.verbose)
verbose=options.verbose,
recalculate=options.recalculate)
if builder.version != orig_version:
# we've already done the work, better go ahead and save it!
builder.save(builder_file)
print('Dispersion is %.06f, Balance is %.06f, Overload is %0.2f%%' % (
builder.dispersion, builder.get_balance(), builder.overload * 100))
print('Required overload is %.6f%%' % (
Expand Down
2 changes: 1 addition & 1 deletion swift/common/ring/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,6 @@ def rebalance(self, seed=None):
{'status': finish_status, 'count': gather_count + 1})

self.devs_changed = False
self.version += 1
changed_parts = self._build_dispersion_graph(old_replica2part2dev)

# clean up the cache
Expand Down Expand Up @@ -639,6 +638,7 @@ def _build_dispersion_graph(self, old_replica2part2dev=None):
parts_at_risk += max(part_risk_depth.values())
self._dispersion_graph = dispersion_graph
self.dispersion = 100.0 * parts_at_risk / (self.parts * self.replicas)
self.version += 1
return changed_parts

def validate(self, stats=False):
Expand Down
5 changes: 3 additions & 2 deletions swift/common/ring/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,8 +606,9 @@ def build_dev_from_opts(opts):
'replication_port': replication_port, 'weight': opts.weight}


def dispersion_report(builder, search_filter=None, verbose=False):
if not builder._dispersion_graph:
def dispersion_report(builder, search_filter=None,
verbose=False, recalculate=False):
if recalculate or not builder._dispersion_graph:
builder._build_dispersion_graph()
max_allowed_replicas = builder._build_max_replicas_by_tier()
worst_tier = None
Expand Down
22 changes: 22 additions & 0 deletions test/unit/cli/test_ringbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2278,6 +2278,28 @@ def test_dispersion_command(self):
self.assertIn('dispersion', out.lower())
self.assertFalse(err)

def test_dispersion_command_recalculate(self):
rb = RingBuilder(8, 3, 0)
for i in range(3):
i += 1
rb.add_dev({'region': 1, 'zone': i, 'weight': 1.0,
'ip': '127.0.0.%d' % i, 'port': 6000, 'device': 'sda'})
# extra device in z1
rb.add_dev({'region': 1, 'zone': 1, 'weight': 1.0,
'ip': '127.0.0.1', 'port': 6000, 'device': 'sdb'})
rb.rebalance()
self.assertEqual(rb.dispersion, 16.666666666666668)
# simulate an out-of-date dispersion calculation
rb.dispersion = 50
rb.save(self.tempfile)
old_version = rb.version
out, err = self.run_srb('dispersion')
self.assertIn('Dispersion is 50.000000', out)
out, err = self.run_srb('dispersion --recalculate')
self.assertIn('Dispersion is 16.666667', out)
rb = RingBuilder.load(self.tempfile)
self.assertEqual(rb.version, old_version + 1)

def test_use_ringfile_as_builderfile(self):
mock_stdout = six.StringIO()
mock_stderr = six.StringIO()
Expand Down

0 comments on commit 3aa17e6

Please sign in to comment.