Podivné chování cache a database

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Růžička
Člen | 43
+
0
-

Narazil jsem na zvláštní problém při použití Nette\Database, související zřejmě s kešováním a optimalizací dotazů do db.

Následující kód normálně bez problémů funguje, vypíšou se položky z db (před spuštěním je dobré vymazat cache, abychom začínali za stejných podmínek):

//----skript1-----
$items = $database->table('dbTableName');
$arr = array();
foreach($items as $item)
{
	$arr[] = $item;
}

foreach ($arr as $arrayItem)
{
	dump("$arrayItem->id $arrayItem->name");
}

přeukládání do pole je tu zbytečné, ale v mém případě jsem to potřeboval a chyba se vyskytne právě jen když to přeuložím do pole.

Chybu lze navodit takto:
Pokud vymažu cache a ihned zavolám následující skript (skript2), pak už předchozí příklad nebude nadále fungovat a bude hlásit ‚Cannot read an undeclared column „name“‘ (skript1 se ale nesmí volat ze stejné stránky hned po skript2, protože pak to z nějakého důvodu funguje. Musí to prostě být dvě oddělené zobrazení stránky)

//----skript2-----
$items = $database->table('dbTableName');
dump($items->count());

Je možné, že jsem narazil na nějakou chybu? Nebo něco dělám špatně? Používám Nette 2.0.1 (29.2.2012)

hrach
Člen | 1834
+
0
-
  • vyzkoušej nightly, jestli to tam taky nefunguej
  • plus jaky se při chybě vola dotaz v prvnim skriptu?

diky, H

David Růžička
Člen | 43
+
0
-

hrach napsal(a):

  • vyzkoušej nightly, jestli to tam taky nefunguej
  • plus jaky se při chybě vola dotaz v prvnim skriptu?

diky, H

Takže potvrzuji, že se to chová stejně i v nejnovější verzi: nette-v2.0–99-g064ddb0

skript1 s čerstvě vymazanou keší volá tento dotaz (v tomto případě žádný problém):

SELECT * FROM `category`

skript2 s čerstvě vymazanou keší volá stejný dotaz (také žádný problém):

SELECT * FROM `category`

následné volání skript1 (další http request), už bez vymazání keše, volá tyto dotazy:

SELECT `id` FROM `category`
SELECT * FROM `category`

řádek s dump v tomto případě vyvolá výjimku: Cannot read an undeclared column „name“

Glottis
Člen | 129
+
0
-

hola, mam take jedno podivne chovani, kteremu nerozumim a kdo vi jestli to nesouvisi.
mam dve tabule provazane pres FK. vse funguje, i dotahovani hodnot z cizi tabulky ale jen do doby kdy dotoho zatahnu razeni podle sloupce ukazujici do druhe tabulky (ciselnik). povede se presne kazde druhe zobrazeni stranky. v mysql query logu pak vidim toto

120309 12:23:26   145 Connect
                  145 Query     SET NAMES 'utf8'
                  145 Query     SET time_zone='+01:00'
                  145 Query     SELECT COUNT(*) FROM `log_dhcp`
                  145 Query     SELECT COUNT(*) FROM `log_dhcp`
                  145 Query     SELECT `log_dhcp`.`id`, `log_dhcp`.`time`, `log_dhcp`.`dhcp_type`, `log_dhcp`.`mac`, `log_dhcp`.`ip`, `log_dhcp`.`if`, `log_dhcp`.`unknown_id` FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` ASC LIMIT 25 OFFSET 0
                  145 Query     SELECT `log_dhcp`.* FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` ASC LIMIT 25 OFFSET 0
120309 12:23:27   145 Quit

tohle se nepovede, prestoze vsechny dotazy dopadnou dobre (ale uz se nedotahuje ta cizi hodnota a proto to asi zhavaruje)

120309 12:23:29   146 Connect
                  146 Query     SET NAMES 'utf8'
                  146 Query     SET time_zone='+01:00'
                  146 Query     SELECT COUNT(*) FROM `log_dhcp`
                  146 Query     SELECT COUNT(*) FROM `log_dhcp`
                  146 Query     SELECT `log_dhcp`.`id`, `log_dhcp`.`time`, `log_dhcp`.`dhcp_type`, `log_dhcp`.`mac`, `log_dhcp`.`ip`, `log_dhcp`.`if`, `log_dhcp`.`unknown_id`, `log_dhcp`.`unknown` FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` DESC LIMIT 25 OFFSET 0
                  146 Query     SELECT `log_dhcp`.* FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` DESC LIMIT 25 OFFSET 0
