* @copyright Copyright (c) 2014, Matthias Mullie. All rights reserved * @license LICENSE MIT */ class BufferedStore implements KeyValueStore { /** * Transaction will already buffer all writes (until the transaction * has been committed/rolled back). As long as we immediately commit * to real store, it'll look as if no transaction is in progress & * all we'll be left with is the local copy of all data that can act * as buffer for follow-up requests. * All we'll need to add is also buffering non-write results. * * @var Transaction */ protected $transaction; /** * Local in-memory storage, for the data we've already requested from * or written to the real cache. * * @var Buffer */ protected $local; /** * @var BufferedStore[] */ protected $collections = array(); /** * @param KeyValueStore $cache The real cache we'll buffer for */ public function __construct(KeyValueStore $cache) { $this->local = new Buffer(); $this->transaction = new Transaction($this->local, $cache); } /** * In addition to all writes being stored to $local, we'll also * keep get() values around ;). * * {@inheritdoc} */ public function get($key, &$token = null) { $value = $this->transaction->get($key, $token); // only store if we managed to retrieve a value (valid token) and it's // not already in cache (or we may mess up tokens) if (false !== $value && false === $this->local->get($key, $localToken) && null === $localToken) { $this->local->set($key, $value); } return $value; } /** * In addition to all writes being stored to $local, we'll also * keep get() values around ;). * * {@inheritdoc} */ public function getMulti(array $keys, array &$tokens = null) { $values = $this->transaction->getMulti($keys, $tokens); $missing = array_diff_key($values, $this->local->getMulti($keys)); if (!empty($missing)) { $this->local->setMulti($missing); } return $values; } /** * {@inheritdoc} */ public function set($key, $value, $expire = 0) { $result = $this->transaction->set($key, $value, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function setMulti(array $items, $expire = 0) { $result = $this->transaction->setMulti($items, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function delete($key) { $result = $this->transaction->delete($key); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function deleteMulti(array $keys) { $result = $this->transaction->deleteMulti($keys); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function add($key, $value, $expire = 0) { $result = $this->transaction->add($key, $value, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function replace($key, $value, $expire = 0) { $result = $this->transaction->replace($key, $value, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function cas($token, $key, $value, $expire = 0) { $result = $this->transaction->cas($token, $key, $value, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function increment($key, $offset = 1, $initial = 0, $expire = 0) { $result = $this->transaction->increment($key, $offset, $initial, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function decrement($key, $offset = 1, $initial = 0, $expire = 0) { $result = $this->transaction->decrement($key, $offset, $initial, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function touch($key, $expire) { $result = $this->transaction->touch($key, $expire); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function flush() { foreach ($this->collections as $collection) { $collection->flush(); } $result = $this->transaction->flush(); $this->transaction->commit(); return $result; } /** * {@inheritdoc} */ public function getCollection($name) { if (!isset($this->collections[$name])) { $collection = $this->transaction->getCollection($name); $this->collections[$name] = new static($collection); } return $this->collections[$name]; } }