Database refetch failed; row does not exist

před 4 lety

kolsi
Člen | 130
+
+2
-

Ahoj,

chtěl bych se zeptat, jestli někdo už nezažil tento problém či jak ho řešit. Přijde mi, že neděláme nic speciálního, ale čas od času se objeví chyba „Nette\InvalidStateException: Database refetch failed; row does not exist!“.

Nedokážu říct přesně za jakých podmínek se tak stane, ale vypadá to, že je větší pravděpodobnost výskytu, když se vymaže cache. Nejčastěji se to objevuje u tohoto kódu:

Presenter:

public function actionDefault($id) {
	...
	$comments_model = array();
	foreach ($this->commentRepository->findByProjectId($id)->order('timestamp DESC') as $comment) {
		$comm = ArrayHash::from($comment);
		$comm->attachments = $comment->related('project_comment_attachment', 'comment_id');
		$comments_model[] = $comm;
	}
	...

Šablona pak prochází komentáře a každého vypisuje jeho přílohy:

<li n:foreach="$comment->attachments as $attachment" class="{$attachment->type}">
...
</li>

a nejčasteji to padne právě na tom „{$attachment->type}“

V databázi jsou dvě tabulky: project_comment a project_comment_attachment, kde ta druhá obsahuje cizí klíč „comment_id“ do té první. Sloupec „type“ je pak varchar(45) v tabulce project_comment_attachment. Používáme NetteDatabase.

Editoval kolsi (15. 3. 2016 9:37)

před 4 lety

Oli
Člen | 1219
+
+1
-

Taky mě to na jednom projektu dělá. Taky netuším proč. Ale nestojí mě za to to zjišťovat (náklady x užitek). Ale mám pocit, že to mělo něco společného s NDBT cachí. Jednou za čas to prostě jednomu člověku spadne, další requesty už chodí v pořádku. Začal jsem používat Doctrine :-) (Ne kvůli tomuhle problemu)

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Ahoj, potýkám se se stejnou chybou… V šabloně plním proměnnou hodnotou z tabulky takto:

{var $value = $oneData[$key]}

a tady to spadne. Stejně jak psal Kolsi, nejpravděpodobněji to spadne hned po tom co vymažu soubory z cache, ale až tak při druhém načtení stránky. A dělá to jen na produkčním serveru s Ubuntu. Na lokále s Windows 10 se to ještě nestalo…

Tracy mám uloženou kdyby to pomohlo…

před 4 lety

davidindra
Člen | 2
+
0
-

Taky mi to teď dělá, je to pro mě dost velkej problém (stává se mi to podstatně častěji než občas). Nic nestandardního nedělám, netuším, kde je problém.

před 4 lety

Unlink
Člen | 298
+
0
-

Vieš niekam uploadnuť celú tracy (len pozor lebo môže obsahovať citlivé údaje)

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Mě to dělá celkem pravidelně. Když na produkčním serveru vymažu cache, otevřu si dvě anonymní okna a v každém se přihlásím do své aplikace pod jiným uživatelem (každý má vidět jiná data) tak se ta chyba stane. Když nastane tak stačí refresh stránky a jede to dál…

Tracy jsem nahrál zde: „:http://faktury.cz/…te_tracy.htm

Vůbec si s tím nevím rady.. a dělá to jen na produkčním serveru…

před 4 lety

Unlink
Člen | 298
+
0
-

Skúsim sa na to pozrieť, ale mám otázočku

každý má vidět jiná data

Tým myslíš rovnaké stĺpce ale iné riadky keďže chyba čo si poslal je z datagridu
A druhá otázka, ako vyzerá primárny kľúč tej tabuľky, z ktorej selectuješ + selectuješ aj niečo specialne tj. máš špecifikované vlastné ->select() ?

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Ano mají vidět stejné sloupce, ale jiné řádky.
Primární klíč je ID záznamu. Select je pak pro každého uživatele s podmínkou cl_company_id = idCompany kde idCompany je ID firmy, ke které má uživatel povolen přístup.
Nic speciálního neselectuju, až v šabloně vybírám pole, které chci zobrazit.

