Browse Source

Use a single integer to store and check the current state of a transaction.

Daniele Alessandri 13 years ago
parent
commit
03d408ddad
1 changed files with 54 additions and 34 deletions
  1. 54 34
      lib/Predis/Transaction/MultiExecContext.php

+ 54 - 34
lib/Predis/Transaction/MultiExecContext.php

@@ -11,15 +11,18 @@ use Predis\CommunicationException;
 use Predis\Protocol\ProtocolException;
 
 class MultiExecContext {
+    const STATE_RESET       = 0x00000;
+    const STATE_INITIALIZED = 0x00001;
+    const STATE_INSIDEBLOCK = 0x00010;
+    const STATE_DISCARDED   = 0x00100;
+    const STATE_CAS         = 0x01000;
+    const STATE_WATCH       = 0x10000;
+
     private $_client;
     private $_options;
-    private $_commands;
+    private $_state;
     private $_supportsWatch;
-    private $_initialized;
-    private $_discarded;
-    private $_insideBlock;
-    private $_checkAndSet;
-    private $_watchedKeys;
+    private $_commands;
 
     public function __construct(Client $client, Array $options = null) {
         $this->checkCapabilities($client);
@@ -28,6 +31,22 @@ class MultiExecContext {
         $this->reset();
     }
 
+    protected function setState($flags) {
+        $this->_state = $flags;
+    }
+
+    protected function flagState($flags) {
+        $this->_state |= $flags;
+    }
+
+    protected function unflagState($flags) {
+        $this->_state &= ~$flags;
+    }
+
+    protected function checkState($flags) {
+        return ($this->_state & $flags) === $flags;
+    }
+
     private function checkCapabilities(Client $client) {
         if (Helpers::isCluster($client->getConnection())) {
             throw new ClientException(
@@ -52,37 +71,37 @@ class MultiExecContext {
     }
 
     private function reset() {
-        $this->_initialized = false;
-        $this->_discarded   = false;
-        $this->_checkAndSet = false;
-        $this->_insideBlock = false;
-        $this->_watchedKeys = false;
-        $this->_commands    = array();
+        $this->setState(self::STATE_RESET);
+        $this->_commands = array();
     }
 
     private function initialize() {
-        if ($this->_initialized === true) {
+        if ($this->checkState(self::STATE_INITIALIZED)) {
             return;
         }
         $options = $this->_options;
-        $this->_checkAndSet = isset($options['cas']) && $options['cas'];
+        if (isset($options['cas']) && $options['cas']) {
+            $this->flagState(self::STATE_CAS);
+        }
         if (isset($options['watch'])) {
             $this->watch($options['watch']);
         }
-        if (!$this->_checkAndSet || ($this->_discarded && $this->_checkAndSet)) {
+        $cas = $this->checkState(self::STATE_CAS);
+        $discarded = $this->checkState(self::STATE_DISCARDED);
+        if (!$cas || ($cas && $discarded)) {
             $this->_client->multi();
-            if ($this->_discarded) {
-                $this->_checkAndSet = false;
+            if ($discarded) {
+                $this->unflagState(self::STATE_CAS);
             }
         }
-        $this->_initialized = true;
-        $this->_discarded   = false;
+        $this->unflagState(self::STATE_DISCARDED);
+        $this->flagState(self::STATE_INITIALIZED);
     }
 
     public function __call($method, $arguments) {
         $this->initialize();
         $client = $this->_client;
-        if ($this->_checkAndSet) {
+        if ($this->checkState(self::STATE_CAS)) {
             return call_user_func_array(array($client, $method), $arguments);
         }
         $command  = $client->createCommand($method, $arguments);
@@ -96,36 +115,37 @@ class MultiExecContext {
 
     public function watch($keys) {
         $this->isWatchSupported();
-        $this->_watchedKeys = true;
-        if ($this->_initialized && !$this->_checkAndSet) {
+        if ($this->checkState(self::STATE_INITIALIZED) && !$this->checkState(self::STATE_CAS)) {
             throw new ClientException('WATCH inside MULTI is not allowed');
         }
+        $this->flagState(self::STATE_WATCH);
         return $this->_client->watch($keys);
     }
 
     public function multi() {
-        if ($this->_initialized && $this->_checkAndSet) {
-            $this->_checkAndSet = false;
+        if ($this->checkState(self::STATE_INITIALIZED | self::STATE_CAS)) {
+            $this->unflagState(self::STATE_CAS);
             $this->_client->multi();
-            return $this;
         }
-        $this->initialize();
+        else {
+            $this->initialize();
+        }
         return $this;
     }
 
     public function unwatch() {
         $this->isWatchSupported();
-        $this->_watchedKeys = false;
+        $this->unflagState(self::STATE_WATCH);
         $this->_client->unwatch();
         return $this;
     }
 
     public function discard() {
-        if ($this->_initialized === true) {
-            $command = $this->_checkAndSet ? 'unwatch' : 'discard';
+        if ($this->checkState(self::STATE_INITIALIZED)) {
+            $command = $this->checkState(self::STATE_CAS) ? 'unwatch' : 'discard';
             $this->_client->$command();
             $this->reset();
-            $this->_discarded = true;
+            $this->flagState(self::STATE_DISCARDED);
         }
         return $this;
     }
@@ -135,7 +155,7 @@ class MultiExecContext {
     }
 
     private function checkBeforeExecution($block) {
-        if ($this->_insideBlock === true) {
+        if ($this->checkState(self::STATE_INSIDEBLOCK)) {
             throw new ClientException(
                 "Cannot invoke 'execute' or 'exec' inside an active client transaction block"
             );
@@ -170,7 +190,7 @@ class MultiExecContext {
         do {
             $blockException = null;
             if ($block !== null) {
-                $this->_insideBlock = true;
+                $this->flagState(self::STATE_INSIDEBLOCK);
                 try {
                     $block($this);
                 }
@@ -184,14 +204,14 @@ class MultiExecContext {
                     $blockException = $exception;
                     $this->discard();
                 }
-                $this->_insideBlock = false;
+                $this->unflagState(self::STATE_INSIDEBLOCK);
                 if ($blockException !== null) {
                     throw $blockException;
                 }
             }
 
             if (count($this->_commands) === 0) {
-                if ($this->_watchedKeys) {
+                if ($this->checkState(self::STATE_WATCH)) {
                     $this->discard();
                     return;
                 }