* @license http://github.com/basdenooijer/solarium/raw/master/COPYING * @link http://www.solarium-project.org/ * * @package Solarium */ /** * Weighted random choice class * * For use in the loadbalancer plugin * * @package Solarium * @subpackage Plugin */ class Solarium_Plugin_Loadbalancer_WeightedRandomChoice { /** * Total weight of all choices * * @var int */ protected $_totalWeight = 0; /** * Choices total lookup array * * @var array */ protected $_lookup = array(); /** * Values lookup array * * @var array */ protected $_values = array(); /** * Constructor * * @param array $choices */ public function __construct($choices) { $i = 0; foreach ($choices AS $key => $weight) { if ($weight <=0) throw new Solarium_Exception('Weight must be greater than zero'); $this->_totalWeight += $weight; $this->_lookup[$i] = $this->_totalWeight; $this->_values[$i] = $key; $i++; } } /** * Get a (weighted) random entry * * @param array $excludes Keys to exclude * @return string */ public function getRandom($excludes = array()) { if (count($excludes) == count($this->_values)) { throw new Solarium_Exception('No more server entries available'); } // continue until a non-excluded value is found // @todo optimize? $result = null; while (1) { $result = $this->_values[$this->_getKey()]; if(!in_array($result, $excludes)) break; } return $result; } /** * Get a (weighted) random entry key * * @return int */ protected function _getKey() { $random = mt_rand(1, $this->_totalWeight); $high = count($this->_lookup)-1; $low = 0; while ( $low < $high ) { $probe = (int)(($high + $low) / 2); if ($this->_lookup[$probe] < $random) { $low = $probe + 1; } else if ($this->_lookup[$probe] > $random) { $high = $probe - 1; } else { return $probe; } } if ($this->_lookup[$low] >= $random) { return $low; } else { return $low+1; } } }