před 4 lety

CZechBoY
Člen | 3464
+
0
-

Ja si do modelu predam uzivatele a z nej vyberu treba roli nebo neco z identity.
Nevim jak moc je to good practise… Jestli je treba lepsi predavat roli/id firmy parametrem..

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

CZechBoY napsal(a):

Ja si do modelu predam uzivatele a z nej vyberu treba roli nebo neco z identity.
Nevim jak moc je to good practise… Jestli je treba lepsi predavat roli/id firmy parametrem..

To ano takto to dělám (výběr id firmy z identity), ale problém nastává až potom při selectu nad tabulkou, kde použiju filtr právě na id firmy.

před 4 lety

CZechBoY
Člen | 3464
+
0
-

A kdyby sis dal ty attachmenty nekde do vedlejsiho pole? Asociovany treba podle id ty nadrazeny tabulky..

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

CZechBoY napsal(a):

A kdyby sis dal ty attachmenty nekde do vedlejsiho pole? Asociovany treba podle id ty nadrazeny tabulky..

Moc nerozumím jak to myslíš. Ale povedlo se mi trošku více problém izolovat. Totiž kromě filtru podle firmy tam mám ještě filtr na uživatel dané firmy, kterým je povolen přístup. Ti jsou zapsaní v další tabulce cl_partners_event_users.

Hlavní tabulka s daty je definována takto:
CREATE TABLE cl_partners_event (
id int(11) NOT NULL,
cl_partners_book_id int(11) DEFAULT NULL,
cl_company_id int(11) NOT NULL,
cl_users_id int(11) DEFAULT NULL,
work_label varchar(255) COLLATE utf32_czech_ci NOT NULL,
description longtext COLLATE utf32_czech_ci NOT NULL);

ALTER TABLE cl_partners_event
ADD PRIMARY KEY (id),
ADD KEY cl_company_id (cl_company_id),
ADD KEY cl_users_id (cl_users_id),
ADD KEY cl_partners_book_id (cl_partners_book_id);

ALTER TABLE cl_partners_event
MODIFY id int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE cl_partners_event
ADD CONSTRAINT cl_partners_event_ibfk_1 FOREIGN KEY (cl_company_id) REFERENCES cl_company (id),
ADD CONSTRAINT cl_partners_event_ibfk_2 FOREIGN KEY (cl_users_id) REFERENCES cl_users (id),
ADD CONSTRAINT cl_partners_event_ibfk_3 FOREIGN KEY (cl_partners_book_id) REFERENCES cl_partners_book (id);

