Merge "Fix unbalanced rings after initial creation."

This commit is contained in:
Jenkins
2013年09月09日 22:57:15 +00:00
committed by Gerrit Code Review

View File

@@ -332,7 +332,7 @@ class RingBuilder(object):
:returns: (number_of_partitions_altered, resulting_balance)
"""
if seed:
if seed is not None:
random.seed(seed)
self._ring = None
@@ -821,26 +821,35 @@ class RingBuilder(object):
#
# This used to be a cute, recursive function, but it's been
# unrolled for performance.
candidate_tiers = tier2children[tier]
# We sort the tiers here so that, when we look for a tier
# with the lowest number of replicas, the first one we
# find is the one with the hungriest drive (i.e. drive
# with the largest sort_key value). This lets us
# short-circuit the search while still ensuring we get the
# right tier.
candidate_tiers = sorted(
tier2children[tier],
key=lambda tier: tier2devs[tier][-1]['sort_key'],
reverse=True)
candidates_with_replicas = \
unique_tiers_by_tier_len[len(tier) + 1]
if len(candidate_tiers) > len(candidates_with_replicas):
# There exists at least one tier with 0 other replicas,
# so work backward among the candidates, accepting the
# first which isn't in other_replicas.
#
# This optimization is to avoid calling the min()
# below, which is expensive if you've got thousands of
# drives.
for t in reversed(candidate_tiers):
if other_replicas[t] == 0:
tier = t
break
# There exists at least one tier with 0 other
# replicas, so avoid calling the min() below, which is
# expensive if you've got thousands of drives.
min_replica_count = 0
else:
min_count = min(other_replicas[t]
for t in candidate_tiers)
tier = (t for t in reversed(candidate_tiers)
if other_replicas[t] == min_count).next()
min_replica_count = min(other_replicas[t]
for t in candidate_tiers)
# Find the first tier with the minimal replica count.
# Since they're sorted, this will also have the hungriest
# drive among all the tiers with the minimal replica
# count.
for t in candidate_tiers:
if other_replicas[t] == min_replica_count:
tier = t
break
depth += 1
dev = tier2devs[tier][-1]
dev['parts_wanted'] -= 1

View File

@@ -382,7 +382,7 @@ def get_info(app, env, account, container=None, ret_not_found=False):
if ret_not_found or is_success(info['status']):
return info
return None
# Not in cached, let's try the account servers
# Not in cache, let's try the account servers
path = '/v1/%s' % account
if container:
# Stop and check if we have an account?

View File

@@ -258,6 +258,33 @@ class TestRingBuilder(unittest.TestCase):
max_run = run
return max_run > len(parts) / 2
def test_initial_balance(self):
# 2 boxes, 2 drives each in zone 1
# 1 box, 2 drives in zone 2
#
# This is balanceable, but there used to be some nondeterminism in
# rebalance() that would sometimes give you an imbalanced ring.
rb = ring.RingBuilder(8, 3, 1)
rb.add_dev({'region': 1, 'zone': 1, 'weight': 4000.0,
'ip': '10.1.1.1', 'port': 10000, 'device': 'sda'})
rb.add_dev({'region': 1, 'zone': 1, 'weight': 4000.0,
'ip': '10.1.1.1', 'port': 10000, 'device': 'sdb'})
rb.add_dev({'region': 1, 'zone': 1, 'weight': 4000.0,
'ip': '10.1.1.2', 'port': 10000, 'device': 'sda'})
rb.add_dev({'region': 1, 'zone': 1, 'weight': 4000.0,
'ip': '10.1.1.2', 'port': 10000, 'device': 'sdb'})
rb.add_dev({'region': 1, 'zone': 2, 'weight': 4000.0,
'ip': '10.1.1.3', 'port': 10000, 'device': 'sda'})
rb.add_dev({'region': 1, 'zone': 2, 'weight': 4000.0,
'ip': '10.1.1.3', 'port': 10000, 'device': 'sdb'})
_, balance = rb.rebalance(seed=2)
# maybe not *perfect*, but should be close
self.assert_(balance <= 1)
def test_multitier_partial(self):
# Multitier test, nothing full
rb = ring.RingBuilder(8, 3, 1)
Reference in New Issue
openstack/swift
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.

The note is not visible to the blocked user.