Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

DbSimple v2.x: обсуждения ТОЛЬКО для разработчиков библиотеки. (Константин Жинько [tIT])
Author Message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 12:32 am (написано за 2 минуты 3 секунды)
   Post subject: DbSimple2: добиваем до релиза.
Reply with quote

Второй день копаюсь со второй версией библиотеки. За это время добавил поддержку СУБД PostgreSQL и Interbase/Firebird. Версия пока еще не релизная, но подозреваю, что в ближайшее время это изменится. А пока выкладываю в следующих постах этой темы для интересующихся небольшую переписку с ДК на этот счет.
Back to top
View user's profile Send private message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 12:44 am (спустя 11 минут; написано за 7 минут 6 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
Константин Жинько [tIT] wrote:
1. единственный способ узнать размер блоба в постгресе - функция
Code (php): скопировать код в буфер обмена
pg_lo_read_all (www.php.net/pg_lo_read_all)
но у нее есть один побочный эффект - она весь блоб, никого не спрашивая пихает в выходной поток...
будет ли это решение как-то конфликтовать с другими буферами?
Code (php): скопировать код в буфер обмена
ob_start (www.php.net/ob_start)('ob_clean');
$len = pg_lo_read_all (www.php.net/pg_lo_read_all)($this->blob);
ob_end_clean (www.php.net/ob_end_clean)();
Может есть более оптимальная идея решения?
Конфликтовать оно не должно, по идее. Однако само решение, я
считаю, очень плохое: представь, что блоб будет размером 50 М -
это что же, он по сети передастся, а затем - в переменную
запишется? Слишком долго и слишком тормозит... Уж проще прочитать
блоб, а потом сделать strlen от него.

Присмотрись к функциям
ru.php.net/manual/ru/function.pg-lo-seek.php
(whence = PGSQL_SEEK_END)
и
ru.php.net/manual/ru/function.pg-lo-tell.php

