Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Firebird, InterBase Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 3 4 5 [6] 7   вперед  Ctrl      все
 Re: PDO Firebird bugs  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48163

Павел Ишенин
Если вдаваться в логику, то statement при смерти должен удалять буферы

Не должен. Блобы могут читаться отдельно без всякого статемента. Их кэш может быть
привязан к транзакции или коннекту. В твоём коде не освобождается ни то ни другое.

Posted via ActualForum NNTP Server 1.5

28 май 18, 12:21    [21446009]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Dimitry Sibiryakov,

поскольку PDO не умеет читать идентификаторы BLOB, а всегда читает сразу его содержимое (хотя по уму могли бы и поток для этого организовать), то в самом драйвере они должны освобождать внутренние структуры блоба сразу после фетча.
28 май 18, 12:53    [21446159]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
а не вру, есть возможность читать BLOB как поток, но через опу
http://php.net/manual/ru/pdo.lobs.php
28 май 18, 12:58    [21446189]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Дегтярев Евгений
Member

Откуда: Барнаул
Сообщений: 1642
Павел Ишенин
Дегтярев Евгений
а что с ibase_?
извиняюсь, в пред сообщении написал ibx

Может ли это помочь проблеме? И если да, то как?

как вариант, да, там может не быть этой проблемы
когда сталкивался со связкой php+fb использовал функции ibase_xxx, pdo_firebird обходил стороной, т.к. с ним периодически всплывали какие то траблы

за ответом как, сюда - http://php.net/manual/ru/book.ibase.php
28 май 18, 14:08    [21446628]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Павел Ишенин
При анализе кода pdo_firebird вот первое за что цепляется глаз:
*ptr = S->fetch_buf[colno] = erealloc(*ptr, *len+1);


Зачем там erealloc? Разве где-то память выделяется ранее? И если нет, то всегда ли там null?

Под все остальные типы используется следующая конструкция:
*ptr = FETCH_BUF(S->fetch_buf[colno], char, *len, NULL);


дело в том что у остальных типов длина фиксирована, поэтому достаточно выделить память один раз. А для BLOB который сразу преобразуется в текст приходится переаллокировать буфер при каждом фетче.
28 май 18, 14:29    [21446770]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Павел Ишенин
Member

Откуда: Красноярск
Сообщений: 358
Dimitry Sibiryakov
Павел Ишенин
Если вдаваться в логику, то statement при смерти должен удалять буферы

Не должен. Блобы могут читаться отдельно без всякого статемента. Их кэш может быть
привязан к транзакции или коннекту. В твоём коде не освобождается ни то ни другое.


Имелся ввиду вот этот код pdo_firebird:

	/* clean up the fetch buffers if they have been used */
	for (i = 0; i < S->out_sqlda.sqld; ++i) {
		if (S->fetch_buf[i]) {
			efree(S->fetch_buf[i]);
		}
	}
28 май 18, 16:54    [21447685]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Павел Ишенин
Member

Откуда: Красноярск
Сообщений: 358
Дегтярев Евгений
как вариант, да, там может не быть этой проблемы
когда сталкивался со связкой php+fb использовал функции ibase_xxx, pdo_firebird обходил стороной, т.к. с ним периодически всплывали какие то траблы


Если прочитать моё начальное сообщение, то видно что я пишу про работу с Firebird в библиотеке Yii. Там используется PDO. Какой смысл проверять не PDO, если мне надо разобраться с проблемой именно в нём?
28 май 18, 16:57    [21447703]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Павел Ишенин
Member

Откуда: Красноярск
Сообщений: 358
Симонов Денис
дело в том что у остальных типов длина фиксирована, поэтому достаточно выделить память один раз. А для BLOB который сразу преобразуется в текст приходится переаллокировать буфер при каждом фетче.


Спасибо, мне что-то в голову это не пришло. Тогда всё вроде верно написано. Ну может вместо realloc было бы выгодней сделать free + malloc если realloc ведет к фрагментации памяти. Тем не менее, это не должно порождать утечку.
28 май 18, 17:03    [21447752]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Дегтярев Евгений
Member

Откуда: Барнаул
Сообщений: 1642
Павел Ишенин
Дегтярев Евгений
как вариант, да, там может не быть этой проблемы
когда сталкивался со связкой php+fb использовал функции ibase_xxx, pdo_firebird обходил стороной, т.к. с ним периодически всплывали какие то траблы


Если прочитать моё начальное сообщение, то видно что я пишу про работу с Firebird в библиотеке Yii. Там используется PDO. Какой смысл проверять не PDO, если мне надо разобраться с проблемой именно в нём?

в том чтобы проверить, локализовать и зарепортить все возможные проблемы
28 май 18, 17:04    [21447758]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Dorin Marcoci
Member

