Потеря данных при репликации, IB 7.5

Access Violation, некорректное выполнение запросов или вызовов API, ошибки утилит командной строки, в общем все, что вам мешает работать

Модераторы: kdv, dimitr

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 23 авг 2007, 12:32

У меня по результатам всего нашего длинного обсуждения сложилось впечатление, что с проблемой подобной нашей (исчезания данных) никто не сталкивался. В это верится с трудом, т.к. не у нас же одних большая база на IB, и ничего особо уникального в нашей системе нет. Кроме, возможно, этих самых режимов. Не в этом ли дело?
вариантов только два

1. поврежденные индексы
2. кривой софт

судя по цитате проблема с пунктом 2. Как у вас могут быть "неправильные данные" в транзакции snapshot, я не знаю. очевидно, что данные меняются не "транзакционно", отсюда снапшот видит только "часть" изменений. Т.е. проблема логическая на уровне приложения.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 23 авг 2007, 12:41

Kabaev Sergey писал(а):Запускаем запрос в IB Expert . Данные нормальные. Тот же запрос из программы - данные неверные. Параметры запроса одинковые. Разница только в режиме открытия транзаций - в программе snapshot, в Experte - read comitted. Т.е. в read comitted транзакции чудес с данными нет. Так вот, у нас в системе стандартный режим работы транзакций как раз snapshot.
Уверен, что к одной и той же базе конектитесь? Вопрос совершенно недурацкий, частенько случается. В плане отчётов разница между снапшотом и рк простая - снапшот видит всю базу в том состоянии, в котором она была на момент его старта. То есть, если согласованные модификации выполняются правильно, в одной транзакции, то он видит согласованную информацию во всех таблицах, то есть правильную. РК для отчётов в многопользовательской среде - игра в гусарскую рулетку, он видит данные в таком состоянии, в котором они закоммиченны на момент фетча каждой записи. Другой разницы промеж них в этом плане нет. Что у вас принято считать верным и неверным и как организовано управление модифицирующими транзакциями - я отсюда не вижу. Есть ещё одна идея - амбициозности в запросе нет? В смысле вариаций чего- типа

Код: Выделить всё

Table_1 
ID
A

Table_2
ID
A

Select A From Table_1, Table_2
Where ID=ID
то есть, серверу не указаны где-то в запросе имена или алиасы таблиц и он волен сам решать какое поле с одним и тем же названием из какой таблицы в каком месте тащить. Что вернёт такой запрос при каждом конкретном вызове зависит от фазы луны. В третьем диалекте в FB такие чудеса отсекаются парсером и выдаётся ексепшен, в первом, к сожалению, нет, для "соместимости" со старыми приложениями. В IB, насколько я помню, на это нигде не обращается внимания вообще. А грабельки конкретные, сам несколько раз наступал по невнимательности.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 23 авг 2007, 12:47

kdv писал(а): Как у вас могут быть "неправильные данные" в транзакции snapshot, я не знаю. очевидно, что данные меняются не "транзакционно", отсюда снапшот видит только "часть" изменений. Т.е. проблема логическая на уровне приложения.
Могут :) я как-то раз выключил Autocommit в компоненте с транзакцией snapshot и долго удивленно таращился на то, что в гриде, которы работал с read comitted данные свежие, а в отчете со snapshot - старые :)

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 23 авг 2007, 14:11

Уверен, что к одной и той же базе конектитесь? Вопрос совершенно недурацкий, частенько случается. В плане отчётов разница между снапшотом и рк простая - снапшот видит всю базу в том состоянии, в котором она была на момент его старта.
База одна и та же, уверен. Насчет режимо ты совершенно прав. Я тоже считаю, что при нормальной работе сервера и snapshot и read comitted должны видть совершенно одинаковые записи если транзакции кторые изменяли эти данные были закончены до того, как их считывали. Но в нашем случае это правило похоже не выполняется.

Вот чего я сейчас своими глазами обнаружил:

