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

Отработанное время:
Продуктивное время:
Bug 3759 - Время загрузки 1с77 существенно увеличивается с ростом количества пользователей   Make a simular bug
Summary: Время загрузки 1с77 существенно увеличивается с ростом количества пользователей
Status: CLOSED FIXED
Alias: None
Product: CIFS@Etersoft
Classification: Продукты (Products)
Component: блокировки файлов и доступ (show other bugs)
Version: не указана
Hardware: PC All
: P3 normal
Target Milestone: ---
Assignee: Vitaly Lipatov
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 3589
  Show dependency treegraph
 
In work:
Reported: 2009-04-01 10:13 MSD by Боренко Денис
Modified: 2010-03-08 16:16 MSK (History)
7 users (show)

See Also:
Заявки RT:
Связано с:
Дата напоминания:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Боренко Денис 2009-04-01 10:13:01 MSD
Время загрузки существенно растет при увеличении количества пользователей разделенного режима 1с. Причем файлы открываются быстро. Время увеличивается только за счет длительной попытки получить блокировки за концами файлов links.tmp и 1cv7.lck.
Дамп сетевой активности показывает, что время растет из-за двойного запроса блокировки занятого байта (см. мой пост в баге 2915).
Почитав исходник file.c нашел следующее в строке 710:

		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
				 0, 1, lockType, 0 /* wait flag */ );
		
		if (rc == 0) {
			
			rc = CIFSSMBLock(xid, pTcon, netfid, length,
					 pfLock->fl_start, 1 /* numUnlock */ ,
					 0 /* numLock */ , lockType,
					 0 /* wait flag */ );
			pfLock->fl_type = F_UNLCK;
			if (rc != 0)
				cERROR(1, ("Error unlocking previously locked "
					   "range %d during test of lock", rc));
			rc = 0;

		} else {
			/* if rc == ERR_SHARING_VIOLATION ? */
			rc = 0;

			if (lockType & LOCKING_ANDX_SHARED_LOCK) {
				pfLock->fl_type = F_WRLCK;
			} else {



Этог вызова CIFSSMBLock быть не должно (из-за него все тормозит и виндовый клиент такого не делает):
				rc = CIFSSMBLock(xid, pTcon, netfid, length,
					pfLock->fl_start, 0, 1,
					lockType | LOCKING_ANDX_SHARED_LOCK,
					0 /* wait flag */ );
				if (rc == 0) {
					rc = CIFSSMBLock(xid, pTcon, netfid,
						length, pfLock->fl_start, 1, 0,
						lockType |
						LOCKING_ANDX_SHARED_LOCK,
						0 /* wait flag */ );
					pfLock->fl_type = F_RDLCK;
					if (rc != 0)
						cERROR(1, ("Error unlocking "
						"previously locked range %d "
						"during test of lock", rc));
					rc = 0;
				} else {
					pfLock->fl_type = F_WRLCK;
					rc = 0;
				}
			}
		}

		FreeXid(xid);
		return rc;
	}