Откуда:
Сообщений: 261
Можете протестить тот же код на таблицы/полей без блобов и проверить память или скажем на Postgres блобах?
Глянул еще раз на firebird_fetch_blob( вроди ничего криминального не нашел.
К выходу идет ptr и len который потом освобождается в базовой PDO классе.
Обычно пхп девы тестят все изминения Valgrind-ом и другими тулами, чтобы минимизировать утечки.
Если все же уверен что утечка есть, то создай баг репорт с юнит тест кэйсом наподобие: https://github.com/php/php-src/tree/8582e53430f12ce36f621d034a40d10ea01061fc/ext/pdo_firebird/tests
5 июн 18, 13:06    [21469461]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Dorin Marcoci,

оно легко воспроизводится

+
<?php

$sql = '
SELECT
    RDB$PROCEDURE_NAME AS NAME,
    RDB$PROCEDURE_SOURCE AS SRC
--    CAST(SUBSTRING(RDB$PROCEDURE_SOURCE FROM 1 FOR 8191) AS VARCHAR(8191)) AS SRC
FROM
    RDB$PROCEDURES   
';

try {
    $dbh = new \PDO('firebird:dbname=localhost:test', 'SYSDBA', 'masterkey');
    $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_NATURAL);
    //$dbh->setAttribute(\PDO::ATTR_AUTOCOMMIT, false);

    echo "First used: " . memory_get_usage(true) . "<br>";
 
  
    for ($i = 0; $i < 20; $i++) {
	//$dbh->beginTransaction();
        $sth = $dbh->prepare($sql);
        $sth->execute();          
        $rows = $sth->fetchAll();
	unset($rows);
        //$sth->closeCursor();
	unset($sth);
	//$dbh->commit();
        echo "$i itteration used: " . memory_get_usage(true) . "<br>";
    }
    unset($dbh);
    echo "Last used: " . memory_get_usage(true) . "<br>";
} catch (\Exception $e) {
    echo $e->getMessage();
}


+
автор
First used: 2097152
0 itteration used: 4194304
1 itteration used: 4194304
2 itteration used: 6291456
3 itteration used: 6291456
4 itteration used: 8388608
5 itteration used: 8388608
6 itteration used: 8388608
7 itteration used: 10485760
8 itteration used: 12582912
9 itteration used: 12582912
10 itteration used: 12582912
11 itteration used: 14680064
12 itteration used: 16777216
13 itteration used: 16777216
14 itteration used: 16777216
15 itteration used: 18874368
16 itteration used: 18874368
17 itteration used: 20971520
18 itteration used: 23068672
19 itteration used: 23068672
Last used: 23068672


в базе данных ~200 процедур. При замене BLOB на строку утечек нет. Интересно что при повторном запуске скрипта память постепенно стабилизируется. Наверное менеджер памяти там такой хитрый.

