Files
predis/tests/Predis/Cluster/Distribution/HashRingTest.php
T
Daniele Alessandri 09de7be7cb Add optional callable to drive extraction of node hash in distributor.
This is mainly in response to the longstanding issue #36 in which my
proposed solution was fine in terms of functionalities, but eventually
never made into the repository since it was far from being clean enough
for my taste.

Now developers can optionally pass a callable object when creating the
hashring instance to decide how the distributor should extract the hash
from a node (really a connection instance) to populate the ring:

  use Predis\Cluster\Distribution\HashRing;
  use Predis\Connection\PredisCluster;

  $servers = array(
    'tcp://10.0.0.1?alias=node01',
    'tcp://10.0.0.2?alias=node02',
  );

  $options = array(
    'nodehash' => function ($connection) {
      return $connection->getParameters()->alias;
    },
    'cluster' => function ($options) {
      $replicas = HashRing::DEFAULT_REPLICAS;
      $hashring = new HashRing($replicas, $options->nodehash);
      $cluster  = new PredisCluster($hashring);

      return $cluster;
    },
  );

  $client = new Predis\Client($servers, $options);

Both HashRing and KetamaPureRing in the Predis\Cluster\Distribution
namespace support this new approach.
2013-01-13 13:10:01 +01:00

154 lines
3.7 KiB
PHP

<?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\Distribution;
/**
* @todo To be improved.
*/
class HashRingTest extends DistributionStrategyTestCase
{
/**
* {@inheritdoc}
*/
public function getDistributorInstance()
{
return new HashRing();
}
/**
* @group disconnected
*/
public function testHash()
{
$ring = $this->getDistributorInstance();
$this->assertEquals(crc32('foobar'), $ring->hash('foobar'));
}
/**
* @group disconnected
*/
public function testSingleNodeInRing()
{
$node = '127.0.0.1:7000';
$ring = $this->getDistributorInstance();
$ring->add($node);
$expected = array_fill(0, 20, $node);
$actual = $this->getNodes($ring, 20);
$this->assertSame($expected, $actual);
}
/**
* @group disconnected
*/
public function testMultipleNodesInRing()
{
$nodes = array(
'127.0.0.1:7000',
'127.0.0.1:7001',
'127.0.0.1:7002',
);
$ring = $this->getDistributorInstance();
foreach ($nodes as $node) {
$ring->add($node);
}
$expected = array(
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7002',
'127.0.0.1:7002',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7000',
'127.0.0.1:7001',
'127.0.0.1:7002',
'127.0.0.1:7002',
'127.0.0.1:7002',
'127.0.0.1:7002',
'127.0.0.1:7000',
'127.0.0.1:7002',
'127.0.0.1:7002',
'127.0.0.1:7002',
'127.0.0.1:7000',
'127.0.0.1:7001',
'127.0.0.1:7002',
);
$actual = $this->getNodes($ring, 20);
$this->assertSame($expected, $actual);
}
/**
* @group disconnected
*/
public function testSubsequendAddAndRemoveFromRing()
{
$ring = $this->getDistributorInstance();
$expected1 = array_fill(0, 10, '127.0.0.1:7000');
$expected3 = array_fill(0, 10, '127.0.0.1:7001');
$expected2 = array(
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7001',
'127.0.0.1:7000',
'127.0.0.1:7001',
'127.0.0.1:7000',
);
$ring->add('127.0.0.1:7000');
$actual1 = $this->getNodes($ring, 10);
$ring->add('127.0.0.1:7001');
$actual2 = $this->getNodes($ring, 10);
$ring->remove('127.0.0.1:7000');
$actual3 = $this->getNodes($ring, 10);
$this->assertSame($expected1, $actual1);
$this->assertSame($expected2, $actual2);
$this->assertSame($expected3, $actual3);
}
/**
* @todo This tests should be moved in Predis\Cluster\Distribution\DistributionStrategyTestCase
* @group disconnected
*/
public function testCallbackToGetNodeHash()
{
$node = '127.0.0.1:7000';
$replicas = HashRing::DEFAULT_REPLICAS;
$callable = $this->getMock('stdClass', array('__invoke'));
$callable->expects($this->once())
->method('__invoke')
->with($node)
->will($this->returnValue($node));
$ring = new HashRing($replicas, $callable);
$ring->add($node);
$this->getNodes($ring);
}
}