По-моему, через них можно все сделать. (Только потом не забудь
восстанавливать старое значение указателя, которое у него было до
seek.) Кстати, вероятно, в классе *_Blob также нужны методы seek
и tell (включая их реализацию для MySQL).
Константин Жинько [tIT] wrote:
2. forum.dklab.ru/viewtopic.php?p=106796#106796:
Дмитрий Котеров wrote:
Возможность указывать атрибуты у запросов (примеры атрибутов: "результат
кэшируется" (на будущее), "объектные BLOB-поля" и т.д.). С синтаксисом
еще не определился: либо так:
Code (php): скопировать код в буфер обмена
$DB->query('
  -- BLOB_OBJ: true
  SELECT * FROM table_with_blobs
'
);
либо так:
Code (php): скопировать код в буфер обмена
$DB->query(array (www.php.net/array)(DBSIMPLE_ATTR, 'BLOB_OBJ'), '
   SELECT * FROM table_with_blobs
'
);
Второе кажется несколько более уродливым, но зато в перспективе можно
сделать через такой синтаксис то, что раньше делалось в selectPage() - в
PHP поддерживается синтаксис array(&$total).
Нужен ли метод в DbSimple_Generic_Database для создания нового блоба (то
бишь, еще отсутствующего в БД)... подозреваю, что да:
Code (php): скопировать код в буфер обмена
$blob_obj = $DB->blob($id) // для существующего
$blob_obj = $DB->blob() // для несуществующего
 
Есть метод _performNewBlob($id). Его и следует переопределять в
драйверах разных БД. А метод function& blob($blobid=null) -
конечно, нужен (я его забыл, видимо, за ненадобностью в MySQL),
но он должен просто вызывать _performNewBlob.
Константин Жинько [tIT] wrote:
3. еще непонятно, зачем ты повторно вызываешь parseDSN:
Code (php): скопировать код в буфер обмена
function DbSimple_Mysql($dsn)
{
    $p = DbSimple_Generic::parseDSN($dsn);
если в переменной $dsn и так распарсенный результат отсюда:
Code (php): скопировать код в буфер обмена
function& connect($dsn)
{
    // Load database driver and create its instance.
    $parsed = DbSimple_Generic::parseDSN($dsn);
Потому что конструктор может вызываться не только из Generic.
Вполне допустимо создавать объект типа DbSimple_Mysql вручную,
оператором new. И вот тогда-то там и передается строка. Это может
потребоваться, например, если ты хочешь сделать производный класс
с дополнительными параметрами.
Константин Жинько [tIT] wrote:
4. Почему бы свойство link не вынести в Generic - используется оно во
всех наследниках и в каждом определяется заново. В принципе я его и
вынес, но может, есть возражения?
Возражение очень простое: класс Generic задает, по сути,
интерфейс DbSimple. А в этом интерфейсе link ни к чему, потому
что для разных СУБД он несет совершенно разный смысл. Например,
для ibase таких link-ов два: один - для соединения, второй - для
текущей транзакции. Т.е. по сути link - это private-метод.

(Кстати, только в ibase поддерживается одновременное создание
нескольких транзакций для одного соединения; ни одна другая СУБД
в PHP этого не поддерживает. Так что я решил в версии 2.0 убрать
промежуточный слой абстракции "транзакция", считая, что есть
только соединение.)
Back to top
View user's profile Send private message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 12:50 am (спустя 6 минут; написано за 3 минуты 40 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
Конфликтовать оно не должно, по идее. Однако само решение, я
считаю, очень плохое: представь, что блоб будет размером 50 М -
это что же, он по сети передастся, а затем - в переменную
запишется? Слишком долго и слишком тормозит... Уж проще прочитать
блоб, а потом сделать strlen от него.
Проверил - не конфликтует. Как же это он по сети передастся, если я буферизацию включил? %
Дмитрий Котеров wrote:
Присмотрись к функциям
ru.php.net/manual/ru/function.pg-lo-seek.php
(whence = PGSQL_SEEK_END)
и
ru.php.net/manual/ru/function.pg-lo-tell.php
По-моему, через них можно все сделать. (Только потом не забудь
восстанавливать старое значение указателя, которое у него было до
seek.) Кстати, вероятно, в классе *_Blob также нужны методы seek
и tell (включая их реализацию для MySQL).
Старый указатель я и так восстанавливаю, ибо pg_lo_read_all его на конец сдвигает. Твой вариант более прост - так и сделаю.
seek и tell добавлю.
Дмитрий Котеров wrote:
Есть метод _performNewBlob($id). Его и следует переопределять в
драйверах разных БД. А метод function& blob($blobid=null) -
конечно, нужен (я его забыл, видимо, за ненадобностью в MySQL),
но он должен просто вызывать _performNewBlob.
Так собственно и сделал.
Дмитрий Котеров wrote:
Потому что конструктор может вызываться не только из Generic.
Вполне допустимо создавать объект типа DbSimple_Mysql вручную,
оператором new. И вот тогда-то там и передается строка. Это может
потребоваться, например, если ты хочешь сделать производный класс
с дополнительными параметрами.
тогда так:
Code (php): скопировать код в буфер обмена
function DbSimple_Mysql($dsn)
{
    $p = is_array (www.php.net/is_array)($dsn) ? $dsn : DbSimple_Generic::parseDSN($dsn);
Дмитрий Котеров wrote:
Возражение очень простое: класс Generic задает, по сути,
интерфейс DbSimple. А в этом интерфейсе link ни к чему, потому
что для разных СУБД он несет совершенно разный смысл. Например,
для ibase таких link-ов два: один - для соединения, второй - для
текущей транзакции. Т.е. по сути link - это private-метод.
Только не метод, а свойство (-;
Дмитрий Котеров wrote:
(Кстати, только в ibase поддерживается одновременное создание
нескольких транзакций для одного соединения; ни одна другая СУБД
в PHP этого не поддерживает. Так что я решил в версии 2.0 убрать
промежуточный слой абстракции "транзакция", считая, что есть
только соединение.)
Хм.. Я для транзакции в ibase отдельное свойство trans ввел. Кстати, нужна ли поддержка нескольких транзакций для ibase?
Back to top
View user's profile Send private message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 12:54 am (спустя 3 минуты; написано за 2 минуты 32 секунды)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
Константин Жинько [tIT] wrote:
Проверил - не конфликтует. Как же это он по сети передастся, если я
буферизацию включил? %
От сервера СУБД в PHP-скрипт - очень просто. Даже если БД на
локалхосте, все равно накладные расходы большие.
Константин Жинько [tIT] wrote:
Старый указатель я и так восстанавливаю, ибо pg_lo_read_all
его на конец сдвигает. Твой вариант более прост - так и сделаю.
seek и tell добавлю.
ОК.

Да, кстати, по поводу кэширования. Все-таки мне способ с --
BLOB_OBJ: true и -- CACHE больше нравится, потому что в логе
запросов сразу видно, какой запрос что делал. Особенно для
кэширования.

Синтаксис для кэш-функционала, например, такой:

-- CACHE: time

(где time - на сколько секунд кэшировать, или

-- CACHE: uniqKey

(где кэш валиден до момента, когда изменится uniqKey), или

-- CACHE: табл1.поле1 табл2.поле2 табл3.поле3

(где таблN - таблица, от которой зависит запрос, а полеN - имя
поля, хранящего TIMESTAMP изменения записи в таблице; кэшируется
по совокупности MAX значения во всех этих полях, причем строка
"табл1.поле1 табл2.поле2 табл3.поле3" просто заменяется на
uniqKey и сводится к предыдущему; получится аналог встроенного в
MySQL кэширования запросов, но только для любых СУБД).

Но только вот, думаю, кэширование не надо прямо в GENERIC
вставлять, а лучше сделать производный класс, куда уже и
вставлять. Для этого нужна некоторая доработка, чтобы классы типа
DbSimple_Mysql понимали, что они должны использовать методы из
класса с кэшированием, а не из Generic. Т.е. DbSimple_Mysql, по
сути, не должен быть производным от Generic во всех отношениях, а
какую-то часть содержать как ссылку на Generic_Cache-класс.

В общем, тут еще думать и думать.
Константин Жинько [tIT] wrote:
тогда так:
Code (php): скопировать код в буфер обмена
function DbSimple_Mysql($dsn)
{
    $p = is_array (www.php.net/is_array)($dsn) ? $dsn : DbSimple_Generic::parseDSN($dsn);
А в первых строках parseDSN это и делается вроде. Разве нет?
Константин Жинько [tIT] wrote:
Хм.. Я для транзакции в ibase отдельное свойство trans ввел.
Кстати, нужна ли поддержка нескольких транзакций для ibase?
Нет, не нужна, я же выше написал. Скрипты многопоточными не
бывают, так что всегда можно переключаться туда-обратно, с
пишущей на читающую и наоборот.
Back to top
View user's profile Send private message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 1:01 am (спустя 7 минут; написано за 5 минут 51 секунду)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
От сервера СУБД в PHP-скрипт - очень просто. Даже если БД на
локалхосте, все равно накладные расходы большие.
Логично (-;
Дмитрий Котеров wrote:
А в первых строках parseDSN это и делается вроде. Разве нет?
Ну да... Сразу не заметил %
Дмитрий Котеров wrote:
Нет, не нужна, я же выше написал.
Ну и ладненько.
Дмитрий Котеров wrote:
Все-таки мне способ с --BLOB_OBJ: true и -- CACHE больше нравится
Мне тоже. Я же придумал ;)
Дмитрий Котеров wrote:
где кэш валиден до момента, когда изменится uniqKey
мм.. а uniqKey это вообще что?
Дмитрий Котеров wrote:
Но только вот, думаю, кэширование не надо прямо в GENERIC
вставлять, а лучше сделать производный класс, куда уже и
вставлять.
Мне думается вообще отдельный класс. Как мы делаем $DB->setLogger($callback);, так можем делать и $DB->setCacher($callback);
Ну и разумеется так же, как есть хакерская консоль, так же будет и кэширование на файлах. Как думаешь?

И еще: в ibase нет понятий seek и tell в API. Пусть уж юзер сам пишет
Code (php): скопировать код в буфер обмена
pg_lo_tell (www.php.net/pg_lo_tell)($blob->blobid); // надо б blobid на id заменить - некрасиво смотрится
 
ИМХО
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 09, 2006 1:14 am (спустя 12 минут; написано за 6 минут 43 секунды)
   Post subject:
Reply with quote

Константин Жинько [tIT] wrote:
а uniqKey это вообще что?
Ну, некоторая величина (типа DJHGSJHGDKJSHG). Если она не изменяется, запрос берется из кэша. Если изменяется - то кэш инвалидируется.
Но мне вот какая мысль пришла. Кэшировать надо, естественно, по полному тексту запроса после подстановки всех placeholder-ов. Включая все комментарии и т.д. Если так сделать, то тогда синтаксис

-- CACHE: uniqKey
SELECT * FROM abc

вообще не нужен, достаточно

-- CACHE:
-- uniqKey
SELECT * FROM abc

Первая строчка говорит "кэшировать навсегда", а вот вторая - делает запрос уникальным для уникальных uniqKey. Т.е. я меняю строку, подставляемую вместо uniqKey, и кэш обновляется. Как частный случай - в качестве uniqKey можно использовать max от timestamp-ов зависимых таблиц.

Правда, такая техника приводит к разрастанию количества кэшей. Т.е. встает проблема удаления старых кэшей, чтобы они место не забивали. Это единственный недостаток, пожалуй; если его не удастся легко преодолеть, то тогда можно вернуться к варианту с -- CACHE: uniqKey. Там уж кэшей разведется не так много - по числу запросов (впрочем, все равно много: placeholder-ы то разные бывают).
Константин Жинько [tIT] wrote:
Как мы делаем $DB->setLogger($callback);, так можем делать и $DB->setCacher($callback);
Честно говоря, мне эта мысль не очень нравится, т.к. кэширование можно реализовать через _performTransformQuery (собственно, этот метод для того и предназначен). Обрати, кстати, внимание на метод case _transformQuery в Generic, со слов 'GET_ATTRIBUTES'. Видишь, парсинг строки вида "-- CACHE: xxx" уже есть, только не используется нигде.
Константин Жинько [tIT] wrote:
И еще: в ibase нет понятий seek и tell в API. Пусть уж юзер сам пишет
Согласен. Раз не во всех СУБД есть - то тогда лучше минимальный интерфейс.
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 1:48 am (спустя 33 минуты; написано за 5 минут 46 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
если его не удастся легко преодолеть
Уже знаю, как (-;
Долго описывать - проще код написать, потом прокомментировать.
Дмитрий Котеров wrote:
Обрати, кстати, внимание на метод case _transformQuery в Generic, со слов 'GET_ATTRIBUTES'. Видишь, парсинг строки вида "-- CACHE: xxx" уже есть, только не используется нигде.
Давно обратил.
Дмитрий Котеров wrote:
кэширование можно реализовать через _performTransformQuery (собственно, этот метод для того и предназначен)
Ну может быть... Просто кто-то захочет memcache использовать, кто-то простые файлы.. Кто-то свой велосипед прикрутить (-;
Дмитрий Котеров wrote:
Как частный случай - в качестве uniqKey можно использовать max от timestamp-ов зависимых таблиц.
Хм... Даже два раза хм...
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 09, 2006 3:12 pm (спустя 13 часов 24 минуты; написано за 4 минуты 46 секунд)
   Post subject:
Reply with quote

Memcache, кстати, идеальный вариант для кэширования, потому что он сам умеет кэш чистить, вытесняя наиболее редко используемые записи. Естественно, какой-то слой абстракции, позволяющий подменять кэш-хранилище, должна быть. В принципе, setCacher($func) - вариант неплохой, согласен; вместо $func можно, например, подставлять функцию вида

function cacher($key, $value=null)

где если $value = null, то возвращается элемент кэша $key, а если $value != null, то - устанавливает элемент кэша $key.

(Почему именно функция, а не класс - да из соображений простоты. Создать новую функцию проще и понятнее, чем создавать новый класс. Кроме того, одно другого не искллючает: можно же вместо функции передавать array(&$obj, 'cacherMethod').)

Ну а операцию чистку кэша (чтобы разрастался в случае, если кэш на файлах, а не на memcache) можно встроить при необходимости в сам этот cacher - при записи очередного элемента проверяется, не надо ли "вытеснить" какой-то другой элемент.

Я думаю, в такой подстановке можно включать кэширование прямо в класс Generic.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 09, 2006 3:14 pm (спустя 1 минуту 25 секунд; написано за 51 секунду)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
в качестве uniqKey можно использовать max от timestamp-ов зависимых таблиц
...но, т.к. мы не знаем, от каких таблиц зависит запрос, то и перечисляем их явно (парсить запрос для определения таблиц - это уж слишком, для этого надо быть SQL-сервером).
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 4:45 pm (спустя 1 час 31 минуту; написано за 3 минуты)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
Почему именно функция, а не класс - да из соображений простоты.
Ну я это и имел в виду..(-; Функция может быть атомарной, а может служить оберткой для метода класса - как юзеру удобнее.
Дмитрий Котеров wrote:
Memcache, кстати, идеальный вариант для кэширования
Ага. Тока не у всех стоит.
Дмитрий Котеров wrote:
в качестве uniqKey можно использовать max от timestamp-ов зависимых таблиц
Все равно не догоняю, что значит timestamp зависимой таблицы. Поле типа timestamp - понимаю. Timestamp таблицы - не понимаю.
Back to top
View user's profile Send private message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Sat Dec 09, 2006 5:54 pm (спустя 1 час 9 минут; написано за 3 минуты 51 секунду)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
со слов 'GET_ATTRIBUTES'.
Там кстати баг в регулярном выражении:
Code (php): скопировать код в буфер обмена
while (preg_match (www.php.net/preg_match)('/^ \s* -- [ \t]+ (\w+): [ \t]* [^\r\n] [\r\n]* /sx', $query[0], $m)) {
    $options[$m[1]] = rtrim (www.php.net/rtrim)($m[2]); // откуда $m[2], если в выражении только одни круглые скобки
    $query[0] = substr (www.php.net/substr)($query[0], strlen (www.php.net/strlen)($m[0])); // зачем вырезаешь строку из запроса?
 
Например, такой запрос до GET_ATTRIBUTES:
Code (SQL): скопировать код в буфер обмена
-- CACHE: 10m
SELECT DATA
FROM my
LIMIT 5 OFFSET 0
и после:
Code (SQL): скопировать код в буфер обмена
0m
SELECT DATA
FROM my
LIMIT 5 OFFSET 0
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 09, 2006 6:01 pm (спустя 6 минут; написано за 19 секунд)
   Post subject:
Reply with quote

Константин Жинько [tIT] wrote:
Timestamp таблицы - не понимаю
select max(modified) from table - timestamp таблицы. Что непонятного?
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sun Dec 10, 2006 3:49 am (спустя 9 часов 48 минут; написано за 9 секунд)
   Post subject:
Reply with quote

Релиз!
forum.dklab.ru/viewtopic.php?t=23775
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sun Dec 10, 2006 4:01 am (спустя 11 минут; написано за 42 секунды)
   Post subject:
Reply with quote

Константин Жинько [tIT] wrote:
откуда $m[2], если в выражении только одни круглые скобки
Добавил еще одни.
Константин Жинько [tIT] wrote:
зачем вырезаешь строку из запроса?
Как зачем? Чтобы не зациклилось на следующей итерации. Но, действительно, текст запроса менять не нужно; сделал сейчас через временную переменную.
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Mon Dec 11, 2006 11:35 am (спустя 1 день 7 часов 34 минуты; написано за 2 минуты 2 секунды)
   Post subject:
Reply with quote

Добавил поддержку родных плэйсхолдеров в PostgreSQL, а так же поддержку prepare/execute.
Плюс несколько корректировок - не все функции были собакой предварены, убрал лишние printr и пр.

Следующий шаг - система кэширования.
Потом добавлю поддержку для SQLite, ибо народ требуеть (-:
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Wed Dec 13, 2006 12:38 am (спустя 1 день 13 часов 2 минуты)
   Post subject:
Reply with quote

dk, 12.12.2006 17:17:41:
описываю алгоритм

1. есть запрос
-- CACHE: 1m t.modified
SELECT * FROM t

2. создаем хэш запроса: queryHash = md5(query)
3. проверяем, есть ли кэш-данные для queryHash: cachedData = cacheGet(queryHash)
4. сверяем cachedData.storeTime > time() - 1m; сверяем cachedData.invalHash == t.modified
5. если все совпало, отдаем кэш
6. если нет, записываем в кэш false (типа очистили), выполняем запрос, и записывам
   array(storeTime=>time(), invalHash=>t.modified, result=>$result) в кэш

dk, 17:18:07:
вот такой алгоритм будет минимизировать число кэш-ключей

dk, 17:18:21:
плюс никакой ttl не передается

dk, 17:19:10:
правда, в нем-таки подразумевается, что 1m - источник инвалидации, отличный от t.modified
(в разных полях сохраненных данных они хранятся)

dk, 17:21:09:
интерфейс вот такой:

// Connect to database.
$DB = DbSimple_Generic::connect($dsn);
// Set caching function.
$DB->setCacher('myCacher');
// Define caching function.
function myCacher($key, $value)
{
    // Если $value !== null, то следует записать его в кэш с ключом $key.
    // Если $value === null, то следует вернуть значение кэша с ключом $key.
}

dk, 17:21:25:
и все, ttl нету

tIT, 17:21:29:
ок... случай с файловым кэшом понятен - filemtime()

а теперь найди мне способ узнать время создания
ru.php.net/manual/ru/function.memcache-get.php

мораль: не все механизмы кэширования предоставляют возможность узнать этот самый storeTime
вывод: все же не зря используется TTL

dk, 17:21:41:
читай алгоритм лучше

dk, 17:21:50:
6. если нет, записываем в кэш false (типа очистили), выполняем запрос, и записывам
   array(storeTime=>time(), invalHash=>t.modified, result=>$result) в кэш

dk, 17:22:11:
время создания кэша можно взять из самого этого кэша

dk, 17:22:19:
равно как и предыдущие modified

dk, 17:23:10:
даже false, кстати, не нужно записывать, это я нагнал
все равно же он тут же новым значением перезаписывается
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Wed Dec 13, 2006 1:06 am (спустя 28 минут; написано за 17 секунд)
   Post subject:
Reply with quote

Thx, а то логи на работе остались %
Back to top
View user's profile Send private message
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Wed Dec 13, 2006 9:27 pm (спустя 20 часов 21 минуту; написано за 33 секунды)
   Post subject:
Reply with quote

Переделал кэширование.
Исправил несколько серьезных багов.
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 16, 2006 6:50 pm (спустя 2 дня 21 час 22 минуты; написано за 9 минут 36 секунд)
   Post subject:
Reply with quote

Я прикрутил автоматическую систему тестирования.

ВНИМАНИЕ:
1. Для любого крупного изменения, вносимого в библиотеку, необходимо писать отдельный тест-скрипт (см. ниже), это очень просто.
2. Перед коммитом необходимо прогонять имеющиеся тесты, чтобы убедиться, что ничего не сломалось.

Скрипт для запуска тестов - t/rt.bat. Если его запустить, он последовательно прогонит все тесты, расположенные в текущей директории (и ниже). Если в каком-то тесте обнаружится ошибка, в директории с тестом создастся куча файлов (*.out, *.diff и т.д.), в которых подробно написано, что произошло, что вывел скрипт, что должен был вывести и т.д. Если ошибки нет, эти файлв ВЫЧИСТЯТСЯ. Так что надо запускать rt.bat до тех пор, пока отовсюду не исчезнут паразитные файлы, и останутся только *.phpt.

Чтобы скрипт работал, нужно, во-первых, иметь PHP4, установленный в z:\usr\local\php, и во-вторых, иметь в нем установленный PEAR (устанавливается путем запуска z:\usr\local\php\go-pear.bat, если еще не установлен). Кроме того (и увы):
Code (Windows BAT file): скопировать код в буфер обмена
echo !!
echo !! Note that if you need to test MySQL functions from command-line,
echo !! you MUST create C:\mysql\share and copy content of corresponding
echo !! folder there. Then add "cp1251 51" to C:\mysql\share\charsets\Index.
echo !! This is because of well-known BUG in PHP libmysql DLL.
echo !!
Писать скрипты тестирования очень просто. Достаточно заглянуть в t\DbSimple\Generic\010_array_key.phpt, чтобы в этом убедиться:
Code (php): скопировать код в буфер обмена
--TEST--
Generic: ARRAY_KEY* usage
--FILE--
<?php
require_once dirname (www.php.net/dirname)(__FILE__) . '/../init.php';

function main(&$DB)
{
        @$DB->query("DROP TABLE test");
        $DB->query("CREATE TABLE test(id INTEGER, pid INTEGER, str TEXT)");
        $DB->query("INSERT INTO test(id, pid, str) VALUES(100, 10, 'a')");
        $DB->query("INSERT INTO test(id, pid, str) VALUES(101, 10, 'b')");
        $DB->query("INSERT INTO test(id, pid, str) VALUES(200, 20, 'x')");
        $DB->query("INSERT INTO test(id, pid, str) VALUES(201, 20, 'y')");
        printr($DB->query("SELECT id AS ARRAY_KEY, str FROM test ORDER BY id"));
        printr($DB->query("SELECT id AS ARRAY_KEY_2, pid AS ARRAY_KEY_1, str FROM test ORDER BY id"));
        printr($DB->query("SELECT NULL AS ARRAY_KEY_2, pid AS ARRAY_KEY_1, str FROM test ORDER BY id"
Тесты DbSimple разделены на директории:
- директория Generic: функциональность, независимая от СУБД (в настоящий момент тесты запускаются для MySQL);
- все остальные директории: функциональность, специфичная для конкретной СУБД

DSN-ы задаются в файле dsn.txt (по умолчанию там юзер, пароль и база - "test"). Если в dsn "*", то тесты прогоняются для ВСЕХ СУБД. Если в dsn имя СУБД, то DSN берется из директории соответствующей базы. Если DSN указан явно, то коннектимся к указанной БД.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sun Dec 17, 2006 11:52 pm (спустя 1 день 5 часов 1 минуту; написано за 3 минуты 48 секунд)
   Post subject:
Reply with quote

Решил тут вот глянуть на Postgresql.php. Есть несколько замечаний.

1. Насчет
   // PostgreSQL uses specific placeholders such as $1, $2, etc.
   // So we have to change simple placeholders ?, ?d, ?f
   case 'NATIVE_PHOLDERS':
       $query_substr = preg_split('/(?>(\?))/sx', $queryMain[0]);
   Мне думается, что поддержку данной вещи надо было бы реализовывать не здесь, а в том месте, где анализируется запрос на предмет наличия в нем placeholder-ов. А именно, в том куске, где ?d и ?f заменяется на обычный ? в Generic. Почему? Очень просто: SELECT 'a ? b' преобразуется в SELECT 'a $1 b', хотя строки в кавычках трогать нельзя (и для этого есть поддержка в Generic).

2. Насчет
   // AS DBSIMPLE_KEY --> AS "DBSIMPLE_KEY"
   case 'QUOTE_FIELDS':
   - это по аське обсудим. Замечание точно такое же: запрос SELECT 'a AS ARRAY_KEY' трансформируется, хотя не должен. Возможное рещение - case-insensitive сравнение на предмет выявления PARENT_KEY/ARRAY_KEY.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sun Dec 17, 2006 11:54 pm (спустя 2 минуты; написано за 1 минуту 28 секунд)
   Post subject:
Reply with quote

P.S.
По поводу 1 - вот это место в Generic:
Code (php): скопировать код в буфер обмена
            // Native arguments are not processed.
            if ($this->_placeholderNativeArgs !== null) {
                $this->_placeholderNativeArgs[] = $value;
                return '?';
            }
Видишь, вставляется '?' для native. А надо, чтобы в зависимости от БД вставлялось что-то свое. Как это определить - надо еще подумать (можно - _performGetNativePlaceholder($number); по умолчанию дает '?').
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Mon Dec 18, 2006 12:00 am (спустя 5 минут; написано за 38 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
А надо, чтобы в зависимости от БД вставлялось что-то свое.
Работать это явно будет быстрее.
Дмитрий Котеров wrote:
SELECT 'a ? b'
Дмитрий Котеров wrote:
SELECT 'a AS ARRAY_KEY'
Ык... Мда... Нехорошо получилось.
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Mon Dec 18, 2006 1:43 am (спустя 1 час 43 минуты; написано за 50 секунд)
   Post subject:
Reply with quote

Все исправил, закоммитил в trunk. Как только народ попользуется (да и сам опробую на практике чуть-чуть), перенесу в релиз.
Вообще, надо сказать, вся эта возня с ветками немного напрягает...
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Mon Dec 18, 2006 2:33 am (спустя 50 минут; написано за 8 секунд)
   Post subject:
Reply with quote

Еще как!
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
Post a reply
Username
Subject
Господа спамеры и оптимизаторы!

Вы можете даже и не пытаться вставлять в текст поста ссылки - они все равно автоматически удаляются (вернее, тэги <a> заменяются на тэги <u>).

Но если не поверите и все же попытаетесь - как только увидите, что все безрезультатно, удалите свой пост, пожалуйста. Модераторы тоже люди, нехорошо, если они погрязнут в тоннах спама.
     

Disable BBCode in this post
Disable Smilies in this post
    HTML is OFF
BBCode is ON
Smilies are ON
You cannot post new topics in this forum. You can reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML