Skip to content

Commit

Permalink
Storing items into previous cache pool (#158)
Browse files Browse the repository at this point in the history
* fix merging loaded items, when return type of getItems method from chained pool is Generator instead of array
add unsetting loaded key from next chain pool loading for better performance
fix psr2 code style

* change array_merge($loadedItems, $hits);

* add storing items into previous cache pool in getItems method

* change code style

* change code style

* added test for CachePoolChain

* change code style

* added testGetItemsWithEmptyCache
  • Loading branch information
panki3a authored and Nyholm committed Apr 27, 2017
1 parent 0cd9a75 commit c795099
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 9 deletions.
43 changes: 34 additions & 9 deletions CachePoolChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class CachePoolChain implements CacheItemPoolInterface, LoggerAwareInterface
*/
public function __construct(array $pools, array $options = [])
{
$this->pools = $pools;
$this->pools = $pools;

if (!isset($options['skip_on_failure'])) {
$options['skip_on_failure'] = false;
Expand Down Expand Up @@ -97,8 +97,10 @@ public function getItem($key)
*/
public function getItems(array $keys = [])
{
$hits = [];
$items = [];
$hits = [];
$loadedItems = [];
$notFoundItems = [];
$keysCount = count($keys);
foreach ($this->getPools() as $poolKey => $pool) {
try {
$items = $pool->getItems($keys);
Expand All @@ -107,19 +109,41 @@ public function getItems(array $keys = [])
foreach ($items as $item) {
if ($item->isHit()) {
$hits[$item->getKey()] = $item;
unset($keys[array_search($item->getKey(), $keys)]);
} else {
$notFoundItems[$poolKey][$item->getKey()] = $item->getKey();
}
$loadedItems[$item->getKey()] = $item;
}

if (count($hits) === count($keys)) {
return $hits;
if (count($hits) === $keysCount) {
break;
}
} catch (CachePoolException $e) {
$this->handleException($poolKey, __FUNCTION__, $e);
}
}

// We need to accept that some items where not hits.
return array_merge($hits, $items);
if (!empty($hits) && !empty($notFoundItems)) {
foreach ($notFoundItems as $poolKey => $itemKeys) {
try {
$pool = $this->getPools()[$poolKey];
$found = false;
foreach ($itemKeys as $itemKey) {
if (!empty($hits[$itemKey])) {
$found = true;
$pool->saveDeferred($hits[$itemKey]);
}
}
if ($found) {
$pool->commit();
}
} catch (CachePoolException $e) {
$this->handleException($poolKey, __FUNCTION__, $e);
}
}
}

return array_merge($loadedItems, $hits);
}

/**
Expand Down Expand Up @@ -326,7 +350,8 @@ private function handleException($poolKey, $operation, CachePoolException $excep

$this->log(
'warning',
sprintf('Removing pool "%s" from chain because it threw an exception when executing "%s"', $poolKey, $operation),
sprintf('Removing pool "%s" from chain because it threw an exception when executing "%s"', $poolKey,
$operation),
['exception' => $exception]
);

Expand Down
111 changes: 111 additions & 0 deletions Tests/CachePoolChainTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

/*
* This file is part of php-cache organization.
*
* (c) 2015 Aaron Scherer <[email protected]>, Tobias Nyholm <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Cache\Adapter\Chain\Tests;

use Cache\Adapter\Chain\CachePoolChain;
use Cache\Adapter\Common\CacheItem;
use Cache\Adapter\PHPArray\ArrayCachePool;

/**
* Class ChainPoolTest.
*/
class CachePoolChainTest extends \PHPUnit_Framework_TestCase
{
public function testGetItemStoreToPrevious()
{
$firstPool = new ArrayCachePool();
$secondPool = new ArrayCachePool();
$chainPool = new CachePoolChain([$firstPool, $secondPool]);

$key = 'test_key';
$item = new CacheItem($key, true, 'value');
$item->expiresAfter(60);
$secondPool->save($item);

$loadedItem = $firstPool->getItem($key);
$this->assertFalse($loadedItem->isHit());

$loadedItem = $secondPool->getItem($key);
$this->assertTrue($loadedItem->isHit());

$loadedItem = $chainPool->getItem($key);
$this->assertTrue($loadedItem->isHit());

$loadedItem = $firstPool->getItem($key);
$this->assertTrue($loadedItem->isHit());
}

public function testGetItemsStoreToPrevious()
{
$firstPool = new ArrayCachePool();
$secondPool = new ArrayCachePool();
$chainPool = new CachePoolChain([$firstPool, $secondPool]);

$key = 'test_key';
$item = new CacheItem($key, true, 'value');
$item->expiresAfter(60);
$secondPool->save($item);
$firstExpirationTime = $item->getExpirationTimestamp();

$key2 = 'test_key2';
$item = new CacheItem($key2, true, 'value2');
$item->expiresAfter(60);
$secondPool->save($item);
$secondExpirationTime = $item->getExpirationTimestamp();

$loadedItem = $firstPool->getItem($key);
$this->assertFalse($loadedItem->isHit());

$loadedItem = $firstPool->getItem($key2);
$this->assertFalse($loadedItem->isHit());

$loadedItem = $secondPool->getItem($key);
$this->assertTrue($loadedItem->isHit());

$loadedItem = $secondPool->getItem($key2);
$this->assertTrue($loadedItem->isHit());

$items = $chainPool->getItems([$key, $key2]);

$this->assertArrayHasKey($key, $items);
$this->assertArrayHasKey($key2, $items);

$this->assertTrue($items[$key]->isHit());
$this->assertTrue($items[$key2]->isHit());

$loadedItem = $firstPool->getItem($key);
$this->assertTrue($loadedItem->isHit());
$this->assertEquals($firstExpirationTime, $loadedItem->getExpirationTimestamp());

$loadedItem = $firstPool->getItem($key2);
$this->assertTrue($loadedItem->isHit());
$this->assertEquals($secondExpirationTime, $loadedItem->getExpirationTimestamp());
}

public function testGetItemsWithEmptyCache()
{
$firstPool = new ArrayCachePool();
$secondPool = new ArrayCachePool();
$chainPool = new CachePoolChain([$firstPool, $secondPool]);

$key = 'test_key';
$key2 = 'test_key2';

$items = $chainPool->getItems([$key, $key2]);

$this->assertArrayHasKey($key, $items);
$this->assertArrayHasKey($key2, $items);

$this->assertFalse($items[$key]->isHit());
$this->assertFalse($items[$key2]->isHit());
}
}

0 comments on commit c795099

Please sign in to comment.