Summary: | Обновление динамического курсора только при изменении данных | ||
---|---|---|---|
Product: | SELTA@Etersoft | Reporter: | Станислав Коробейников <stas> |
Component: | ODBC-драйвер | Assignee: | Станислав Коробейников <stas> |
Status: | CLOSED FIXED | QA Contact: | |
Severity: | minor | ||
Priority: | P4 | CC: | boris, goga, lav, shan |
Version: | 1.0.5 | ||
Target Milestone: | версия 1.0.4 | ||
Hardware: | PC | ||
OS: | All | ||
Whiteboard: | |||
Заявки RT: | Связано с: | ||
Дата напоминания: | |||
Bug Depends on: | 3720 | ||
Bug Blocks: | 2965, 3166 |
Description
Станислав Коробейников
2009-02-18 17:52:41 MSK
Пока решил сделать так. При создании курсора в odbc драйвере сохранять значение pg_stat_all_tables у таблицы этого курсора (там есть количество всех изменений). При SQLFetchScroll смотреть значение pg_stat_all_tables и сравнивать с сохраненным. Если оно изменилось -- обновлять. Обновлять с помошью тригеров не получится. Т.к. тригеры не видят курсоры созданные в odbc драйвере. Пробую достать это значение(pg_stat_all_tables) в odbc драйвере. Значение в odbc драйвере достается без проблем, создав новый handle команды. Его можно открывать при открытии курсора, а закрывать, при его закрытии. Таблицы можно передавать просто строкой из parser'a, при парсинге и хранить в StatementHandle, что бы не путались курсоры. Уже почти все наладил. Таблицы при парсинге берутся, передаются в odbc драйвер. Там при создании курсоров создается свой handle команды(внутренний), запрос, создает свой динамический курсор(внутренний). Далее при каждом обновлении курсора, обращается уже к созданному handle команды, и обновляется уже имеющийся(внутренний) курсор, смотрит, не изменилось ли его значение. Если изменилось, обновляется и основной курсор. Далее, при уничтожении handle основной команды, уничтожается и внутренний handle. Все это уже работает. Только запрос пока автоматически не делается, я проверял уже с готовым, проверяющим изменение в одной таблице. Все доделал, закоммитил. Теперь буду смотреть. Наладил, проверил. С помощью теста, действительно ли он при обновлении все-таки обновит курсор. И в 1с, просто погонял, не смотрел, как он чего обновляет. И то, и то работает. Народ просил дать ему потестить. Так что надо протестить остальные обновления, и выложить в какое-нибудь укромное место. (In reply to comment #5) > надо протестить остальные обновления, и > выложить в какое-нибудь укромное место. Укромное место для экспериментов - это pub/Etersoft/SELTA@Etersoft/unstable/Windows/ Падает при загрузке данных, это из-за того, что системные таблицы по другому обрабатываются парсером, и не регистрируются. Их можно обновлять ничего не выясняя. Ошибку нашел, но никак не могу проверить. SELTA вылетает с сообщеним "Порядок сортировки, установленный для бд, отличается от системного". При этом selta отправляет и получает 'a' -- все нормально, при этом все это происходит даже с selta 1.0.5. с сервера. Исправил ошибку. Не падает. Но при тестировании выяснил, что обновляются курсоры неправильно. Для проверки обновления я пользуюсь функциями: pg_stat_get_tuples_inserted pg_stat_get_tuples_updated pg_stat_get_tuples_deleted Сумма, возвращаемая этими функциями меняется поздно, т.е. при обновлении курсора не меняется. Хотя если еще раз вызвать исходный запрос, сумма уже будет новой. появился вопрос когда обновляются эти данные. В тесте все обновлялось правильно. Но там данные обновляет другой connection. Выяснил, что statement тут не при чем. Имеет значение время. Если перед обновлением курсора, проверяющего обновления в таблице, сделать Sleep(1000) значение количества изменений в таблице меняется, Sleep(200) не успевает. Надо как-то это дело подогнать, или отказаться от использования функций pg_stat_get_tuples, а использовать триггеры. Выяснилось, что есть параметр времени обновления статистики PGSTAT_STAT_INTERVAL, он равен 500мс и задается в postgres в pgstat.c. Менять его не надо. Не нашел, как сделать что бы все принудительно обновилось, и похоже, что так сделать нельзя. Есть два варианта развития событий. 1. немного postgres подковырять. Сделать переменную, устанавливать ее каждый раз перед тем, как нужно обновлять статистику в true. В postgres'е в функции, которая сравнивает время добавить проверку на эту переменную и установку ее в false. Если несколько человек будут разом бегать курсором по записям, обновлять статистику придется очень часто. 2. Не использовать функции, и заменить их на триггеры. Придется сделать точно такую же таблицу, как и postgres'овский запрос pg_stat_all_tables. Набивать его такими же данными, некоторое дублирование. Второй вариант, наверное получше будет. Сделал с помощью триггеров. Все обновляется об обновлении поступает сразу же. Еще не тестировал нормально. Падало при проведении документов (но проводило). Перепроведение все нормально проводилось. Сделал что бы не падало. Погонял, не падает, обновляется, вроде все нормально. Версия для тестирования: ftp://updates.etersoft.ru/pub/Etersoft/SELTA@Etersoft/unstable/Windows/WorkCurs/selta-1.0.5.20090311.msi В настоящее время решается проблема увеличение времени проводок. Ее можно решить не делая триггеры на регистры. Но тут надо подумать об универсальности решения. С статистическими функциями(pg_stat_get_tuples_*) оказалось все сложнее, чем я думал. Они берут данные из файла pgstat.stat. В нем хранится в структура со статистикой. А уже запихивают ее туда раз в какое-то время. Таким образом надо как-то сделать, что бы все срочно записались, а самому это подождать, если несколько человек будут этим заниматься -- это явно замедлит такую проверку. Не уверен в правдивости схемы на 100%, я еще посмотрю. Думаю надо сделать настройки в каком-нибудь conf файле, в котором написать, на какие таблицы вешать индексы, а какие оставить в покое. Или нарисовать формочку и хранить это дело в реестре. Так же надо сделать статистику с созданием курсоров и с запросом на их пересоздание к каждой таблице. На основании этого сделать соответствующие настройки. Активный пользователь предложил сделать эти настройки в самой базе (сделать отдельную табличку). Мне кажется это хорошей идеей, Настройки привязаны к базе, что удобно. Триггеры может создавать функция, используя информацию из таблицы. К тому же с таким методом можно и отследить, кто этим занимается 1с или какая другая программа. Конечно минус может быть в том, что при загрузки/выгрузки базы эта инфа может не сохранится. Но с другой стороны, кто догадался настроить, тот догадается и сохранить. Я всё же предлагаю не забывать, что по хорошему это надо реализовать в самом сервере PG, поэтому не надо сейчас глубоко закладываться на хаки, а надо выпустить необходимые релизы, и в спокойной обстановке покопаться в PG. (In reply to comment #19) > Я всё же предлагаю не забывать, что по > хорошему это надо реализовать в самом > сервере PG, поэтому не надо сейчас глубоко > закладываться на хаки, а надо выпустить > необходимые релизы, и в спокойной > обстановке покопаться в PG. Хорошо. В принципе почти закончил. Не смог узнать строку подключения 1с. Но сделал механизм. Есть табличка в которой лежат маски таблиц для которых надо или не надо делать триггеры. Есть функция, которая, во время первого к ней обращения заполняет табличку, а во время последующих, смотрит делает триггеры для таблиц, если они проходят по маскам. Можно вычислить 1с, она первым делом создает таблицу 1susers. Ну а если база уже есть, то там тем более есть эта таблица. И надо еще посмотреть каким таблицам делать триггеры, каким нет. Сделал функцию, для первоначального изготовления всех триггеров (и добавления/удаления, если изменились маски). Все изменения закинул в sql скрипты installa и update SELTA. Надо протестировать, работоспособность. Но только пока в таблице с масками только написано, что не надо создавать триггеры для таблиц pg_. Надо сделать тест и на основе него сделать маски. Посмотрел. Механизм работает. Осталось сделать нужные маски и будет работать. Сделал так, что бы SELTA вела логи созданных и обновлённых курсоров. Подробнее http://bugs.etersoft.ru/show_bug.cgi?id=3720 На всякий случай я предлагаю не забывать, что это всё временный костыль, и не надо слишком усердствовать в разработке вспомогательных средств для него. (In reply to comment #24) > На всякий случай я предлагаю не забывать, > что это всё временный костыль, и не надо > слишком усердствовать в разработке > вспомогательных средств для него. > Да. На этом закончили. Просто добились нормальной работы. |