Значения столбца WAIT в Promon
С помощью утилиты Promon можно определить, какой ресурс ожидает процесс. Это полезно, когда необходимо понять, что происходит с процессом, если есть подозрения что он "завис".
Ниже приведена расшифровка значений, которые могут появляться в столбце Wait на экранах Promon, а так же по возможности будут приведены краткие комментарии к ним.
Значения столбца Wait в Promon-> 1. User Control ->1. Display all entries
Значение |
Расшифровка |
Примечание |
-- |
|
Процесс ничего не ождает |
REC* |
Record Lock |
Процесс ожидает разблокировки записи, к которой он должен получить доступ. При этом в столбце Table отображается ID таблицы, а в столбце DBKey указывается RECID блокированной записи. |
SCHM* |
Schema lock |
Процесс ожидает блокировку схемы. В один момент времени только один пользователь может блокировать схему. |
TSK* |
Another task |
Возникает во время завершения транзакции. Процесс ожидает, чтобы обратиться к записи, помеченной на удаление или значение поля которой было изменено транзакцией, которая еще не завершилась. Как только эта транзакция завершится, процесс сможет продолжить работу. |
DEAD |
Process termination |
Процесс фактически завершился, хотя он все еще находится в списке процессов. Такое может произойти, например, когда процесс "убивают" командой kill -9 |
BUFF ** |
Database buffer |
Процесс ожидает буфер базы данных |
DB ** |
Database service |
Процесс ожидает сервер базы данных |
IX ** |
Index lock |
Процесс ожидает разблокировку индекса |
MT ** |
Microtransaction |
Процесс ожидает завершения микротранзакции |
READ ** |
Block read |
Процесс ожидает, чтобы прочитать блок |
WRT ** |
Block write |
Процесс ожидает, чтобы записать блок |
* - REC, SCHM и TSK - это ожидание приложений. Они не ограничены во времени по продолжительности.
** - BUFF, DB, IX, MT READ и WRT - используются для внутренних целей Progress. Они очень короткие по продолжительности, от микро до миллисекунд. Пример:User Control:
Usr Name Type Wait Table Dbkey Trans PID
0 valeriy BROK -- 0 0 0 3337
5 valeriy MON -- 0 0 0 7338
6 valeriy SELF/ABL -- 0 0 0 7179
7 sysprogr SELF/ABL REC 2 98 0 7229
Sem Srv Login Time
0 0 02/02/10 13:37
2 0 02/03/10 19:04
3 0 02/03/10 18:08
3 0 02/03/10 18:09
RETURN - repeat, U - continue uninterrupted, Q - quit:
Здесь видно, что пользователь sysprogress ожидает получения доступа к записи с RECID 98 из таблицы c ID 2. Здесь мы так же можем видеть PID каждого процесса в операционной системе, а так же тип процесса, по которым можем быстрее найти пользователя и, например, корректно его отключить ;-)
Значения столбца Wait в Promon-> R&D-> 1. Status Displays > 4. Processes/Clients > 1. All Processes
Если в столбце Wait у процесса нет никаких значений, это значит, что процесс не ждет никакого события, связанного с базой данных.
Значение |
Расшифровка |
Ожидание блокировок |
REC |
Record Lock |
SCH |
Schema lock ( |
TRAN |
Transaction commit |
Ожидание ресурсов |
AIRD |
After-image buffer read from disk |
AIWR |
After-image buffer write to disk |
BIRD |
Before-image buffer read from disk |
BIWR |
Before-image buffer write to disk |
BKEX |
Exclusive lock on database buffer |
BKSH |
Share lock on database buffer |
BKSI |
Share lock with intent to update on database buffer |
DBBK |
Database buffer being backed up |
DBRD |
Database buffer read from disk |
DBWR |
Database buffer write to disk |
RGET |
Row get lock |
TXE |
Transaction commit lock |
Ожидание латча ( latch) |
AIB |
After-image buffer latch |
BFP |
Buffer pool latch |
BHT |
Buffer pool hash table latch |
BUF |
Buffer pool buffer latch |
CPQ |
Checkpoint queue latch |
DLC |
Index delete chain |
GST |
Global storage pool latch |
IXD |
Index delete chain latch |
LK F |
Lock table free chain latch |
LKP |
Lock table purge chain latch |
LKT |
Lock table latch |
LRS |
Secondary LRU chain |
LRU |
Buffer pool LRU chain latch |
MTX |
Log space allocation latch |
PWQ |
Page writer queue latch |
SCH |
Shared schema cache latch |
SEQ |
Sequence cache latch |
TXQ |
Transaction queue latch |
TXT |
Transaction table latch |
USR |
User table latch |
Пример. 02/03/10 Status: All Processes
19:07:28
Usr Name Type Wait Trans id Login time
0 valeriy BROK -- 0 0 02/02/10 13:37
5 valeriy MON -- 0 0 02/03/10 19:04
6 valeriy SELF/ABL -- 0 0 02/03/10 18:08
7 sysprogr SELF/ABL REC 98 0 02/03/10 18:09
Enter , R, P, T, or X (? for help):
Здесь мы видим почти ту же информацию, что и в Promon-> 1. User Control-> 1. Display all entries, но только в более сжатом виде. Запомнив значение поля Trans id (в данном случае это 98), переходим в меню R&D -> 1. Status Displays -> 6. Lock Table -> 3. Display locks for one RECID. Вводим запомненное значение и получаем следующий экран: 02/03/10 Status: Lock Table
19:12:50
Usr Name Trans id Type Table RECID Flags Trans State
6 valeriy 0 REC 2 98 X Dead
7 sysprogr 0 REC 2 98 X Q H Dead
Enter , R, P, T, or X (? for help):
Нашего блокированного пользователя мы идентифицируем по его номеру из поля Usr. А второй пользователь - тот, кто блокировал запись.
Пользователей, которые блокировали друг друга, также можно посмотреть в меню R& D-> 1. Status Displays-> 4. Processes/ Clients-> 2. Blocked Clients. Этот экран использовать удобнее, особенно когда к базе подключено множество пользователей.
Теперь остается только выяснить, что же такое запустил на выполнение пользователь valeriy ( Usr= 6) и решить, что делать с ним, чтобы разблокировать несчастного пользователя sysprogress ;-) Для этого можно либо просто позвонить пользователю valeriy, либо сформировать ABL-стек с помощью стандартной команды $DLC/proGetStack, передав ей в качестве параметра PID процесса пользователя. После этого в рабочем каталоге процесса будет сформирован файл с именем protrace.< PID>. В этом файле и можно увидеть, какая программа запущена в текущий момент времени у пользователя.
При желании, вы можете по RECID узнать, какая именно запись в таблице блокирована. Сделать это можно с помощью следующего ABL-кода: /*Узнаем название таблицы*/
for each _file where _file-num = 2 no-lock.
displ _file-name.
end.
В данном случае - это таблица Customer. Смотрим, какая запись скрывается под RECID 98: for each customer where recid(customer) = 98 no-lock.
displ customer.name.
end.
Это запись о клиенте Urpon Frisbee. Спросите, зачем искать блокированную запись, когда можно либо дождаться завершения транзакции, которая ее блокировала, либо принудительно прекратить работу этой транзакции. Отвечу. Понимание того, какая таблица, и даже какая именно запись блокируется, особенно если именно эта запись блокируется очень часто, может помочь найти ошибку в логике программы, ну, или хотя бы определить направление для поиска. Приведу подобный пример из жизни. В некой базе данных было замечено, что определенные фоновые процессы, которые отвечали за автоматическую обработку платежей, очень часто блокировали всю работу платежной системы, пока этот процесс не завершали принудительно. Анализ блокируемых таблиц и записей выявил, что в большинстве случаев блокировалась таблица, в которой находились некие счетчики (не спрашивайте почему). Пока активность в платежной системе была в пределах нормы, обращения к этой таблице с целью получения нового значения счетчика не приводили к проблемам. Как только количество платежей увеличивалось, процессы просто не успевали разблокировать запись. Теперь мы, как минимум, знали название конкретной таблицы. По найденной записи, точнее, по названию счетчика, который в ней хранился, без труда был найден кусок кода в программе, состоящей из нескольких тысяч строк. В итоге оказалось, что имели место две ошибки в логике программы. Первая, это конечно та, что для счетчиков использовалась таблица вместо сиквенсов. Вторая заключалась в неправильно написанном коде, который обращался к записи с Share Lock, тем самым создавая так называемые "смертельные объятия" при одновременном обращении к записи из нескольких экземпляров этой программы.
В итоге, старая таблица счетчиков была заменена на сиквенсы, и проблема с блокировками исчезла навсегда.
|