Tabulka s oprávněními pro jednotlivé uživatele je zde:
CREATE TABLE IF NOT EXISTS cl_partners_event_users (
id int(11) NOT NULL AUTO_INCREMENT,
cl_partners_event_id int(11) NOT NULL,
cl_users_id int(11) NOT NULL,
cl_company_id int(11) NOT NULL,
PRIMARY KEY (id),
KEY cl_partners_event_id (cl_partners_event_id),
KEY cl_users_id (cl_users_id),
KEY cl_company_id (cl_company_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=87 ;

Samotný dotaz v modelu se pak skládá takto:

<?php
$this->tableName = 'cl_partners_event';
$this->userAccesTableName = 'cl_partners_event_users';
$company_id = 1 //id firmy z identity uzivatele;
$user_id = 2 //id uzivatele z identity;
return $this->database->table($this->tableName)->where($this->tableName.'.cl_company_id = ? AND ('.$this->tableName.'.cl_users_id = ?'.' OR :'.$this->userAccesTableName.'.cl_users_id = ?)',$company_id,$user_id,$user_id);
?>

Dotaz má fungovat tak, že vybere všechny záznamy, které patří dané firmě a uživateli, nebo patří dané firmě a uživatel je definován v přístupové tabulce cl_partners_event_users.

Tak jak to mám to funguje jak potřebuju, kromě těch pádů po vymazání cache…

před 4 lety

Unlink
Člen | 298
+
+1
-

No, tá výnimka sa vyhadzuje v prípade, keď je nutný refetch dát (kvôli chýbajúcemu stĺpcu) a po znovunačítaní sa nepodarí načítať všetky pôvodné riadky.
https://github.com/…4cc47133f151

To je dôvod, prečo sa to nedá nasimulovať pri vývoji, kde nieje moc reálne, aby ti daný riadok zmizol. Takže podľa môjho názoru je výnimka legitímna, lebo sa nič s tým spraviť nedá. Každopádne, k tejto situácii by dochádzať nemalo, jedine ako som spomínal, že jeden používateľ vidí iné stĺpce ako druhý, vtedy to nastať môže.

Ono sa to samozrejme dá obísť. Pokiaľ špecifikuješ stĺpce pomocou ->select() manuálne, tak nette sa nepokúša využívať túto chytrú cache.

Mohol by si prosím ťa ešte ukázať, ako ďalej s danou selection pracuješ?
Mne sa podarilo nájsť trošku okrajový use-case ktorý nefunguje tak ako by mal ale to súvisí skôr s týmto
https://forum.nette.org/…mazani-cache
i keď po tom mojom commite to môže namiesto Undefined offset vyhadzovať výnimku.

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Unlink napsal(a):

No, tá výnimka sa vyhadzuje v prípade, keď je nutný refetch dát (kvôli chýbajúcemu stĺpcu) a po znovunačítaní sa nepodarí načítať všetky pôvodné riadky.
https://github.com/…4cc47133f151

To je dôvod, prečo sa to nedá nasimulovať pri vývoji, kde nieje moc reálne, aby ti daný riadok zmizol. Takže podľa môjho názoru je výnimka legitímna, lebo sa nič s tým spraviť nedá. Každopádne, k tejto situácii by dochádzať nemalo, jedine ako som spomínal, že jeden používateľ vidí iné stĺpce ako druhý, vtedy to nastať môže.

Teď nevím jestli myslíš sloupce nebo řádky :-)
Pokud jde o řádky tak způsob jak je získávám jsem popsal výše. A je pravda, že v jiných částech programu, kde nepoužívám způsob přidělení záznamů uživatelům pomocí další tabulky se ta chyba zatím nevyskytla.

Pokud by šlo o sloupce tak tam mám ještě udělanou takovou věc, že si každý uživatel může nastavit jaké sloupce chce vidět… ale chyba o kterou jde říká, že "nemůže najít řádek ":http://faktury.cz/…te_tracy.htm

před 4 lety

Unlink
Člen | 298
+
0
-

TomasHalasz napsal(a):
Pokud by šlo o sloupce tak tam mám ještě udělanou takovou věc, že si každý uživatel může nastavit jaké sloupce chce vidět…

No, a toto bude jadro toho problému, pokiaľ sa to deje len v po vymazaní cache a potom už nie, tak je je kvôli tomu, že medzi tým ako si prvý krát načítal záznamy a potom ako sa načítali po druhý krát (keďže mu chýbal nejaký stĺpec) nejaký záznam zmizol.

Malo by sa to dať obísť takto

return $this->database->table($this->tableName)->select($this->tableName.'.*')->where($this->tableName.'.cl_company_id = ? AND ('.$this->tableName.'.cl_users_id = ?'.' OR :'.$this->userAccesTableName.'.cl_users_id = ?)',$company_id,$user_id,$user_id);

(keď tam pridáš ->select($this->tableName.'.*') tak sa nebude cachovať to použivanie stĺpcov a problém by mal zmiznúť)

Editoval Unlink (15. 5. 2016 14:34)

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Unlink napsal(a):

No, a toto bude jadro toho problému, pokiaľ sa to deje len v po vymazaní cache a potom už nie, tak je je kvôli tomu, že medzi tým ako si prvý krát načítal záznamy a potom ako sa načítali po druhý krát nejaký záznam zmizol.

Aha, to co píšeš se může stát. Po vymazání cache první uživatel zobrazí stránku se záznamy s ID řekněme 1,2,3,4,5,6 a se sloupci A,B,C,D. Stránka se mu otevře v pořádku. Pak druhý uživatel otevře stránku, ale vidí jen záznamy 2,3,4,5 (protože k jiným nemá práva) a sloupce B,C,D (protože si to takto nastavil).
Takže v takovémto případě nette chce udělat refresh dat, protože je ještě nemá v cache. Je to tak? A chce dělat refresh pro záznam s ID 1 i když je tento záznam podmínkou vyloučen? Dá se říct proč to tak je?

Jinak zkusím tu úpravu co jsi psal a dám vědět.

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Unlink napsal(a):

(keď tam pridáš ->select($this->tableName.'.*') tak sa nebude cachovať to použivanie stĺpcov a problém by mal zmiznúť)

Super! Zatím to vypadá, že to pomohlo. Po vymazání cache žádný problém :-) Ještě budu testovat.

