From c4064e5801026ab6ad5b10e1cb93a281f268f4ed Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Sun, 27 Mar 2011 12:12:51 +0200 Subject: [PATCH] Some commands accepting multiple keys can be hashed if all the keys return the same hash (key tags). List of the commands affected by this change (based on Redis 2.2): MSET, MGET, DEL, BLPOP, BRPOP, RPOPLPUSH, BRPOPLPUSH, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, ZINTERSTORE, ZUNIONSTORE. --- lib/Predis/Commands/Command.php | 15 +++++++++++++++ lib/Predis/Commands/Delete.php | 7 +++++++ lib/Predis/Commands/GetMultiple.php | 4 +++- lib/Predis/Commands/ListPopFirstBlocking.php | 5 +++++ lib/Predis/Commands/ListPopLastBlocking.php | 2 +- lib/Predis/Commands/ListPopLastPushHead.php | 3 +++ .../Commands/ListPopLastPushHeadBlocking.php | 5 +++++ lib/Predis/Commands/SetIntersection.php | 4 +++- lib/Predis/Commands/SetIntersectionStore.php | 4 +++- lib/Predis/Commands/SetMultiple.php | 9 ++++++++- lib/Predis/Commands/ZSetIntersectionStore.php | 1 - lib/Predis/Commands/ZSetUnionStore.php | 7 ++++++- 12 files changed, 59 insertions(+), 7 deletions(-) diff --git a/lib/Predis/Commands/Command.php b/lib/Predis/Commands/Command.php index ce904b70..5c607280 100644 --- a/lib/Predis/Commands/Command.php +++ b/lib/Predis/Commands/Command.php @@ -23,6 +23,21 @@ abstract class Command implements ICommand { return $key; } + protected function checkSameHashForKeys(Array $keys) { + if (($count = count($keys)) === 0) { + return false; + } + $currentKey = $this->getHashablePart($keys[0]); + for ($i = 1; $i < $count; $i++) { + $nextKey = $this->getHashablePart($keys[$i]); + if ($currentKey !== $nextKey) { + return false; + } + $currentKey = $nextKey; + } + return true; + } + public function getHash(IDistributionStrategy $distributor) { if (isset($this->_hash)) { return $this->_hash; diff --git a/lib/Predis/Commands/Delete.php b/lib/Predis/Commands/Delete.php index ba5cd5eb..a844acdf 100644 --- a/lib/Predis/Commands/Delete.php +++ b/lib/Predis/Commands/Delete.php @@ -5,6 +5,13 @@ namespace Predis\Commands; use Predis\Utils; class Delete extends Command { + protected function canBeHashed() { + $args = $this->getArguments(); + if (count($args) === 1) { + return true; + } + return $this->checkSameHashForKeys($args); + } public function getId() { return 'DEL'; } public function filterArguments(Array $arguments) { return Utils::filterArrayArguments($arguments); diff --git a/lib/Predis/Commands/GetMultiple.php b/lib/Predis/Commands/GetMultiple.php index 8a557ffc..1c652c13 100644 --- a/lib/Predis/Commands/GetMultiple.php +++ b/lib/Predis/Commands/GetMultiple.php @@ -5,7 +5,9 @@ namespace Predis\Commands; use Predis\Utils; class GetMultiple extends Command { - protected function canBeHashed() { return false; } + protected function canBeHashed() { + return $this->checkSameHashForKeys($this->getArguments()); + } public function getId() { return 'MGET'; } public function filterArguments(Array $arguments) { return Utils::filterArrayArguments($arguments); diff --git a/lib/Predis/Commands/ListPopFirstBlocking.php b/lib/Predis/Commands/ListPopFirstBlocking.php index 097026ed..ee48a269 100644 --- a/lib/Predis/Commands/ListPopFirstBlocking.php +++ b/lib/Predis/Commands/ListPopFirstBlocking.php @@ -3,5 +3,10 @@ namespace Predis\Commands; class ListPopFirstBlocking extends Command { + protected function canBeHashed() { + return $this->checkSameHashForKeys( + array_slice(($args = $this->getArguments()), 0, count($args) - 1) + ); + } public function getId() { return 'BLPOP'; } } diff --git a/lib/Predis/Commands/ListPopLastBlocking.php b/lib/Predis/Commands/ListPopLastBlocking.php index 11687c15..3e0372d5 100644 --- a/lib/Predis/Commands/ListPopLastBlocking.php +++ b/lib/Predis/Commands/ListPopLastBlocking.php @@ -2,6 +2,6 @@ namespace Predis\Commands; -class ListPopLastBlocking extends Command { +class ListPopLastBlocking extends ListPopFirstBlocking { public function getId() { return 'BRPOP'; } } diff --git a/lib/Predis/Commands/ListPopLastPushHead.php b/lib/Predis/Commands/ListPopLastPushHead.php index 9e32ffd1..a5b934f6 100644 --- a/lib/Predis/Commands/ListPopLastPushHead.php +++ b/lib/Predis/Commands/ListPopLastPushHead.php @@ -3,5 +3,8 @@ namespace Predis\Commands; class ListPopLastPushHead extends Command { + protected function canBeHashed() { + return $this->checkSameHashForKeys($this->getArguments()); + } public function getId() { return 'RPOPLPUSH'; } } diff --git a/lib/Predis/Commands/ListPopLastPushHeadBlocking.php b/lib/Predis/Commands/ListPopLastPushHeadBlocking.php index 6e43fc1a..02152170 100644 --- a/lib/Predis/Commands/ListPopLastPushHeadBlocking.php +++ b/lib/Predis/Commands/ListPopLastPushHeadBlocking.php @@ -3,5 +3,10 @@ namespace Predis\Commands; class ListPopLastPushHeadBlocking extends Command { + protected function canBeHashed() { + return $this->checkSameHashForKeys( + array_slice($args = $this->getArguments(), 0, count($args) - 1) + ); + } public function getId() { return 'BRPOPLPUSH'; } } diff --git a/lib/Predis/Commands/SetIntersection.php b/lib/Predis/Commands/SetIntersection.php index e2484665..0fd86d6c 100644 --- a/lib/Predis/Commands/SetIntersection.php +++ b/lib/Predis/Commands/SetIntersection.php @@ -5,7 +5,9 @@ namespace Predis\Commands; use Predis\Utils; class SetIntersection extends Command { - protected function canBeHashed() { return false; } + protected function canBeHashed() { + return $this->checkSameHashForKeys($this->getArguments()); + } public function getId() { return 'SINTER'; } public function filterArguments(Array $arguments) { return Utils::filterArrayArguments($arguments); diff --git a/lib/Predis/Commands/SetIntersectionStore.php b/lib/Predis/Commands/SetIntersectionStore.php index 78ea568c..0ba71d71 100644 --- a/lib/Predis/Commands/SetIntersectionStore.php +++ b/lib/Predis/Commands/SetIntersectionStore.php @@ -5,7 +5,9 @@ namespace Predis\Commands; use Predis\Utils; class SetIntersectionStore extends Command { - protected function canBeHashed() { return false; } + protected function canBeHashed() { + return $this->checkSameHashForKeys($this->getArguments()); + } public function getId() { return 'SINTERSTORE'; } public function filterArguments(Array $arguments) { return Utils::filterArrayArguments($arguments); diff --git a/lib/Predis/Commands/SetMultiple.php b/lib/Predis/Commands/SetMultiple.php index f26977ff..a0e14e5d 100644 --- a/lib/Predis/Commands/SetMultiple.php +++ b/lib/Predis/Commands/SetMultiple.php @@ -3,7 +3,14 @@ namespace Predis\Commands; class SetMultiple extends Command { - protected function canBeHashed() { return false; } + protected function canBeHashed() { + $args = $this->getArguments(); + $keys = array(); + for ($i = 0; $i < count($args); $i += 2) { + $keys[] = $args[$i]; + } + return $this->checkSameHashForKeys($keys); + } public function getId() { return 'MSET'; } public function filterArguments(Array $arguments) { if (count($arguments) === 1 && is_array($arguments[0])) { diff --git a/lib/Predis/Commands/ZSetIntersectionStore.php b/lib/Predis/Commands/ZSetIntersectionStore.php index 8e8b6a09..11bc9e91 100644 --- a/lib/Predis/Commands/ZSetIntersectionStore.php +++ b/lib/Predis/Commands/ZSetIntersectionStore.php @@ -3,6 +3,5 @@ namespace Predis\Commands; class ZSetIntersectionStore extends ZSetUnionStore { - protected function canBeHashed() { return false; } public function getId() { return 'ZINTERSTORE'; } } diff --git a/lib/Predis/Commands/ZSetUnionStore.php b/lib/Predis/Commands/ZSetUnionStore.php index aed60729..658c50cf 100644 --- a/lib/Predis/Commands/ZSetUnionStore.php +++ b/lib/Predis/Commands/ZSetUnionStore.php @@ -3,7 +3,12 @@ namespace Predis\Commands; class ZSetUnionStore extends Command { - protected function canBeHashed() { return false; } + protected function canBeHashed() { + $args = $this->getArguments(); + return $this->checkSameHashForKeys( + array_merge(array($args[0]), array_slice($args, 2, $args[1])) + ); + } public function getId() { return 'ZUNIONSTORE'; } public function filterArguments(Array $arguments) { $options = array();