#!/usr/bin/env python
#Copyright (c) 2010 Ivan Skytte Jørgensen
#
#This software is provided 'as-is', without any express or implied
#warranty. In no event will the authors be held liable for any damages
#arising from the use of this software.
#
#Permission is granted to anyone to use this software for any purpose,
#including commercial applications, and to alter it and redistribute it
#freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
#
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
#
# 3. This notice may not be removed or altered from any source
# distribution.
class Distributor:
"""A load balancer class supporting sticky server selection.
The Distributor keeps track of which backends are available and their
estimated load capacity. It then assigns load to them usign stikcy
selection based on input keys (eg. IP addresses).
"""
class Node:
def __init__(self,c,kga):
self.capacity = c
self.key_groups_assigned = kga
def __init__(self,granularity_bits=10):
self.key_mask = ~((~0)<key_group:
return self.keygroup_to_nodeid[key_group]
else:
return None
def redistribute(self):
if self.fully_distributed:
return False
if len(self.nodes)<=1:
#If there is only 1 node then the load cannot be evened out.
self.fully_distributed = True
return False
#Find relatively minimum and maximum loaded nodes.
min_load_node_id = None
min_load_node = None
max_load_node_id = None
max_load_node = None
for (node_id,node) in self.nodes.items():
nl = self.__node_load_n(node)
if min_load_node==None or nlself.__node_load_n(max_load_node):
max_load_node_id = node_id
max_load_node = node
#calculate what the load inequality and if it would improve if we moved a key group
current_min_load = self.__node_load_n(min_load_node)
current_max_load = self.__node_load_n(max_load_node)
swapped_min_load = self.__node_load(min_load_node.key_groups_assigned+1,min_load_node.capacity)
swapped_max_load = self.__node_load(max_load_node.key_groups_assigned-1,max_load_node.capacity)
current_load_diff = current_max_load - current_min_load
swapped_load_diff = abs(swapped_max_load-swapped_min_load)
if swapped_load_diff0
assert load[1]>0
assert load[2]>0
assert load[0]>=load[2]
assert load[1]>=load[2]