Comment 1 Боренко Денис 2009-04-01 10:27:19 MSD
Вот на всякий случай дебаг с таймингами:
[ 3120.734159] file.c: CIFS VFS: in cifs_lock as Xid: 142 with uid: 1000
[ 3120.734169] file.c: Lock parm: 0x5 flockflags: 0x1 flocktype: 0x1 start: 10000006 end: 10000006
[ 3120.734178] file.c: Posix
[ 3120.734185] file.c: F_WRLCK 
[ 3120.734200] cifssmb.c: CIFSSMBLock timeout 0 numLock 1
[ 3120.734213] transport.c: For smb_command 36
[ 3120.734222] transport.c: Sending smb:  total_len 75
[ 3120.938554] connect.c: rfc1002 length 0x27
[ 3120.938612] netmisc.c: Mapping smb error code 33 to POSIX err -13
[ 3120.938625] cifssmb.c: Send error in Lock = -13
[ 3120.938638] cifssmb.c: CIFSSMBLock timeout 0 numLock 1
[ 3120.938650] transport.c: For smb_command 36
[ 3120.938656] transport.c: Sending smb:  total_len 75
[ 3121.141408] connect.c: rfc1002 length 0x27
[ 3121.141439] netmisc.c: Mapping smb error code 33 to POSIX err -13
[ 3121.141448] cifssmb.c: Send error in Lock = -13
[ 3121.141455] file.c: CIFS VFS: leaving cifs_lock (xid = 142) rc = 0
Comment 2 Pavel Shilovsky 2009-04-01 10:44:56 MSD
Этот вызов должен быть. Мы ограничены возможностями SMB протокола в данном случае и лучшего решения выполнить запрос F_GETLK, чем попытаться заблокировать этот участок, нет. Два раза вызов выполняется в том случае, если первый раз обвалился запрос на блокировку на запись, и мы не можем без дополнительных проверок выяснить, какая блокировка стоит - на запись или чтение.
Comment 3 Боренко Денис 2009-04-01 10:50:25 MSD
Обратите внимание, двойной вызов выполняется на запросе F_WRLCK.
Comment 4 Pavel Shilovsky 2009-04-01 10:56:36 MSD
Да! Происходит запрос F_GETLK на F_WRLCK. Обламывается. Какие варианты? Или стоит блокировка на запись или на чтение - непонятно. Пробуем ставить блокировку на чтение и по результатам однозначно определяем установленную блокировку.
Comment 5 Боренко Денис 2009-04-01 11:01:06 MSD
К сожалению я не вник в этот долбаный cifs настолько, что бы ответить вам. Буду думать. Но ограничения SMB не причем вроде -- винда же обходится одним запросом.
Comment 6 Боренко Денис 2009-04-01 11:19:56 MSD
Судя по дампу, винде хватает только запроса с LockType=0x10.
Т.е. ей пофиг какая там стоит блокировка -- стоит и ладно.
В линуксе такой номер не проходит (не возвращать тип блокировки)? Это ограничение самой системы?
Comment 7 Pavel Shilovsky 2009-04-01 11:28:57 MSD
Ну это уже зависит от того, в каких случаях
F_GETLK используется в Wine. Думаю
непосредственные разработчики Wine прояснят
этот вопрос. В Windows такого запроса вообще
нет.

