Úložiště
Úložiště určuje, kde data z cache fyzicky leží: v souborech na disku, na serveru Memcached nebo v databázi SQLite. Vyměnit ho můžete, aniž byste sáhli na kód, který cache používá. Tato stránka vám pomůže:
- vybrat správné úložiště a zjistit, co které umí
- nastavit ho v aplikaci Nette, případně cache vypnout
- použít úložiště z Nette jako PSR-16 cache
- napsat si vlastní úložiště
Výběr úložiště
Pokud si nejste jistí, nechte výchozí FileStorage. Stačí mu adresář, je bezpečné, i když najednou čte
a zapisuje mnoho požadavků, a podporuje všechny druhy závislostí.
Když aplikace běží na více serverech, FileStorage dá každému z nich vlastní cache.
MemcachedStorage ukládá data na server, který sdílejí všechny, jenže tagy a priority si drží v journalu, což je soubor na každém serveru zvlášť, takže mazání podle tagu na jednom serveru se
k ostatním nedostane.
Úložiště se liší tím, které závislosti umí respektovat:
| Úložiště | Tagy, priority | Soubory, konstanty, callbacky | Jiné položky | Klouzavá expirace | Mazání jmenných prostorů | Ochrana proti stampede |
|---|---|---|---|---|---|---|
| FileStorage | s journalem | ano | ano | ano | ano | ano |
| MemcachedStorage | s journalem | ano | ne | ano | ignoruje | ne |
| SQLiteStorage | jen tagy | ignoruje | ignoruje | ano | ignoruje | ne |
| MemoryStorage | ignoruje | ignoruje | ignoruje | ignoruje | ignoruje | ne |
| DevNullStorage | nic neukládá |
Kde tabulka uvádí ignoruje, úložiště závislost potichu zahodí, takže položka podle ní prostě nevyexpiruje.
MemoryStorage ignoruje dokonce i expiraci. Jen MemcachedStorage vyhodí
Nette\NotSupportedException, a to pro závislost na jiných položkách.
Ochrana proti stampede znamená, že když o chybějící položku požádá najednou mnoho požadavků, generátor z
load() spustí jen první z nich a ostatní počkají na jeho výsledek. Bez ní hodnotu počítají všechny
zároveň.
Konfigurace
V aplikaci postavené na Nette poskytuje DI kontejner FileStorage, které ukládá data do podadresáře
cache v adresáři pro dočasné soubory, a k němu i journal.
Dostanete ho pomocí dependency injection, když
si řeknete o typ Nette\Caching\Storage.
Pokud chcete jiné úložiště, nahraďte v konfiguraci službu cache.storage:
services:
cache.storage: Nette\Caching\Storages\MemcachedStorage('10.0.0.5')
Kontejner obsahuje tyto dvě služby:
| Název | Typ | Popis |
|---|---|---|
cache.storage |
Nette\Caching\Storage | úložiště |
cache.journal |
Nette\Caching\Storages\Journal | journal pro tagy a priority |
Vypnutí cache
Pokud chcete cache vypnout, třeba v testech, použijte DevNullStorage, které nic neukládá:
services:
cache.storage: Nette\Caching\Storages\DevNullStorage
Na cache šablon Latte a DI kontejneru to nemá vliv, ty jsou samostatné a toto úložiště nepoužívají. Během vývoje je ostatně není potřeba vypínat.
FileStorage
Nette\Caching\Storages\FileStorage zapisuje každou položku do souboru v zadaném adresáři, který musí
existovat. Tagy a priority potřebují journal:
$journal = new Nette\Caching\Storages\SQLiteJournal('/path/to/temp/journal.s3db');
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp', $journal);
Všechny operace jsou atomické. Nikdy nepřečtete soubor, který jiný požadavek ještě nedopsal, a nikdo vám ho nemůže smazat pod rukama, zatímco ho čtete. Úložiště je proto bezpečné i pod velkou zátěží.
Navíc chrání před cache stampede. Když o chybějící položku požádá najednou mnoho požadavků, třeba hned po nasazení, první z nich soubor zamkne a spustí generátor. Ostatní počkají na zámek a pak přečtou čerstvou hodnotu, místo aby ji počítaly znovu.
Vyexpirované soubory čas od času smaže konstruktor. Pokud je chcete smazat v okamžiku, který si zvolíte sami, zavolejte
$storage->clean([]).
MemcachedStorage
Nette\Caching\Storages\MemcachedStorage ukládá data na server Memcached.
Konstruktor přijímá adresu serveru a port, výchozí je 11211. Tagy a priority potřebují journal.
Vyžaduje PHP rozšíření memcached.
services:
cache.storage: Nette\Caching\Storages\MemcachedStorage('10.0.0.5')
Memcached neumí vypsat své klíče, takže úložiště mazání podle jmenných prostorů ignoruje. Pro závislost na jiných položkách vyhodí výjimku. Smazání celé cache vyprázdní celý server Memcached včetně dat jiných aplikací.
SQLiteStorage
Nette\Caching\Storages\SQLiteStorage drží celou cache v jediném souboru databáze SQLite. Tagy si ukládá do
vlastní tabulky, takže nepotřebuje journal.
Vyžaduje PHP rozšíření pdo a pdo_sqlite.
services:
cache.storage: Nette\Caching\Storages\SQLiteStorage('%tempDir%/cache.db')
Úložiště podporuje expiraci, klouzavou expiraci a tagy. Priority, závislosti na souborech, konstantách, callbackech a jiných položkách i mazání podle jmenných prostorů potichu ignoruje.
MemoryStorage
Nette\Caching\Storages\MemoryStorage drží data v PHP poli, takže se s koncem požadavku ztratí. Hodí se pro
testy a pro cachování v rámci jednoho požadavku.
Ignoruje všechny závislosti včetně expirace a z podmínek metody clean() respektuje jen
Cache::All. Myslete na to, když jím v testech nahrazujete skutečné úložiště: položka, která by tam
vyexpirovala, tady zůstane.
DevNullStorage
Nette\Caching\Storages\DevNullStorage nic neukládá, takže každé load() zavolá generátor.
Použijte ho pro vypnutí cache.
Journal
FileStorage a MemcachedStorage neumí své položky vyhledávat podle tagu nebo priority, proto si
vedou samostatný index, tzv. journal. Vestavěný Nette\Caching\Storages\SQLiteJournal ho ukládá do databáze
SQLite:
$journal = new Nette\Caching\Storages\SQLiteJournal('/path/to/temp/journal.s3db');
Vyžaduje PHP rozšíření pdo a pdo_sqlite.
V aplikaci postavené na Nette se journal vytvoří za vás jako služba cache.journal v souboru
journal.s3db a úložišti se předá automaticky. Nahradit ho může vaše vlastní implementace rozhraní
Nette\Caching\Storages\Journal:
services:
cache.journal: MyJournal
Bez journalu tato úložiště fungují také, jen uložení položky s tagy nebo prioritou vyhodí výjimku.
Úložiště jako PSR-16 cache
Některé knihovny očekávají PSR-16 cache. Adaptér
Nette\Bridges\Psr\PsrCacheAdapter jim ji poskytne nad libovolným úložištěm z Nette:
$psrCache = new Nette\Bridges\Psr\PsrCacheAdapter($storage);
$psrCache->set('key', 'value', 3600); // uloží hodnotu na 1 hodinu
$value = $psrCache->get('key', 'default');
Adaptér podporuje všechny metody PSR-16 včetně getMultiple(), setMultiple() a
deleteMultiple().
Vlastní úložiště
Úložiště je třída, která implementuje rozhraní Nette\Caching\Storage (před verzí 3.1 se jmenovalo
Nette\Caching\IStorage) s pěti metodami:
read(string $key)vrátí uloženou hodnotu, nebonull, když položka neexistuje nebo vyexpirovalalock(string $key): voidzamkne položku, nežCachespustí generátor; zámek uvolníwrite()neboremove()a úložiště, které před cache stampede nechrání, nechá metodu prázdnouwrite(string $key, mixed $data, array $dependencies): voidhodnotu uložíremove(string $key): voidpoložku smažeclean(array $conditions): voidsmaže položky podle podmínek metody clean(); prázdné pole znamená odstranit vyexpirované položky
Závislosti přicházejí jako pole s klíči Cache::*, které už Cache zjednodušila: expirace je
počet sekund od teď, ze souborů a konstant se staly callbacky a jiné položky jsou dané svými klíči v úložišti. Při
čtení položky ověřte její callbacky pomocí Nette\Caching\Cache::checkCallbacks(). Pro závislost nebo
podmínku, kterou vaše úložiště neumí, vyhoďte Nette\NotSupportedException.
Další schopnosti přidávají volitelná rozhraní. Nette\Caching\BulkReader a od verze 3.3 i
Nette\Caching\BulkWriter umožní úložišti číst a zapisovat více položek najednou.
Krátkým úplným příkladem je zdrojový kód SQLiteStorage.