120309 12:23:30   146 Query     SELECT `id`, `value` FROM `unknown` WHERE (`unknown`.`id` IN (2))
                  146 Quit

toto kliknuti na razeni naopak projde, prestoze prni dotaz po count(*) nemuze projit. select chce sloupec log_dhcp.unknown a ten tam neni. data ovsem ziskaji dalsi prikazy uz dobre a tabulka se naplni. taham to ajaxem do dataTables. kdyz za akci zatahnu rucne, ladenka vyhodi chybu

Notice
Undefined offset: 2964

a zasekne se tu

foreach ($dhcp_log->limit($limit, $from) as $log) {
	$row = array();
	$row[] = "".$log->time;
	$row[] = $log->dhcp_type;
	$row[] = $log->mac;
	$row[] = $log->ip;
	$row[] = $log->if;
	$row[] = $log->unknown->value;      //tady se ladenka zasekne

	$output['aaData'][] = $row;
}

je to chyba? nebo mam neco ja spatne? ale uz me nenapada absolutne co. nette mam posledni, tedy asi tyden stare

dik

Glottis
Člen | 129
+
0
-

tak se omlouvam za poplach. v 2.0.1 to funguje ok

radas
Člen | 221
+
0
-

Doporučuju sledovat RSS kanál commitů Nette, myslím, že to tam právě bylo zmíněno.

echo
Člen | 134
+
0
-

Připojuji se.

{foreach $article->related('articles_categories')->limit(5) as $articles_categories}
    <a href="{link ':Admin:Categories:info', id => $articles_categories->categories->id}" class="btn btn-mini btn-primary">{!$articles_categories->categories->title}</a>
{/foreach}
{if $article->related('articles_categories')->count() > 5}
    <a href="{link ':Admin:Articles:info', id => $article->id}">...</a>
{/if}

Problém je při vytváření cache. Když je přítomna poslední podmínka v kódu, čili ->count(), tak se do cache nezapíše přítomnost sloupce categories_id, a při následném refreshi to celé padne chybou Cannot read undeclared column.

Když při vytváření cache nevolám ->count(), cache se zapíše korektně a k chybám nedochází ani při pozdějším doplnění oné podmínky.

Zkoušel jsem jak verzi 2.0.1 tak i nejnovější z github.com a bug je přítomen v obou verzích.

Filip Procházka
Moderator | 4668
+
0
-

Související https://forum.nette.org/…ache-sloupcu, možná?

Editoval HosipLan (16. 3. 2012 23:57)

echo
Člen | 134
+
0
-

Vypadá, že ano. Plus další chyba, $row->ref(„articles“) != $row->articles, resp. nefunguje funkce ref(), při volání $row->ref(„articles“)->content vyhodí Trying to get property on non object. Zase půjde o cache, protože při prvním volání proběhne v pořádku.

hrach
Člen | 1834
+
0
-

@echo: motas tu nekolik veci dohromady a tezko se pak vyznat.

  • $article->related('articles_categories')->limit(5) a $article->related('articles_categories')->count() > 5 je blbost. Pokud v sql olimitujes vysledek, tak pak dostanes vzdy max. 5 radku. Metoda count() spocita vracene radky, takze nikdy nemuze byt ta podminka splnena.
  • nenapasal jsou celou chybu. Kterej column to pak pri cteni nemuze najit? To mam vestit z koule?
  • vubec nechapu souvislost s ref acticles v poslednim postu.

Zaloz nove vlakno (pro kazdy problem), pridej verzi nette (zkus posledni), pridej kus kodu a vypis ladenky.

David Růžička
Člen | 43
+
0
-

Nainstaloval jsem Nette 2.0.2 a příklad, který jsem uváděl na začátku, v něm už funguje. Nicméně jsem narazil na velmi podobný kód, který stále chybu vyvolává:

Následující kód normálně bez problémů funguje, vypíšou se položky z db (před spuštěním vymazat cache):

//----skript1-----
$items = $database->table('dbTableName')->where('id > 1');
$arr = array();
foreach($items as $item)
{
	$arr[] = $item;
}

