Kešování objektu

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Tomik
Nette Evangelist | 485
+
0
-

Zdravím!
Omlouvám se, zda již budu otvírat řešené téma, hledal jsem, ale nenašel.

Můžu poprosit o podělení se o rady v oblasti kešování objektů? Konkrétně mi jde o Acl objekt.

Ale princip se určitě hodí i pro jiné objekty, které jsou např. generované z DB.

Napadlo mě sice pár nápadů, ovšem buď jsem při jejich realizaci udělal nějakou chybu, či ty nápady nevedou k cíly.

Díky!

romansklenar
Člen | 655
+
0
-

Mrkni na toto. Sice je to zralé na přepsání, ale než bych se k tomu dostal … (proč nemůžu zastavit čas aspoň na týden? :))

V bootstrapu pak je registrace služeb a jejich přiřazení k objektu User.

Environment::getServiceLocator()->addService(array('Acl', 'factory'), 'Nette\Security\IAuthorizator');
Environment::getServiceLocator()->addService('Users', 'Nette\Security\IAuthenticator');
$user = Environment::getUser();
$acl  = Environment::getService('Nette\Security\IAuthorizator');
$user->setAuthorizationHandler($acl);

Celá továrnička funguje tak, že pokud není v keši objekt Acl, vytoří se a jako klíč se použije název třídy + checksum z tabulky ve které je uložená ACL (což je celé číslo). Pokud se něco v tabulce Acl změní, změní se i vlastnost tabulky checksum → v keši nebude položka s takovým klíčem → pak se zovu sestaví celý celý objekt Acl a nakešuje se. Aby to celé fungovalo, musí mít tabulka nastaveno CHECKSUM = 1 a ROW_FORMAT = FIXED (pokud není, provede se ALTER TABLE a nastaví to, viz. kód, zálohuj si ale před tím DB).

That's it.

Tomik
Nette Evangelist | 485
+
0
-

Díky. Vypadá to pěkně, jen mám drobný problém s tím, že přes toto se to nedostane:

<?php
$table = dibi::fetch("SHOW TABLE STATUS FROM [:database:] WHERE [name] LIKE %s;", $aclTable);
$checksum = $table['Checksum'];

if (!$checksum) {
    /*try {*/
        if (dibi::query("ALTER TABLE [:cms:acl] CHECKSUM = 1 ROW_FORMAT = FIXED")) {
            $table = dibi::fetch("SHOW TABLE STATUS FROM [:database:] WHERE [name] LIKE %s;", $aclTable);
            $checksum = $table['Checksum'];

        } else {
            throw new RuntimeException("Can't find out 'Checksum' atribute on table '$aclTable' at database");
        }

    /*} catch (RuntimeException $e) { return $acl = new self; }*/
}
?>

