cacheJournal v SQLite funguje podivně
- Wosonj
- Člen | 36
Nefunguje nám kešování s 9.3-stable. Občas (často) se cache nějakým způsobem zasekne a soubory s daty pak mají délku 0. V php_error.log je pak pro každý request několikrát následující warning:
[16-Feb-2010 14:55:35] PHP Warning: sqlite_exec(): cannot start a transaction within a transaction in /var/www/html/libraries/server/nette/0.9.3-stable/loader.php on line 1476
Čas od času se ještě objeví:
[16-Feb-2010 14:55:35] PHP Warning: sqlite_exec(): database disk image is malformed in /var/www/html/libraries/server/nette/0.9.3-stable/loader.php on line 1476
Smazání tempu tento problém občas vyřeší, občas ne. Objevuje se to jen na produkčním serveru, předpokládáme, že to bude mít souvislost s poměrně vysokou zátěží.
Nette 9.3-stable (min) / PHP5.3
Snažím se to právě nějak debuggovat a postnu update, pokud to ale už někdo řešil, budu vděčný za zprávu.
- Wosonj
- Člen | 36
Asi jsem našel chybu:
Nette\Caching\FileStorage::write(), r.216:
<?php
if (!sqlite_exec($db, "BEGIN; DELETE FROM cache WHERE file = '$dbFile'; $query COMMIT;")) {
return;
}
?>
Podle dokumentace pokud tady dojde k chybě, tak může zůstat otevřená transakce a pak všechny další volání write() skončí výše uvedenou chybou. Měl by se vždy zavolat ROLLBACK.
Nemám s SQLite zkušenosti, jenom hádám. Pravděpodobně tam ale bude ještě nějaký jiný bug, který způsobí, že ten sqlite soubor se poškodí.
- David Grudl
- Nette Core | 8227
Že se poškodí SQLite soubor je průšvih, k tomu by nemělo dojít používáním jakkoliv chybných SQL konstrukcí.
Můžeš každopádně zkusit před return
dát
sqlite_exec($db, "ROLLBACK")
, jestli to pomůže?
- Wosonj
- Člen | 36
David:
Jo, to jsem tam hned přidal a zatím to s tím běží.
Obávám se, že ta poškozená DB mohla být výsledkem mé činnosti, kdy první, co mne napadlo, bylo samozřejmě smazat temp, čímž jsem tu DB vlastně mazal SQLite pod rukama…
Jinak rychlý workaround, pokud by to postihlo ještě někoho, je dočasně cache vypnout:
do config.ini:
service.Nette-Caching-ICacheStorage = Nette\Caching\DummyStorage
- Wosonj
- Člen | 36
Ještě se vracím k této chybě – z našich zkušeností vyplývá, že k poškození SQLite databáze dochází při mazání tempu při deploymentu nové verze webu.
Pravděpodobně dojde k tomu, že nějaké vlákno s db pracuje, zatímco se databáze spolu s celým tempem smaže.
Aktuálně to řešíme tak, že součástí skriptu na nasazení nové verze je vypnutí a zapnutí httpd, aby k tomu nemohlo docházet. To je ale luxus, který si může dovolit jen někdo s vlastním serverem a není to rozhodně ideální stav (deploy jednoho webu způsobí výpadky všem ostatním a utnou se vlákna, kde může být rozdělaná důležitá práce).
Do budoucna by se mělo toto nějakým způsobem ošetřit na úrovni Nette – například chyby SQLite detekovat a pokud nějaká nastane, celý soubor preventivně zahodit.
- Honza Kuchař
- Člen | 1662
Nebo v deploy procesu nastavit storage na Dummy. 10 sekund počkat. Smazat cache. Nastavit zpět na FileStorage. Ale je fakt, že i po těch deseti sekundách s tou keší může pořád nějaké vlákno pracovat.
Editoval honzakuchar (14. 4. 2010 10:44)
- David Grudl
- Nette Core | 8227
Není nejlepší (i když ne nejjednodušší) jít nejčistší cestou a
připojit se k souboru přes SQLite a zavolat
DELETE * FROM cache
?
Druhou možností, která se mi jeví jako atomická a snadná, je nejprve přejmenovat adresář v tempu a teprve poté jeho obsah mazat.
- Michalek
- Člen | 211
No, už týden to na ostrém serveru řeším taky. Každých pět minut mažu cronem celý temp (neptejte se proč, prostě proto :-) a občas se stane prostě nějaká chyba a soubor se poškodí. Celý web pak hází 500 a vůbec nic se pak nikam neloguje.
- Přejmenování a smazání tempu nepomáhá, pravděpodobně tam zůstane nějaké vlákno i tak a v nově vytvořeném souboru se to vytvoří blbě a je poškozený.
- DELETE FROM cache jsem zkoušel, ale stejně jako minule, zrovna se souborem asi pracuje přímo aplikace a smazání cache z jiného místa nemá účinek, protože se vzápětí obnoví starý obsah.
Odchytil jsem si poškozený cachejournal.sdb (můžu poskytnout) a po nakopírování na localhost dostávám také 500, takže jsem se pustil do nějakého zjišťování, kde to umře.
Za všechno „může“ FileStorage.php
, kde ve funkci
getDb()
ještě sqlite_open
funguje správně
(nepozná, že je soubor nějak poškozený),
sqlite_last_error($this->db)
nehlásí chybu. Chyba nastane až
po dalším řádku s @sqlite_exec
a pak se hlásí chyba 1,
respektive „SQL logic error or missing database
“.
Prozatím jsem to vyřešil naprosto prasácky, prostě když je chyba, smažu soubor s databází. Při dalším načtení stránky se založí už dobře.
<?php
FileStorage.php
447 if(sqlite_last_error($this->db) == 1) {
448 sqlite_close($this->db);
449 unlink($this->dir . '/cachejournal.sdb');
450 return null;
451 }
?>
Za normálních okolností se to pravděpodobně nestane, takže asi není potřeba aby to nette nějak řešilo, spíš píšu kdyby na to někdy někdo narazil.
Editoval Michalek (15. 9. 2010 18:50)