54a002554d
Fix typo error in StochasticHostWeightHandler. Change-Id: I141ef7ba204a556642f5891b1da19c8dad220d1d
83 lines
3.3 KiB
Python
83 lines
3.3 KiB
Python
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""
|
|
Stochastic weight handler
|
|
|
|
This weight handler differs from the default weight
|
|
handler by giving every pool a chance to be chosen
|
|
where the probability is proportional to each pools'
|
|
weight.
|
|
"""
|
|
|
|
import random
|
|
|
|
from cinder.scheduler import base_weight
|
|
from cinder.scheduler import weights as wts
|
|
|
|
|
|
class StochasticHostWeightHandler(base_weight.BaseWeightHandler):
|
|
def __init__(self, namespace):
|
|
super(StochasticHostWeightHandler, self).__init__(wts.BaseHostWeigher,
|
|
namespace)
|
|
|
|
def get_weighed_objects(self, weigher_classes, obj_list,
|
|
weighing_properties):
|
|
# The normalization performed in the superclass is nonlinear, which
|
|
# messes up the probabilities, so override it. The probabilistic
|
|
# approach we use here is self-normalizing.
|
|
# Also, the sorting done by the parent implementation is harmless but
|
|
# useless for us.
|
|
|
|
# Compute the object weights as the parent would but without sorting
|
|
# or normalization.
|
|
weighed_objs = [wts.WeighedHost(obj, 0.0) for obj in obj_list]
|
|
for weigher_cls in weigher_classes:
|
|
weigher = weigher_cls()
|
|
weights = weigher.weigh_objects(weighed_objs, weighing_properties)
|
|
for i, weight in enumerate(weights):
|
|
obj = weighed_objs[i]
|
|
obj.weight += weigher.weight_multiplier() * weight
|
|
|
|
# Avoid processing empty lists
|
|
if not weighed_objs:
|
|
return []
|
|
|
|
# First compute the total weight of all the objects and the upper
|
|
# bound for each object to "win" the lottery.
|
|
total_weight = 0
|
|
table = []
|
|
for weighed_obj in weighed_objs:
|
|
total_weight += weighed_obj.weight
|
|
max_value = total_weight
|
|
table.append((max_value, weighed_obj))
|
|
|
|
# Now draw a random value with the computed range
|
|
winning_value = random.random() * total_weight
|
|
|
|
# Scan the table to find the first object with a maximum higher than
|
|
# the random number. Save the index of the winner.
|
|
winning_index = 0
|
|
for (i, (max_value, weighed_obj)) in enumerate(table):
|
|
if max_value > winning_value:
|
|
# Return a single element array with the winner.
|
|
winning_index = i
|
|
break
|
|
|
|
# It's theoretically possible for the above loop to terminate with no
|
|
# winner. This happens when winning_value >= total_weight, which
|
|
# could only occur with very large numbers and floating point
|
|
# rounding. In those cases the actual winner should have been the
|
|
# last element, so return it.
|
|
return weighed_objs[winning_index:] + weighed_objs[0:winning_index]
|