Extract slot map logic to separate class.

In addition to that, the methods askSlotsMap() and buildSlotsMap() of
the redis-cluster connection backend have been renamed respectively
to askSlotMap() and buildSlotMap().
This commit is contained in:
Daniele Alessandri
2016-06-17 16:13:28 +02:00
parent 028992cf1b
commit 69e40dab2b
4 changed files with 741 additions and 143 deletions
+195
View File
@@ -0,0 +1,195 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Cluster;
/**
* Slot map for redis-cluster.
*/
class SlotMap implements \ArrayAccess, \IteratorAggregate, \Countable
{
private $slots = array();
/**
* Checks if the given slot is valid.
*
* @param int $first Slot index.
*
* @return bool
*/
public static function isValid($slot)
{
return $slot >= 0x0000 && $slot <= 0x3FFF;
}
/**
* Checks if the given slot range is valid.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
*
* @return bool
*/
public static function isValidRange($first, $last)
{
return $first >= 0x0000 && $first <= 0x3FFF && $last >= 0x0000 && $last <= 0x3FFF && $first <= $last;
}
/**
* Resets the slot map.
*/
public function reset()
{
$this->slots = array();
}
/**
* Checks if the slot map is empty.
*
* @return bool
*/
public function isEmpty()
{
return empty($this->slots);
}
/**
* Returns the current slot map as a dictionary of $slot => $node.
*
* The order of the slots in the dictionary is not guaranteed.
*
* @return array
*/
public function toArray()
{
return $this->slots;
}
/**
* Returns the list of unique nodes in the slot map.
*
* @return array
*/
public function getNodes()
{
return array_keys(array_flip($this->slots));
}
/**
* Assigns the specified slot range to a node.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
* @param NodeConnectionInterface|string $connection ID or connection instance.
*
* @throws \OutOfBoundsException
*/
public function setSlots($first, $last, $connection)
{
if (!static::isValidRange($first, $last)) {
throw new \OutOfBoundsException("Invalid slot range $first-$last for `$connection`");
}
$this->slots += array_fill($first, $last - $first + 1, (string) $connection);
}
/**
* Returns the specified slot range.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
*
* @return array
*/
public function getSlots($first, $last)
{
if (!static::isValidRange($first, $last)) {
throw new \OutOfBoundsException("Invalid slot range $first-$last");
}
return array_intersect_key($this->slots, array_fill($first, $last - $first + 1, null));
}
/**
* Checks if the specified slot is assigned.
*
* @param int $slot Slot index.
*
* @return bool
*/
public function offsetExists($slot)
{
return isset($this->slots[$slot]);
}
/**
* Returns the node assigned to the specified slot
*
* @param int $slot Slot index.
*
* @return string
*/
public function offsetGet($slot)
{
if (isset($this->slots[$slot])) {
return $this->slots[$slot];
}
}
/**
* Assigns the specified slot to a node.
*
* @param int $slot Slot index.
* @param NodeConnectionInterface|string $connection ID or connection instance.
*
* @return string
*/
public function offsetSet($slot, $connection)
{
if (!static::isValid($slot)) {
throw new \OutOfBoundsException("Invalid slot $slot for `$connection`");
}
$this->slots[(int) $slot] = (string) $connection;
}
/**
* Returns the node assigned to the specified slot
*
* @param int $slot Slot index.
*
* @return string
*/
public function offsetUnset($slot)
{
unset($this->slots[$slot]);
}
/**
* Returns the current number of assigned slots.
*
* @return int
*/
public function count()
{
return count($this->slots);
}
/**
* Returns an iterator over the slot map.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->slots);
}
}
+41 -90
View File
@@ -13,6 +13,7 @@ namespace Predis\Connection\Cluster;
use Predis\ClientException;
use Predis\Cluster\RedisStrategy as RedisClusterStrategy;
use Predis\Cluster\SlotMap;
use Predis\Cluster\StrategyInterface;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
@@ -49,7 +50,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
private $useClusterSlots = true;
private $pool = array();
private $slots = array();
private $slotsMap;
private $slotmap;
private $strategy;
private $connections;
private $retryLimit = 5;
@@ -64,6 +65,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
) {
$this->connections = $connections;
$this->strategy = $strategy ?: new RedisClusterStrategy();
$this->slotmap = new SlotMap();
}
/**
@@ -120,7 +122,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
public function add(NodeConnectionInterface $connection)
{
$this->pool[(string) $connection] = $connection;
unset($this->slotsMap);
$this->slotmap->reset();
}
/**
@@ -129,12 +131,9 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
public function remove(NodeConnectionInterface $connection)
{
if (false !== $id = array_search($connection, $this->pool, true)) {
unset(
$this->pool[$id],
$this->slotsMap
);
$this->slotmap->reset();
$this->slots = array_diff($this->slots, array($connection));
unset($this->pool[$id]);
return true;
}
@@ -152,10 +151,9 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
public function removeById($connectionID)
{
if (isset($this->pool[$connectionID])) {
unset(
$this->pool[$connectionID],
$this->slotsMap
);
$this->slotmap->reset();
$this->slots = array_diff($this->slots, array($connectionID));
unset($this->pool[$connectionID]);
return true;
}
@@ -171,12 +169,10 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
* cluster, so it is most effective when all of the connections supplied on
* initialization have the "slots" parameter properly set accordingly to the
* current cluster configuration.
*
* @return array
*/
public function buildSlotsMap()
public function buildSlotMap()
{
$this->slotsMap = array();
$this->slotmap->reset();
foreach ($this->pool as $connectionID => $connection) {
$parameters = $connection->getParameters();
@@ -192,11 +188,9 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
$slots[1] = $slots[0];
}
$this->setSlots($slots[0], $slots[1], $connectionID);
$this->slotmap->setSlots($slots[0], $slots[1], $connectionID);
}
}
return $this->slotsMap;
}
/**
@@ -210,7 +204,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
*
* @return mixed
*/
private function queryClusterNodeForSlotsMap(NodeConnectionInterface $connection)
private function queryClusterNodeForSlotMap(NodeConnectionInterface $connection)
{
$retries = 0;
$command = RawCommand::create('CLUSTER', 'SLOTS');
@@ -246,18 +240,16 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
* the pool.
*
* @param NodeConnectionInterface $connection Optional connection instance.
*
* @return array
*/
public function askSlotsMap(NodeConnectionInterface $connection = null)
public function askSlotMap(NodeConnectionInterface $connection = null)
{
if (!$connection && !$connection = $this->getRandomConnection()) {
return array();
return;
}
$this->resetSlotsMap();
$this->slotmap->reset();
$response = $this->queryClusterNodeForSlotsMap($connection);
$response = $this->queryClusterNodeForSlotMap($connection);
foreach ($response as $slots) {
// We only support master servers for now, so we ignore subsequent
@@ -265,61 +257,11 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
list($start, $end, $master) = $slots;
if ($master[0] === '') {
$this->setSlots($start, $end, (string) $connection);
$this->slotmap->setSlots($start, $end, (string) $connection);
} else {
$this->setSlots($start, $end, "{$master[0]}:{$master[1]}");
$this->slotmap->setSlots($start, $end, "{$master[0]}:{$master[1]}");
}
}
return $this->slotsMap;
}
/**
* Resets the slots map cache.
*/
public function resetSlotsMap()
{
$this->slotsMap = array();
}
/**
* Returns the current slots map for the cluster.
*
* The order of the returned $slot => $server dictionary is not guaranteed.
*
* @return array
*/
public function getSlotsMap()
{
if (!isset($this->slotsMap)) {
$this->slotsMap = array();
}
return $this->slotsMap;
}
/**
* Pre-associates a connection to a slots range to avoid runtime guessing.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
* @param NodeConnectionInterface|string $connection ID or connection instance.
*
* @throws \OutOfBoundsException
*/
public function setSlots($first, $last, $connection)
{
if ($first < 0x0000 || $first > 0x3FFF ||
$last < 0x0000 || $last > 0x3FFF ||
$last < $first
) {
throw new \OutOfBoundsException(
"Invalid slot range for $connection: [$first-$last]."
);
}
$slots = array_fill($first, $last - $first + 1, (string) $connection);
$this->slotsMap = $this->getSlotsMap() + $slots;
}
/**
@@ -337,12 +279,12 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
throw new ClientException('No connections available in the pool');
}
if (!isset($this->slotsMap)) {
$this->buildSlotsMap();
if ($this->slotmap->isEmpty()) {
$this->buildSlotMap();
}
if (isset($this->slotsMap[$slot])) {
return $this->slotsMap[$slot];
if ($node = $this->slotmap[$slot]) {
return $node;
}
$count = count($this->pool);
@@ -400,7 +342,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
*/
public function getConnectionBySlot($slot)
{
if ($slot < 0x0000 || $slot > 0x3FFF) {
if (!SlotMap::isValid($slot)) {
throw new \OutOfBoundsException("Invalid slot [$slot].");
}
@@ -451,6 +393,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
{
$this->pool[(string) $connection] = $connection;
$this->slots[(int) $slot] = $connection;
$this->slotmap[(int) $slot] = $connection;
}
/**
@@ -495,7 +438,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
}
if ($this->useClusterSlots) {
$this->askSlotsMap($connection);
$this->askSlotMap($connection);
}
$this->move($connection, $slot);
@@ -557,7 +500,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
if ($failure) {
throw $exception;
} elseif ($this->useClusterSlots) {
$this->askSlotsMap();
$this->askSlotMap();
}
$failure = true;
@@ -612,15 +555,13 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
*/
public function getIterator()
{
if ($this->useClusterSlots) {
$slotsmap = $this->getSlotsMap() ?: $this->askSlotsMap();
} else {
$slotsmap = $this->getSlotsMap() ?: $this->buildSlotsMap();
if ($this->slotmap->isEmpty()) {
$this->useClusterSlots ? $this->askSlotMap() : $this->buildSlotMap();
}
$connections = array();
foreach (array_unique($slotsmap) as $node) {
foreach ($this->slotmap->getNodes() as $node) {
if (!$connection = $this->getConnectionById($node)) {
$this->add($connection = $this->createConnection($node));
}
@@ -631,6 +572,16 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
return new \ArrayIterator($connections);
}
/**
* Returns the underlying slot map.
*
* @return SlotMap
*/
public function getSlotMap()
{
return $this->slotmap;
}
/**
* Returns the underlying command hash strategy used to hash commands by
* using keys found in their arguments.
@@ -661,7 +612,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
* procedure, mostly when targeting many keys that would end up in a lot of
* redirections.
*
* The slots map can still be manually fetched using the askSlotsMap()
* The slots map can still be manually fetched using the askSlotMap()
* method whether or not this option is enabled.
*
* @param bool $value Enable or disable the use of CLUSTER SLOTS.
+471
View File
@@ -0,0 +1,471 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Cluster;
use PredisTestCase;
/**
*
*/
class SlotMapTest extends PredisTestCase
{
/**
* @group disconnected
*/
public function testIsValidReturnsTrueOnValidSlot()
{
$this->assertTrue(SlotMap::isValid(0));
$this->assertTrue(SlotMap::isValid(16383));
$this->assertTrue(SlotMap::isValid(5000));
$this->assertTrue(SlotMap::isValid('5000'));
}
/**
* @group disconnected
*/
public function testIsValidReturnsFalseOnInvalidSlot()
{
$this->assertFalse(SlotMap::isValid(-1));
$this->assertFalse(SlotMap::isValid(16384));
}
/**
* @group disconnected
*/
public function testIsValidRangeReturnsTrueOnValidSlotRange()
{
$this->assertTrue(SlotMap::isValidRange(0, 16383));
$this->assertTrue(SlotMap::isValidRange(2000, 2999));
$this->assertTrue(SlotMap::isValidRange(3000, 3000));
}
/**
* @group disconnected
*/
public function testIsValidRangeReturnsFalseOnInvalidSlotRange()
{
$this->assertFalse(SlotMap::isValidRange(0, 16384));
$this->assertFalse(SlotMap::isValidRange(-1, 16383));
$this->assertFalse(SlotMap::isValidRange(-1, 16384));
$this->assertFalse(SlotMap::isValidRange(2999, 2000));
}
/**
* @group disconnected
*/
public function testToArrayReturnsEmptyArrayOnEmptySlotMap()
{
$slotmap = new SlotMap();
$this->assertEmpty($slotmap->toArray());
}
/**
* @group disconnected
*/
public function testSetSlotsAssignsSpecifiedNodeToSlotRange()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$slotmap->setSlots(10922, 16383, '127.0.0.1:6381');
$expectedMap = array_merge(
array_fill(0, 5461, '127.0.0.1:6379'),
array_fill(5460, 5461, '127.0.0.1:6380'),
array_fill(10921, 5462, '127.0.0.1:6381')
);
$this->assertSame($expectedMap, $slotmap->toArray());
}
/**
* @group disconnected
*/
public function testSetSlotsOverwritesSlotRange()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(1000, 2000, '127.0.0.1:6380');
$expectedMap =
array_fill(0, 5461, '127.0.0.1:6379') +
array_fill(1000, 2000, '127.0.0.1:6380');
$this->assertSame($expectedMap, $slotmap->toArray());
}
/**
* @group disconnected
*/
public function testSetSlotsAssignsSingleSlotWhenFirstAndLastSlotMatch()
{
$slotmap = new SlotMap();
$slotmap->setSlots(10, 10, '127.0.0.1:6379');
$this->assertSame(array(10 => '127.0.0.1:6379'), $slotmap->toArray());
}
/**
* @group disconnected
*/
public function testSetSlotsCastsValueToString()
{
$slotmap = new SlotMap();
$connection = $this->getMockConnection();
$connection
->expects($this->once())
->method('__toString')
->will($this->returnValue('127.0.0.1:6379'));
$slotmap->setSlots(10, 10, $connection);
$this->assertSame(array(10 => '127.0.0.1:6379'), $slotmap->toArray());
}
/**
* @group disconnected
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Invalid slot range 0-16384 for `127.0.0.1:6379`
*/
public function testSetSlotsThrowsExceptionOnInvalidSlotRange()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 16384, '127.0.0.1:6379');
}
/**
* @group disconnected
*/
public function testGetSlotsReturnsEmptyArrayOnEmptySlotMap()
{
$slotmap = new SlotMap();
$this->assertEmpty($slotmap->getSlots(3, 11));
}
/**
* @group disconnected
*/
public function testGetSlotsReturnsDictionaryOfSlotsWithAssignedNodes()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5, '127.0.0.1:6379');
$slotmap->setSlots(10, 13, '127.0.0.1:6380');
$expectedMap = array(
3 => '127.0.0.1:6379',
4 => '127.0.0.1:6379',
5 => '127.0.0.1:6379',
10 => '127.0.0.1:6380',
11 => '127.0.0.1:6380',
);
$this->assertSame($expectedMap, $slotmap->getSlots(3, 11));
}
/**
* @group disconnected
*/
public function testGetSlotsReturnsEmptyArrayOnEmptySlotRange()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5, '127.0.0.1:6379');
$slotmap->setSlots(10, 13, '127.0.0.1:6380');
$this->assertEmpty($slotmap->getSlots(100, 200));
}
/**
* @group disconnected
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Invalid slot range 0-16384
*/
public function testGetSlotsThrowsExceptionOnInvalidSlotRange()
{
$slotmap = new SlotMap();
$slotmap->getSlots(0, 16384);
}
/**
* @group disconnected
*/
public function testIsEmptyReturnsTrueOnEmptySlotMap()
{
$slotmap = new SlotMap();
$this->assertTrue($slotmap->isEmpty());
}
/**
* @group disconnected
*/
public function testIsEmptyReturnsFalseOnNonEmptySlotMap()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertFalse($slotmap->isEmpty());
}
/**
* @group disconnected
*/
public function testCountReturnsZeroOnEmptySlotMap()
{
$slotmap = new SlotMap();
$this->assertSame(0, count($slotmap));
}
/**
* @group disconnected
*/
public function testCountReturnsAssignedSlotsInSlotMap()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertSame(5461, count($slotmap));
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$this->assertSame(10922, count($slotmap));
$slotmap->setSlots(10922, 16383, '127.0.0.1:6381');
$this->assertSame(16384, count($slotmap));
}
/**
* @group disconnected
*/
public function testResetEmptiesSlotMap()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$slotmap->setSlots(10922, 16383, '127.0.0.1:6381');
$this->assertFalse($slotmap->isEmpty());
$slotmap->reset();
$this->assertTrue($slotmap->isEmpty());
}
/**
* @group disconnected
*/
public function testGetNodesReturnsEmptyArrayOnEmptySlotMap()
{
$slotmap = new SlotMap();
$this->assertEmpty($slotmap->getNodes());
}
/**
* @group disconnected
*/
public function testGetNodesReturnsArrayOfNodesInSlotMap()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$slotmap->setSlots(10922, 16383, '127.0.0.1:6381');
$this->assertSame(array('127.0.0.1:6379', '127.0.0.1:6380', '127.0.0.1:6381'), $slotmap->getNodes());
}
/**
* @group disconnected
*/
public function testOffsetExistsReturnsTrueOnAssignedSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertTrue(isset($slotmap[0]));
$this->assertTrue(isset($slotmap[2000]));
}
/**
* @group disconnected
*/
public function testOffsetExistsReturnsFalseOnAssignedSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertFalse(isset($slotmap[6000]));
}
/**
* @group disconnected
*/
public function testOffsetExistsReturnsFalseOnInvalidSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertFalse(isset($slotmap[-100]));
$this->assertFalse(isset($slotmap[16384]));
}
/**
* @group disconnected
*/
public function testOffsetGetReturnsNodeOfAssignedSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$slotmap->setSlots(10922, 16383, '127.0.0.1:6381');
$this->assertSame('127.0.0.1:6379', $slotmap[0]);
$this->assertSame('127.0.0.1:6380', $slotmap[5461]);
$this->assertSame('127.0.0.1:6381', $slotmap[10922]);
}
/**
* @group disconnected
*/
public function testOffsetGetReturnsNullOnUnassignedSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertNull($slotmap[5461]);
}
/**
* @group disconnected
*/
public function testOffsetGetReturnsNullOnInvalidSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertNull($slotmap[-100]);
$this->assertNull($slotmap[16384]);
}
/**
* @group disconnected
*/
public function testOffsetUnsetRemovesSlotAssignment()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertTrue(isset($slotmap[100]));
unset($slotmap[100]);
$this->assertFalse(isset($slotmap[100]));
}
/**
* @group disconnected
*/
public function testOffsetUnsetDoesNotDoAnythingOnUnassignedSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertFalse(isset($slotmap[5461]));
unset($slotmap[5461]);
$this->assertFalse(isset($slotmap[5461]));
}
/**
* @group disconnected
*/
public function testOffsetSetAssignsNodeToSlot()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertSame('127.0.0.1:6380', $slotmap[100] = '127.0.0.1:6380');
$this->assertSame('127.0.0.1:6380', $slotmap[100]);
$this->assertNull($slotmap[5461]);
$this->assertSame('127.0.0.1:6380', $slotmap[5461] = '127.0.0.1:6380');
$this->assertSame('127.0.0.1:6380', $slotmap[5461]);
}
/**
* @group disconnected
*/
public function testOffsetSetCastsValueToString()
{
$slotmap = new SlotMap();
$connection = $this->getMockConnection();
$connection
->expects($this->once())
->method('__toString')
->will($this->returnValue('127.0.0.1:6379'));
$this->assertSame($connection, $slotmap[0] = $connection);
$this->assertSame('127.0.0.1:6379', $slotmap[0]);
}
/**
* @group disconnected
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Invalid slot 16384 for `127.0.0.1:6379`
*/
public function testOffsetSetThrowsExceptionOnInvalidSlot()
{
$slotmap = new SlotMap();
$slotmap[16384] = '127.0.0.1:6379';
}
/**
* @group disconnected
*/
public function testGetIteratorReturnsIteratorOverSlotMap()
{
$slotmap = new SlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$slotmap->setSlots(10922, 16383, '127.0.0.1:6381');
$expectedMap = array_merge(
array_fill(0, 5461, '127.0.0.1:6379'),
array_fill(5460, 5461, '127.0.0.1:6380'),
array_fill(10921, 5462, '127.0.0.1:6381')
);
$this->assertSame($expectedMap, iterator_to_array($slotmap));
}
}
@@ -348,34 +348,6 @@ class RedisClusterTest extends PredisTestCase
$this->assertSame($connection4, $connections[2]);
}
/**
* @group disconnected
*/
public function testCanAssignConnectionsToCustomSlots()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381');
$cluster = new RedisCluster(new Connection\Factory());
$cluster->add($connection1);
$cluster->add($connection2);
$cluster->add($connection3);
$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');
$expectedMap = array_merge(
array_fill(0, 1365, '127.0.0.1:6379'),
array_fill(1364, 1365, '127.0.0.1:6380'),
array_fill(2729, 1366, '127.0.0.1:6381')
);
$this->assertSame($expectedMap, $cluster->getSlotsMap());
}
/**
* @group disconnected
*/
@@ -388,12 +360,14 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection1);
$cluster->setSlots(0, 4095, '127.0.0.1:6379');
$this->assertSame(array_fill(0, 4096, '127.0.0.1:6379'), $cluster->getSlotsMap());
$slotmap = $cluster->getSlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$this->assertSame(array_fill(0, 5461, '127.0.0.1:6379'), $slotmap->toArray());
$cluster->add($connection2);
$this->assertEmpty($cluster->getSlotsMap());
$this->assertCount(0, $slotmap);
}
/**
@@ -409,18 +383,20 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection1);
$cluster->add($connection2);
$cluster->setSlots(0, 2047, '127.0.0.1:6379');
$cluster->setSlots(2048, 4095, '127.0.0.1:6380');
$slotmap = $cluster->getSlotMap();
$slotmap->setSlots(0, 5460, '127.0.0.1:6379');
$slotmap->setSlots(5461, 10921, '127.0.0.1:6380');
$expectedMap = array_merge(
array_fill(0, 2048, '127.0.0.1:6379'),
array_fill(2048, 2048, '127.0.0.1:6380')
array_fill(0, 5461, '127.0.0.1:6379'),
array_fill(5460, 5461, '127.0.0.1:6380')
);
$this->assertSame($expectedMap, $cluster->getSlotsMap());
$this->assertSame($expectedMap, $slotmap->toArray());
$cluster->remove($connection1);
$this->assertEmpty($cluster->getSlotsMap());
$this->assertCount(0, $slotmap);
}
/**
@@ -438,7 +414,7 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection2);
$cluster->add($connection3);
$cluster->buildSlotsMap();
$cluster->buildSlotMap();
$expectedMap = array_merge(
array_fill(0, 5461, '127.0.0.1:6379'),
@@ -446,7 +422,8 @@ class RedisClusterTest extends PredisTestCase
array_fill(10921, 5462, '127.0.0.1:6381')
);
$actualMap = $cluster->getSlotsMap();
$actualMap = $cluster->getSlotMap()->toArray();
ksort($actualMap);
$this->assertSame($expectedMap, $actualMap);
@@ -467,7 +444,7 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection2);
$cluster->add($connection3);
$cluster->buildSlotsMap();
$cluster->buildSlotMap();
$expectedMap = array_merge(
array_fill(0, 5461, '127.0.0.1:6379'),
@@ -479,7 +456,8 @@ class RedisClusterTest extends PredisTestCase
array_fill(11000, 5383, '127.0.0.1:6381')
);
$actualMap = $cluster->getSlotsMap();
$actualMap = $cluster->getSlotMap()->toArray();
ksort($actualMap);
$this->assertSame($expectedMap, $actualMap);
@@ -504,7 +482,7 @@ class RedisClusterTest extends PredisTestCase
$this->assertSame($connection2, $cluster->getConnectionBySlot(5461));
$this->assertSame($connection3, $cluster->getConnectionBySlot(10922));
$cluster->setSlots(5461, 7096, '127.0.0.1:6380');
$cluster->getSlotMap()->setSlots(5461, 7096, '127.0.0.1:6380');
$this->assertSame($connection2, $cluster->getConnectionBySlot(5461));
}
@@ -679,7 +657,7 @@ class RedisClusterTest extends PredisTestCase
/**
* @group disconnected
*/
public function testRetriesExecutingCommandOnConnectionFailureButDoNotAskSlotsMapWhenDisabled()
public function testRetriesExecutingCommandOnConnectionFailureButDoNotAskSlotMapWhenDisabled()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=0-5500');
$connection1
@@ -766,7 +744,7 @@ class RedisClusterTest extends PredisTestCase
/**
* @group disconnected
*/
public function testAskSlotsMapReturnEmptyArrayOnEmptyConnectionsPool()
public function testAskSlotMapReturnEmptyArrayOnEmptyConnectionsPool()
{
$factory = $this->getMock('Predis\Connection\FactoryInterface');
$factory
@@ -774,14 +752,15 @@ class RedisClusterTest extends PredisTestCase
->method('create');
$cluster = new RedisCluster($factory);
$cluster->askSlotMap();
$this->assertEmpty($cluster->askSlotsMap());
$this->assertCount(0, $cluster->getSlotMap());
}
/**
* @group disconnected
*/
public function testAskSlotsMapRetriesOnDifferentNodeOnConnectionFailure()
public function testAskSlotMapRetriesOnDifferentNodeOnConnectionFailure()
{
$slotsmap = array(
array(0, 5460, array('127.0.0.1', 9381), array()),
@@ -836,7 +815,9 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection2);
$cluster->add($connection3);
$this->assertCount(16384, $cluster->askSlotsMap());
$cluster->askSlotMap();
$this->assertCount(16384, $cluster->getSlotMap());
}
/**
@@ -844,7 +825,7 @@ class RedisClusterTest extends PredisTestCase
* @expectedException \Predis\Connection\ConnectionException
* @expectedExceptionMessage Unknown connection error [127.0.0.1:6382]
*/
public function testAskSlotsMapHonorsRetryLimitOnMultipleConnectionFailures()
public function testAskSlotMapHonorsRetryLimitOnMultipleConnectionFailures()
{
$slotsmap = array(
array(0, 5460, array('127.0.0.1', 9381), array()),
@@ -897,7 +878,7 @@ class RedisClusterTest extends PredisTestCase
$cluster->setRetryLimit(1);
$cluster->askSlotsMap();
$cluster->askSlotMap();
}
/**
@@ -1190,7 +1171,7 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection1);
$cluster->askSlotsMap();
$cluster->askSlotMap();
$this->assertSame($cluster->getConnectionBySlot('6144'), $connection1);
}
@@ -1198,7 +1179,7 @@ class RedisClusterTest extends PredisTestCase
/**
* @group disconnected
*/
public function testAskSlotsMapToRedisClusterOnMovedResponseByDefault()
public function testAskSlotMapToRedisClusterOnMovedResponseByDefault()
{
$cmdGET = Command\RawCommand::create('GET', 'node:1001');
$rspMOVED = new Response\Error('MOVED 1970 127.0.0.1:6380');
@@ -1223,7 +1204,7 @@ class RedisClusterTest extends PredisTestCase
))
->will($this->returnValue($rspSlotsArray));
$connection2
->expects($this->at(2))
->expects($this->at(3))
->method('executeCommand')
->with($cmdGET)
->will($this->returnValue('foobar'));
@@ -1278,7 +1259,7 @@ class RedisClusterTest extends PredisTestCase
$cluster->add($connection2);
$cluster->add($connection3);
$cluster->buildSlotsMap();
$cluster->buildSlotMap();
$unserialized = unserialize(serialize($cluster));