powered by simpleCommunicator - 2.0.28     © 2024 Programmizd 02
Map
Форумы / Informix [игнор отключен] [закрыт для гостей] / Параллельная работа с таблицей
3 сообщений из 3, страница 1 из 1
Параллельная работа с таблицей
    #39904424
Выбегалло
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Столкнулся с такой проблемой: требуется обеспечить выборку токенов (записей) из таблицы и их удаление (после какой-то обработки, в условия задачи не входит) двумя и более сессиями. Идеально было бы получить рост производительности при увеличении числа сессий.

Токены имеют серийный номер, номер владельца, и тип операции (создать/добавить телефонный номер владельца/удалить).
Токены для одного и того же владельца должны выдаваться в порядке возрастания номеров, даже если они выдаются разными сессиями.

Пример.
Таблица
1 Влад_1 Создать
2 Влад_1 Добавить номер
3 Влад_2 Создать
4 Влад_1 Удалить

Имея 2 сессии, допустимый порядок выполнения
Сес1 Сес2
1 3
2
4

Недопустимо, чтобы Сес2 выдала 2 или 4 до того как Сес1 выдаст (и удалит) 1.

Выдачу токенов написал в хранимой процедуре, ее вызов и удаление токена после получения - в перле, но это не принципиально.
Оказалось на удивление нетривиально, и что самое неприятное - производительность сильно падает при добавлении сессий.

Пришлось добавлять поля locked для анализа "захвачен ли токен другой сессией" и session_id для предотвращения появления "сирот" после внепланового убийства сессии, задействовать SAVEPOINT Самый неприятный сюрприз от информикса - курсоры для UPDATE не могут иметь внутри "ORDER BY"

Удивительно, что такая казалось бы популярная и простая задача не имеет легко находимого в гугле решения :) .

Если кто-то хочет заучаствовать в ее решении, то вот структура таблицы токенов:

create table test_token
(
token_id serial not null ,
action_id CHAR(5),
owner_number integer,
locked smallint default 0,
sid int8
) mode row;

И заголовок процедуры:

CREATE PROCEDURE get_test2( p_num int default 0)
RETURNING INT AS token_id,
CHAR(5) AS t_action_id,
INTEGER AS t_owner_number,
SMALLINT AS eot;

где p_num - Номер сессии ( используется для создания уникального имени отладочного файла)
eot - 1 - признак конца транзакции, последняя запись для данного владельца.

Поскольку из-за конфликтов блокировок транзакции могут откатываться, и ранее блокированные записи становиться свободными, то процедура проверяет наличие свободных токенов для текущего владельца и если они есть, сначала выдает их, с eot установленным в 0.

Предлагаю всем желающим попробовать свои силы в этом элегантном программистском этюде и окунуться в чарующий мир блокировок Informix ! :)

----------
P.S. Внешняя программа :


$dbh_ace = DBI->connect("dbi:Informix:$config{'dbname_ace'}",
$config{'user_ace'},
$config{'pass_ace'},
{ AutoCommit => 0,
PrintError => 1,
RaiseError => 0,
ChopBlanks => 1 } )
or oops(" Connect failed $config{dbname_ace}", $DBI::errstr, 1);

$dbh_ace->do("SET LOCK MODE TO WAIT 60");

-- разлочить токены - сироты
$dbh_ace->do("UPDATE test_token SET locked = 0 WHERE locked = 1 AND (sid NOT IN (SELECT sid from sysmaster:syssessions) OR sid IS NULL)")
or oops(" UPDATE test_token failed $config{dbname_ace}", $DBI::errstr, 0);

$dbh_ace->do("SET LOCK MODE TO NOT WAIT");

my $get_test_tokens = $dbh_ace->prepare(" EXECUTE PROCEDURE get_test2()")
or oops(" Prepare for EXECUTE PROC failed $config{dbname_ace}", $DBI::errstr, 1);

my $del_test_token = $dbh_ace->prepare("DELETE FROM test_token WHERE token_id = ?")
or oops(" Prepare for delete failed $config{dbname_ace}", $DBI::errstr, 1) ;

$get_test_tokens->bind_columns( \$l_token_id, \$l_action, \$l_owner_number, \$eot);

my $l_continue = 1;
my $rand_sleep = 1;

while ($l_continue) {

$dbh_ace->do('BEGIN WORK');
$dbh_ace->do('SET ISOLATION CURSOR STABILITY RETAIN UPDATE LOCKS');

$get_test_tokens ->execute($num, $start_id)
or oops("EXECUTE get_test2 failed", $DBI::errstr, 1);

$l_continue = 0;

while ( $get_test_tokens->fetch or ( $l_exception == 1) ) {
$l_continue = 1;
if ( $l_exception ) {
$l_exception = 0;
oops("FETCH failed $config{dbname_ace}", $DBI::errstr, 0);
print "$num:ROLLBACK TRANSACTION AFTER FETCH\n" ;
$| = 1;
$dbh_ace->do("ROLLBACK WORK")
or oops("ROLLBACK failed $config{dbname_ace}", $DBI::errstr, 1);
last;
}

print "$num: Get token $l_token_id, action $l_action, owner_number $l_owner_number eot $eot \n";

$del_test_token ->execute( $l_token_id)
or ( $l_rollback = 1 );
if ( $l_rollback ) {
$dbh_ace->do("ROLLBACK WORK");

last;
}

else {
if ( $eot == 1 ) {
$dbh_ace->do('COMMIT WORK');
last;
}
}
}
}



В таком вот аксепте
...
Рейтинг: 0 / 0
Параллельная работа с таблицей
    #39922731
cpr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
cpr
Гость
А почему бы изначально не развести потоки обработки?

Каждый поток берет свою запись и никаких конфликтов.
Я в аналогичных случаях ввожу простое правило. Каждый поток обрабатывает записи у которых остаток от деления сериального номера на количество потоков равен номеру потока.
Производительность растет практически линейно .
...
Рейтинг: 0 / 0
Параллельная работа с таблицей
    #39924099
Выбегалло
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cpr
А почему бы изначально не развести потоки обработки?

Каждый поток берет свою запись и никаких конфликтов.
Я в аналогичных случаях ввожу простое правило. Каждый поток обрабатывает записи у которых остаток от деления сериального номера на количество потоков равен номеру потока.
Производительность растет практически линейно .


потому что записи принадлежащие одному владельцу должны выдаваться последовательно.
А с вашим алгоритмом нет никакой гарантии что запись "удалить владельца" появится ПОСЛЕ записи "создать владельца".
В результате мы останемся с неудаленным владельцем.
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / Informix [игнор отключен] [закрыт для гостей] / Параллельная работа с таблицей
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]