From 8559c2cb303089c671bb5aba981c576e4841f9fb Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Sun, 29 Jul 2012 14:14:11 +0200 Subject: [PATCH] Make it possible to pre-associate slots to a connection. This is useful to avoid guessing the correct server instance at runtime thus reducing the overhead of a guess-and-try approach since relying on -ASK or -MOVED responses returned by a node is a costly operation. For now, you can pre-associate slots using the "cluster" client option: $parameters = array( 'tcp://127.0.0.1:6379', 'tcp://127.0.0.1:6380', 'tcp://127.0.0.1:6381', ); $options = array( 'cluster' => function ($options) { $cluster = new Predis\Connection\RedisCluster(); $cluster->setSlots(0, 1364, '127.0.0.1:6379'); $cluster->setSlots(1365, 2729, '127.0.0.1:6380'); $cluster->setSlots(2730, 4095, '127.0.0.1:6381'); return $cluster; }, ); $client = new Predis\Client($parameters, $options); In the future we will make the slots configuration easier by fetching the configuration from a node using the command "CLUSTER NODES" or by pre-computing the slices of slots associated to a node when adding it to the cluster connection object. --- lib/Predis/Connection/RedisCluster.php | 30 +++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/Predis/Connection/RedisCluster.php b/lib/Predis/Connection/RedisCluster.php index 64c53f58..1299e5d3 100644 --- a/lib/Predis/Connection/RedisCluster.php +++ b/lib/Predis/Connection/RedisCluster.php @@ -29,6 +29,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C { private $pool; private $slots; + private $slotsMap; private $connections; private $distributor; private $cmdHasher; @@ -40,6 +41,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C { $this->pool = array(); $this->slots = array(); + $this->slotsMap = array(); $this->connections = $connections ?: new ConnectionFactory(); $this->distributor = new CRC16HashGenerator(); $this->cmdHasher = new RedisClusterHashStrategy(); @@ -119,6 +121,27 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C return false; } + /** + * Preassociate a connection to a set of slots to avoid runtime guessing. + * + * @todo Check type or existence of the specified connection. + * + * @param int $first Initial slot. + * @param int $last Last slot. + * @param ConnectionSingleInterface|string $connection ID or connection instance. + */ + public function setSlots($first, $last, $connection) + { + $connection = (string) $connection; + + if ($first < 0 || $first > 4095 || $last < 0 || $last > 4095 || $last < $first) { + throw new \OutOfBoundsException("Invalid slot values for $connection: [$first-$last]"); + } + + $slots = array_fill($first, $last - $first + 1, $connection); + $this->slotsMap = array_merge($this->slotsMap, $slots); + } + /** * {@inheritdoc} */ @@ -142,7 +165,12 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C return $this->slots[$slot]; } - $this->slots[$slot] = $connection = $this->pool[array_rand($this->pool)]; + if (isset($this->slotsMap[$slot])) { + $this->slots[$slot] = $connection = $this->pool[$this->slotsMap[$slot]]; + } + + $connection = $this->pool[isset($this->slotsMap[$slot]) ? $this->slotsMap[$slot] : array_rand($this->pool)]; + $this->slots[$slot] = $connection; return $connection; }