![]() |
#1 |
Участник
|
Анализатор незакрытых транзакций
У нас нередко возникала проблема с незакрытыми транзакциями (непарные ttsbegin/ttscommit). Мы пытались их устранять, искали и исправляли код с такими ошибками, но это было медленно и не очень успешно.
Для возможно более полного решения этой проблемы я написал программу для автоматического поиска подобных ошибок, с помощью которой мы выявили (а затем устранили) немалое их количество. Программа предназначена для Ax 3.0, (но, наверное, будет работать и с другими версиями Axapta, но с худшими результатами) и обрабатывает .xpo-файлы (но job-ы не обрабатываются). Принцип работы простой: считается, что все открытые в методе транзакции должны быть в нём закрыты. Вообще программа использует набор эвристик, из-за чего могут быть как ложноположительные, так и ложноотрицательные результаты. В частности, циклы обрабатываются очень приблизительно. Кроме того, макросы программа не раскрывает, а просто "угадывает", что там могло быть (синтаксически). Как пользоваться: 1. Эскпортируете объекты в какой-нибудь файл.xpo. 2. В cmd.exe или его аналоге (analyzer --- консольное приложение): > analyzer.exe этот_файл.xpo > result.txt 3. Упорно ждёте завершения обработки, затем анализируете result.txt. ![]() Если хотите попробовать на новых версиях Dynamics AX, то указывайте кодировку обрабатываемых файлов, например: > analyzer.exe aot.xpo utf-8 > aot_result.txt При сбоях в работе анализатора выдаются такие сообщения: . Parse error. Token <x> in block <y>, state <z> Данное сообщение означает, что произошёл сбой синтаксического анализатора, при этом указанный метод НЕ анализируется. Пример: public void insert() { if if(!this.ABCCalcJourID) ttscommit; \Tables\ABCCalcJour\insert, line 3: -- Parse error. Token <if> in block <CondExpr>, state <Start> . !ParseWarning: Unrecognized command (something) Данные сообщения означают, что выявлена неизвестная анализатору команда или слово, открывающее блок. Анализ при этом продолжается. Выявляемые предупреждения: . 'break' is used outside of a loop or switch! . 'continue' is used outside of a loop! -- использование break/continue вне циклов/switch-ей. . 'ttsabort' inside 'catch' is useless! -- ttsabort внутри catch бесполезен (в нашей Ax 3.0/MSSQL это так). . multiple ttsbegin/ttscommit pairs in linear block! -- несколько транзакций в линейном блоке, обычно это ошибка. Выявляемые ошибки: . 'try' is useless inside transaction!" -- try внутри транзакции бесполезен (в нашей Ax 3.0/MSSQL это так). . 'return' with incorrect ttslevel! -- выход из метода с некорректным уровнем tts. . ttslevel<0! . unpaired transaction! ------------------------------------------------- В нашем случае результаты для всего AOT такие: Время анализа: около 5 минут (313 сек). Всего выявлено ошибок и предупреждений: 335 Из них: Корректных ошибок и предупреждений: 286, ~85% Формально ошибочных, но корректных (методы 'ttsbegin' и т.п.): 30, ~9% Некорректных предупреждений: 7, ~2% Ложноположительных результатов: 10, ~3% Hack-ов (while (appl.ttsLevel()>0) ttscommit; ) : 2, менее 1% Интересно, какие результаты получатся у Вас. |
|
|
За это сообщение автора поблагодарили: Logger (10), Raven Melancholic (1), alex55 (3), imir (2). |
![]() |
#2 |
Участник
|
Это конечно круто.
Но если вам приходится прибегать к таким ухищрениям, то какое же наследство вы разгребаете ![]() |
|
![]() |
#3 |
Участник
|
Это да: "Корректных ошибок и предупреждений: 286". Из них около 40 ошибок с транзакциями в методах, которые реально используются. На этом приложении многие разрабатывали...
![]() А Вы на своих приложениях/проектах попробовали? |
|
![]() |
#4 |
Участник
|
Такую задачу решают стандартные проверки best practics. Правда по всему приложению не за 5 минут (313 сек), а за то время, которое требуется на компиляцию.
|
|
![]() |
#5 |
Участник
|
Цитата:
Мы настолько все не запускали. У нас другое развлечение было - диалоги в транзакциях. Ну это легко отлавливается. |
|
![]() |
#6 |
Участник
|
А у Вас какая версия Axapta?
Я вот беру код типа: ------ X++: ttsbegin; if (!inventTable.AFPGroupId) { if (cry) warning(strfmt("@KCL2642", inventTable.ItemId)); return; } while select AFPGroupLines where AFPGroupLines.GroupId == inventTable.AFPGroupId { AFPUnit::createUnit(inventTable.ItemId, AFPGroupLines.InventLocationId, _combination); } ttscommit; Запускаю проверку Best Practices, и никаких предупреждений не вижу. |
|
![]() |
#7 |
Участник
|
|
|
![]() |
#8 |
Участник
|
Возможно я слишком самонадеян.
Попробую прогнать вашим инструментом. |
|
![]() |
#9 |
Участник
|
Да, и у нас встречалась пара - тройка таких косяков. Поскольку у нас ничего критичного(кроме неудобства) не происходило, остановились на том, что джобик с одной строчкой ttsabort; всегда есть под рукой.
__________________
-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. |
|
![]() |
#10 |
Роман Долгополов (RDOL)
|
Цитата:
![]() |
|
![]() |
#11 |
Участник
|
Цитата:
Сообщение от db
![]() Ну по всякому бывает. Бывает что не сильно критично, а бывает что и очень даже. На моей памяти был косяк когда пакетник в трешке несколько суток импортировал из внешней системы документы и справочники. Из за вставленного кем-то посреди метода return всё это накопилось в очень длинные транзакции, "завершившиеся" только когда на оракловой базе в логах кончилось место вместе с вполне логичным откатом всего нажитого за эти дни
![]()
__________________
-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. |
|
![]() |
#12 |
Участник
|
Цитата:
X++: ttsCommit; ... ttsBegin; Просто когда-то на одной из прошлых работ я расширял BP по поводу парности ttsBegin/ttsCommit таким образом, чтобы проверялось не только количество, но и порядок и наличие между началом и подтверждение транзакции возвратов, прерываний, продолжений (в этом случае выдавал не ошибку или предупреждение, а просто сообщение, поэтому ловилось только при определенной настройке BP). За давностью лет решил, что это и есть стандарт. Ладно, вспомню что тогда делал и добавлю в наше приложение. А Вам рекомендую вписать Вашу проверку в метод checkSource класса SysBPCheckMemberFunction. В этом случае не нужно будет что-то выгружать в проекты, а контролировать все это дело в рамках текущей разработки. |
|
![]() |
#13 |
Участник
|
|
|
![]() |
#14 |
Участник
|
Мощно конечно, но если возникают такие вещи в коде, напрашивается вопрос: Вы вообще рефакторинг делаете? Разбив сложный метод с транзакциями на несколько простых, можно все-таки транзакции вычленить примерно в такую форму:
X++: void complexMethod() { ttsbegin; simpleMethods(); ttscommit; }
__________________
// no comments |
|
![]() |
#15 |
Участник
|
В любом приложении должен быть на первом месте такой джоб
![]() X++: static void aaa_ttscommit(Args _args) { ; info(int2str(appl.ttsLevel())); while (appl.ttsLevel()) ttscommit; } |
|
![]() |
#16 |
Участник
|
|
|
![]() |
#17 |
Участник
|
Попробовал на АХ3 и АХ4, пишет ошибку:
invalid command name "Exportfile" while executing "Exportfile for AOT version 1.0 or later"
__________________
// no comments |
|
![]() |
#18 |
Участник
|
А у меня работает на этом файле. А как Вы запускаете (какая командная строка, с локального или сетевого диска), какая у Вас операционная система?
|
|
![]() |
#19 |
Участник
|
Цитата:
Просто, если он уже читает первую строчку "Exportfile for AOT version 1.0 or later" и пишет, что это invalid command, то вам надо смотреть в сторону обработки строк.
__________________
// no comments |
|
![]() |
#20 |
Участник
|
Цитата:
![]() И ещё, можете попробовать версию из вложенного файла? Последний раз редактировалось Ярослав Щекин; 16.07.2013 в 11:38. |
|
Теги |
ttscomit, best practice |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|