Насколько я знаю, в 1cv77 вообще не
используется функция LockFileEx(), которая может
установить блокировку на чтение - потому
можно собрать версию etercifs для неё без
второй проверки. Но в таком случае не
гарантируется правильная работа остальных
приложений с шарой.
Comment 8 Pavel Shilovsky 2009-04-01 11:30:28 MSD
(In reply to comment #5)
> Но ограничения SMB не причем вроде -- винда же
> обходится одним запросом.
> 

В случае F_GETLK запроса следует говорить именно об ограничениях протокола.

Comment 9 Боренко Денис 2009-04-01 11:32:33 MSD
А можно какой-нибудь ключик при монтировании отключающий второй запрос?
Просто реально задолбало, при сорока пользователях ожидание растягивается на 15 сек до ввода пароля и 15 сек после ввода. Причем самое интересное, что сервер долго отвечает именно на второй запрос.
Comment 10 Vitaly Lipatov 2009-04-01 11:54:24 MSD
Я правильно понимаю, что дополнительное обращение к серверу вызвано особенностями реализации LockFile в Wine?
Можно ли синтетически воспроизвести проблему с большой задержкой в RECT?
Comment 11 Pavel Shilovsky 2009-04-01 12:02:43 MSD
Ключик можно. Тоже кстати, вариант только для 1cv77.

Да, именно LockFile. В каких случаях используется запрос на F_GETLK?
Comment 12 Боренко Денис 2009-04-01 12:05:32 MSD
Да. Воспроизводится уверенно на сервере самбой 3.2.3. Надо открыть одну и ту же базу несколько раз. С каждым новым пользователем время после выбора базы и до окошка ввода пароля будет расти. При 40 пользователях это около 15 сек. Причем не важно заходить в базу по сети или на локальную подмаунченую по цивс.
Comment 13 Боренко Денис 2009-04-03 12:01:08 MSD
Скомпилил без вторго запроса (просто возвращаю тип F_WRLCK). Время появления окна ввода пароля уменьшилось, но все равно очень большое, по сравнению с виндой. Наверное что-то с пакетом на запрос блокировки не так. Попробую на досуге получить более подробный дамп.

[ 1635.006329] file.c: CIFS VFS: in cifs_lock as Xid: 12788 with uid: 1000
[ 1635.006339] file.c: Lock parm: 0x5 flockflags: 0x1 flocktype: 0x1 start: 10000010 end: 10000010
[ 1635.006345] file.c: Posix
[ 1635.006351] file.c: F_WRLCK 
[ 1635.006357] cifssmb.c: CIFSSMBLock timeout 0 numLock 1
[ 1635.006366] transport.c: For smb_command 36
[ 1635.006372] transport.c: Sending smb:  total_len 75
**********Вот откуда такая задержка?***************
[ 1635.209658] connect.c: rfc1002 length 0x27
[ 1635.209717] netmisc.c: Mapping smb error code 33 to POSIX err -13
[ 1635.209731] cifssmb.c: Send error in Lock = -13
[ 1635.209739] file.c: CIFS VFS: leaving cifs_lock (xid = 12788) rc = 0

На том же сервере окно ввода пароля в виндовом клиенте появляется за 1 сек.
Может кто подскажет почему там в третей строке Posix написано? Шара смонтирована с forcemand. Не может это влиять?
Comment 14 Боренко Денис 2009-04-03 12:27:50 MSD
Блин, вообще полтергейст. Иногда (в 1 из 20 случаев) задержка отсутствует. Искуственно добится этого не получается, но как правило это первый вход после первого монтирования ресурса или рестарта модуля. Не может сервер какое-то время ждать блокировки перед ответом?
Comment 15 Боренко Денис 2009-04-03 12:31:56 MSD
(In reply to comment #14)
> Иногда (в 1 из 20 случаев) задержка отсутствует. 
Возможно, это когда кто-то выходит из 1С и освобождается один из первых залоченых байтов. Тогда все логично и моя паника напрасна.

Comment 16 Vitaly Lipatov 2009-04-03 12:54:19 MSD
(In reply to comment #14)
...
> это первый вход после первого монтирования
> ресурса или рестарта модуля. Не может
Так это не запуск с оплоками (когда никто другой ещё не держит файлы)?

> сервер какое-то время ждать блокировки
> перед ответом?
Насколько я знаю, некоторые искусственные задержки есть в сервере SAMBA (или в протоколе??). Но это легко проверяется, с виндовым сервером.

Comment 17 Боренко Денис 2009-04-03 13:10:12 MSD
> (In reply to comment #14)
> Так это не запуск с оплоками (когда никто
> другой ещё не держит файлы)?
Нет. Оплоки не причем.
Проблема только в одном:
В момент запуска 1С происходит попытка захватить на запись байт лежащий за концом файлов 1CV7.LCK и /SYSLOG/links.tmp
Лок на запись этого байта удерживается экземпляром 1С все время его работы. Именно по этим байтам работает Монитор пользователей.
При попытке захватить лок 1с перебирает байты по одному с 10000000 и если захватить не удалось пробует следующий, пока не добьется установки блокировки. Ответ сервера при занятом байте линуксовому клиенту занимает много времени (~200 мс запрос блокировки на запись и ~500 мс запрос блокировки на чтение ).Виндовая же машина делает только запрос на запись и получает ответ значительно быстрее.


Comment 18 Боренко Денис 2009-04-03 13:14:01 MSD
Логично предположить, что подобным же образом ставятся локи на файлы базы при проведении документов. Таким образом этот глюк также может влиять на производительность проведения и записи документов (правда в значительно меньшей степени).
Comment 19 Боренко Денис 2009-04-18 21:16:09 MSD
Корень зла найден.

Обнаружилось, что запросов на блокировку не 2, а 3. Первые два на запись, последний -- на чтение. 
На первый мы получаем ответ NT_STATUS_LOCK_NOT_GRANDED (0х55)
На два последующих -- NT_STATUS_LOCK_CONFLICT (0x54)
Такая последовательность не случайна, это специально написаная на самбовском сервере процедура, пытающаяся спародировать w2k3 и меняющая тип ответа при повторном запросе блокировки одного и того же окна байтов.
Причем интересен следующий комментарий в smbd/reply.c
/* This heuristic seems to match W2K3 very well. If a
lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
it pretends we asked for a timeout of between 150 - 300 milliseconds as
far as I can tell. Replacement for do_lock_spin(). JRA. */
Вобщем все. Исследование закончено. Паузу 200 мс во 2 и 3 запросе делает сервер.
Решается в [globals] 
lock spin time = 0
Comment 20 Боренко Денис 2009-04-19 09:53:04 MSD
Остался не выясненым вопрос по количеству запросов на блокировку.
Путаница с количеством запросов возникла из-за того, что в версии цифс 4.1.х второго запроса на блокировку на чтение в file.c не производилось, а сетевой дамп (см. багу 2915) я снимал как раз на этой версии. Пакетов было два! К сожалению, тогда я не обратил внимание на тип запроса на блокировку, но судя по всему оба запроса были на блокировку на запись. Клиента почему-то не удовлетворяет ответ NT_STATUS_LOCK_NOT_GRANDED и он посылает второй точно такой же запрос. Баг?
В новых версиях цифс запросов, как я написал выше, три! При этом трейс в комментарии #1 снят именно на новых версиях.
Зачем и где происходит повторный запрос блокировки на запись?
Я не могу этого в исходниках нарыть, всю бошку уже сломал. Может кто подскажет?
Comment 21 Pavel Shilovsky 2009-04-19 11:29:23 MSD
Дело в том, что Wine сначала посылает запрос на установку блокировки, потом, если он обваливается, он посылает запрос F_GETLK, которому соответствует уже 2 запроса внутри cifs драйвера. Итого: 3 запроса на блокировку.
Comment 22 Vitaly Lipatov 2009-04-19 12:08:20 MSD
(In reply to comment #19)
...
> Вобщем все. Исследование закончено. Паузу
> 200 мс во 2 и 3 запросе делает сервер.
> Решается в [globals] 
> lock spin time = 0
Интересно, получается что с Windows-серверами проблема останется?

Comment 23 Боренко Денис 2009-04-19 12:13:46 MSD
Получается, что остается.
Comment 24 Боренко Денис 2009-04-19 12:17:54 MSD
Вот прикольно получается. Линуксовый цифс клиент всегда будет плохо работать с линуксовой же самбой с настройками по умолчанию (потому что самба эмулирует какую-то долбаную w23k). Может при компиляции самбы в алте поменять умолчания для lock spin time?
Comment 25 Боренко Денис 2009-04-19 12:26:01 MSD
(In reply to comment #21)
> Итого: 3 запроса на блокировку.
Весь парадокс в том, что с самбой по умолчанию так будет всегда очень медлено (0.5 секунды на запрос!), а с виндовым сервером вообще всегда писец.

Comment 26 Боренко Денис 2009-04-20 16:14:48 MSD
(In reply to comment #19)
> If a lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
Может при повторных запросах блокировки выставлять таймаут 1? 
Comment 27 Боренко Денис 2009-04-21 16:24:24 MSD
В общем воркэраунд это хорошо, но хотелось бы по человечески. Хотя бы в песпективе.
На kernel.org сейчас лежит file.c без второго запроса на лок. Вы будете патч им туда пропихивать?
Если да, то надо и самбу патчить (brl_lock_failed в locking/brlock.c), что бы при повторном запросе отличающимся по типу блокировки она выдавала NT_STATUS_LOCK_NOT_GRANTED.
Тогда все будет шоколадно.

И все таки не въехал почему зароса 3, а не 2. Виноват не cifs, а wine? Не правильно реализована lockfile в wine?
Comment 28 Pavel Shilovsky 2009-04-21 22:44:05 MSD
Виноват SMB протокол. Раньше он вообще некорректное значение возвращал на F_GETLK. Чтобы заставить его возвращать корректное, пришлось написать дополнительный запрос: итого 2.

Плюс wine вызывает F_GETLK после обломившегося запроса на установку блокировки: +1

Всего: 3 запроса.

Изменения протихиваются, но их не особо охотно принимают пока.
Comment 29 Боренко Денис 2009-04-21 23:43:30 MSD
(In reply to comment #28)
> Виноват SMB протокол. Раньше он вообще
> некорректное значение возвращал на F_GETLK.
Да, согласен, патч идейно верный, но с текущей реализацией самбы привдет к заметному падению производительности на данной операции. Может во втором запросе временно ставить время ожидания отличное от нуля? Это изменит поведение сервера.

> Плюс wine вызывает F_GETLK после обломившегося
> запроса на установку блокировки: +1
Во! Вот нафиг? Че-то с не привычки затрахался за последнее время по гитам всяким лазить, может пальцем покажете где это в исходниках и самое главное нафига оно там?
Comment 30 Pavel Shilovsky 2009-04-23 10:38:41 MSD
http://git.etersoft.ru/projects/?p=eterwine.git;a=blob;f=server/fd.c;h=d9688e1e0d9860f64625fb6e58ca2da32d028d0b;hb=HEAD

Там анализируется почему запрос на блокировку не прошёл.
Comment 31 Боренко Денис 2009-04-23 11:04:57 MSD
Ура! Кто б мне дал это раньше почитать! Я правильно нашел?:
set_unix_lock( ... ):
case EACCES:
    /* check whether locks work at all on this file system */
       if (fcntl( fd->unix_fd, F_GETLK, &fl ) != -1)
       {
           set_error( STATUS_FILE_LOCK_CONFLICT );
           return 0;
       }
    /* fall through */
Т.е. запрос на F_SETLK делается верно. Одним пакетом.
А вот проверка подерживаются ли блокировки файловой системой -- двумя, и жутко тормозит! Нельзя ли кешировать ответы (файловая система для конкретного файла ведь не изменится за время работы) и тем самым не делать повторные F_GETLK? Поведение стане точь-вточь как у винды.
Comment 32 Боренко Денис 2009-04-23 11:11:02 MSD
Кстати, есть предположение, что на виндовом серваке F_GETLK будет обрабатываться быстро, т.к. там может анализироваться тип блокировки (F_WRLCK,F_RDLCK). 
Тогда надо пачить самбу (brl_lock_failed в locking/brlock.c).
Правда с текущим wine это не поможет.
Comment 33 Александр Морозов 2009-07-22 16:06:20 MSD
> Ура! Кто б мне дал это раньше почитать! Я
> правильно нашел?:
> set_unix_lock( ... ):
> case EACCES:
>     /* check whether locks work at all on this file system */
>        if (fcntl( fd->unix_fd, F_GETLK, &fl ) != -1)
>        {
>            set_error( STATUS_FILE_LOCK_CONFLICT );
>            return 0;
>        }
>     /* fall through */
> Т.е. запрос на F_SETLK делается верно. Одним
> пакетом.
> А вот проверка подерживаются ли блокировки
> файловой системой -- двумя, и жутко
> тормозит! Нельзя ли кешировать ответы
> (файловая система для конкретного файла
> ведь не изменится за время работы) и тем
> самым не делать повторные F_GETLK? Поведение
> стане точь-вточь как у винды.

Вот такой патч приводит к увеличению скорости работы блокировок при открытии файла на запись:
diff --git a/server/fd.c b/server/fd.c
index bc6a4e1..146e918 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1174,7 +1174,7 @@ static int set_unix_lock( struct fd *fd, file_pos_t start, file_pos_t end, int t
         case EACCES:
             /* check whether locks work at all on this file system */
            TRACE(stderr,"EACCES\n");
-            if (fcntl( fd->unix_fd, F_GETLK, &fl ) != -1)
+            if (fd->cifs || (fcntl( fd->unix_fd, F_GETLK, &fl ) != -1))
             {
                 set_error( STATUS_FILE_LOCK_CONFLICT );
                 return 0;

Без патча:

[amorozov@cellar amorozov]$ ww /srv/amorozov/Projects/prog/winlock/winlock.exe r exclusive
fixme:ntdll:NtLockFile I/O completion on lock not implemented yet
0.001794 sec
Press F6 and Enter in Windows or Ctrl-D in WINE...

[amorozov@cellar amorozov]$ WINEPREFIX=/home/amorozov/wine_2 ww /srv/amorozov/Projects/prog/winlock/winlock.exe r exclusive 10000
fixme:ntdll:NtLockFile I/O completion on lock not implemented yet
LockFileEx failed: 33
41.588622 sec
[amorozov@cellar amorozov]$ WINEPREFIX=/home/amorozov/wine_2 ww /srv/amorozov/Projects/prog/winlock/winlock.exe w exclusive 10000
fixme:ntdll:NtLockFile I/O completion on lock not implemented yet
LockFileEx failed: 33
81.929839 sec

После применения патча:

[amorozov@cellar amorozov]$ ww /srv/amorozov/Projects/prog/winlock/winlock.exe r exclusive
fixme:ntdll:NtLockFile I/O completion on lock not implemented yet
0.001797 sec
Press F6 and Enter in Windows or Ctrl-D in WINE...

[amorozov@cellar amorozov]$ WINEPREFIX=/home/amorozov/wine_2 ww /srv/amorozov/Projects/prog/winlock/winlock.exe w exclusive 10000
fixme:ntdll:NtLockFile I/O completion on lock not implemented yet
LockFileEx failed: 33
40.739485 sec
[amorozov@cellar amorozov]$ WINEPREFIX=/home/amorozov/wine_2 ww /srv/amorozov/Projects/prog/winlock/winlock.exe r exclusive 10000
fixme:ntdll:NtLockFile I/O completion on lock not implemented yet
LockFileEx failed: 33
40.340272 sec

winlock лежит в wine-etersoft-devel/locks/winlock

winlock.exe {r|w|rw} [exclusive] [count]
r|w|rw - открывать файл на чтение, запись или и то, и другое
exclusive - использовать эксклюзивную блокировку
count - если равно 1, то программа устанавливает блокировку и ждёт, когда пользователь нажмёт Ctrl-D (в WINE) или F6 и Enter (в Windows), если больше 1, то программа устанавливает и снимает блокировки на файл count раз
По умолчанию предполагается, что count = 1
Comment 34 Vitaly Lipatov 2009-07-22 18:42:03 MSD
Патч применён в сборке 1.0.11-eter2.1. Считаем, что от нас пока ничего не требуется.
Просьба к заинтересованным проверить улучшение ситуации.