Created
October 1, 2015 10:45
-
-
Save marcojetson/dc0ca815634cebe53cfc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class PoolManagerException extends Exception {} | |
class PoolManagerInvalidWeightException extends PoolManagerException {} | |
class PoolManagerNodeNotFoundException extends PoolManagerException {} | |
class PoolManagerEmptyException extends PoolManagerException {} | |
/** | |
* Generic pool manager with horizontal scaling in mind | |
* | |
* @license http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 Modified BSD license | |
* @version 1.0 | |
*/ | |
class PoolManager | |
{ | |
/** Cache de las keys */ | |
private $_cache; | |
/** Pool keys */ | |
private $_circle; | |
/** Node tracking */ | |
private $_nodes; | |
/** | |
* Constructor generico | |
* | |
* @return PoolManager | |
*/ | |
public function __construct() | |
{ | |
$this->_cache = false; | |
$this->_circle = array(); | |
$this->_nodes = array(); | |
return $this; | |
} | |
/** | |
* Agrega un nodo al pool con un peso (opcional) | |
* | |
* @param $node string | |
* @param $weight int | |
* @throws PoolManagerInvalidWeightException peso no valido | |
* @return PoolManager | |
*/ | |
public function add($node, $weight = 100) | |
{ | |
if ($weight < 1 || $weight > 100) { | |
// peso invalido | |
throw new PoolManagerInvalidWeightException; | |
} | |
// agrega el nodo al tracker | |
$this->_nodes[$node] = $weight; | |
// agrega las keys (tantas como el peso) al circulo | |
for ($i = 0; $i < $weight; ++$i) { | |
$index = self::hash($node . '/' . $i); | |
$this->_circle[$index] = $node; | |
} | |
// limpia cache | |
$this->_cache = false; | |
return $this; | |
} | |
/** | |
* Quita un nodo del pool | |
* | |
* @param $node string | |
* @throws PoolManagerNodeNotFoundException nodo no encontrado | |
* @return PoolManager | |
*/ | |
public function remove($node) | |
{ | |
if (!isset($this->_nodes[$node])) { | |
// el nodo no existe | |
throw new PoolManagerNodeNotFoundException; | |
} | |
// obtiene el peso y lo elimina del tracker | |
$weight = $this->_nodes[$node]; | |
unset($this->_nodes[$node]); | |
// lo borra del circulo (tantas keys como su peso) | |
for ($i = 0; $i < $weight; ++$i) { | |
$index = self::hash($node . '/' . $i); | |
unset($this->_circle[$index]); | |
} | |
// limpia cache | |
$this->_cache = false; | |
return $this; | |
} | |
/** | |
* Calcula un nodo para una key especifica | |
* | |
* @param $key string | |
* @throws PoolManagerEmptyException pool vacio | |
* @return string | |
*/ | |
public function getNode($key) | |
{ | |
if (!$this->size()) { | |
// no hay nodos en el pool | |
throw new PoolManagerEmptyException; | |
} | |
if (!$this->_cache) { | |
// cache is empty, generate it | |
$this->_cache = array_keys($this->_circle); | |
sort($this->_cache); | |
} | |
// busca la key mas cercana | |
$hash = self::hash($key); | |
$begin = 0; | |
$end = sizeof($this->_cache) - 1; | |
if ($this->_cache[0] > $hash) { | |
$hash += $this->_cache[0]; | |
} else if ($this->_cache[$end] < $hash) { | |
$hash -= $this->_cache[$end]; | |
} | |
while ($end - $begin > 1) { | |
$mid = ($end + $begin) >> 1; | |
if ($this->_cache[$mid] >= $hash) { | |
$end = $mid; | |
} else { | |
$begin = $mid; | |
} | |
} | |
// obtiene el pool para la key correspondiente | |
$index = $this->_cache[$end]; | |
$node = $this->_circle[$index]; | |
return $node; | |
} | |
/** | |
* Devuelve el tamano del pool | |
* | |
* @return int | |
*/ | |
public function size() | |
{ | |
$size = sizeof($this->_nodes); | |
return $size; | |
} | |
/** | |
* Calcula una representacion decimal (y safe) de un string | |
* | |
* @param $string string | |
* @return string | |
*/ | |
static public function hash($string) | |
{ | |
$hash = md5($string); | |
$hash = substr($hash, 1, 4); | |
$hash = base_convert($hash, 16, 10); | |
return $hash; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment