Unverified Commit 4332e36a authored by Alex Pott's avatar Alex Pott
Browse files

fix: #3584324 Make the chained fast backend self-heal when last_write_timestamp is missing

By: catch
By: smustgrave
By: dries
By: kristiaanvandeneynde
(cherry picked from commit c3a6c1a5)
parent 75f04581
Loading
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
+52 −0
Original line number Diff line number Diff line
@@ -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');
@@ -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);
  }

}