Эх сурвалжийг харах

Add support for check-and-set (CAS) for transactions with Predis\MultiExecBlock.

Daniele Alessandri 14 жил өмнө
parent
commit
39619d0c54

+ 21 - 5
lib/Predis.php

@@ -813,6 +813,7 @@ class MultiExecBlock {
         $this->checkCapabilities($redisClient);
         $this->_initialized = false;
         $this->_discarded   = false;
+        $this->_checkAndSet = false;
         $this->_insideBlock = false;
         $this->_redisClient = $redisClient;
         $this->_options     = $options ?: array();
@@ -844,10 +845,14 @@ class MultiExecBlock {
 
     private function initialize() {
         if ($this->_initialized === false) {
-            if (isset($this->_options['watch'])) {
-                $this->watch($this->_options['watch']);
+            $options = &$this->_options;
+            $this->_checkAndSet = isset($options['cas']) && $options['cas'];
+            if (isset($options['watch'])) {
+                $this->watch($options['watch']);
+            }
+            if (!$this->_checkAndSet) {
+                $this->_redisClient->multi();
             }
-            $this->_redisClient->multi();
             $this->_initialized = true;
             $this->_discarded   = false;
         }
@@ -859,8 +864,14 @@ class MultiExecBlock {
 
     public function __call($method, $arguments) {
         $this->initialize();
-        $command  = $this->_redisClient->createCommand($method, $arguments);
-        $response = $this->_redisClient->executeCommand($command);
+        $client = $this->_redisClient;
+
+        if ($this->_checkAndSet) {
+            return call_user_func_array(array($client, $method), $arguments);
+        }
+
+        $command  = $client->createCommand($method, $arguments);
+        $response = $client->executeCommand($command);
         if (isset($response->queued)) {
             $this->_commands[] = $command;
             return $this;
@@ -890,6 +901,11 @@ class MultiExecBlock {
     }
 
     public function multi() {
+        if ($this->_initialized && $this->_checkAndSet) {
+            $this->_checkAndSet = false;
+            $this->_redisClient->multi();
+            return $this;
+        }
         $this->initialize();
     }
 

+ 27 - 0
test/PredisClientFeatures.php

@@ -609,5 +609,32 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
 
         $this->assertEquals('client2', $client1->get('sentinel'));
     }
+
+    function testMultiExecBlock_CheckAndSet() {
+        $client = RC::getConnection();
+        $client->flushdb();
+        $client->set('foo', 'bar');
+
+        $options = array('watch' => 'foo', 'cas' => true);
+        $replies = $client->multiExec($options, function($tx) {
+            $tx->watch('foobar');
+            $foo = $tx->get('foo');
+            $tx->multi();
+            $tx->set('foobar', $foo);
+            $tx->mget('foo', 'foobar');
+        });
+        $this->assertType('array', $replies);
+        $this->assertEquals(array(true, array('bar', 'bar')), $replies);
+
+        $tx = $client->multiExec($options);
+        $tx->watch('foobar');
+        $foo = $tx->get('foo');
+        $replies = $tx->multi()
+                      ->set('foobar', $foo)
+                      ->mget('foo', 'foobar')
+                      ->execute();
+        $this->assertType('array', $replies);
+        $this->assertEquals(array(true, array('bar', 'bar')), $replies);
+    }
 }
 ?>