Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MUMPS СУБД. Практика применения и опыт программирования.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
5.4. $STACK() 391
или дополнительный код состояния стека
$STACK(level,"ETRAP")
чтобы можно было определить, что строка команд не принадлежит ру­тине, а задана в обработчике ошибок, выполняющегося в этот момент, в $ETRAP.
Этот пример показывает отличие системной переменной $STACK и максимально доступного для анализа уровня $STACK(-1). Показано, что в состоянии ошибки система удерживает максимально доступную для анализа ошибки информацию о стеке.
При этом выполнение обработчика ошибки
d show
в состоянии стека не отображается, хотя при его выполнении произво­дится изменение состояния стека.
Этот нюанс очень важен, поскольку именно обработчик ошибки, стро­ка команд указанная в $ETRAP, выполняется вместо строки, вызвавшей ошибку, и, если бы $STACK() возвращала информацию о стеке как он исполняется, то информация о собственно месте происхождения ошибки была бы утрачена.
К ключевой проблеме функции $STACK(), как видно из ее опреде­ления и поведения, можно отнести то, что она возвращает данные в зависимости от того, находится ли процесс в состоянии ошибки или нет. Технически, в процессе могут возникнуть также ошибки в обработчи­ке ошибок, сам обработчик ошибок может использовать и перезаписы­вать фреймы стека и использовать большие уровни, чем сохраняется для функции $STACK() в момент ошибки.
Выглядит более разумным такое определение функции $STACK(), чтобы ее поведение было точным и однозначным. Например, для того, чтобы $STACK() возвращала реальное состояние стека как он исполня­ется на текущий момент, а дополнительная функция $ESTACK() возвра­щала бы состояния стека в зависимости от заданного первым парамет­ром номера ошибки. В этом случае программисты могут получить точ­ные состояния стека для каждой из последовательности произошедших ошибок, пока процесс не выйдет из состояния ошибки присваиванием:
set $ecode=""
392 ГЛАВА 5. ОБРАБОТКА ОШИБОК

5.5 Трассировка

