diff --git a/core/lib/Drupal/Core/Cache/StaticCache/LruStaticCache.php b/core/lib/Drupal/Core/Cache/StaticCache/LruStaticCache.php new file mode 100644 index 0000000..7762c70 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/StaticCache/LruStaticCache.php @@ -0,0 +1,164 @@ +allowedSlots = $slots; + } + $this->availableSlots = $this->allowedSlots; + } + + /** + * {@inheritdoc} + */ + public function get($cid, $allow_invalid = FALSE) { + if ($cached = parent::get($cid, $allow_invalid)) { + // Check if the item is already at the end of the positions array. If it + // is, it can't be moved any further up. Otherwise move it there. + if (end($this->positions) !== $cid) { + $current_position = array_search($cid, $this->positions); + unset($this->positions[$current_position]); + $this->positions[] = $cid; + } + } + return $cached; + } + + /** + * {@inheritdoc} + */ + public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) { + // If there are still available slots, decrement the counter. + if ($this->availableSlots) { + $this->availableSlots--; + } + // Otherwise remove the least recently used item. + else { + $key = array_shift($this->positions); + unset($this->cache[$key]); + } + // Add this item to the most recently used slot. + $this->positions[] = $cid; + return parent::set($cid, $data, $expire, $tags); + } + + /** + * {@inheritdoc} + */ + public function delete($cid) { + $this->availableSlots++; + $current_position = array_search($cid, $this->positions); + unset($this->positions[$current_position]); + parent::delete($cid); + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple(array $cids) { + foreach ($cids as $cid) { + $this->delete($cid); + } + } + + /** + * {@inheritdoc} + */ + public function invalidate($cid) { + parent::invalidate($cid); + // Move the item to the least recently used position if it's not already + // there. + if (isset($this->cache[$cid])) { + if (reset($this->positions) !== $cid) { + $current_position = array_search($cid, $this->positions); + unset($this->positions[$current_position]); + array_unshift($this->positions, $cid); + } + } + } + + /** + * {@inheritdoc} + */ + public function invalidateMultiple(array $cids) { + foreach ($cids as $cid) { + $this->invalidate($cid); + } + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) { + foreach ($this->cache as $cid => $item) { + if (array_intersect($tags, $item->tags)) { + $this->invalidate($cid); + } + } + } + + /** + * {@inheritdoc} + */ + public function deleteAll() { + $this->resetSlots(); + return parent::deleteAll(); + } + + /** + * {@inheritdoc} + */ + public function reset() { + $this->resetSlots(); + return parent::reset(); + } + + /** + * Reset the available slots and positions. + */ + protected function resetSlots() { + $this->availableSlots = $this->allowedSlots; + $this->positions = []; + } + +} diff --git a/core/tests/Drupal/Tests/Core/Cache/LruStaticCacheTest.php b/core/tests/Drupal/Tests/Core/Cache/LruStaticCacheTest.php new file mode 100644 index 0000000..9c8fdb7 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Cache/LruStaticCacheTest.php @@ -0,0 +1,92 @@ +staticCache = new LruStaticCache(3); + $cids = [ + ['sparrow', 'sparrow'], + ['pidgie', 'pidgie'], + ['crow', 'crow'], + ]; + foreach ($cids as $items) { + $this->staticCache->set($items[0], $items[0]); + } + $this->assertCids($cids); + $this->staticCache->set('cuckoo', 'cuckoo'); + $cids[0] = ['sparrow', FALSE]; + $cids[]= ['cuckoo', 'cuckoo']; + $this->assertCids($cids); + + // Now bring pidgie to the most recently used spot. + $this->staticCache->get('pidgie'); + + $this->staticCache->set('bigger_cuckoo', 'bigger_cuckoo'); + $cids[2] = ['crow', FALSE]; + $cids[5] = ['bigger_cuckoo', 'bigger_cuckoo']; + $this->assertCids($cids); + } + + public function testInvalidate() { + $this->staticCache = new LruStaticCache(3); + $cids = [ + ['sparrow', 'sparrow'], + ['pidgie', 'pidgie'], + ['crow', 'crow'], + ]; + foreach ($cids as $items) { + $this->staticCache->set($items[0], $items[0]); + } + $this->assertCids($cids); + $this->staticCache->invalidate('crow'); + $this->staticCache->set('cuckoo', 'cuckoo', LruStaticCache::CACHE_PERMANENT, ['cuckoo']); + $cids[2] = ['crow', FALSE]; + $cids[]= ['cuckoo', 'cuckoo']; + $this->assertCids($cids); + $this->staticCache->invalidateTags(['cuckoo']); + $this->staticCache->set('crow', 'crow'); + $cids[2] = ['crow', 'crow']; + $cids[3] = ['cuckoo', FALSE]; + $this->assertCids($cids); + + $this->staticCache->invalidateMultiple(['pidgie', 'crow']); + $this->staticCache->set('duck', 'duck'); + $cids[1] = ['pidgie', FALSE]; + $this->staticCache->set('chicken', 'chicken'); + $cids[2] = ['crow', FALSE]; + $this->assertCids($cids); + } + + protected function assertCids($cids) { + foreach ($cids as $items) { + $cached = $this->staticCache->get($items[0]); + if ($items[1]) { + $this->assertEquals($items[1], $cached->data); + } + else { + $this->assertFalse($cached); + } + } + } + + +}