И ещё вот здесь
static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,  /* {{{ */
	zend_ulong *len, int *caller_frees)
{
	pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
	XSQLVAR const *var = &S->out_sqlda.sqlvar[colno]; // тадам!!!

	if (*var->sqlind == -1) {
...


нет проверки на допустимость номера столбца. В результате при вызове PDOStatement::fetchColumn с номером большим чем количество столбцов имеем segfault с падением web сервера. Надо бы ошибку бросать
5 июн 18, 13:51    [21469630]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
hvlad
Member

Откуда:
Сообщений: 10531
Dorin Marcoci
Глянул еще раз на firebird_fetch_blob( вроди ничего криминального не нашел.
К выходу идет ptr и len который потом освобождается в базовой PDO классе.
А сам блоб - закрывается ?

Симонов Денис
оно легко воспроизводится
Тут автокоммит вкл ?
5 июн 18, 13:57    [21469647]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
hvlad,

я пробовал его отключать (по умолчанию включен). Разницы никакой.
Кстати разве после закрытия блоб всё ещё будет потреблять ресурсы на клиенте, даже если транзакция не завершена?
5 июн 18, 14:02    [21469661]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
hvlad
Member

Откуда:
Сообщений: 10531
Симонов Денис
Кстати разве после закрытия блоб всё ещё будет потреблять ресурсы на клиенте, даже если транзакция не завершена?
После закрытия - конечно не будет.
Вопрос в том - закрыты ли они.
Однако, коммит (роллбек) должен освобождать клиентские ресурсы, связанные с блобами.
Отсюда был вопрос об автокоммите.
5 июн 18, 14:13    [21469721]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Павел Ишенин
Member

Откуда: Красноярск
Сообщений: 358
hvlad
А сам блоб - закрывается ?


Да, после чтения блоб закрывается.
7 июн 18, 18:11    [21477153]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Павел Ишенин
Member

Откуда: Красноярск
Сообщений: 358
Dorin Marcoci,

Если есть возможность поотлаживать код pdo-firebird, то в какой момент вызывается firebird_stmt_dtor? И что если добавить вывод потребления памяти до и после erealloc? Я не знаю как работает этот erealloc, но традиционно перевыделение вызывает фрагментацию и медленнее освобождения с повторным выделением поскольку менеджер должен, помимо прочего, скопировать содержимое старого блока памяти в новый (чего, как я понимаю, в данном случае не требуется).
7 июн 18, 18:21    [21477176]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Павел Ишенин,

там КМК это можно оптимизировать. Например выделять для начала 32K памяти, если блоб больше увеличивать, т.е. перевыделять память только если для БЛОБа её требуется больше.
7 июн 18, 19:51    [21477382]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Павел Ишенин,

ура!!! Нашёл утечку. Не зря тебе подозрительным вот этот кусок показался

Павел Ишенин
При анализе кода pdo_firebird вот первое за что цепляется глаз:
*ptr = S->fetch_buf[colno] = erealloc(*ptr, *len+1);



только дело не в erealloc, а в том память перевыделяют для для ptr, в котором вообще чужой буфер может быть из столбца к которому обращались до BLOBa (в моём тесте из NAME). Вот правильный код

*ptr = S->fetch_buf[colno] = erealloc(S->fetch_buf[colno], *len+1);


+ тест
try {
    $dbh = new \PDO('firebird:dbname=localhost:horses', 'SYSDBA', 'masterkey');
    $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_NATURAL);

$sql = '
SELECT
    RDB$PROCEDURE_NAME AS NAME,
    RDB$PROCEDURE_SOURCE AS SRC
FROM
    RDB$PROCEDURES   
';

    echo "First used: " . memory_get_usage(true) . "<br>";
  
    for ($i = 0; $i < 20; $i++) {
        $sth = $dbh->prepare($sql);
        $sth->execute();          
        $rows = $sth->fetchAll();
	    unset($rows);
	    unset($sth);
        echo "$i itteration used: " . memory_get_usage(true) . "<br>";
    }
    unset($dbh);
    echo "Last used: " . memory_get_usage(true) . "<br>";
}
catch(Exception $e) {
	var_dump($e);
}


First used: 2097152
0 itteration used: 2097152
1 itteration used: 2097152
2 itteration used: 2097152
3 itteration used: 2097152
4 itteration used: 2097152
5 itteration used: 2097152
6 itteration used: 2097152
7 itteration used: 2097152
8 itteration used: 2097152
9 itteration used: 2097152
10 itteration used: 2097152
11 itteration used: 2097152
12 itteration used: 2097152
13 itteration used: 2097152
14 itteration used: 2097152
15 itteration used: 2097152
16 itteration used: 2097152
17 itteration used: 2097152
18 itteration used: 2097152
19 itteration used: 2097152
Last used: 2097152


теперь надо бы патч оформить. Буду разбираться как им написать
16 июн 18, 16:39    [21496219]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
в трекер написал https://bugs.php.net/bug.php?id=76488 патч приложил ждём реакции
17 июн 18, 16:19    [21497619]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Dorin Marcoci
Member

Откуда:
Сообщений: 261
Денис, спасибо за фикс!
Нужно сделать тест-кэйс и пулл реквест на гитхабе, о то будешь ждать бесконечно долго.
Попробую, может сделаю я, но дико не хватает время. Последние месяцы занят повседневными проэктами.
25 июн 18, 11:46    [21518116]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Dorin Marcoci
Member

Откуда:
Сообщений: 261
Денис, там тест кэйс должен падать при нынешнем коде, и пройти успешно с твоим кодом.
Например, типа утечка ноль, а с текущим кодом > 0. Но думаю смерджят.
4 июл 18, 16:36    [21543336]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Dorin Marcoci,

оно падает только при segfault, а если утечка идёт, то оно скорее всего просто упрётся в ограничения на потребляемую память процессом php, который зависит от настроек. То же надеюсь что смержат. Мне комменты присылаются на почту.
4 июл 18, 16:43    [21543367]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Dorin Marcoci
Member

Откуда:
Сообщений: 261
не то что прямо падал процес :) мой рускиш не родной..
имел ввиду чтоб не прошел тест, тоесть другой результат, не тот что в еxpected
4 июл 18, 17:54    [21543687]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
Dorin Marcoci,

а.. так ты про это. Мне дали вот такой коммент

nikic
It shouldn't be necessary to test memory usage explicitly (because a leak message will be printed in debug builds), just have a code that was previously leaking.
4 июл 18, 17:58    [21543707]     Ответить | Цитировать Сообщить модератору
 Re: PDO Firebird bugs  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
патч приняли :-)
6 июл 18, 19:02    [21550637]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 3 4 5 [6] 7   вперед  Ctrl      все
Все форумы / Firebird, InterBase Ответить