diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-02-01 04:04:07 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-02-01 04:04:07 +0000 |
commit | 65baec39d221b05c61eb58e635157db754b9f869 (patch) | |
tree | 7a5909e215c411dd174f5a23db573cbb597a5452 | |
parent | c0d497c421bf0d3969dafd3a6e8f5b3d12bae412 (diff) | |
parent | e189723fec3a26dc4a9a120c09336038df44d7d6 (diff) | |
download | swift-65baec39d221b05c61eb58e635157db754b9f869.tar.gz |
Merge "Allow rebalance to take a seed."
-rw-r--r-- | AUTHORS | 1 | ||||
-rwxr-xr-x | bin/swift-ring-builder | 10 | ||||
-rw-r--r-- | swift/common/ring/builder.py | 19 | ||||
-rw-r--r-- | test/unit/common/ring/test_builder.py | 29 |
4 files changed, 51 insertions, 8 deletions
@@ -56,6 +56,7 @@ Ed Leafe (ed.leafe@rackspace.com) Tong Li (litong01@us.ibm.com) Victor Lowther (victor.lowther@gmail.com) Zhong Yue Luo (lzyeval@gmail.com) +Christopher MacGown (chris@pistoncloud.com) Dragos Manolescu (dragosm@hp.com) Juan J. Martinez (juan@memset.com) Marcelo Martins (btorch@gmail.com) diff --git a/bin/swift-ring-builder b/bin/swift-ring-builder index 4349c4389..d2ec782fb 100755 --- a/bin/swift-ring-builder +++ b/bin/swift-ring-builder @@ -473,14 +473,20 @@ swift-ring-builder <builder_file> remove <search-value> [search-value ...] def rebalance(): """ -swift-ring-builder <builder_file> rebalance +swift-ring-builder <builder_file> rebalance <seed> Attempts to rebalance the ring by reassigning partitions that haven't been recently reassigned. """ + def get_seed(index): + try: + return argv[index] + except IndexError: + pass + devs_changed = builder.devs_changed try: last_balance = builder.get_balance() - parts, balance = builder.rebalance() + parts, balance = builder.rebalance(seed=get_seed(3)) except exceptions.RingBuilderError, e: print '-' * 79 print ("An error has occurred during ring validation. Common\n" diff --git a/swift/common/ring/builder.py b/swift/common/ring/builder.py index 09d630358..ba1f5b920 100644 --- a/swift/common/ring/builder.py +++ b/swift/common/ring/builder.py @@ -16,12 +16,11 @@ import bisect import itertools import math +import random import cPickle as pickle - from array import array from collections import defaultdict -from random import randint, shuffle from time import time from swift.common import exceptions @@ -276,7 +275,7 @@ class RingBuilder(object): self.devs_changed = True self.version += 1 - def rebalance(self): + def rebalance(self, seed=None): """ Rebalance the ring. @@ -294,6 +293,10 @@ class RingBuilder(object): :returns: (number_of_partitions_altered, resulting_balance) """ + + if seed: + random.seed(seed) + self._ring = None if self._last_part_moves_epoch is None: self._initial_balance() @@ -576,7 +579,10 @@ class RingBuilder(object): # We randomly pick a new starting point in the "circular" ring of # partitions to try to get a better rebalance when called multiple # times. - start = self._last_part_gather_start / 4 + randint(0, self.parts / 2) + + start = self._last_part_gather_start / 4 + start += random.randint(0, self.parts / 2) # GRAH PEP8!!! + self._last_part_gather_start = start for replica in xrange(self.replicas): part2dev = self._replica2part2dev[replica] @@ -604,7 +610,7 @@ class RingBuilder(object): # it would concentrate load during failure recovery scenarios # (increasing risk). The "right" answer has yet to be debated to # conclusion, but working code wins for now. - shuffle(reassign_parts_list) + random.shuffle(reassign_parts_list) return reassign_parts_list def _reassign_parts(self, reassign_parts): @@ -630,6 +636,7 @@ class RingBuilder(object): """ for dev in self._iter_devs(): dev['sort_key'] = self._sort_key_for(dev) + available_devs = \ sorted((d for d in self._iter_devs() if d['weight']), key=lambda x: x['sort_key']) @@ -720,7 +727,7 @@ class RingBuilder(object): # parts_wanted end up sorted above positive parts_wanted. return '%016x.%04x.%04x' % ( (self.parts * self.replicas) + dev['parts_wanted'], - randint(0, 0xffff), + random.randint(0, 0xFFFF), dev['id']) def _build_max_replicas_by_tier(self): diff --git a/test/unit/common/ring/test_builder.py b/test/unit/common/ring/test_builder.py index 6ffc2edc9..f58008237 100644 --- a/test/unit/common/ring/test_builder.py +++ b/test/unit/common/ring/test_builder.py @@ -68,6 +68,35 @@ class TestRingBuilder(unittest.TestCase): r4 = rb.get_ring() self.assert_(r3 is r4) + def test_rebalance_with_seed(self): + devs = [(0, 10000), (1, 10001), (2, 10002), (1, 10003)] + ring_builders = [] + for n in range(3): + rb = ring.RingBuilder(8, 3, 1) + for idx, (zone, port) in enumerate(devs): + rb.add_dev({'id': idx, 'zone': zone, 'weight': 1, + 'ip': '127.0.0.1', 'port': port, 'device': 'sda1'}) + ring_builders.append(rb) + + rb0 = ring_builders[0] + rb1 = ring_builders[1] + rb2 = ring_builders[2] + + r0 = rb0.get_ring() + self.assertTrue(rb0.get_ring() is r0) + + + rb0.rebalance() # NO SEED + rb1.rebalance(seed=10) + rb2.rebalance(seed=10) + + r1 = rb1.get_ring() + r2 = rb2.get_ring() + + self.assertFalse(rb0.get_ring() is r0) + self.assertNotEquals(r0.to_dict(), r1.to_dict()) + self.assertEquals(r1.to_dict(), r2.to_dict()) + def test_add_dev(self): rb = ring.RingBuilder(8, 3, 1) dev = \ |