před 4 lety

Unlink
Člen | 298
+
0
-

Nie, najskôr sa prihlási prvý používateľ, nette, keďže nemá cache tak načíta všetky stĺpce tabuľky, ale používateľ si zobrazí len A,B,C čo si nette zapamätá. Príde druhý používateľ, nette si zapamätalo že minule sa použili stĺpce A,B,C tak načíta z databázy len nie. No druhý používateľ požaduje povedzme A,B,D. Stĺpec D nieje k dispozícii tak nette spraví to, že zoberie si IDčka všetkých záznamov ktoré načítalo a pokúsi sa načítať všetky stĺpce pre dané IDčka (SELECT * FROM table WHERE id IN(...)) no a teraz sa môže stať, že medzi tým ako prvý krát načítalo záznamy, a teraz keď ich číta druhý krát, tak nejaký záznam zmizol čo sa na zaťaženom serveri stať môže.

před 4 lety

TomasHalasz
Bronze Partner | 80
+
0
-

Unlink napsal(a):

Nie, najskôr sa prihlási prvý používateľ, nette, keďže nemá cache tak načíta všetky stĺpce tabuľky, ale používateľ si zobrazí len A,B,C čo si nette zapamätá. Príde druhý používateľ, nette si zapamätalo že minule sa použili stĺpce A,B,C tak načíta z databázy len nie. No druhý používateľ požaduje povedzme A,B,D. Stĺpec D nieje k dispozícii tak nette spraví to, že zoberie si IDčka všetkých záznamov ktoré načítalo a pokúsi sa načítať všetky stĺpce pre dané IDčka (SELECT * FROM table WHERE id IN(...)) no a teraz sa môže stať, že medzi tým ako prvý krát načítalo záznamy, a teraz keď ich číta druhý krát, tak nejaký záznam zmizol čo sa na zaťaženom serveri stať môže.

No jenže u mě jsem na tom produkčním serveru úplně sám… takže nemůže jít o vymazání záznamu nebo změnu práv k záznamu takříkajíc „pod rukama“. Udělal jsem jen otevření stránky u jednoho uživatele a pak otevření u druhého.

A ještě jsem se chtěl zeptat, když to funguje tak, že nette nemá sloupec D k dispozici tak bere všechny ID, které načetlo předtím a podle nich hledá záznamy. Proč v tu chvíli nepracuje podle aktuálně požadovaného ID?

před 4 lety

Unlink
Člen | 298
+
0
-

TomasHalasz napsal(a):

A ještě jsem se chtěl zeptat, když to funguje tak, že nette nemá sloupec D k dispozici tak bere všechny ID, které načetlo předtím a podle nich hledá záznamy. Proč v tu chvíli nepracuje podle aktuálně požadovaného ID?

Je to pre to, aby „obnovilo“ celú selection a nepokladalo dotazy pre každý riadok zvlášť.
A načítanie len konkrétneho riadku by nepomohlo, pretože táto výnimka nastáva práve vtedy, keď sa nepodarilo nájsť aktuálny riadok (inak to vypisuje undefined offset).

