mirror of
https://github.com/predis/predis.git
synced 2026-08-24 14:09:27 +00:00
Implement "crc16" client option for redis-cluster.
By default Predis chooses automatically which hash generator to use: if a suitable version of ext-phpiredis is loaded (that is, a version that implements the phpiredis_utils_crc16() function) it uses the new Predis\Cluster\Hash\PhpiredisCRC16 generator, otherwise it falls back to the usual pure-PHP Predis\Cluster\Hash\CRC16 generator.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
<?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\Configuration\Option;
|
||||
|
||||
use Predis\Cluster\Hash;
|
||||
use Predis\Configuration\OptionInterface;
|
||||
use Predis\Configuration\OptionsInterface;
|
||||
|
||||
/**
|
||||
* Configures an hash generator used by the redis-cluster connection backend.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class CRC16 implements OptionInterface
|
||||
{
|
||||
/**
|
||||
* Returns an hash generator instance from a descriptive name.
|
||||
*
|
||||
* @param OptionsInterface $options Client options.
|
||||
* @param string $description Identifier of a hash generator (`predis`, `phpiredis`)
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
protected function getHashGeneratorByDescription(OptionsInterface $options, $description)
|
||||
{
|
||||
if ($description === 'predis') {
|
||||
return new Hash\CRC16();
|
||||
} elseif ($description === 'phpiredis') {
|
||||
return new Hash\PhpiredisCRC16();
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
'String value for the crc16 option must be either `predis` or `phpiredis`'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(OptionsInterface $options, $value)
|
||||
{
|
||||
if (is_callable($value)) {
|
||||
$value = call_user_func($value, $options);
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
return $this->getHashGeneratorByDescription($options, $value);
|
||||
} elseif ($value instanceof Hash\HashGeneratorInterface) {
|
||||
return $value;
|
||||
} else {
|
||||
$class = get_class($this);
|
||||
throw new \InvalidArgumentException("$class expects a valid hash generator");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefault(OptionsInterface $options)
|
||||
{
|
||||
return function_exists('phpiredis_utils_crc16')
|
||||
? new Hash\PhpiredisCRC16()
|
||||
: new Hash\CRC16();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Predis\Configuration\Option;
|
||||
|
||||
use Predis\Cluster\RedisStrategy;
|
||||
use Predis\Configuration\OptionsInterface;
|
||||
use Predis\Connection\Cluster\PredisCluster;
|
||||
use Predis\Connection\Cluster\RedisCluster;
|
||||
@@ -38,7 +39,7 @@ class Cluster extends Aggregate
|
||||
$callback = $this->getDefault($options);
|
||||
} elseif ($description === 'redis') {
|
||||
$callback = function ($options) {
|
||||
return new RedisCluster($options->connections);
|
||||
return new RedisCluster($options->connections, new RedisStrategy($options->crc16));
|
||||
};
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
|
||||
@@ -50,6 +50,7 @@ class Options implements OptionsInterface
|
||||
'commands' => 'Predis\Configuration\Option\Commands',
|
||||
'exceptions' => 'Predis\Configuration\Option\Exceptions',
|
||||
'prefix' => 'Predis\Configuration\Option\Prefix',
|
||||
'crc16' => 'Predis\Configuration\Option\CRC16',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
<?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\Configuration\Option;
|
||||
|
||||
use Predis\Cluster\Hash;
|
||||
use PredisTestCase;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class CRC16Test extends PredisTestCase
|
||||
{
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testDefaultOptionValue()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
$hashGenerator = $option->getDefault($options);
|
||||
|
||||
$this->assertInstanceOf('Predis\Cluster\Hash\HashGeneratorInterface', $hashGenerator);
|
||||
|
||||
if (function_exists('phpiredis_utils_crc16')) {
|
||||
$this->assertInstanceOf('Predis\Cluster\Hash\PhpiredisCRC16', $hashGenerator);
|
||||
} else {
|
||||
$this->assertInstanceOf('Predis\Cluster\Hash\CRC16', $hashGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testAcceptsHashGeneratorInstance()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
$hashGenerator = $this->getMock('Predis\Cluster\Hash\HashGeneratorInterface');
|
||||
|
||||
$this->assertSame($hashGenerator, $option->filter($options, $hashGenerator));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testAcceptsCallableAsHashGeneratorInitializer()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
$hashGenerator = $this->getMock('Predis\Cluster\Hash\HashGeneratorInterface');
|
||||
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
$callable
|
||||
->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'))
|
||||
->will($this->returnValue($hashGenerator));
|
||||
|
||||
$this->assertSame($hashGenerator, $option->filter($options, $callable));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage Predis\Configuration\Option\CRC16 expects a valid hash generator
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidReturnTypeOfHashGeneratorInitializer()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
$wrongValue = $this->getMock('stdClass');
|
||||
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
$callable
|
||||
->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'))
|
||||
->will($this->returnValue($wrongValue));
|
||||
|
||||
$option->filter($options, $callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testAcceptsShortNameStringPredis()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
|
||||
$this->assertInstanceOf('Predis\Cluster\Hash\CRC16', $option->filter($options, 'predis'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @group ext-phpiredis
|
||||
* @requires extension phpiredis
|
||||
* @requires function phpiredis_utils_crc16
|
||||
*/
|
||||
public function testAcceptsShortNameStringPhpiredis()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
|
||||
$this->assertInstanceOf('Predis\Cluster\Hash\PhpiredisCRC16', $option->filter($options, 'phpiredis'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage String value for the crc16 option must be either `predis` or `phpiredis`
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidShortNameString()
|
||||
{
|
||||
$option = new CRC16();
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
|
||||
$option->filter($options, 'unknown');
|
||||
}
|
||||
}
|
||||
@@ -102,12 +102,19 @@ class ClusterTest extends PredisTestCase
|
||||
|
||||
$options = $this->getMock('Predis\Configuration\OptionsInterface');
|
||||
$options
|
||||
->expects($this->once())
|
||||
->expects($this->at(0))
|
||||
->method('__get')
|
||||
->with('connections')
|
||||
->will($this->returnValue(
|
||||
$this->getMock('Predis\Connection\FactoryInterface')
|
||||
));
|
||||
$options
|
||||
->expects($this->at(1))
|
||||
->method('__get')
|
||||
->with('crc16')
|
||||
->will($this->returnValue(
|
||||
$this->getMock('Predis\Cluster\Hash\HashGeneratorInterface')
|
||||
));
|
||||
|
||||
$this->assertInstanceOf('Closure', $initializer = $option->filter($options, 'redis'));
|
||||
$this->assertInstanceOf('Predis\Connection\Cluster\RedisCluster', $initializer($parameters = array()));
|
||||
|
||||
Reference in New Issue
Block a user