Есть таблица T_MESSAGE, через неё приложения обмнениваются сообщениями. Всё происходило на рабочей Аналитической базе.
шаг 1 Есть приложение, назовём её Program1, которая обнуляет флаг в этой таблице. Запрос типа update t_message set messagevalue = 0 where messageid = 37
шаг 2 Затем Program1 удаленно запускает вторую задачу Program2, которая находитяс на другой машине, и которая должна при своем успешном окончании этот флаг выставить в "2",
запрос типа update t_message seе messagevalue = 2 where messageid = 37
шаг 3 Первая задача чтобы определить момент окончания работы program2 тем временем сканирует флаг в T_MESSAGE (режим опять snapshot) в ожидании, когда значения флага будет равно "2", запрос типа select * from t_message where messageid = 37.

На этапе 1 первая задача была убита, предполагаю, что update записи был выполнен, а commit выполнен не был. Autocommita там нет. Режим транзакции snapshot. Всё это я выполнял на своей локальной машине.

Через некоторое время последовали звонки от юзеров с жалобами на ошибки.

Вот что делали пользователи:
Запуск своего экземпляра Program1 со своего рабочего места.
1 Та выполняет шаг 1, update прошел
2 Далее запускается Program2
3 После чего Program1 пытается просматривать флаг и выдает сообщение, что запись в T_MESSAGE с нужным ID отсутствует. Это возможно, только если select * from t_message where messageid = 37 дает пустую выборку.

Смотрю под отладчиком. Выборка действительно пустая.
Запускаю тот же запрос в IB Expert. Там режим read comitted. Выборка непустая.

Для проверки до перезагрузки сервера выполнял с других машин select * from t_message where messageid = 37 в разных режимах. При snapshot выборка пустая. При read comitted нет.

Предположили, что в базе зависшая транзакция. Выгнали всех юзеров. и перегрузили сервер. После перезагрузки записи опять НЕТ. Смотрели через IB Expert. Пришлось добавлять её вручную. Это при том, что в софте работающем с этой таблицей нигде нет команд на какие-либо удаления записей из T_MESSAGE. Везде только чтения и update. Все это происходит на одной и той же базе.

Т.е. получается, что IB как-то некорректно отработал при сочетании событий update + обрыв коннекта?
Последний раз редактировалось Kabaev Sergey 23 авг 2007, 14:43, всего редактировалось 2 раза.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 23 авг 2007, 14:27

Kabaev Sergey писал(а): Вот что делали пользователи:
Запуск Program1.
1 Та выполняет шаг 1, update прошел
Commit был?
Force Write в конфиге?

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 23 авг 2007, 14:41

Forced write = on.
Commita не было при первом запуске, я убил задачу из отладчика.
При последующих запусках юзерами commit был.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 23 авг 2007, 15:11

Kabaev Sergey писал(а):
В плане отчётов разница между снапшотом и рк простая - снапшот видит всю базу в том состоянии, в котором она была на момент его старта.
Я тоже считаю, что при нормальной работе сервера и snapshot и read comitted должны видть совершенно одинаковые записи если транзакции кторые изменяли эти данные были закончены до того, как их считывали.
Чё-та кто-то из нас не умеет то ли читать, то ли писать. НЕ ДОЛЖНЫ ОНИ ВИДЕТЬ ОДИНАКОВОЕ, ДОЛЖНЫ РАЗНОЕ! То, что ты пишешь, относится к read_commited. То, что ты цитируешь - к concurrency (снапшот). Почувствуй разницу.
Kabaev Sergey писал(а): Вот чего я сейчас своими глазами обнаружил:

Есть таблица T_MESSAGE, через неё приложения обмнениваются сообщениями. Всё происходило на рабочей Аналитической базе.
шаг 1 Есть приложение, назовём её Program1, которая обнуляет флаг в этой таблице. Запрос типа update t_message set messagevalue = 0 where messageid = 37
шаг 2 Затем Program1 удаленно запускает вторую задачу Program2, которая находитяс на другой машине, и которая должна при своем успешном окончании этот флаг выставить в "2",
запрос типа update t_message seе messagevalue = 2 where messageid = 37
шаг 3 Первая задача чтобы определить момент окончания работы program2 тем временем сканирует флаг в T_MESSAGE (режим опять snapshot) в ожидании, когда значения флага будет равно "2", запрос типа select * from t_message where messageid = 37.
Замяв для ясности всё что мне хочется сказать о проктологии и количестве углов у колеса велосипеда (а то перерастёт в дискуссию о консерватории в жанре очень многабукв), - а мож всё-таки перейдём от лирики к конкретному коду, названию набора клиентских компонент и запросам? Если снапшот-транзакция, в которой Первая задача мучает сеть и сервак сканированием, начата ДО коммита Program2 своего апдейта, то она может заниматься этим богоугодным делом до второго пришествия Спасителя. Снапшот в этом случае надо стартовать перед каждым циклом сканирования и тут же после него коммитить. А как это выглядит у вас, мне опять в Телепатический Локатор не видать.
Kabaev Sergey писал(а): На этапе 1 первая задача была убита, предполагаю, что update записи был выполнен, а commit выполнен не был. Autocommita там нет. Режим транзакции snapshot. Всё это я выполнял на своей локальной машине.
Ну если и на своей локальной можно только предполагать, что делаешь, то мне в Космосе делать больше нечего (С) Зелёный.
Kabaev Sergey писал(а): Вот что делали пользователи:
Запуск своего экземпляра Program1 со своего рабочего места.
1 Та выполняет шаг 1, update прошел
2 Далее запускается Program2
3 После чего Program1 пытается просматривать флаг и выдает сообщение, что запись в T_MESSAGE с нужным ID отсутствует. Это возможно, только если select * from t_message where messageid = 37 дает пустую выборку.
А также это возможно если в where у селекта дальше идёт ещё что-то, например, messagevalue = 2. Или транзакция не concurrency, а, скажем read_commited no_rec_version nowait и селект выполняется в трае с игнорированием лок конфликтов. Или...
Kabaev Sergey писал(а): Смотрю под отладчиком. Выборка действительно пустая.
Запускаю тот же запрос в IB Expert. Там режим read comitted. Выборка непустая.

Для проверки до перезагрузки сервера выполнял с других машин select * from t_message where messageid = 37 в разных режимах. При snapshot выборка пустая. При read comitted нет.
Зависит опять же от того, когда запущена снапшот-транзакция под отладчиком и с других машин. И когда закоммичены изменения.
Kabaev Sergey писал(а): Предположили, что в базе зависшая транзакция. Выгнали всех юзеров. и перегрузили сервер. После перезагрузки записи опять НЕТ. Смотрели через IB Expert. Пришлось добавлять её вручную. Это при том, что в софте работающем с этой таблицей нигде нет команд на какие-либо удаления записей из T_MESSAGE. Везде только чтения и update. Все это происходит на одной и той же базе.

Т.е. получается, что IB как-то некорректно обработал обрыв коннекта?
А вот если ЭТО правда, то есть записи в базе были и были закоммичены, а потом волшебным образом растворились в тумане, то IB7.5 можно посоветовать только завернуть в трубочку и засунуть... Но, поскольку её пользует толпа народу, и особо не жужжит про такие чудеса, то сдаёццо мне, что таки что-то где-то не так посмотрено-коммичено. Например, записи были видны в породившей их же транзакции, которая так и не была закоммичена. Или файл базы включён в систем рестор виндов и они почему-то при остановке сервера решили, что файлу худо и восстановили старый слепок из-за щеки. В общем, устал я от этого сумбура. На всякий - сервис-пак-то устанавливали? Тут http://www.ibase.ru/ibinstall/ib751sp1_readme.htm вроде ничего похоже в списке исправлений нет, но чем чёрт не шутит.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 23 авг 2007, 16:05

Чё-та кто-то из нас не умеет то ли читать, то ли писать. НЕ ДОЛЖНЫ ОНИ ВИДЕТЬ ОДИНАКОВОЕ, ДОЛЖНЫ РАЗНОЕ! То, что ты пишешь, относится к read_commited. То, что ты цитируешь - к concurrency (снапшот). Почувствуй разницу.
Прошу прощения, я неточно написал. Нужно было написать: "Я тоже считаю, что при нормальной работе сервера и snapshot и read comitted должны видть совершенно одинаковые записи если транзакции кторые изменяли эти данные были закончены до того, как ОТКРЫТЫ СЧИТЫВАЮЩИЕ ИХ ТРАНЗАКЦИИ".

А как это выглядит у вас, мне опять в Телепатический Локатор не видать.
Все чтения и update T_MESSAGE проводятся в отдельных транзакциях. код примерно такой:

Для изменения T_MESSAGE

Код: Выделить всё

void CMessage::setMessageValue(KContour contur, int MessageId, const String& MessageValue)
{
    TIBTransaction* transaction;
    TIBSQL* update;

    try
    {
        switch (contur)
        {
            case kcAC:
            {
                transaction = DM2->TallSetMessage;
                update = DM2->UallMessage;
                break;
            }
            case kcOC:
            {
                transaction = DM1->TallSetMessage;
                update = DM1->UallMessage;
                break;
            }
            case kcShadowOC:
            {
                transaction = DM3->TallSetMessage;
                update = DM3->UallMessage;
                break;
            }
        }
        transaction->StartTransaction();

        update->Close();
        update->Prepare();
        update->ParamByName("MessageValue_var")->AsString = MessageValue;
        update->ParamByName("MessageId_var")->AsInteger = MessageId;
        update->ExecQuery();

        transaction->Commit();
    }
    catch (Exception& e)
    {
        if(transaction->Active)
            transaction->Rollback();
        throw Exception("CMessage::setMessageValue() exception\n" + e.Message);
    }
}
Для чтения из T_MESSAGE

Код: Выделить всё

int CMessage::getMessageValue(KContour contur, int MessageId)
{
    TIBTransaction* transaction;
    TIBQuery* query;
    try
    {
        switch (contur)
        {
            case kcAC:
            {
                transaction = DM2->TallMessage;
                query = DM2->QallMessage;
                break;
            }
            case kcOC:
            {
                transaction = DM1->TallMessage;
                query = DM1->QallMessage;
                break;
            }
            case kcShadowOC:
            {
                transaction = DM3->TallMessage;
                query = DM3->QallMessage;
                break;
            }
        }

        transaction->StartTransaction();

        query->Close();
        query->Prepare();
        query->ParamByName("MESSAGEID_VAR")->AsInteger = MessageId;
        query->Open();

        if(query->RecordCount == 0)
            throw Exception("Â T_MESSAGE íåò íàñòðîéêè ¹" + String(MessageId) );

        int retVal = query->FieldByName("MESSAGEVALUE")->AsInteger;

        transaction->Commit();

        return retVal;
    }
    catch (Exception& e)
    {
        if( transaction->Active )
            transaction->Rollback();
        throw Exception("CMessage::getMessageValue() exception\n" + e.Message);
    }
}
Т.е. все чтения-записи выполняются в отдельных транзкциях.
По принципу Открыл транзакцию- посмотрел/изменил данные - закрыл. Постоянно открытых транзкций нет.
Kabaev Sergey писал(а):

На этапе 1 первая задача была убита, предполагаю, что update записи был выполнен, а commit выполнен не был. Autocommita там нет. Режим транзакции snapshot. Всё это я выполнял на своей локальной машине.


Ну если и на своей локальной можно только предполагать, что делаешь, то мне в Космосе делать больше нечего (С) Зелёный.
Пардон. Склероз проклятый. Задача была убита до commita, => commita не было.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 23 авг 2007, 16:43

Kabaev Sergey писал(а): Пардон. Склероз проклятый. Задача была убита до commita, => commita не было.
Тогда сервак ее откатит.
В момент жижнедеятельности Проги1, если апдейт был закомичен, то вторая прога и новая транзакция в проге1 изменения должны увидеть.
мучают смутные сомнения: CommitRetaining не пользуется?

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 23 авг 2007, 16:53

Commit Retaining не используется. Я тоже всю жизнь был уверен, что при потере коннекта неподтвержденные изменения откатываются.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 23 авг 2007, 17:15

Kabaev Sergey писал(а):Commit Retaining не используется. Я тоже всю жизнь был уверен, что при потере коннекта неподтвержденные изменения откатываются.
Я дельфист, посему могу ошибаться

Код: Выделить всё

            { 
                transaction = DM2->TallMessage; 
                query = DM2->QallMessage; 
                break; 
            } 
            case kcOC: 
            { 
                transaction = DM1->TallMessage; 
                query = DM1->QallMessage; 
                break; 
            } 
            case kcShadowOC: 
            { 
                transaction = DM3->TallMessage; 
                query = DM3->QallMessage; 
                break; 
            } 
        } 
