mirror of
https://github.com/predis/predis.git
synced 2026-08-30 04:02:22 +00:00
Support EVAL and EVALSHA with client-side sharding (Predis cluster).
We extract the keys from commands using the second argument of EVAL / EVALSHA which specifies the number of arguments that must be treated as keys (used to populate the KEYS table in the Lua script) and then we check if all the keys generate the same hash using the usual method. Our scripted command abstraction is also supported. It comes without saying that accessing or setting keys from within the Lua script is something that might not work as expected, so you should be careful when using EVAL and EVALSHA in the context of client-side sharding.
This commit is contained in:
@@ -13,6 +13,7 @@ namespace Predis\Cluster;
|
||||
|
||||
use Predis\Cluster\Hash\HashGeneratorInterface;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\ScriptedCommand;
|
||||
|
||||
/**
|
||||
* Default class used by Predis for client-side sharding to calculate
|
||||
@@ -146,6 +147,10 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
'HSET' => $keyIsFirstArgument,
|
||||
'HSETNX' => $keyIsFirstArgument,
|
||||
'HVALS' => $keyIsFirstArgument,
|
||||
|
||||
/* scripting */
|
||||
'EVAL' => array($this, 'getKeyFromScriptingCommands'),
|
||||
'EVALSHA' => array($this, 'getKeyFromScriptingCommands'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -281,6 +286,23 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the key from EVAL and EVALSHA commands.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
{
|
||||
$keys = $command instanceof ScriptedCommand
|
||||
? $command->getKeys()
|
||||
: array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
|
||||
if ($keys && $this->checkSameHashForKeys($keys)) {
|
||||
return $keys[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -149,6 +149,41 @@ class PredisClusterHashStrategyTest extends StandardTestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testKeysForScriptCommand()
|
||||
{
|
||||
$strategy = $this->getHashStrategy();
|
||||
$profile = ServerProfile::getDevelopment();
|
||||
$arguments = array('%SCRIPT%', 2, '{key}:1', '{key}:2', 'value1', 'value2');
|
||||
|
||||
foreach ($this->getExpectedCommands('keys-script') as $commandID) {
|
||||
$command = $profile->createCommand($commandID, $arguments);
|
||||
$this->assertNotNull($strategy->getHash($command), $commandID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testKeysForScriptedCommand()
|
||||
{
|
||||
$strategy = $this->getHashStrategy();
|
||||
$arguments = array('{key}:1', '{key}:2', 'value1', 'value2');
|
||||
|
||||
$command = $this->getMock('Predis\Command\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue('return true'));
|
||||
$command->expects($this->exactly(2))
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertNotNull($strategy->getHash($command), "Scripted Command [{$command->getId()}]");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -315,6 +350,10 @@ class PredisClusterHashStrategyTest extends StandardTestCase
|
||||
'HSET' => 'keys-first',
|
||||
'HSETNX' => 'keys-first',
|
||||
'HVALS' => 'keys-first',
|
||||
|
||||
/* scripting */
|
||||
'EVAL' => 'keys-script',
|
||||
'EVALSHA' => 'keys-script',
|
||||
);
|
||||
|
||||
if (isset($type)) {
|
||||
|
||||
Reference in New Issue
Block a user