/** * Since our CAS is deferred, the CAS token we got from our original * get() will likely not be valid by the time we want to store it to * the real cache. Imagine this scenario: * * a value is fetched from (real) cache * * an new value key is CAS'ed (into temp cache - real CAS is deferred) * * this key's value is fetched again (this time from temp cache) * * and a new value is CAS'ed again (into temp cache...). * * In this scenario, when we finally want to replay the write actions * onto the real cache, the first 3 actions would likely work fine. * The last (second CAS) however would not, since it never got a real * updated $token from the real cache. * * To work around this problem, all get() calls will return a unique * CAS token and store the value-at-that-time associated with that * token. All we have to do when we want to write the data to real cache * is, right before was CAS for real, get the value & (real) cas token * from storage & compare that value to the one we had stored. If that * checks out, we can safely resume the CAS with the real token we just * received. * * {@inheritdoc} */ public function cas($token, $key, $value, $expire = 0) { $originalValue = isset($this->tokens[$token]) ? $this->tokens[$token] : null; // value is no longer the same as what we used for token if (serialize($this->get($key)) !== $originalValue) { return false; } // "CAS" value to local cache/memory $success = $this->local->set($key, $value, $expire); if ($success === false) { return false; } // only schedule the CAS to be performed on real cache if it was OK on // local cache $this->defer->cas($originalValue, $key, $value, $expire); return true; }