Трассировка, и как механизм, и как методика, относится к простейшим и общедоступным отладочным средствам. В некоторой степени трассиров­ка является намного более детализированным вариантом логгирования работы программы.
В книге часто применяется трассирование выполнения программ для иллюстрирования их работы. В своей основе трассировка программ есть внедрение в программу команд вывода информации, необходимой и по­нятной для разработчика, а логгирование это внедрение в программу команд вывода информации, необходимой для администратора.
По логгированию обычно видна работы программы в сильно укруп­ненном виде, например операция старта или останова, как именно они закончились, происходили ли критические ошибки.
По трассировке программ видна последовательность их выполнения, значения необходимых для анализа величин - локальных, глобальных и системных переменных, вычисленные параметры оценки работы, напри­мер общее время или количество чего-то.
В отличие от логгирования, команды трассировки удаляются из гото­вой программы и, наоборот, добавляются для проведения отладки.
При локализации ошибки общий прицип поиска ошибок состоит в объединении следующих пунктов:
1. Составление контрольного теста для воспроизведения проблемы.
2. Определение критерия момента перехода программы в некоррект­ное состояние.
3. Установка контрольных меток трассировки с выводом индикатора корректности.
4. Найдя моменты, между которыми возникает проблемное состояние, этот участок кода детализируется более подробно.
Последовательность таких шагов локализует место происхождения проблемы, последовательно сужая интервал между найденными состоя­ниями "до ошибки" и "после ошибки".
В MUMPS системах зачастую в комплект инсталляции входит рутина или набор рутин для проведения трассировки состояния виртуальной машины исполнения. Обычно такие рутины именуются с префиксами, производными от Error Trapping:
5.5. ТРАССИРОВКА 393
^%ET ^%ETN ^%ETL
Рутины трассировки состояния виртуальной машины обычно имеют две точки входа - трассирование с завершением состояния обработки ошибок и трассирование без завершения состояния обработки ошибок. В этом случае их можно использовать в зависимости от необходимости.
При этом рутины трассировки по умолчанию производят сохранение состояния процесса в относительно универсальном виде, включая, на­пример, все значения локальных переменных. В реальных прикладных системах сама такая информация может быть недостаточно информатив­ной для анализа ошибки и многие прикладные системы содержат соб­ственные средства трассировки состояния процесса и его отображения. В этом случае разработчики могут вывести более информативно состояние контекста процесса, например, кроме идентификатора текущего поль­зователя его более осмысленное описание, прочитанное из глобалов, а также состояние критичных для анализа глобалов.
Как вариант трассировки состояния виртуальной машины можно по­смотреть пример вывода состояния стека с использованием функции $STACK().
Собственно сам вывод информации о состоянии процесса в осмыс­ленном виде может занять большой объем, поскольку в него могут включаться значения $STACK(), системных переменных, локальных пе­ременных, обращение к различного рода системно-зависимым функциям $VIEW() и командам VIEW, критичные для понимания работы програм­мы записи в глобалах.
В большинстве случаев вывод данных производится не совсем так, как приведено в книге (в виде простого вывода на экран), хотя во многих случаях для локализации проблем и такого варианта может быть доста­точно. Трассировка зачастую выполняется либо в файл, либо в глобал. После чего можно просмотреть состояние файла или глобала или при­менить к глобалу специальные средства поиска.
В некоторых случаях отладочная информация о выполнении програм­мы может занимать мегабайты относительно одинаковых строк, в кото­рых необходимо что-то найти или сопоставить. Поэтому, в тех случаях, когда по характеристикам выполнения программы ожидается очень боль­шой вывод, разработчики чаще применяют вывод в текстовые файлы, а когда небольшой - в глобалы.
При выводе в текстовый файл (и вообще при любой трассировке) разработчики должны понимать, то функция трассировки должна изме­нить контекст выполнения процесса наименьшим образом, и необходимо
394 ГЛАВА 5. ОБРАБОТКА ОШИБОК
сохранять и восстанавливать значения системных переменных, которые могут быть критичны для выполнения процесса. К таким в первую оче­редь относятся:
1. Текущее устройство ввода-вывода, значение $IO.
2. В случае если значение $PRINCIPAL может быть изменено, то его также надо восстанавливать.
3. Значение последней глобальной ссылки (naked indicator), значение $REFERENCE или $ZREFERENCE.
4. Значение системной переменной $TEST.
5. Все используемые функцией трассировки локальные переменные не должны сохраниться после выхода из трассировки и, желательно, не должны измениться критические для работы процесса локаль­ные переменные.
При многопользовательской работе необходимо также различать раз­личные трассировки, выполненные разными процессами, запущенные разными пользователями. В этом случае разработчики при выводе в файл получают следующий номер файла, либо при выводе в глобал, получают следующий индекс глобала, например, системной функцией $INCREMENT(), и используя в имени индекса или глобала что-то иден­тифицирующее или пользователя, запустившего процесс, или компьютер с которого подключились к MUMPS системе. В этом случае в общем списке имеющихся трассировок можно относительно просто найти инте­ресующую.
При работе функции трассировки могут возникнуть проблемы, кото­рые она может быть неспособна преодолеть и функция должна корректно отнестись к ситуации невозможности выполнить трассировку. К таким условиям относится работа в состоянии нехватки ресурсов.
Нехватка ресурсов может наступить как до срабатывания трассиров­ки (работа в контексте обработчика ошибки, возникшей из-за нехватки ресурса), так и во время (программа работает на пределе доступных ресурсов).
В практической работе автор сталкивался с такими ситуациями, ко­гда программа исчерпывает доступный ей ресурс, переходит к обработке ошибок, но обработчик ошибок сам не может выполниться корректно, поскольку ему также необходимы какие-то ресурсы. Обычно такая си­туация характеризуется тем, что одновременно и программа не работает
5.5. ТРАССИРОВКА 395
корректно и, при этом, нет и не может появиться никаких диагностиче­ских сообщений.
В такую ситуацию могут попасть не только программы на MUMPS, но и любые другие, которые в обработчике ошибок полагают, что все необходимые им ресурсы доступны. Как раз при исчерпании таких ре­сурсов эти обработчики не могут выполниться корректно.
Те случаи, когда программа не выполняет необходимые действия и не сообщает об этом, хотя имеет такую возможность, относятся к ошибкам программистов. В частности, если утилита копирования файлов может ничего не сообщить на экран о неудаче копирования файла в случае полного исчерпания места на диске.
В MUMPS системах к типовым ситуациям нехватки ресурсов в кон­тексте работы функций трассировки состояния относятся:
1. Исчерпание памяти для локальных переменных (ошибка STORE в системах Cach´e и MiniM).
2. Исчерпание доступного места в базе данных и невозможность его расширения из-за административного ограничения.
3. Исчерпание доступного места в базе данных и невозможность его расширения из-за исчерпания дискового пространства.
4. Исчерпание лимита на число одновременно открытых устройств ввода-вывода.
5. Исчерпание таблицы блокировок, если они используются при трас­сировке.
При правильном проектировании функции трассировки и обработ­чика ошибок такие ситуации должны определяться программно и, при невозможности выполнить трассировку обычными средствами, должны использоваться аварийные средства логгирования, не расходующие ре­сурсы MUMPS системы.
К таким могут быть отнесены встроенные в MUMPS системы сред­ства логгирования в текущий лог самой MUMPS системы или средства логгирования, предоставляемые операционной системой. В Windows си­стемах, в частности, к таким средствам могут быть отнесены средства Event Logging.
И, к числу проблем, специфических для трассировки в контексте СУБД, относится работа трассировки с сохранением информации в гло­бал в контексте транзакции. В случае, если после функции трассировки
396 ГЛАВА 5. ОБРАБОТКА ОШИБОК
процесс вызывает откат транзакции, могут быть также отменены и все записи, сделанные в глобал трассирования. В этом случае разработчи­ки должны выбрать подходящее решение, поддерживаемое используемой MUMPS системой:
1. Трассирование в глобал, на который не распространяется откат транзакции.
2. Трассирование в глобал в базе данных, на которую не распростра­няется откат транзакции.
3. На время трассировки отключать режим журналирования для про­цесса.
Разумеется, что при использовании отключения режима журналиро­вания он, после выполнения трассировки, также должен быть восстанов­лен в предыдущее состояние.
Несмотря на то, что общий принцип трассировки выполнения про­цесса и состояния процесса на первый взгляд очень простой, реальное и полноценное его исполнение может потребовать достаточно больших усилий из-за необходимости учитывать множество нюансов и самой раз­рабатываемой прикладной системы, и используемой MUMPS системы, и операционной системы.