получается транзакция одна на чтение и запись?
компоненты, если я правильно понял - IBX?
что мешает на запись пользовать короткую snapshot, а на чтение read comitted?
эти чудеса в базе, коя восстановлена из скрипта? и данные залиты скриптом?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 23 авг 2007, 17:58

stix-s писал(а):что мешает на запись пользовать короткую snapshot, а на чтение read comitted?
эээ.... может, наоборот? ;)

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 23 авг 2007, 18:14

WildSery писал(а):
stix-s писал(а):что мешает на запись пользовать короткую snapshot, а на чтение read comitted?
эээ.... может, наоборот? ;)
нет, не согласен, обоснуй, плиз
короткую snapshot - это я имел ввиду на Insert/Update
зачем мне на чтение snapshot держать - он обновлений ваще не увидит
я на чтение открываю длинную (на время работы приложения)

Код: Выделить всё

read
nowait
rec_version
read_committed
Рефреш при изменениях, полный - в случае необходимости, все видно, в чем я прокалывюсь?
на отчеты - там да, snapshot на время построения отчета

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 23 авг 2007, 18:26

получается транзакция одна на чтение и запись?
компоненты, если я правильно понял - IBX?
что мешает на запись пользовать короткую snapshot, а на чтение read comitted?
эти чудеса в базе, коя восстановлена из скрипта? и данные залиты скриптом?
Да, транзакция одна, настроек у неё нет. Компоненты доступа - IBX 6.08 . У них по умолчанию стоит snapshot.
Почему именно принят режим snapshot? использовано в соотв-ии с нашим внутренним стандартом. Все транзакции такие, кроме репликатора.
Чудеса происходят в рабочей Аналитической базе.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 23 авг 2007, 18:29

Нет, это я тебя не понял. Зачем на insert/update - то снэпшот?
А вот на чтение данных для отчёта - как раз снэпшот, а то такого насчитает...
Или мы друга друг непонимай?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 23 авг 2007, 18:37

WildSery писал(а):Нет, это я тебя не понял. Зачем на insert/update - то снэпшот?
Если транзакция короткая и содержит один простейший оператор или все апдейты в приращениях - в общем и целом излишество. А в общем случае - оно правильно. Получаем гарантированный конфликт если с момента старта транзакции хоть что-то из изменяемого изменено в других транзакциях.

Да, по сути вопроса ничего сказать не могу - в сях как свинья в ляпасинах.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 23 авг 2007, 19:29

Хм. А, точно. Можно и так следить за изменениями, методом конфликтов :)

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 23 авг 2007, 20:09

автору топика, на всякий случай: если в транзакции был апдейт, инсерт, или удаление, но коммита не было а случился обрыв соединения, то этих изменений никто не увидит ни при каких условиях ни в какой версии ИБ-ФБ, тем более в последних. Я сильно подозреваю что у вас в приложениях где-то делаются промежуточные коммиты, из-за чего и получается что данные "видны частично", если я правильно понял что происходит. В общем, ковыряйте приложение, как минимум сделайте вначале локально логи того что происходит в приложении, чтобы отловить косяки.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 23 авг 2007, 20:21

kdv писал(а):автору топика, на всякий случай: если в транзакции был апдейт, инсерт, или удаление, но коммита не было а случился обрыв соединения, то этих изменений никто не увидит ни при каких условиях ни в какой версии ИБ-ФБ, тем более в последних.
А вот если случился не обрыв, а аборт, в смысле приложения, то будет выполнено default action транзакции. Наверное. Ибо пути Джеффа в разных версиях IBX вокруг автостартов, автокоммитов и аварийных завершений были трудноразноисповедимы. Что при малоосмысленной группировке операторов в транзакции (это не в конкретный огород, а вообще) приводит к загадочным картинкам в базе.

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 23 авг 2007, 20:35

kdv писал(а):если в транзакции был апдейт, инсерт, или удаление, но коммита не было а случился обрыв соединения, то этих изменений никто не увидит ни при каких условиях ни в какой версии ИБ-ФБ
иногда shit все-таки happens:
http://tracker.firebirdsql.org/browse/CORE-118

Ответить