Browse Source

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.
Daniele Alessandri 13 years ago
parent
commit
8559c2cb30
1 changed files with 29 additions and 1 deletions
  1. 29 1
      lib/Predis/Connection/RedisCluster.php

+ 29 - 1
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;
     }