Укажите отработанное время

Отработанное время:
Продуктивное время:
Bug 3785 - 1с виснет при проведении документов другим пользователем   Make a simular bug
Summary: 1с виснет при проведении документов другим пользователем
Status: CLOSED FIXED
Alias: None
Product: SELTA@Etersoft
Classification: Продукты (Products)
Component: Общее (show other bugs)
Version: 1.0.6
Hardware: PC All
: P4 minor
Target Milestone: версия 1.0.7
Assignee: Станислав Коробейников
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 3880 3881 3973
Blocks: 3246
  Show dependency treegraph
 
In work:
Reported: 2009-04-06 17:47 MSD by Станислав Коробейников
Modified: 2009-08-31 12:31 MSD (History)
3 users (show)

See Also:
Заявки RT: http://rt.etersoft.ru/Ticket/Display.html?id=9967
Связано с:
Дата напоминания:


Attachments
Миграция блокировок ms на postgres (1.65 KB, text/plain)
2010-11-18 03:58 MSK, Станислав Коробейников
Details
Вывод теста блокировок для ms. (6.45 KB, text/plain)
2010-11-18 03:58 MSK, Станислав Коробейников
Details
Вывод теста блокировок для pg. (6.66 KB, text/plain)
2010-11-18 03:58 MSK, Станислав Коробейников
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Станислав Коробейников 2009-04-06 17:47:11 MSD
При проведении документа работа с документами другого пользователя зависает до окончания проведения.
Comment 1 Станислав Коробейников 2009-04-06 17:55:29 MSD
Это легко можно воспроизвести, запускаем две версии 1с под разнами 1с пользователями, одну бд. В одной проводим документ, в другой, есть открыть документы, все подвисает, ждет коммита. Что бы затянуть мироприятие, можно в конфигураторе добавить в функцию провидения: Предупреждение("!!!",0);
Надо разобраться, можно ли как-нибудь избавится от этого.
В 1с8 вроде можно увидеть тот же эффект при работе с Postgres. Что конечно не внушает особого оптимизма.
Comment 2 Станислав Коробейников 2009-04-07 11:59:44 MSD
Итак, ситуация такая:
При проведении 1с принудительно блокикует таблицу _1sjourn:
{call _1sp__1SJOURN_TLockX}
Create procedure _1sp__1SJOURN_TLockX AS
set nocount on declare @i integer select @i=1 from _1SJOURN(TABLOCKX HOLDLOCK) where 0=1
GO

