From 5cf10ddbfa48200d96a5b8568b6593f0a3aebad1 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Sat, 26 Jun 2010 12:49:57 +0200 Subject: [PATCH 1/9] Add support for variable arguments in Predis\Client::pipeline(). --- lib/Predis.php | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/Predis.php b/lib/Predis.php index 698c3988..98781aa0 100644 --- a/lib/Predis.php +++ b/lib/Predis.php @@ -228,16 +228,44 @@ class Client { return $this->_connection->rawCommand($rawCommandData, $closesConnection); } - public function pipeline($pipelineBlock = null) { - return $this->pipelineExecute(new CommandPipeline($this), $pipelineBlock); + public function pipeline(/* arguments */) { + $argv = func_get_args(); + $argc = func_num_args(); + + if ($argc === 0) { + return $this->initPipeline(); + } + else if ($argc === 1) { + list($arg0) = $argv; + return is_array($arg0) ? $this->initPipeline($arg0) : $this->initPipeline(null, $arg0); + } + else if ($argc === 2) { + list($arg0, $arg1) = $argv; + return $this->initPipeline($arg0, $arg1); + } } public function pipelineSafe($pipelineBlock = null) { - $connection = $this->getConnection(); - $pipeline = new CommandPipeline($this, $connection instanceof Connection - ? new Pipeline\SafeExecutor($connection) - : new Pipeline\SafeClusterExecutor($connection) - ); + return $this->initPipeline(array('safe' => true), $pipelineBlock); + } + + private function initPipeline(Array $options = null, $pipelineBlock = null) { + $pipeline = null; + if (isset($options)) { + if (isset($options['safe']) && $options['safe'] == true) { + $connection = $this->getConnection(); + $pipeline = new CommandPipeline($this, $connection instanceof Connection + ? new Pipeline\SafeExecutor($connection) + : new Pipeline\SafeClusterExecutor($connection) + ); + } + else { + $pipeline = new CommandPipeline($this); + } + } + else { + $pipeline = new CommandPipeline($this); + } return $this->pipelineExecute($pipeline, $pipelineBlock); } From 6d1c4a209639a94102a12fcf96ed7f1115f2f9c3 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Sat, 26 Jun 2010 12:54:12 +0200 Subject: [PATCH 2/9] Update CHANGELOG. --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d82bf4dd..519aae30 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,11 @@ v0.6.1 (2010-xx-xx) accept an array of options for the underlying Predis\MultiExecBlock, but it is still backwards compatible with previous releases of Predis. + * New method signature for Predis\Client::pipeline(). Now it is able to + accept an array of options for the underlying Predis\CommandPipeline, + but it is still backwards compatible with previous releases of Predis. + Predis\Client::pipelineSafe() is to be considered obsolete. + v0.6.0 (2010-05-24) * Switched to the new multi-bulk request protocol for all of the commands in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now From adb489b4d3d36ea0544b146d287df4fa6a34f520 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Tue, 29 Jun 2010 14:39:24 +0200 Subject: [PATCH 3/9] Internal optimizations for the Predis\PubSubContext class. --- lib/Predis.php | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/lib/Predis.php b/lib/Predis.php index 98781aa0..31b0a5b0 100644 --- a/lib/Predis.php +++ b/lib/Predis.php @@ -988,13 +988,16 @@ class PubSubContext implements \Iterator { const MESSAGE = 'message'; const PMESSAGE = 'pmessage'; + const STATUS_VALID = 0x0001; + const STATUS_SUBSCRIBED = 0x0010; + const STATUS_PSUBSCRIBED = 0x0100; + private $_redisClient, $_subscriptions, $_isStillValid, $_position; public function __construct(Client $redisClient) { $this->checkCapabilities($redisClient); - $this->_redisClient = $redisClient; - $this->_isStillValid = true; - $this->_subscriptions = false; + $this->_redisClient = $redisClient; + $this->_statusFlags = self::STATUS_VALID; } public function __destruct() { @@ -1014,9 +1017,13 @@ class PubSubContext implements \Iterator { } } + private function isFlagSet($value) { + return ($this->_statusFlags & $value) === $value; + } + public function subscribe(/* arguments */) { $this->writeCommand(self::SUBSCRIBE, func_get_args()); - $this->_subscriptions = true; + $this->_statusFlags |= self::STATUS_SUBSCRIBED; } public function unsubscribe(/* arguments */) { @@ -1025,7 +1032,7 @@ class PubSubContext implements \Iterator { public function psubscribe(/* arguments */) { $this->writeCommand(self::PSUBSCRIBE, func_get_args()); - $this->_subscriptions = true; + $this->_statusFlags |= self::STATUS_PSUBSCRIBED; } public function punsubscribe(/* arguments */) { @@ -1034,10 +1041,12 @@ class PubSubContext implements \Iterator { public function closeContext() { if ($this->valid()) { - // TODO: as an optimization, we should not send both - // commands if one of them has not been issued. - $this->unsubscribe(); - $this->punsubscribe(); + if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) { + $this->unsubscribe(); + } + if ($this->isFlagSet(self::STATUS_PSUBSCRIBED)) { + $this->punsubscribe(); + } } } @@ -1062,19 +1071,20 @@ class PubSubContext implements \Iterator { } public function next() { - if ($this->_isStillValid) { + if ($this->isFlagSet(self::STATUS_VALID)) { $this->_position++; } return $this->_position; } public function valid() { - return $this->_subscriptions && $this->_isStillValid; + $subscriptions = self::STATUS_SUBSCRIBED + self::STATUS_PSUBSCRIBED; + return $this->isFlagSet(self::STATUS_VALID) + && ($this->_statusFlags & $subscriptions) > 0; } private function invalidate() { - $this->_isStillValid = false; - $this->_subscriptions = false; + $this->_statusFlags = 0x0000; } private function getValue() { From ed105ab4fc51de065f0d3155f9a37ab20b555fd9 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Tue, 29 Jun 2010 19:54:32 +0200 Subject: [PATCH 4/9] Centralize code used to check if a connection object instance is a cluster of connections. --- lib/Predis.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/Predis.php b/lib/Predis.php index 31b0a5b0..0581a18f 100644 --- a/lib/Predis.php +++ b/lib/Predis.php @@ -153,7 +153,7 @@ class Client { } public function getClientFor($connectionAlias) { - if (!($this->_connection instanceof ConnectionCluster)) { + if (!Shared\Utils::isCluster($this->_connection)) { throw new ClientException( 'This method is supported only when the client is connected to a cluster of connections' ); @@ -189,7 +189,7 @@ class Client { return $this->_connection; } else { - return $this->_connection instanceof ConnectionCluster + return Shared\Utils::isCluster($this->_connection) ? $this->_connection->getConnectionById($id) : $this->_connection; } @@ -210,7 +210,7 @@ class Client { public function executeCommandOnShards(Command $command) { $replies = array(); - if ($this->_connection instanceof \Predis\ConnectionCluster) { + if (Shared\Utils::isCluster($this->_connection)) { foreach($this->_connection as $connection) { $replies[] = $connection->executeCommand($command); } @@ -222,7 +222,7 @@ class Client { } public function rawCommand($rawCommandData, $closesConnection = false) { - if ($this->_connection instanceof \Predis\ConnectionCluster) { + if (Shared\Utils::isCluster($this->_connection)) { throw new ClientException('Cannot send raw commands when connected to a cluster of Redis servers'); } return $this->_connection->rawCommand($rawCommandData, $closesConnection); @@ -2108,6 +2108,10 @@ class KetamaPureRing extends HashRing { namespace Predis\Shared; class Utils { + public static function isCluster(\Predis\IConnection $connection) { + return $connection instanceof \Predis\ConnectionCluster; + } + public static function onCommunicationException(\Predis\CommunicationException $exception) { if ($exception->shouldResetConnection()) { $connection = $exception->getConnection(); From 3853e62d341a20fa5aa59beaab0e348b263ba909 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Tue, 29 Jun 2010 20:05:02 +0200 Subject: [PATCH 5/9] Make sure that Predis\MultiExecBlock and Predis\PubSubContext are not initialized over a cluster of connections. --- lib/Predis.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/Predis.php b/lib/Predis.php index 0581a18f..48184929 100644 --- a/lib/Predis.php +++ b/lib/Predis.php @@ -828,6 +828,11 @@ class MultiExecBlock { } private function checkCapabilities(Client $redisClient) { + if (Shared\Utils::isCluster($redisClient->getConnection())) { + throw new \Predis\ClientException( + 'Cannot initialize a MULTI/EXEC context over a cluster of connections' + ); + } $profile = $redisClient->getProfile(); if ($profile->supportsCommands(array('multi', 'exec', 'discard')) === false) { throw new \Predis\ClientException( @@ -1008,6 +1013,11 @@ class PubSubContext implements \Iterator { } private function checkCapabilities(Client $redisClient) { + if (Shared\Utils::isCluster($redisClient->getConnection())) { + throw new \Predis\ClientException( + 'Cannot initialize a PUB/SUB context over a cluster of connections' + ); + } $profile = $redisClient->getProfile(); $commands = array('publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe'); if ($profile->supportsCommands($commands) === false) { From 735c92089cb8db7551f476f3cc0dcdb75f0614bd Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Tue, 29 Jun 2010 20:15:03 +0200 Subject: [PATCH 6/9] Update CHANGELOG. --- CHANGELOG | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 519aae30..ec74aa96 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,9 @@ v0.6.1 (2010-xx-xx) * Minor internal improvements and clean ups. * Predis\MultiExecBlock and Predis\PubSubContext will throw an exception - when trying to create their instances when using a profile that does - not support the required Redis commands. + when trying to create their instances using a profile that does not + support the required Redis commands or when the client is connected to + a cluster of connections. * Various improvements to Predis\MultiExecBlock: - fixes and more consistent behaviour across various usage cases. From 34cfebdc149011f0ffd7eebd462f0aa7c7e5a1ed Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Tue, 29 Jun 2010 20:47:36 +0200 Subject: [PATCH 7/9] Update CHANGELOG. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index ec74aa96..76399f65 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,7 @@ v0.6.1 (2010-xx-xx) + * New commands available in the Redis v2.2 profile (dev): + - Misc. : WATCH, UNWATCH + * Minor internal improvements and clean ups. * Predis\MultiExecBlock and Predis\PubSubContext will throw an exception From 50970c003bc2b226b1a3319a21c21c60021a8169 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Wed, 30 Jun 2010 16:17:19 +0200 Subject: [PATCH 8/9] Accept instances of Predis\ConnectionParameters in Predis\Client::__construct(). --- lib/Predis.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Predis.php b/lib/Predis.php index 48184929..1546c4cd 100644 --- a/lib/Predis.php +++ b/lib/Predis.php @@ -111,7 +111,9 @@ class Client { } private function createConnection($parameters) { - $params = new ConnectionParameters($parameters); + $params = $parameters instanceof ConnectionParameters + ? $parameters + : new ConnectionParameters($parameters); $connection = new Connection($params, $this->_responseReader); if ($params->password !== null) { From f073bc8f70dad3f0766b71690f4ec6ff197077d8 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Wed, 30 Jun 2010 16:24:02 +0200 Subject: [PATCH 9/9] Update CHANGELOG. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 76399f65..392cc0dd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,9 @@ v0.6.1 (2010-xx-xx) * Minor internal improvements and clean ups. + * The constructor of Predis\Client::__construct now accepts also instances + of Predis\ConnectionParameters. + * Predis\MultiExecBlock and Predis\PubSubContext will throw an exception when trying to create their instances using a profile that does not support the required Redis commands or when the client is connected to