/** * Roll the cache back to pre-transaction state by comparing the current * cache values with what we planned to set them to. * * @param array $old * @param array $new */ protected function rollback(array $old, array $new) { foreach ($old as $key => $value) { $current = $this->cache->get($key, $token); /* * If the value right now equals the one we planned to write, it * should be restored to what it was before. If it's yet something * else, another process must've stored it and we should leave it * alone. */ if ($current === $new) { /* * CAS the rollback. If it fails, that means another process * has stored in the meantime and we can just leave it alone. * Note that we can't know the original expiration time! */ $this->cas($token, $key, $value, 0); } } $this->clear(); }
/** * {@inheritdoc} */ public function get($key, &$token = null) { $value = $this->local->get($key, $token); // short-circuit reading from real cache if we have an uncommitted flush if ($this->suspend && $token === null) { // flush hasn't been committed yet, don't read from real cache! return false; } if ($value === false) { if ($this->local->expired($key)) { /* * Item used to exist in local cache, but is now expired. This * is used when values are to be deleted: we don't want to reach * out to real storage because that would respond with the not- * yet-deleted value. */ return false; } // unknown in local cache = fetch from source cache $value = $this->cache->get($key, $token); } // no value = quit early, don't generate a useless token if ($value === false) { return false; } /* * $token will be unreliable to the deferred updates so generate * a custom one and keep the associated value around. * Read more details in PHPDoc for function cas(). * uniqid is ok here. Doesn't really have to be unique across * servers, just has to be unique every time it's called in this * one particular request - which it is. */ $token = uniqid(); $this->tokens[$token] = serialize($value); return $value; }