Модераторы: Akella
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как избавиться от deadlock'а? два потока удаляют записи из одной т-цы 
:(
    Опции темы
ksili
Дата 3.7.2007, 06:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Такая проблема: несколько потоков удаляют записи из одной таблицы, используют для этого хранимую процедуру CUT_SMS, которая возвращает значения полей удалённой записи. И если вдруг два потока хватаются за одну запись, то, насколько я понял, происходит deadlock: один из них успевает удалить запись, а второй не может удалить уже удалённую запись.
При запуске из-под Билдера ситуация выглядит следующим образом: вылетает длинное сообщение об исключении, в котором есть слово deadlock, имя процедуры CUT_SMS, а также слова о конфликтующих апдейтах. Если продолжить выполнение программы, то она работает, но один из потоков перестает работать (то есть обращаться к таблице).
Если просто запустить приложение из-под Винды, то никакого сообщения не выскакивает, но видно, что один поток перестаёт работать, и записи из таблицы удаляет только другой поток.

Пробовал исправить проблему так. В БД создал таблицу, в которой хранится флаг занятости таблицы. Если он равен 1, то таблица занята другим потоком и сейчас из неё ничего читать и удалять не надо. При этом в начале процедуры CUT_SMS добавил:
Код

    select USED from t_db_flags where TABLENAME='T_SMS_OUT' into :flag;
    if(flag=1)  then exit;
    else execute procedure catch_sms_buffer;

где catch_sms_buffer - это процедура, которая просто устанавливает этот флаг в 1.
Ну и соответственно в конце процедуры CUT_SMS освобождаю таблицу:
Код

update t_db_flags set USED=0 where TABLENAME='T_SMS_OUT';

Но это проблемы не решило: теперь вылетает такое же сообщение, но именами двух процедур: CUT_SMS и CATCH_SMS_BUFFER.
Я в этих блокировках не очень понимаю, но по-моему проблему можно решить как-то просто. Объясните мне пожалуйста, что я в этой ситации могу сделать.

Это сообщение отредактировал(а) ksili - 3.7.2007, 06:12


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
ksili
Дата 3.7.2007, 06:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Вот суть сообщения об исключении:
Цитата

Lock coflict on no wait transaction.
Deadlock.
Update coflicts with concurrent update.
At procedure 'CATCH_SMS_BUFFER'
At procedure 'CUT_SMS'.


Добавлено через 2 минуты и 6 секунд
Сейчас заметил, что оно может возникнуть даже если в таблице не было ни одной записи.


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Akella
Дата 3.7.2007, 07:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Оствляй на сервере в таблице или в контекстной переменной какое-то значение в удаляющем потоке, мол идёт удаление, и перед удалением во втором потоке проверяй значение
Код

   a = 1;
  while a=1 do begin
    if "условие разрешает удаление" then  begin
     удаление
     a = 0;
    end;
  end;


PM MAIL   Вверх
ksili
Дата 3.7.2007, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Дык я по-моему так и делаю:
Код

    select USED from t_db_flags where TABLENAME='T_SMS_OUT' into :flag;
    if(flag=1)  then exit;
    else execute procedure catch_sms_buffer;

    /*читаем и удаляем*/

В первой строке смотрим "на сервере в таблице" значение флага
Во второй проверяем его и если он равен 1, значит сейчас с таблицей работает другой поток и ничего делать нельзя - exit
Иначе сами занимаем таблицу (процедура catch_sms_buffer устанавливает значение флага в 1)
и дальше читаем и удаляем, будучи уверенными, что другой поток в это время не сделает то же самое.

Каждый поток выполняет эту проверку перед удалением. НО ПОЧЕМУ-ТО ТАКАЯ РУЧНАЯ БЛОКИРОВКА ТАБЛИЦЫ НЕ РАБОТАЕТ

Меня вот ещё смущает, что вся моя процедура выполняется в контексте одной транзакции, соответственно, может то, что я занимаю таблицу (catch_sms_buffer) на самом деле не отображается сразу в базе и из-за этого блокировки не происходит. Хотя я же это делаю вызовом отдельной процедуры...


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Akella
Дата 3.7.2007, 08:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Цитата(ksili @  3.7.2007,  07:31 Найти цитируемый пост)
вся моя процедура выполняется в контексте одной транзакции,

так сделай же в двух разных  smile 
PM MAIL   Вверх
ksili
Дата 3.7.2007, 08:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



И как это сделать? У меня такой код:
Код

 SMSQuery->Transaction->StartTransaction();
 SMSQuery->SQL->Text = "select P_PHONE,P_SMS_TEXT from CUT_SMS";
 SMSQuery->ExecQuery();
 SMSQuery->Transaction->Commit();


Пытался ещё поставить в процедуре CUT_SMS commit после установки флага в единицу и перед удалением записи, но в PSQL видимо такой команды нет.

Добавлено через 9 минут и 53 секунды
Ещё я забабашил компонент TpFIBErrorHandler. При возникновении вышеописанной конфликтной ситуации он постоянно выводит сообщение, которое я уже приводил. То есть раньше ещё можно было продолжать работать, но без одного потока, теперь же вообще нельзя, так как постоянно выскакивает MessageBox. Вот было бы неплохо в этом обработчике не только выводить сообщение об ошибке, но и подтверждать или откатывать закосяченную транзакцию, поскольку проблема-то, как я понял, в незавершённой транзакции. Вот только загвоздка в том, что компонент этот на главной форме приложения, а косяк происходит в отдельном потоке, заранее неизвестно каком. 

Это сообщение отредактировал(а) ksili - 3.7.2007, 08:28


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
ksili
Дата 3.7.2007, 09:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Решил тут попробовать заблокировать запись:
Код

select P_PHONE,P_SMS_TEXT from CUT_SMS for update with lock


Но что-то на with lock ругается. Говорит, не знаю такого...

Добавлено через 1 минуту и 50 секунд
Версия сервера: 2.0


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
ksili
Дата 3.7.2007, 10:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Изменил тип транзакции c NO WAIT на WAIT. Ничего не изменилось, только в сообщении об ошибке исчезла строка 
Цитата

Lock coflict on no wait transaction.



--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
ksili
Дата 3.7.2007, 10:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Вроде получилось. Поставил парметры транзакции:
Код

isc_tpb_write
isc_tpb_read_committed
isc_tpb_wait
isc_tpb_no_rec_version


Пока работает без косяков. Дальше посмотрим


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Akella
Дата 3.7.2007, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



у тебя что, несколько потоков в одной транзакции работают?

Это сообщение отредактировал(а) Akella - 3.7.2007, 14:18
PM MAIL   Вверх
ksili
Дата 4.7.2007, 09:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Нет, у меня несколько одинаковых потоков. В каждой кверя со своей транзакцией


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Akella
Дата 9.7.2007, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



а если всё в одну транзакцию впихнуть?
PM MAIL   Вверх
ksili
Дата 9.7.2007, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



А как это сделать? 
Поместить на главной форме pFIBTransaction и у каждой квери в других потоках указывать эту транзакцию как основную? Но ведь тогда придётся наверно каждое обращение к Query запихивать в Synchronize


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Akella
Дата 11.7.2007, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



можно не на главную, а в DataModule, ну и  запихивай, а что здесь плохого?
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Interbase"
Alex

Обязательно указание:

1. Версию InterBase (Firebird, Yaffil)

2. Способа доступа (ADO, BDE, IBX и т.д.)

  • КАК ПРАВИЛЬНО ОФОРМИТЬ КОД - ЗДЕСЬ
  • КАК ПРАВИЛЬНО УКАЗАТЬ ТЕКСТ ОШИБКИ - ЗДЕСЬ
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • FAQ раздела лежит здесь!

Если Вам понравилась атмосфера форума, заходите к нам чаще! С Уважением, Akella.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Firebird, Interbase | Следующая тема »


 




[ Время генерации скрипта: 0.0614 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.