Loading core/lib/Drupal/Core/Cache/ChainedFastBackend.php +8 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,14 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) { // from there. $last_write_timestamp = $this->getLastWriteTimestamp(); // If the last write timestamp is not set, set it with a fresh value so that // items written to the fast backend from this point onwards are treated as // valid immediately. This avoids having to wait for an explicit cache set // before the fast backend can be used. if ($last_write_timestamp === 0) { $this->markAsOutdated(); } // Don't bother to either read from or write to the fast backend if the last // write timestamp is in the future - it is always set with an additional // grace period for this reason. This reduces the likelihood of a cache Loading core/tests/Drupal/Tests/Core/Cache/ChainedFastBackendTest.php +52 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ public function testGetDoesNotHitConsistentBackend(): void { ->willReturn($timestamp_item); $consistent_cache->expects($this->never()) ->method('getMultiple'); $consistent_cache->expects($this->never()) ->method('set'); $fast_cache = new MemoryBackend(new Time()); $fast_cache->set('foo', 'baz'); Loading Loading @@ -240,4 +242,54 @@ public function testFallThroughToConsistentCache(): void { $this->assertEquals('baz', $chained_fast_backend->get('foo')->data); } /** * Tests last_write_timestamp missing from the consistent backend. */ public function testLastWriteTimestampMissing(): void { $timestamp_cid = ChainedFastBackend::LAST_WRITE_TIMESTAMP_PREFIX . 'cache_foo'; $cache_item = (object) [ 'cid' => 'foo', 'data' => 'baz', 'created' => time(), 'expire' => time() + 3600, 'tags' => ['tag'], ]; $consistent_cache = $this->createMock(CacheBackendInterface::class); $fast_cache = $this->createMock(CacheBackendInterface::class); // Simulate the last_write_timestamp being unset on the consistent backend. $consistent_cache->expects($this->once()) ->method('get') ->with($timestamp_cid) ->willReturn(NULL); // Because the last_write_timestamp was missing, it will be newly set on the // consistent backend. $consistent_cache->expects($this->once()) ->method('set') ->with($timestamp_cid); $consistent_cache->expects($this->once()) ->method('getMultiple') ->with([$cache_item->cid]) ->willReturn([$cache_item->cid => $cache_item]); // We should not get a call for the cache item on the fast backend but // because the last_write_timestamp is now in place, the item from the // consistent backend should be written back. $fast_cache->expects($this->never()) ->method('getMultiple'); $fast_cache->expects($this->once()) ->method('set') ->with($cache_item->cid); $chained_fast_backend = new ChainedFastBackend( $consistent_cache, $fast_cache, 'foo' ); $this->assertEquals('baz', $chained_fast_backend->get('foo')->data); } } Loading
core/lib/Drupal/Core/Cache/ChainedFastBackend.php +8 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,14 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) { // from there. $last_write_timestamp = $this->getLastWriteTimestamp(); // If the last write timestamp is not set, set it with a fresh value so that // items written to the fast backend from this point onwards are treated as // valid immediately. This avoids having to wait for an explicit cache set // before the fast backend can be used. if ($last_write_timestamp === 0) { $this->markAsOutdated(); } // Don't bother to either read from or write to the fast backend if the last // write timestamp is in the future - it is always set with an additional // grace period for this reason. This reduces the likelihood of a cache Loading
core/tests/Drupal/Tests/Core/Cache/ChainedFastBackendTest.php +52 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ public function testGetDoesNotHitConsistentBackend(): void { ->willReturn($timestamp_item); $consistent_cache->expects($this->never()) ->method('getMultiple'); $consistent_cache->expects($this->never()) ->method('set'); $fast_cache = new MemoryBackend(new Time()); $fast_cache->set('foo', 'baz'); Loading Loading @@ -240,4 +242,54 @@ public function testFallThroughToConsistentCache(): void { $this->assertEquals('baz', $chained_fast_backend->get('foo')->data); } /** * Tests last_write_timestamp missing from the consistent backend. */ public function testLastWriteTimestampMissing(): void { $timestamp_cid = ChainedFastBackend::LAST_WRITE_TIMESTAMP_PREFIX . 'cache_foo'; $cache_item = (object) [ 'cid' => 'foo', 'data' => 'baz', 'created' => time(), 'expire' => time() + 3600, 'tags' => ['tag'], ]; $consistent_cache = $this->createMock(CacheBackendInterface::class); $fast_cache = $this->createMock(CacheBackendInterface::class); // Simulate the last_write_timestamp being unset on the consistent backend. $consistent_cache->expects($this->once()) ->method('get') ->with($timestamp_cid) ->willReturn(NULL); // Because the last_write_timestamp was missing, it will be newly set on the // consistent backend. $consistent_cache->expects($this->once()) ->method('set') ->with($timestamp_cid); $consistent_cache->expects($this->once()) ->method('getMultiple') ->with([$cache_item->cid]) ->willReturn([$cache_item->cid => $cache_item]); // We should not get a call for the cache item on the fast backend but // because the last_write_timestamp is now in place, the item from the // consistent backend should be written back. $fast_cache->expects($this->never()) ->method('getMultiple'); $fast_cache->expects($this->once()) ->method('set') ->with($cache_item->cid); $chained_fast_backend = new ChainedFastBackend( $consistent_cache, $fast_cache, 'foo' ); $this->assertEquals('baz', $chained_fast_backend->get('foo')->data); } }