Блокировка TABLOCKX HOLDLOCK соответствует postgresовской ACCESS EXCLUSIVE, и закрывает доступ даже к SELECT'у. Т.е. [SELECT * FROM _1SJOURN;] подвиснет на время блокировки.
Но в mssql есть NOLOCK и [SELECT * FROM _1SJOURN(NOLOCK);] выполнится. А что-то у postgres'а я такой чтуки не видел. 
Comment 3 Станислав Коробейников 2009-04-07 16:57:59 MSD
Судя по всему такого в postgres нет. 
Эквивалент блокировки, который использует SELTA "ACCESS EXCLUSIVE" -- это полный аналог TABLOCKX HOLDLOCK у ms sql.
Про эту блокировку(ACCESS EXCLUSIVE) пишут:
This mode guarantees that the holder is the only transaction accessing the table in any way. 
Т.е. аналога NOLOCK для таких блокировок у postgres нет. 
Для postgres есть ISOLATION LEVEL примерно для тех же целей. Но ведет он себя по другому.
Хочется посмотреть правда ли в 1с8 все так же, чего-то не смог завети 1с8 на postgre. 
Comment 4 Станислав Коробейников 2009-04-10 17:01:47 MSD
Склоняюсь к тому что бы просто отменить проверку на изменение. Какая разница первое сохранится или последнее изменение. 
Остается непонятным, как при такой крутой работе блокировок у mssql так оказалось, что данные начали менятся, когде где-то уже начались изменения. 
Написал в odbc драйвер, что бы тот при появлении этой ошибки писал в консоль какой запрос это вызвал. Goga это отправил пользователям.
Comment 5 Станислав Коробейников 2009-04-13 17:35:30 MSD
Последнее сообщедие (#4) для предгозначалось для баги 2544.
Comment 6 Станислав Коробейников 2009-04-13 17:53:26 MSD
Для адекватного воспроизведения блокировок ms sql похоже надо целиком изменить блокировки в SELTA, а именно:
1. ms: SELECT * FROM foo(TABLOCKX HOLDLOCK) 
Используется для хранимых процедур foo_TLockX
Сейчас заменяется на 
pg:LOCK TABLE foo IN ACCESS EXCLUSIVE MODE;
А надо на 
pg:LOCK TABLE foo IN EXCLUSIVE MODE;
2*. Тогда можно будет использовать "грязное" чтение 
ms:SELECT * FROM foo(NOLOCK);
pg:SELECT * FROM foo;
3*. И "чистое" чтение. 
ms:SELECT * FROM foo;
pg:SELECT * FROM foo FOR UPDATE;
*сейчас (NOLOCK) игнорируется.
4. 
ms: SELECT * FROM foo(TABLOCK HOLDLOCK) 
Сейчас используется 
pg:LOCK TABLE foo IN EXCLUSIVE MODE;
А надо на 
pg:LOCK TABLE foo IN SHARE MODE;
Это работает с 2 и 3. 

Я посмотрел на первый взгляд работать начинает аналогично с ms sql, но надо сделать test. Например в транзакции SELECT * FROM foo FOR UPDATE; блокирует таблицу а вне транзакции не блокирует. Надо узнать все ли также.   
Comment 7 Станислав Коробейников 2009-04-14 18:01:12 MSD
Пока тест не дописал. Но узнал 
Что 
SELECT * FROM foo FOR UPDATE; (Чистое чтение )
блокирует таблицу 
IN EXCLUSIVE MODE
а надо 
IN SHARE MODE
Нашел, есть:
SELECT * FROM foo FOR SHARE;
Это подходит лучше. 

Comment 8 Станислав Коробейников 2009-04-17 17:37:30 MSD
Тест дописал. Но еще результаты не разобрал. Пока вроде на удивление все одинаково. 
Comment 9 Станислав Коробейников 2009-04-20 18:04:04 MSD
Нашел разницу в поведении. 
ms: SELECT * FROM foo
Все таки не блокирует данные. 
А собирались его менять на SELECT * FROM foo FOR SHARE; который блокирует данные. Для 1с это мне кажется не очень важно, т.к. ну чуть заблокировали, все лучше, чем сразу блокировать журнал на чтение. 
Можно было бы сделать так:
SAVEPOINT spselta; SELECT * FROM foo FOR SHARE; ROLLBACK TO spselta;
Ничего бы не блокировалось, но SAVEPOINT работает только в транзакции, а при использовании снаружи транзакции выдает ошибку. 
Можно отследить открыта ли транзакция, но пока я знаю как. SQL функций похоже нет. Есть libpq PQtransactionStatus. Не знаю куда бы ее прикрутить. 
Comment 10 Станислав Коробейников 2009-04-22 17:57:21 MSD
Что-то с PQtransactionStatus похоже не получится. В odbc по умолчанию libpq не подключается (библиотека подключается, но подключение по нему(PQconnectdb) не происходит) есть #define DEFAULT_SSLMODE, если его изменить, то подключение будет проходить, но команды SQL все равно проходят не через libpq. 
Пожалуй придется делать в odbc драйвере statement, там выполнять  SAVEPOINT spselta; и ROLLBACK TO spselta; и не обращать внимания на ошибки. Но они будут валится в лог postgres, что неприятно. Может можно этого избежать.? Надо будет попробывать.
Comment 11 Vitaly Lipatov 2009-04-22 20:56:54 MSD
(In reply to comment #10)
> Что-то с PQtransactionStatus похоже не получится. В
> odbc по умолчанию libpq не подключается
> (библиотека подключается, но подключение
> по нему(PQconnectdb) не происходит) есть #define
Каким же образом происходит подключение и работа ODBC-драйвера с сервером?

> Пожалуй придется делать в odbc драйвере
> statement, там выполнять  SAVEPOINT spselta; и ROLLBACK TO
> spselta; и не обращать внимания на ошибки. Но
> они будут валится в лог postgres, что неприятно.
> Может можно этого избежать.? Надо будет
> попробывать.
Так а в транзакцию же вводится командой SQL, нельзя ставить флаг, что мы вошли в транзакцию? 

Comment 12 Станислав Коробейников 2009-04-23 12:29:49 MSD
(In reply to comment #11)
> Каким же образом происходит подключение и
> работа ODBC-драйвера с сервером?
Подключение через функцию работы с сокетами connect, данные посылаются send,  принимаются recv. 
Это в обычном режиме, есть еще SSL.
> Так а в транзакцию же вводится командой SQL,
Начинает транзакцию командой SQL, но заканчиваться могут odbc командой SQLEndTran, 1с так и делает.
> нельзя ставить флаг, что мы вошли в
> транзакцию? 
Думаю можно, надо поробывать. 

Comment 13 Станислав Коробейников 2009-04-23 15:48:38 MSD
С 1с вообще просто все. Она пользется только неявными транзакциями, те устанвливают SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, -6); И дальше что идет, все транзакция, если закончили транзакцию -- EndTran, сразу началась следующая, пока не отменят это: SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OM, -6); 
Т.е. надо только отслеживать статус Connection'а.
Другле дело явные транзакции BEGIN TRANSACTION; COMMIT TRANSACTION; Но они в SELTA даже не транслируются. 
Ух ты нашел свойсво у Connection'а transact_status, отслеживает даже явные транзакции, самому ничего делать не надо!
Таким образом можно передавать в selta.dll состояние транзакции, а парсер в зависимости от этого будет выбирать какую команду использовать.  SAVEPOINT spselta; SELECT * FROM foo FOR SHARE; RELEASE SAVEPOINT spselta; или просто SELECT * FROM foo FOR SHARE;
Comment 14 Станислав Коробейников 2009-04-24 16:45:02 MSD
Заметил,
1. у нас еще в трансляторе есть блокировка UPDLOCK. У нас она заменяется на FOR SHARE, что не правильно, т.к. это эксклюзивная блокировка.
2. Думал делать так, например
ms: SELECT * FROM foo(TABLOCKX HOLDLOCK) заменять на SELECT * FROM foo FOR UPDATE, но у ms это табличная блокировка, а то как я написал для postgres -- это  посточная. А табличная только LOCK TABLE table1 IN EXCLUSIVE MODE; но она разрешает чистое чтение  SELECT * FROM table1 FOR SHARE, что не соответствует ms. Похоже придется как-то комбинировать.


Comment 15 Станислав Коробейников 2009-04-27 17:10:40 MSD
Уже почти все хорошо, оталось только два вопроса:
1 Единственное несоответствие, которое я нашел это в UPDLOCK. 
У нас будет табличная блокировка, а у MS она на уровне строк.
Эта блокировка разрешает чистое чтение. В postgre такое не получится. Чистое чтение у нас реализуется через FOR SHARE, что не не сможет выполнится из-за блокировки. 

2. Создаст ли postgres курсор на такой запрос и нормально ли будет в нем работать:
SAVEPOINT spselta; SELECT * FROM table1 FOR SHARE; ROLLBACK TO spselta;
Особенно беспокоет, откатит ли изменения назад ROLLBACK TO spselta, т.к. RELEASE SAVEPOINT TO spselta не отменяет блокировку. Если это так, то придется тоже блокировть данные даже при простом чистом чтении.

Comment 16 Станислав Коробейников 2009-04-28 12:51:56 MSD
(In reply to comment #15)
> 2. 
На такой запрос курсор конечно создасться не сможет:
> SAVEPOINT spselta; SELECT * FROM table1 FOR SHARE; ROLLBACK TO spselta;
Но можно из selta.dll передовать надобность о курсоре в odbc драйвер, а там перед командой открывать SAVEPOINT, а после закрывать. 
ROLLBACK TO spselta; не отменяет изменения в курсоре, курсор не закрывает.

Comment 17 Станислав Коробейников 2009-04-28 13:54:09 MSD
Created attachment 1169 [details]
Миграция блокировок ms на postgres
Comment 18 Станислав Коробейников 2009-04-28 13:55:56 MSD
Created attachment 1170 [details]
Вывод теста блокировок для ms.
Comment 19 Станислав Коробейников 2009-04-28 13:56:23 MSD
Created attachment 1171 [details]
Вывод теста блокировок для pg.
Comment 20 Станислав Коробейников 2009-04-28 14:08:15 MSD
Закомитил тест. Лежит в /tests/testlock/. Тест блокирует какую нибудь таблицу и смотрит, что с ней можно сделать. 
В тесте в testlock.cpp есть строки 
#define MS_SQL_SERVER
/*#define PG_SQL_SERVER*/
одна и них должна быть закоментирована. В pg работает через SELTA. 
Вывод теста есть здесь(Вывод теста блокировок для ms. и Вывод теста блокировок для pg. удобно смотреть meld'ом)
В /var/ftp/tmp/stas/testlock/ есть уже собранные. 
Comment 21 Станислав Коробейников 2009-06-18 16:07:23 MSD
С новыми блокировками не виснет. Закрываю.