Skús mi napísať na email, a môžme to nejako zdebugovať, pretože ak to vieš nasimulovať tak to je super, lebo táto chyba zvyčajne nastáva náhodne, za situácii aké som popisoval o pár postov vyššie, takže u teba bude problém zrejme inde.

před 4 lety

Pechy.cz
Generous Backer | 21
+
0
-

Taky se připojuji. Pro mě už je to docela velký problém. Vždycky jsem řekl „V pohodě! Aktualizuj stránku“..
Jenže poslední dobou nepomůže ani aktualizace, nebo resp. pomůže, ale až tak třeba 10. aktualizace. V tu chvíli se zase vše tváří nevinně.
Klienti už se začali ozývat, snažím se najít nějaké východisko, nebo hack.
Co jsem si to zkoušel procházet, tak to dělá nahodile v podstatě kdekoliv v systému. Na některých místech sice častěji, ale to je tím, že to jsou více používané a vytěžované místa. (minutový cron a nejnavštěvovanější stránka)

Jestli jsem to pochopil správně, tak se chyba objeví, když tahám data z řádku A, dojde k refetch a stačí že chybí řádek B, který byl v Selection taky? Protože řádek A, který používám je tam vždy..

před 4 lety

Unlink
Člen | 298
+
0
-

Môžeš vyskúšať tento fix?
https://github.com/…ase/pull/137
Ak to robilo náhodne tak by to mohlo pomôcť

Editoval Unlink (2. 6. 2016 17:02)

před 4 lety

Pechy.cz
Generous Backer | 21
+
0
-

Unlink napsal(a):

Môžeš vyskúšať tento fix?
https://github.com/…ase/pull/137
Ak to robilo náhodne tak by to mohlo pomôcť

Večer to hodím na produkční a uvidíme ;-)
Každopádně i pokud to nepůjde, tak ti patří tisíce díků.
A pokud to půjde, tak o tisíce víc ;-)

Editoval Pechy.cz (3. 6. 2016 11:53)

před 3 lety

filsedla
Člen | 82
+
0
-

Pořád se mi tahle chyba občas náhodně vyskytuje. Last muted error je „Warning: fopen(xxx/app/../temp/cache/_Nette.Database.xxx): failed to open stream: No such file or directory“.

edit: Dostávám „Database refetch failed; row with signature ‚xxx‘ does not exist“, je to trochu jiná chyba.

Editoval filsedla (18. 5. 2017 10:21)

před 2 lety

podolinek
Člen | 8
+
0
-

Tato chyba se mi dneska podařila vyextrahovat do separe skeletonu. Ve zkratce to u mě je v tom, že volám metodu related nad resultsetem, pak zavolám count nad získanými related výsledkama a pak procházím foreachem. Bez zavolání count vše funguje jak má. Více v issue na githubu, kde je i uvedený skeleton s danou chybou.

před 2 lety

filsedla
Člen | 82
+
0
-

Super! Taky se mi jednou už povedlo najít konzistentní proceduru, jak to přivodit obsahující načtení stránky 2, 3, 7, 8 seznamu objednávek na produkčním serveru a udělání 10 dřepů. Pak jsem na to zapomněl. Tohle je lepší.

Myslím, že jsem to taky zkoušel xdebugovat, ale vůbec jsem tomu nerozuměl.

před 2 lety

oldrich.valek
Člen | 21
+
+1
-

Mně se toto stává, když ve foreach nad řádky z jedné tabulky tahám pomocí related všechny závislé řádky z tabulky druhé (s použitím nějaké hodnoty z té druhé tabulky). Děje se to při následující sekvenci.

  1. Vymazat cache.
  2. Načíst stránku pouze s řádky v první tabulce, které zrovna nemají žádné závislé řádky v tabulce druhé.
  3. Následně načíst stránku, kde již řádky z první tabulky závislosti v druhé tabulce mají (odehrává se to změnou omezení řádků z první tabulky, např. jiný jazyk/kategorie apod.).