Protože ať dělám co dělám, vždy mi databáze vrátí ve výsledku políčko Checksum prázdné. Resp. dotaz dibi::query("ALTER TABLE [:cms:acl] CHECKSUM = 1 ROW_FORMAT = FIXED") vyhodí FALSE a rovnou to vyhodí výjimku throw new RuntimeException("Can't find out 'Checksum' atribute on table `$aclTable at database");`.

Nevíš co s tím? Díky!

romansklenar
Člen | 655
+
0
-

Zkus dát pryč ten prefix: [:cms:acl][acl]. Já mám tabulky pojmenované oproti tomu obrázku prefixem cms_.

Tomik
Nette Evangelist | 485
+
0
-

romansklenar napsal(a):

Zkus dát pryč ten prefix: [:cms:acl][acl]. Já mám tabulky pojmenované oproti tomu obrázku prefixem cms_.

Tímto nebude, (kupodivu) sám také používám prefix cms. :)

romansklenar
Člen | 655
+
0
-

A když provedeš dotaz ručně v db stane se něco?

Zkus nejdříve

SHOW TABLE STATUS FROM `nazev_db` WHERE `name` LIKE 'cms_acl';

a mrkni co je v Checksum. Pokud to není kladné celé číslo tak spusť (pro jistotu)

ALTER TABLE `cms_acl` CHECKSUM = 1 ROW_FORMAT = FIXED;

pak jdi do cms_acl a proveď tam nějaký UPDATE nebo INSERT, tím by se měl checksum aktualizovat. Nakonec znovu spusť první dotaz mrkni se jestli teď v checksumu je kladné celé číslo.

Jakub Šulák
Člen | 222
+
0
-

Ještě bych zkontroloval, zda oba příkazy CHECKSUM a ROW_FORMAT podporuje DB, na které to provozuješ. Toto je asi psáno na mysql, nevím zda jiné DB mají ty příkazy stejně…

romansklenar
Člen | 655
+
0
-

Nn, viz kód: zkončil by jinou výjimkou:

NotImplementedException("Database drive $driver was not implemented yet into application", 500);
Tomik
Nette Evangelist | 485
+
0
-

romansklenar napsal(a):

A když provedeš dotaz ručně v db stane se něco?

Zkus nejdříve

SHOW TABLE STATUS FROM `nazev_db` WHERE `name` LIKE 'cms_acl';

a mrkni co je v Checksum. Pokud to není kladné celé číslo tak spusť (pro jistotu)

ALTER TABLE `cms_acl` CHECKSUM = 1 ROW_FORMAT = FIXED;

pak jdi do cms_acl a proveď tam nějaký UPDATE nebo INSERT, tím by se měl checksum aktualizovat. Nakonec znovu spusť první dotaz mrkni se jestli teď v checksumu je kladné celé číslo.

Ha! Tak tady bude chyba, na začátku mi to v Checksum ukazovalo NULL, po provedení popsaných operací, bohužel stále NULL. Docela by mě zajímalo čím to. :)

DB mám MySQL verze 5.0.51b-community-nt, tabulky jsou InnoDB a porovnávání utf8_general_ci. Sice to asi není důležité, ale bůhví, co na to bude mít vliv. :(

Editoval Tomik (17. 1. 2009 15:12)

Ondrej
Člen | 110
+
0
-

DB mám MySQL verze 5.0.51b-community-nt, tabulky jsou InnoDB a porovnávání utf8_general_ci. Sice to asi není důležité, ale bůhví, co na to bude mít vliv. :(

CHECKSUM je podporovan pouze pro MyISAM. V InnoDB bude vzdy prazdny.

Editoval Ondrej (17. 1. 2009 15:09)

romansklenar
Člen | 655
+
0
-

Přesně tak, viz dokumentace MySql.

EDIT:
Můžeš ale použít místo ChecksumUpdate_time. Sory, to vlastně tež nejde…

Editoval romansklenar (17. 1. 2009 15:26)

Tomik
Nette Evangelist | 485
+
0
-

Já vůl! :) Díky, tohle mě fakt nenapadlo, přitom jsem o tom četl, asi tak rok zpátky. Začínám evidentně zapomínat.

Díky.

Vzhledem k tomu, že InnoDB nutně nepotřebuji, prostě zmigruju zpátky na MyISAM, ale čistě teoreticky, předpokládám, že by to za určitých podmínek šlo řešit pomocí záznamu Data_length, ne? Vzhledem k tomu, že mám v tabulce ACL ještě sloupec description, stačilo by přidat nakonec upravených záznamů mezeru (popř. pokud tam už je ji odebrat). Tím by se změnila velikost dat a zaznamenal bych změnu. Ale jednodušší pro mě bude prostě přemigrovat na MyISAM. :)

phx
Člen | 651
+
0
-

Nejsem si jist, ale InnoDB ma tu nevyhodu, ze kdyz tam jednou das X MB dat a pak je smazes tak soubor na HDD se jiz nezmensi. Otazka zni co to udela s Data_lenght.

Jinak moznosti by bylo dat tam sloupecek last_update kde pokazde vlozit NOW() a za checksum povazovat MAX(last_update).

Tomik
Nette Evangelist | 485
+
0
-

phx napsal(a):

Nejsem si jist, ale InnoDB ma tu nevyhodu, ze kdyz tam jednou das X MB dat a pak je smazes tak soubor na HDD se jiz nezmensi. Otazka zni co to udela s Data_lenght.

Jinak moznosti by bylo dat tam sloupecek last_update kde pokazde vlozit NOW() a za checksum povazovat MAX(last_update).

Díky. No, stejně asi tu DB zmigruju, je to jednodušší. :)