#1 3. 12. 2009 14:08

David Grudl
Administrator
Registrovaný: 8. 2. 2005
Příspěvky: 4050
Web

[2009–12–03] Caching\FileStorage a SQLite pro ukládání tagů a priorit

Zkusil jsem upravit FileStorage tak, aby metadata Cache::TAGS a Cache::PRIORITY, podle kterých lze mazat metodou clean(), ukládalo žurnálu v podobě SQLite databáze.

Dosud bylo nutné při mazání určitého tagu projít všechny soubory v cache a zjistit, které mají daný štítek. Sice se z každého souboru načetla jen hlavička, ale i tak šlo o operaci, jejíž doba trvání narůstala přímou úměrou s počtem položek v cache. Použití žurnálu by mělo tento problém eliminovat, které soubory smazat se ví i bez procházení.

Sice by to mělo fungovat, ale je možné, že to má chyby, ať už z pohledu atomicity nebo výkonu. To bude chtít otestovat.

Offline

 

#2 3. 12. 2009 15:38

Petr Motejlek
Nette guru
Registrovaný: 9. 1. 2009
Příspěvky: 283

Re: [2009–12–03] Caching\FileStorage a SQLite pro ukládání tagů a priorit

To se mi líbí, zní to super. Přesně to jsem chtěl začít bastlit sám, protože někdy je těch věcí moc, a SQLite bude určitě to pravé.

Nevím, jestli se mám ptát tady, nebo bych měl založit nové vlákno, ale radši se zeptám tady: napsal jsem si vlastní session_handler (slouží k ukládání a načítání session dat) tak, aby používal SQLite (musel jsem použít PDO, protože mi to s Dibi blblo, ale nedávno jsem zjistil, že to asi byla moje blbost…).

Výhodu to má takovou, že pokud nastavíte timeout pro session například na 14 dní (to třeba zajístí, že zákazník uvidí obsah svého košíku i po 14 dnech neaktivity), tak v normální situaci se pro každou session vytváří samostatný soubor – po 14 dnech je to obvykle několik desítek tisíc souborů a výkon serveru začíná klesat, protože jsou defaultně všechny v jednom adresáři. Když se použije SQLite, tak se dá zařídit, aby těch souborů bylo vážně jen minimum a ztráta výkonu není téměř patrná (EDIT: no, záleží na tom, co do té session ukládáte :D).

Zajímalo by mě následující: je zájem o zveřejnění té třídy, která ukládá ta data session do SQLite (díky tomu, že by to bylo v Dibi, tak by byl skutečně minimální problém to převést na nějakou jinou databázi)?

Editoval Petr Motejlek (3. 12. 2009 15:39)

Offline

 

#3 3. 12. 2009 23:34

Honza Kuchař
Moderator
Místo: Brno
Registrovaný: 12. 8. 2007
Příspěvky: 1285
Web

Re: [2009–12–03] Caching\FileStorage a SQLite pro ukládání tagů a priorit

je zájem o zveřejnění té třídy

Já bych měl, zní to zajímavě.

která ukládá ta data session do SQLite (díky tomu, že by to bylo v Dibi, tak by byl skutečně minimální problém to převést na nějakou jinou databázi)?

Určitě. Teď jsem přecházel z MySQL na PgSQL a maká to perfektně.

Offline

 

#4 4. 12. 2009 22:31

Petr Motejlek
Nette guru
Registrovaný: 9. 1. 2009
Příspěvky: 283

Re: [2009–12–03] Caching\FileStorage a SQLite pro ukládání tagů a priorit

Tady je ta třída. Neříkám, že je to to nejlepší, co se pro dané zadání dá udělat, ale mě zatím stačí. Taky ale uvažuju, že vytvořím nějakou PgSQL databázi pro dočasné věci a budu to do cpát do ní a ne do SQLite. Pro použití s jinými databázemi by mělo stačit změnit ty dva řádky, co vytváří tabulku [session] a do self::$conn si uložit DibiConnection na tu vybranou databázi.

Pro použití této třídy je nutné si třeba v $application->onStartup[] zavolat následující (musí to být zavoláno ještě před vlastním nastartováním session):

<?php
session_set_save_handler(array('DBSession', 'open'), array('DBSession', 'close'),
            array('DBSession', 'read'), array('DBSession', 'write'),
            array('DBSession', 'destroy'), array('DBSession', 'clean'));
?>

A tady už je samotný kód třídy:

<?php
class DBSession {
    /**
     * Holds the database connection
     * @var DibiConnection
     */
    private static $conn = null;

    public static function open() {
        if (is_null(self::$conn)) {
            self::$conn = dibi::connect(array('driver' => 'pdo', 'dsn' => 'sqlite://' . APP_DIR . '/sessions/sessions.sqlite', ), __CLASS__);
            dibi::activate(MainConnectionName);
        };
    }

    public static function read($id) {
        if (is_null(self::$conn)) {
            throw new InvalidStateException("The connection to database for session storage is not open!");
        };

        $query = '
            SELECT
                [data]
            FROM [session]
            WHERE
                [id] = %s';
        try {
            $result = self::$conn->query($query, $id);
            return $result->fetchSingle();
        } catch (Exception $e) {
            Debug::processException($e);

            self::$conn->query('CREATE TABLE [session] ([id] varchar(32) not null primary key, [timestamp] timestamp not null, [data] text)');
            self::$conn->query('CREATE INDEX [session_by_timestamp] ON [session] ([timestamp])');

            return '';
        };
    }

    public static function write($id, $data) {
        if (is_null(self::$conn)) {
            throw new InvalidStateException("The connection to database for session storage is not open!");
        };

        self::$conn->begin();
        self::$conn->query('DELETE FROM [session] WHERE [id] = %s', $id);
        self::$conn->query('INSERT INTO [session] VALUES(%s, %s, %s)', $id, time(), $data);
        self::$conn->commit();
    }

    public static function destroy($id) {
        if (is_null(self::$conn)) {
            throw new InvalidStateException("The connection to database for session storage is not open!");
        };

        self::$conn->query('DELETE FROM [session] WHERE [id] = %s', $id);
    }

    public static function clean($max) {
        if (is_null(self::$conn)) {
            throw new InvalidStateException("The connection to database for session storage is not open!");
        };

        $old = (time() - $max);
        self::$conn->query('DELETE FROM [session] WHERE [timestamp] < %s', $old);
    }

    public static function close() {
        self::$conn = null;
    }
}
?>

P. S.: Budu rád, když se mi tady objeví ohlasy, abych případně věděl, jestli nedělám něco složitě nebo podivně a pro příště to mohl opravit ;).

Editoval Petr Motejlek (4. 12. 2009 22:33)

Offline

 

Zápatí