Path: blob/master/src/infrastructure/cache/PhutilKeyValueCacheStack.php
12241 views
<?php12/**3* Stacks multiple caches on top of each other, with readthrough semantics:4*5* - For reads, we try each cache in order until we find all the keys.6* - For writes, we set the keys in each cache.7*8* @task config Configuring the Stack9*/10final class PhutilKeyValueCacheStack extends PhutilKeyValueCache {111213/**14* Forward list of caches in the stack (from the nearest cache to the farthest15* cache).16*/17private $cachesForward;181920/**21* Backward list of caches in the stack (from the farthest cache to the22* nearest cache).23*/24private $cachesBackward;252627/**28* TTL to use for any writes which are side effects of the next read29* operation.30*/31private $nextTTL;323334/* -( Configuring the Stack )---------------------------------------------- */353637/**38* Set the caches which comprise this stack.39*40* @param list<PhutilKeyValueCache> Ordered list of key-value caches.41* @return this42* @task config43*/44public function setCaches(array $caches) {45assert_instances_of($caches, 'PhutilKeyValueCache');46$this->cachesForward = $caches;47$this->cachesBackward = array_reverse($caches);4849return $this;50}515253/**54* Set the readthrough TTL for the next cache operation. The TTL applies to55* any keys set by the next call to @{method:getKey} or @{method:getKeys},56* and is reset after the call finishes.57*58* // If this causes any caches to fill, they'll fill with a 15-second TTL.59* $stack->setNextTTL(15)->getKey('porcupine');60*61* // TTL does not persist; this will use no TTL.62* $stack->getKey('hedgehog');63*64* @param int TTL in seconds.65* @return this66*67* @task config68*/69public function setNextTTL($ttl) {70$this->nextTTL = $ttl;71return $this;72}737475/* -( Key-Value Cache Implementation )------------------------------------- */767778public function getKeys(array $keys) {7980$remaining = array_fuse($keys);81$results = array();82$missed = array();8384try {85foreach ($this->cachesForward as $cache) {86$result = $cache->getKeys($remaining);87$remaining = array_diff_key($remaining, $result);88$results += $result;89if (!$remaining) {90while ($cache = array_pop($missed)) {91// TODO: This sets too many results in the closer caches, although92// it probably isn't a big deal in most cases; normally we're just93// filling the request cache.94$cache->setKeys($result, $this->nextTTL);95}96break;97}98$missed[] = $cache;99}100$this->nextTTL = null;101} catch (Exception $ex) {102$this->nextTTL = null;103throw $ex;104}105106return $results;107}108109110public function setKeys(array $keys, $ttl = null) {111foreach ($this->cachesBackward as $cache) {112$cache->setKeys($keys, $ttl);113}114}115116117public function deleteKeys(array $keys) {118foreach ($this->cachesBackward as $cache) {119$cache->deleteKeys($keys);120}121}122123124public function destroyCache() {125foreach ($this->cachesBackward as $cache) {126$cache->destroyCache();127}128}129130}131132133