mirror of
https://github.com/predis/predis.git
synced 2026-08-27 10:34:10 +00:00
Reworked HashRing::remove to handle hash collisions in a consistent way.
This commit is contained in:
+16
-9
@@ -1267,15 +1267,19 @@ namespace Predis\Utilities;
|
||||
|
||||
class HashRing {
|
||||
const DEFAULT_REPLICAS = 128;
|
||||
private $_ring, $_ringKeys, $_replicas;
|
||||
private $_nodes, $_ring, $_ringKeys, $_replicas;
|
||||
|
||||
public function __construct($replicas = self::DEFAULT_REPLICAS) {
|
||||
$this->_replicas = $replicas;
|
||||
$this->_nodes = array();
|
||||
$this->_ring = array();
|
||||
$this->_ringKeys = array();
|
||||
}
|
||||
|
||||
public function add($node) {
|
||||
// NOTE: in case of collisions in the hashes of the nodes, the node added
|
||||
// last wins, thus the order in which nodes are added is significant.
|
||||
$this->_nodes[] = $node;
|
||||
$nodeHash = (string) $node;
|
||||
$replicas = $this->_replicas;
|
||||
for ($i = 0; $i < $replicas; $i++) {
|
||||
@@ -1287,14 +1291,17 @@ class HashRing {
|
||||
}
|
||||
|
||||
public function remove($node) {
|
||||
$nodeHash = (string) $node;
|
||||
$replicas = $this->_replicas;
|
||||
for ($i = 0; $i < $replicas; $i++) {
|
||||
$key = crc32($nodeHash . ':' . $i);
|
||||
unset($this->_ring[$key]);
|
||||
$this->_ringKeys = array_filter($this->_ringKeys, function($rk) use($key) {
|
||||
return $rk !== $key;
|
||||
});
|
||||
// NOTE: a node is removed by recreating the whole ring from scratch, in
|
||||
// order to reassign possible hashes with collisions to the right node
|
||||
// according to the order in which they were added in the first place.
|
||||
$oldNodes = $this->_nodes;
|
||||
$this->_nodes = array();
|
||||
$this->_ring = array();
|
||||
$this->_ringKeys = array();
|
||||
foreach ($oldNodes as $oldNode) {
|
||||
if ($oldNode !== $node) {
|
||||
$this->add($oldNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user