From ac43cfad2218a869ff1050bba42e902a09f01a8a Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 31 Mar 2020 18:21:16 +0200 Subject: [PATCH] Cache: added events WIP --- src/Caching/Cache.php | 29 ++++++++++++++++++++++------- tests/Caching/Cache.bulkLoad.phpt | 24 ++++++++++++++++++++++++ tests/Caching/Cache.load.phpt | 9 +++++++++ tests/Caching/Cache.save.phpt | 4 ++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/Caching/Cache.php b/src/Caching/Cache.php index c1ebc7f0..53f9c69a 100644 --- a/src/Caching/Cache.php +++ b/src/Caching/Cache.php @@ -33,9 +33,18 @@ class Cache NAMESPACES = 'namespaces', ALL = 'all'; + public const + EVENT_HIT = 'hit', + EVENT_MISS = 'miss', + EVENT_SAVE = 'save', + EVENT_REMOVE = 'remove'; + /** @internal */ public const NAMESPACE_SEPARATOR = "\x00"; + /** @var array */ + public $onEvent; + /** @var Storage */ private $storage; @@ -88,8 +97,9 @@ public function load($key, callable $generator = null) { $storageKey = $this->generateKey($key); $data = $this->storage->read($storageKey); + $this->onEvent($this, $data === null ? self::EVENT_MISS : self::EVENT_HIT, $key); if ($data === null && $generator) { - $this->storage->lock($storageKey); + $this->storage->lock($storageKey); try { $data = $generator(...[&$dependencies]); } catch (\Throwable $e) { @@ -134,12 +144,14 @@ public function bulkLoad(array $keys, callable $generator = null): array foreach ($keys as $i => $key) { $storageKey = $storageKeys[$i]; if (isset($cacheData[$storageKey])) { + $this->onEvent($this, self::EVENT_HIT, $key); $result[$key] = $cacheData[$storageKey]; } elseif ($generator) { $result[$key] = $this->load($key, function (&$dependencies) use ($key, $generator) { return $generator(...[$key, &$dependencies]); }); } else { + $this->onEvent($this, self::EVENT_MISS, $key); $result[$key] = null; } } @@ -165,27 +177,30 @@ public function bulkLoad(array $keys, callable $generator = null): array */ public function save($key, $data, array $dependencies = null) { - $key = $this->generateKey($key); + $storageKey = $this->generateKey($key); if ($data instanceof \Closure) { trigger_error(__METHOD__ . '() closure argument is deprecated.', E_USER_WARNING); - $this->storage->lock($key); + $this->storage->lock($storageKey); try { $data = $data(...[&$dependencies]); } catch (\Throwable $e) { - $this->storage->remove($key); + $this->storage->remove($storageKey); throw $e; } } if ($data === null) { - $this->storage->remove($key); + $this->storage->remove($storageKey); + $this->onEvent($this, self::EVENT_REMOVE, $key); } else { $dependencies = $this->completeDependencies($dependencies); if (isset($dependencies[self::EXPIRATION]) && $dependencies[self::EXPIRATION] <= 0) { - $this->storage->remove($key); + $this->storage->remove($storageKey); + $this->onEvent($this, self::EVENT_REMOVE, $key); } else { - $this->storage->write($key, $data, $dependencies); + $this->storage->write($storageKey, $data, $dependencies); + $this->onEvent($this, self::EVENT_SAVE, $key); } return $data; } diff --git a/tests/Caching/Cache.bulkLoad.phpt b/tests/Caching/Cache.bulkLoad.phpt index 37b1f69b..d8c0aa5d 100644 --- a/tests/Caching/Cache.bulkLoad.phpt +++ b/tests/Caching/Cache.bulkLoad.phpt @@ -18,30 +18,54 @@ require __DIR__ . '/Cache.php'; test(function () { $storage = new TestStorage; $cache = new Cache($storage, 'ns'); + $cache->onEvent[] = function (...$args) use (&$event) { + $event[] = $args; + }; + Assert::same([1 => null, 2 => null], $cache->bulkLoad([1, 2]), 'data'); + Assert::same([[$cache, $cache::EVENT_MISS, 1], [$cache, $cache::EVENT_MISS, 2]], $event); + $event = []; Assert::same([1 => 1, 2 => 2], $cache->bulkLoad([1, 2], function ($key) { return $key; })); + Assert::same([ + [$cache, $cache::EVENT_MISS, 1], [$cache, $cache::EVENT_SAVE, 1], + [$cache, $cache::EVENT_MISS, 2], [$cache, $cache::EVENT_SAVE, 2], + ], $event); + $event = []; $data = $cache->bulkLoad([1, 2]); Assert::same(1, $data[1]['data']); Assert::same(2, $data[2]['data']); + Assert::same([[$cache, $cache::EVENT_HIT, 1], [$cache, $cache::EVENT_HIT, 2]], $event); }); // storage with bulk load support test(function () { $storage = new BulkReadTestStorage; $cache = new Cache($storage, 'ns'); + $cache->onEvent[] = function (...$args) use (&$event) { + $event[] = $args; + }; + Assert::same([1 => null, 2 => null], $cache->bulkLoad([1, 2])); + Assert::same([[$cache, $cache::EVENT_MISS, 1], [$cache, $cache::EVENT_MISS, 2]], $event); + $event = []; Assert::same([1 => 1, 2 => 2], $cache->bulkLoad([1, 2], function ($key) { return $key; })); + Assert::same([ + [$cache, $cache::EVENT_MISS, 1], [$cache, $cache::EVENT_SAVE, 1], + [$cache, $cache::EVENT_MISS, 2], [$cache, $cache::EVENT_SAVE, 2], + ], $event); + $event = []; $data = $cache->bulkLoad([1, 2]); Assert::same(1, $data[1]['data']); Assert::same(2, $data[2]['data']); + Assert::same([[$cache, $cache::EVENT_HIT, 1], [$cache, $cache::EVENT_HIT, 2]], $event); }); // dependencies diff --git a/tests/Caching/Cache.load.phpt b/tests/Caching/Cache.load.phpt index 73b6d976..f6532984 100644 --- a/tests/Caching/Cache.load.phpt +++ b/tests/Caching/Cache.load.phpt @@ -18,16 +18,25 @@ require __DIR__ . '/Cache.php'; // load twice with fallback $storage = new TestStorage; $cache = new Cache($storage, 'ns'); +$cache->onEvent[] = function (...$args) use (&$event) { + $event[] = $args; +}; $value = $cache->load('key', function () { return 'value'; }); Assert::same('value', $value); +Assert::same([ + [$cache, $cache::EVENT_MISS, 'key'], + [$cache, $cache::EVENT_SAVE, 'key'], +], $event); +$event = []; $data = $cache->load('key', function () { return "won't load this value"; // will read from storage }); Assert::same('value', $data['data']); +Assert::same([[$cache, $cache::EVENT_HIT, 'key']], $event); // load twice with closure fallback, pass dependencies diff --git a/tests/Caching/Cache.save.phpt b/tests/Caching/Cache.save.phpt index aa4f6a0a..6b7e2f77 100644 --- a/tests/Caching/Cache.save.phpt +++ b/tests/Caching/Cache.save.phpt @@ -18,9 +18,13 @@ require __DIR__ . '/Cache.php'; // save value with dependencies $storage = new testStorage; $cache = new Cache($storage, 'ns'); +$cache->onEvent[] = function (...$args) use (&$event) { + $event[] = $args; +}; $dependencies = [Cache::TAGS => ['tag']]; $cache->save('key', 'value', $dependencies); +Assert::same([[$cache, $cache::EVENT_SAVE, 'key']], $event); $res = $cache->load('key'); Assert::same('value', $res['data']);