h4kuna / critical-cache
Only one process can to write or to delete to cache.
Fund package maintenance!
h4kuna
revolut.me/milan2m/czk1000/critical-cache
Installs: 2 487
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Open Issues: 0
Requires
- php: >=8.2
- h4kuna/memoize: ^0.1.7
- psr/clock: ^1.0
- psr/simple-cache: ^3.0
Requires (Dev)
- beste/clock: ^3.0
- h4kuna/dir: ^0.1.7
- malkusch/lock: ^2.2
- nette/caching: ^3.2
- nette/tester: ^2.4
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- tracy/tracy: ^2.9
Suggests
- h4kuna/dir: malkusch/lock and nette/cache need to create directories.
- malkusch/lock: As default implementation for Lock system.
- nette/caching: As default implementation for Cache for PSR-16.
README
The library extends PSR-16 about locking when write or delete to cache.
Installation to project
composer require h4kuna/critical-cache
Optional
composer require h4kuna/dir malkusch/lock nette/caching beste/clock
How to use
First time you can use prepared factory CacheFactory. The factory tell you what dependency missing. The dependency are not mandatory, because everything can be replaced by your implementation.
use h4kuna\CriticalCache\PSR16\Locking\CacheLockingFactory; $cacheFactory = new CacheLockingFactory('/my/temp'); $cache = $cacheFactory->create(); assert($cache instanceof Psr\SimpleCache\CacheInterface); $data = $cache->load('foo', fn() => 'done'); echo $data; // done
Method load
try read from cache, if data is not null
that success else create critical section by lock system (Mutex), try read from cache, because any parallel process could be faster, if is success unlock critical section and return data, else call callback for create cache, save data to cache and unlock and return data.
Pool
Support to use multi-level cache implements CacheInterface. By order Memory -> Filesystem.
use h4kuna\CriticalCache\PSR16\Locking\CacheLockingFactory; use h4kuna\CriticalCache\PSR16\Pool\CachePoolFactory; $cacheFactory = new CacheLockingFactory('/my/temp'); $cachePoolFactory = new CachePoolFactory($cacheFactory); $cache = $cachePoolFactory->create(); // by default create MemoryCache and FileSystem. You can choose redis, memcache. $cache->set('foo', 1); // write to memory and filesystem $cache1 = $cachePoolFactory->create(); // try to load from Memory (not found), second is Filesystem (found), and save to Memory, return result. echo $cache1->get('foo'); // 1
Lock
By default, is used malkusch/lock, but if you implement Lock interface you can use different library.
And by default is used FlockMutex this is reason why is need h4kuna/dir. If you use different Lock you don't need previous library.
Cache
By default, is used nette/caching with PSR16 adapter.
Clock PSR-20
internal cache system beste/clock
Services
UseOneTimeService
The service is usable for token and use one time.
/** @var \h4kuna\CriticalCache\Services\UseOneTimeService $useOneTimeService */ $timeToLive = 900; // seconds $useOneTimeService->save('foo', 'token', $timeToLive); // after 900 seconds or one call $useOneTimeService::get() is removed from cache $useOneTimeService->get('foo'); // token $useOneTimeService->get('foo'); // null
ValidService
The service tell you if anything is valid, you can choose date range for valid window.
/** @var \h4kuna\CriticalCache\Services\ValidService $validToService */ $validToService->set('foo', new DateTime('tomorrow midnight')); // from is null it is mean now $validToService->isValid('foo'); // true from 'now' to 'tomorrow midnight' $validToService->value('foo'); // return empty string if is valid and null if is invalid $validToService->from('foo'); // null mean unlimited or DateTimeImmutable $validToService->to('foo'); // null mean does not exist or DateTimeImmutable $validToService->isValid('foo'); // true the time is in range, false is out of range $validToService->set('bar', new DateTime('tomorrow midnight'), new DateTime('+5 minutes'), 'lorem'); // the string 'lorem' it will be a valid after 5 minutes
TokenService
The service generate token and keep it for defined time.
/** @var \h4kuna\CriticalCache\Services\TokenService $tokenService */ $token = $tokenService->make(); // return string token by default uuid v4 dump($tokenService->compare($token)); // true / false // if you want compare your self let use get() $token = $tokenService->make(value: 'lorem'); $value = $tokenService->get($token); // lorem $tokenService->compare(value: $value); // false because you use get()
UniqueHashQueueService
The service generate unique values, witch check mechanism with source for example, with database. Create lock for critical section get one unique values from queue.
For example, we use RandomGeneratorMock, the class generate alphabet, A, B, C, D ... Z, AA...
// implement UniqueValueServiceInterface or extends UniqueValueServiceAbstract $checkUniqueValue = new class extends \h4kuna\CriticalCache\Services\UniqueValueServiceAbstract { public function __construct() { parent::__construct(new \h4kuna\CriticalCache\Tests\Mock\RandomGeneratorMock()); } public function check(array $data): iterable { // example: $data = ['A', 'B', 'C', 'D', 'E']; // SELECT unique_column FROM foo WHERE unique_column IN ('A', 'B', 'C'); // return matched values, for example B, C yield 'B'; yield 'C'; // or return ['B', 'C']; } }; /** @var \h4kuna\CriticalCache\Services\UniqueHashQueueService $uniqueHash */ $value = $uniqueHash->execute($checkUniqueValue); // random unique value, A $value = $uniqueHash->execute($checkUniqueValue); // random unique value, D $value = $uniqueHash->execute($checkUniqueValue); // random unique value, E