5.6 BREAK

Команда BREAK относится к встроенным отладочным средствам. Коман­да декларирована в стандарте языка, но ее реальное поведение, парамет­ры и использование никак не определены и отводятся на усмотрение реализации MUMPS системы.
Общий принцип работы команды BREAK состоит в применении тер­минального или консольного режима, интерактивном вызове команды для выполнения отладочных операций и организации ввода-вывода в консоли непосредственно оператором, разработчиком или администрато­ром.
К отладочным операциям, выполняемым командой BREAK, относят­ся установка и снятие точек или условий останова, либо для явного перехода в режим интерактивной отладки.
В каждой из MUMPS систем реализация команды BREAK выполне­на по-своему. MUMPS системы сохраняют общий стиль и назначение
5.6. BREAK 397
команды BREAK, поэтому у различных реализаций могут быть и совпа­дающие нюансы этой команды.
Принцип использования BREAK состоит в расстановке в нужных программисту местах точек останова либо задании таких точек выпол­нением команды BREAK. В зависимости от параметров команды про­цесс либо продолжает выполнение, либо останавливается в нужном ме­сте и переходит в интерактивный режим. Программист может вывести на экран значения переменных, вызвать системные функции $VIEW() и команду VIEW для определения состоянияи продолжить выполнение программы либо по одной команде либо далее целиком как есть, либо прервать полностью.
Синтаксис применения BREAK в MUMPS системе Cach´e:
BREAK:pc status BREAK:pc "extend"
В первой форме команда отключает либо включает прерывания по комбинации Ctrl+C, а во второй форме устанавливает тип останова для перехода в интеративный режим.
В зависимости от значения параметра "extend" процесс может перей­ти в режим исполнения по одной команде, по одной строке команд, либо отключить остановы по команде BREAK и далее продолжить выпол­нение программы. В состоянии ожидания ввода программиста система поддерживает безаргументную форму команды GOTO для продолжения выполнения программы.
Положим, что есть программа для демонстрации BREAK:
STEPS
B "S+" N I F I=1:1:3 W I,! Q
При ее выполнении получаем пошаговое прохождение ее выполнения, фрагмент работы программы:
USER>d STEPS^BREAK
B "S+"
^ <BREAK>STEPS+1^BREAK USER 2d0>g
N I
398 ГЛАВА 5. ОБРАБОТКА ОШИБОК
^ <BREAK>STEPS+2^BREAK USER 2d0>g
F I=1:1:3 W I,!
^ <BREAK>STEPS+3^BREAK USER 2d1>g
F I=1:1:3 W I,!
<BREAK>STEPS+3^BREAK USER 3f2>g 1
F I=1:1:3 W I,!
<BREAK>STEPS+3^BREAK USER 3f2>
^
^
При этом MUMPS система Cach´e дополнительно предлагает рас­ширенную и намного более мощную по своим возможностям команду ZBREAK, которая работает также в контексте терминального режима:
ZBreak location[:action:condition:execute_code]
Значения параметров команды:
location Задает место останова в виде метки или,
если начинается с символа "*", задает имя локальной переменной для останова при изменении этой локальной переменной.
action Задает режим перехода в отладочное со-
стояние с ожиданием ввода от программи­ста, аналог параметра "extend" для коман­ды BREAK.
condition Задает условие срабатывания точки оста-
нова, выражение на языке MUMPS. Ес­ли параметр опущен, то условие считается истинным по умолчанию.
execute_code Строка команд, которую надо выполнить
при переходе в режим останова.
Например, задание точки останова для переменной A и с проверяе­мым условием останова:
5.6. BREAK 399
ZBreak *A::"’$D(A)"
Эта точка останова срабатывает при таком изменении локальной пе-
ременной A, после которого значение выражения
’$D(A)
становится истинным, например:
%SYS>K A K A ^ <BREAK> %SYS 1s0>
Еще несколько примеров установки точек отладки из документации
по Cach´e:
Установить точку останова при переходе на строку TAGˆROU с пере-
ходом в режим построчного прохождения:
ZBreak TAG^ROU:"L"
Установить точку останова при переходе на строку TAGˆROU, но не останавливаться (action="N"), и если выполняется условие X < 1, то записать в переменную FLAG значение переменной X:
ZBreak TAG^ROU:"N":"X<1":"S FLAG=X"
Полный перечень параметров и опций команд BREAK и ZBREAK приведен в документации на MUMPS систему Cach´e. При использова­нии команд отладки также необходимо изучить способы продолжения выполнения программы, команды GOTO, QUIT и ZQUIT, зависимые от реализации и версии системы.
В MUMPS системе GT.M команда BREAK задает останов выполне­ния программы и выполнение указанной строки команд перед переходом в интерактивный режим отладки:
B[REAK][:tvexpr] [expr[:tvexpr][,...]]
Если выполнение программы доходит до команды BREAK, то прове­ряется ее постусловие, и, если оно выполняется, то процесс переходит в интерактивный режим. При этом выполняются задаваемые строки ко­манд.
Выдержка из документации на команду BREAK в системе GT.M:
400 ГЛАВА 5. ОБРАБОТКА ОШИБОК
GTM>ZPRINT ^br br;
kill for i=1:1:3 do break; quit
break;
write "Iteration ",i,?15,"x=",$get(x,"<UNDEF>"),! break:$data(x) "write ""OK"",!":x,"write ""Wrong again"",!":’x set x=$increment(x,$data(x))
quit GTM>DO ^br Iteration 1 x=<UNDEF> Iteration 2 x=0 %GTM-I-BREAK, Break instruction encountered
GTM>ZCONTINUE Wrong again %GTM-I-BREAK, Break instruction encountered
GTM>ZCONTINUE Iteration 3 x=1 OK %GTM-I-BREAK, Break instruction encountered
GTM>ZCONTINUE %GTM-I-BREAK, Break instruction encountered
At M source location break+2^br
At M source location break+2^br
At M source location break+2^br
At M source location break+2^br
GTM>ZCONTINUE
GTM>
Здесь при выполнении кода процесс переходит в интерактиный ре­жим отладки и сообщает о причине останова, а продолжение выполнения процесса происходит по команде ZCONTINUE.
Кроме команды BREAK MUMPS система GT.M предлагает также более мощную расширенную команду ZBREAK, имеющую больше воз­можностей, чем команда BREAK:
ZB[REAK][:tvexpr] [-]entryref[:[expr][:intexpr]][,...]
Команда ZBREAK может установить и снять точку останова на ука­занной строке, проверить выполняется ли выражение и назначить счет­чик на срабатывание точки останова, чтобы пропустить первые N оста­новов.