Nette\SafeStream a odolnost vůči pádu serveru
- pmg
- Člen | 372
Nette\SafeStream už prošel dlouhým vývojem. O jedné z dřívějších
verzí (kdy ještě Safe
nebyl Stream
) David Grudl píše, že je odolná vůči pádu Apache.
Jak je na tom současná verze? Konkrétně: Co se stane, když spadne server při přepisu souboru?
Ideální by bylo dosáhnout stavu, kdy soubor bude buď kompletní, nebo žádný. Dovolil bych si zde teď nastínit řešení, které jsem použil pro ukládání kešovacích souborů.
- Nenašel jsem reálnou situaci, kdy by bylo potřeba přidávat na konec souboru.
- Pro vytvoření / přepsání souboru se použije techniky dočasného
souboru. Jeho název se odvodí přímo od souboru cílového. Pokud se ho pak
nepodaří otevřít v módu
x
, zjistí se, jak je starý. Pokud moc ne, znamená to, že soubor aktualizuje jiný proces, není potřeba dělat nic. V opačném případě (tzn. poslední úprava byla přerušena) se smaže. - Před přejmenováním dočasného souboru je nutné odstranit starý.
Použije se proto malý trik. Místo mazání starého souboru se mu jen přidá
přípona
.bak
a smaže se až po přejmenování dočasného souboru na originál. - Čtení realizujeme pomocí
@file_get_contents
s tím, že v případě neúspěchu zkusíme i variantu s.bak
.
Jaké to má výhody? Při běžném čtení jsem naměřil o třetinu kratší čas, update zhruba dvakrát pomalejší, ale hlavně – data by měla zůstat konzistentní.
Já vím, SafeStream
je koncipován obecně a mnou navržené
řešení je příliš aplikované. Dále, stream lze také použít s
parse_ini_file
. To by se sice dalo řešit pomocí nějakého
protokolu inline://
nebo dočasných souborů; ale není to ono.
Myslel jsem spíš, že by v Nette mohla přibýt třída pro práci s keší,
ukládání konfigurace ap.
Je to potřeba? Zajímá mě, co na to ostatní.
- David Grudl
- Nette Core | 8218
Zápis do dočasného souboru s přejmenováním dělá SafeStream tehdy,
pokud zapisujete soubor v režimu x, x+
, nebo v režimu
a a+ w w+
a soubor ještě neexistuje. V takovém případě je
skutečně garantováno, že soubor se buď zapíše celý, nebo vůbec.
SafeStream navíc kontroluje, zda se data zapsala na disk všechna (tj. jestli není disk plný).
- pmg
- Člen | 372
To všechno je v pořádku. Problém ale nastane, když server vypadne během přepisu. Pro zajištění konzistence bych buď musel starý soubor na chvíli smazat (a riskovat, že se např. bude generovat vícekrát), nebo to řešit na nižší úrovni pomocí nějakých kontrolních dat.
Edit: Vidím, že Nette v současné verzi kešování přímo podporuje: při použití serializace by to mělo být proti nekompletním souborům rezistentní. Díky za to!
Edit: Bug Report: Jak jsem tak koukal na soubor
FileStorage.php, na řádku 228 by asi mělo být
@unlink($metaFile);
nehází to chybu, ale $file
není
definovaná
Editoval pmg (23. 5. 2008 21:47)
- David Grudl
- Nette Core | 8218
Ona celá věc je ještě složitější.
Že by vypadl server je extrémě nepravděpodobné. Daleko pravděpodobnější je, že během zápisu dojde k chybě v PHP skriptu nebo jeho předčasnému ukončení. Nicméně i v takovém případě se soubor korektně uzavře a těžko lze určit, jestli byl nebo nebyl zapsán celý.
Takže ověřování konzistence bych spíš nechal na vyšší vrstvě.
ad dočasné soubory a SafeStream: díval jsem se, že dočasný soubor se pod Unixem přejmenuje na cílový ihned po získání zámku. Účelem tedy je atomické provedení operací „vytvořit soubor + získat zámek“, což jinak udělat nelze.
- pmg
- Člen | 372
Díky za info.
Tou vyšší vrstvou může být třeba právě Cache v Nette. Souhlasím,
že SafeStream se pro takové ověřování nehodí. Poslední verze bude
splňovat všechny předpoklady najednou: nebude potřeba vytvářet víc
souborů, zaručí se atomicita operací a konzistence dat a soubory půjde
vkládat přímo přes include
. Co víc si přát?
Ad dočasné soubory: Unix se v tomto směru vůbec chová přívětivě: není např. nutné skript uspávat, aby mohl smazat / přejmenovat soubor.