Po chybě již následující requesty probíhají bez problémů. Mám stable Nette 2.4 (Nette database v2.4.4, reference: 9b16e3ea2d9c21579962a17d81e17e4f71f59d6b). Mám pocit, že jsem tu někde kdysi četl, že se ta chyba snad ani nedá vyřešit, nebo jen vypnutím cache. Dosud, když se tato chyba objevila, tak jsem jen v daném místě zavolal po ->related(…) ještě ->select(‚*‘), což problém obchází.

Má konfigurace db spojení:

database:
    default:
        options: [PDO::MYSQL_ATTR_COMPRESS = true]
        debugger: true
        explain: true
        conventions: discovered
        autowired: true

Editoval oldrich.valek (10. 12. 2017 20:48)

před 2 lety

kolsi
Člen | 130
+
+2
-

Chyba se stále objevuje a bude to tak, jak píše oldrich.valek.

  1. Vymažu cache
  2. otevřu stránku s komentáři (foreach), kde žádný nemá přílohu (funguje)
  3. otevřu jinou stránku s komentáři, kde je příloha ⇒ bum „Database refetch failed; row with signature ‚44‘ does not exist!“

Stane se to vždy, když provedu tento postup. Po krátkém debugování jsem přišel na to, že je problém v tomto (snad to popíšu pochopitelně :-)):

  1. vykresluje se první komentář/příloha, a ActiveRow::get zavolá ActiveRow::accessColumn
  2. ActiveRow::accessColumn zavolá Selection::accessColumn
  3. Selection::accessColumn zavolá postupně emptyResultSet (kde vyprázdní $this->rows) a execute (provede SQL a vytáhne nová data z DB do $this->rows)
  4. nyní se začne vykreslovat další komentář/příloha, znovu se postupně zavolá ActiveRow::get → ActiveRow::accessColumn → Selection::accessColumn
  5. Selection::accessColumn zavolá emptyResultSet , které vyprázdní $this->rows
  6. Selection::accessColumn zavolá execute, které ale nic nedělá (viz podmínka !isset($this->refCacheCurrent[‚data‘], která nyní není „false“, protože byla nastavena u předchozího komentáře, v GroupedSelection::execute)
  7. podmínka v ActiveRow: „if (!isset($this->table[$this->getSignature()]))“ způsobí chybu, protože $this->rows (ke kterému se přistupuje přes $this->table) je prázdné (viz bod 5)

před 2 lety

podolinek
Člen | 8
+
0
-

Reportováno před pár měsíci i na githubu, zatím bez odpovědi.

před 2 lety

Pechy.cz
Generous Backer | 21
+
0
-

My jsme se jej už téměř zbavili. Nemám tady kompletní soupis jako kolsi, ale stávalo se nám to hlavně v cronech.

Příklad – odesílání emailů

  • 99% běhu cronu není co posílat, žádné emaily neexistuji, ($items jsou prázdný)
  • pak se přidá email k odeslání, takže se vstoupí do foreach, kdy ale email není ještě autorizovaný, takže na první podmínce ->authorized je vráceno false a tím běh končí.
  • jenomže v tu chvíli si database uložila do cache, že se přistupuje jen k sloupečku authorized.
  • pak uživatel schválí odeslání emailu, a v dalším běhu cronu si již nette pamatuje, že si má tahat jen authorized
  • na jakámkoliv dalším vytažení jiných dat, než je authorized to padne
  • dočasným řešením bylo přidat select(‚*‘) (nebo samozřejmě vypsat sloupečky co budou potřeba) do všech metod, který tohle způsobovaly
  • s tímhle to teď funguje bez problému, ale zbytečně se toho tahá moc

před 2 lety

ZbyRih
Člen | 1
+
0
-

Tahle featura by bylo super kdyby šla vypnout.

před 6 měsíci

dTTb
Člen | 14
+
+1
-

Tyjo, tri roky a tahle chyba se porad jeste objevuje…

před 6 měsíci

TomasHalasz
Bronze Partner | 80
+
0
-

Teď v poslední aktualizace nette/dbase 3.0.2 to je vyřešeno viz. zde: https://github.com/…e/issues/230#…