foreach ($arr as $arrayItem)
{
	dump($arrayItem->name);
}

přeukládání do pole je tu zbytečné, ale v mém případě jsem to potřeboval a chyba se vyskytne právě jen když to přeuložím do pole.

Chybu lze navodit takto:
Pokud vymažu cache a ihned zavolám následující skript (skript2), pak už předchozí příklad nebude nadále fungovat a bude hlásit ‚Cannot read an undeclared column „name“‘ (skript1 se ale nesmí volat ze stejné stránky hned po skript2, protože pak to z nějakého důvodu funguje. Musí to prostě být dvě oddělené zobrazení stránky)

//----skript2-----
$items = $database->table('dbTableName')->where('id > 1');
dump($items->count());

Od původního příkladu se to liší tou podmínkou where. Pokud tam ta podmínka není, kód funguje.
Dále jsem zjistil, že kód funguje i v případě, kdy místo volání count() bez argumentů volám ve druhém skriptu count(‚id‘).

David Růžička
Člen | 43
+
0
-

Zkoušel jsem ještě verzi Nette 2.0.3, ale problém se tam je stále.

keff
Člen | 12
+
0
-

+1, díky za minimální test case – řeším stejný problém, projevuje se jen při současném přístupu různých stránek (v mém případě dlouhoběžící skripty odesílající newslettery).
Prozatím jsem vypnul cache – Conncetion.php:

<?php
	public function setCacheStorage(Nette\Caching\IStorage $storage = NULL)
	{
		$this->cache = $storage ? new Nette\Caching\Cache($storage, 'Nette.Database.' . md5($this->dsn)) : NULL;
		// abdoc HACK!!!!
		$this->cache = null;
		return $this;
	}
?>
vvoody
Člen | 910
+
0
-

Taktiez mam problem s cache / count na selection.

„2.0“
„013c8ee released on 2012–02–03“
aj
„2.1-dev“
„b8ca5b8 released on 2012–04–06“

Ladenka hlasi: Notice – Undefined offset: nejake_cislo
File: Nette\Database\Table\Selection.php
Line: 763

niekedy aj iny riadok, ale vzdy ide o pristupovanie k $this->data[nejake_cislo]

  1. po zmazani cache prvy request ok, dalsie uz vybehne ladenka
  2. po vypnuti cache v Nette\Database\Connection ide vsetko ok
  3. po zapnuti cache v Nette\Database\Connection (cache nebola premazana) vybehne ladenka hned
  4. po odstraneni count() na objekt Nette\Database\Table\Selection (cache zapnuta a stale nepremazana) ladenka stale zostava svietit
  5. po premazani cache (je stale zapnuta) ide vsetko ok aj po opakovanom refresni, len bez toho count ktory mi treba pre inicializaciu paginatora.

Z toho mi vyplyva, ze asi nieco spojene s

<?php
public function count($column = ''){
...
?>

v Nette\Database\Table\Selection „prasi“ obsah cache, takze zatial tiez vypinam cache.

aannubis
Člen | 33
+
0
-

Pridavam se k vvoody – stejne chovani – ndb vyvolava chyby ve filejournalu.
Dale se pridavam i k Davidovi Ruzickovi, taktez mam problem se spatne nacachovanymi sloupci.

hrach
Člen | 1834
+
0
-

Prosim kdokoliv s problemy, vyzkousejte tuto verzi: https://github.com/…-refactoring

Marax
Člen | 28
+
0
-

Tak moje problémy co jsem měl s verzí 2.0.3 to vyřešilo. Dík.

Editoval Marax (30. 7. 2012 18:20)

edke
Člen | 198
+
0
-

hrach wrote:
Prosim kdokoliv s problemy, vyzkousejte tuto verzi: https://github.com/…-refactoring

Kedze v poslednej verzii 2.0.4 mam tiez problemy s cachovanim pouzivanych stlpcov, skusil som tvoj fork, bohuzial v nom mi zas nefunguje spravne schema.table v Postgre, pricom samozrejme zas toto funguje korektne v 2.0.4:

SELECT *
FROM "role.user_default"
WHERE ("id" = ?)

V 2.0.4 je to spravne:

SELECT *
FROM "role"."user_default"
WHERE ("id" = ?)
hrach
Člen | 1834
+
0
-

Vymazal si cache? Ja nic pro postgre nemenil a mam to postavenene nad masterem.