AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 20.01.2023, 14:10   #1  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Post Сборка мусора, освобождение файлов (TextIo) и блокировки.
Всем привет.

Похоже я обнаружил интересный плавающий баг ядра по работе с файлами в аксапте.
Принято считать что при вызове метода finalize() или при обнулении ссылки (а точнее всех ссылок) на файловую переменную в аксапте, ядро закрывает файл и высвобождает все ресурсы.
Finalize & null

Как бы не так. Выявился сценарий, при котором этого не происходит. Что еще хуже - высвобождение происходит, но с некоторой случайностью, может высвободиться сразу, может спустя несколько минут, а может и не высвободиться (но это редко, дольше 6 минут мы не ждали). Хотя в большинстве случаев все высвобождается нормально.

Дано:
Ax2012 R3 или ax4.0 (последний билд)
Сервер аоса win 2016 server version 1607 (OS Build 14393.5427)


Работает пакетная обработка (тестировали как в IL, так и в p-code)
1. Собирает информацию в аксапте.
2. Формирует в темп папке csv файл при помощи класса TextIo
3. Закрывает файл TextIo (finalize + обнуление файловой переменной, хотя после finalize она и так null)
4. Пакует csv файл в zip архив вызовом 7zip архиватора
5. Удаляет csv файл.
6. Кладет zip архив в базу аксапты.

Таких пакетов 35 штук.
Одновременно могут запускаться примерно до 10.

Обнаружилась проблема: случайным образом архиватор при упаковке не может получить доступа csv файлу и поэтому создает пустой архив размером 22 байта.
Как лечили
а. Поставили в коде проверку (между пп 3 и 4) на размер архива, если слишком маленький, то удаляем его, ждем 5 секунд и все по новой. И так до 72 раз (6 минут). Конечно прикрутили запись логов, из которых видно, что иногда с первой попытки все успешно, иногда с 10-й, иногда с 35 а иногда и 72 не хватает. Тогда пакетная обработка вываливается в ошибку. В большинстве случаев все нормально.
Получается, что в большинстве случаев файл отпускается сразу, но иногда спустя некоторое время. Иногда это время очень большое, так что мы не дожидались.

При этом пока идут эти 72 разрешенные попытки, есть 6 минут посмотреть самим что там проиcходит. Тотал коммандер просмотрщиком csv файл на чтение открывает. Копировать тоже позволяет. Архиватор заархивировать не может. Пишет примерно так:
Цитата:
c:\Program Files\Microsoft Dynamics AX\60\Server\YYY\bin>7za.exe a C:\Users\XXXX\AppData\Local\Temp\test-1.zip c:\Users\XXXX\AppData\Local\Temp\Article_2023-01-15_16-51-15.csv

7-Zip (a) [32] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04

Scanning the drive:
1 file, 12826 bytes (13 KiB)

Creating archive: C:\Users\XXXX\AppData\Local\Temp\test-1.zip

Items to compress: 1


WARNING: The process cannot access the file because it is being used by another process.
c:\Users\XXXX\AppData\Local\Temp\Article_2023-01-15_16-51-15.csv


Files read from disk: 1
Archive size: 22 bytes (1 KiB)

WARNINGS for files:

c:\Users\XXXX\AppData\Local\Temp\Article_2023-01-15_16-51-15.csv : The process cannot access the file because it is being used by another process.
----------------
WARNING: Cannot open 1 file
Я подумал, может есть проблема с архиватором и ему нужны какие-то эксклюзивные права на файл или он его открывает как-то не так как Total Commander (другие WinApi функции винды использует).
Попробовал WinRar
Та же проблема. Не может получить доступ к файлу.
Запускал так
Цитата:
c:\Program Files\Microsoft Dynamics AX\60\Server\YYY\bin>"c:\Program Files\WinRAR\WinRAR.exe" a -afzip -ep1 "c:\Users\XXXX\AppData\Local\Temp\Sorting_2023-01-15_18-41-46.csv_rar_ep1.zip" "c:\Users\XXXX\AppData\Local\Temp\Sorting_2023-01-15_18-41-46.csv"
Попробовал из под аоса аксапты через .Net библиотеку создавать архив - тоже выдает ошибку.
Делал через System.IO.Compression.ZipFile
как описано тут
https://community.dynamics.com/ax/f/...les-in-ax-2012

в общем, проблема, похоже, не в архиваторах.


Подумал, может проблема с файловой системой и темповая папка тормозит из-за большого числа мусорных файлов.
Проверил - примерно 9 тысяч файлов было. Зачистил. Особой разницы не заметил. Ну, может чуть реже стало глючить.

Антивируса, который мог бы блокировать в момент проверок, не было, отключили.

В итоге заменили все вызовы TextIo на System.IO.StreamWriter
Очистку ресурсов делаем как
streamWriter.Close();
streamWriter.Dispose();
streamWriter = null;

все заработало. Архиватор всегда пакует все с одной попытки. За 2 суток ни одной проблемы.
За это сообщение автора поблагодарили: Ace of Database (3), _scorp_ (5), Товарищ ♂uatr (4), alex55 (1).
Старый 20.01.2023, 14:58   #2  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Интересно, что пока решал проблему, нагуглил вот такое описание

Цитата:
https://blogs.msdn.microsoft.com/flo...x-and-the-clr/

The garbage collector in Dynamics Ax is very simple: it collects all unreferenced object every
3 seconds (ok, this is a little bit simplified, but it’s pretty much what the GC does).
Consequently you know when the object is collected: about every 3
seconds and if this doesn’t happen you can use the Form SysHeapCheck
to create a dump of the current heap, so you know how many references
are currently held to that object.

Another point that differentiates X++ with C# is the existing of a destructor.
In X++ this destructor is called "finalize()". As described on Msdn:

X++ objects are destructed automatically when there are no more references to them.
You can destruct them explicitly in the following ways:
- Use the finalize method.
- Set the object handle to null.

In X++ it's the finalize method that contains all code that is used to clean up
the instance (releases all objects that are held by this instance, ...).
In C# this is done by the Dispose() method, but I'll describe this later.
An important point is mentioned in the Msdn documentation
(
http://msdn.microsoft.com/en-us/libr...74(AX.10).aspx
https://web.archive.org/web/20130517...8AX.10%29.aspx
https://docs.microsoft.com/en-us/dyn...ectedfrom=MSDN
):

Use finalize carefully. It will destruct an object even if there are references to it.
Из него следует что в каких-то случаях сборщик мусора в аксапте может отставать на 3 секунды. Т.е. теоретически для каких-то сценариев объект может пожить до убийства сборщиком 3 секунды. Но все равно это не объясняет наших мытарств, так как тут и 6 минут ждали и все равно не всегда ресурсы высвобождались.

Вероятнее всего это какой-то глюк в ядре аксапты, воспроизводимость которого зависит от ряда (неизвестных) случайных факторов. Видимо поэтому он и не исправлен до сих пор.
Старый 20.01.2023, 15:57   #3  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Logger Посмотреть сообщение
Работает пакетная обработка (тестировали как в IL, так и в p-code)
1. Собирает информацию в аксапте.
2. Формирует в темп папке csv файл при помощи класса TextIo
3. Закрывает файл TextIo (finalize + обнуление файловой переменной, хотя после finalize она и так null)
4. Пакует csv файл в zip архив вызовом 7zip архиватора
5. Удаляет csv файл.
6. Кладет zip архив в базу аксапты.

Обнаружилась проблема: случайным образом архиватор при упаковке не может получить доступа csv файлу и поэтому создает пустой архив размером 22 байта.
Попробовал WinRar Та же проблема. Не может получить доступ к файлу.
Надо было разморозить курицу добавить параметров архиватору У WinRar это параметр -dh "compress files opened for writing", как щас помню, а у 7z вроде должны были подойти
Код:
-ssw : compress shared files                                         
-sse : stop archive creating, if it can't open some input file
Правда, потом пришлось бы руками удалять csv-файлы, которые не смог бы удалить архиватор...
Цитата:
Сообщение от Logger Посмотреть сообщение
В итоге заменили все вызовы TextIo на System.IO.StreamWriter
Очистку ресурсов делаем как
streamWriter.Close();
streamWriter.Dispose();
streamWriter = null;

все заработало. Архиватор всегда пакует все с одной попытки. За 2 суток ни одной проблемы.
На проектах D365FO тоже наступали на такие грабли, правда, там ситуация попроще, потому что в ядре появился класс TextStreamIO - аналогичный TextIO, но принимающий на вход .NET-овский Stream. В итоге там работа с файлами была переделана так:
  1. Создать FileStream
  2. Создать TextStreamIO
  3. ... что-то делать с файлом ...
  4. Вызывать FileStream.Dispose()
  5. Вызывать TextStreamIO.finalize() и, на всякий случай, делать TextStreamIO = null.

Последний раз редактировалось gl00mie; 20.01.2023 в 16:16.
За это сообщение автора поблагодарили: Logger (15), Товарищ ♂uatr (4).
Старый 20.01.2023, 16:07   #4  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Logger Посмотреть сообщение
Интересно, что пока решал проблему, нагуглил вот такое описание
Цитата:
In X++ it's the finalize method that contains all code that is used to clean up the instance (releases all objects that are held by this instance, ...). In C# this is done by the Dispose() method, but I'll describe this later.
Автор бложика - сознательно или нет - вводит людей в заблуждение: мне лично из Джеффри Рихтера, на которого он ссылается, запомнилось, что в C# метод Dispose() - это не деструктор и не аналог finalize() в X++, а метод высвобождения ограниченных ресурсов операционной системы, которыми не может управлять сборщик мусора. К таким ресурсам относятся разного рода дескрипторы (в т.ч. открытых файлов, но не только), блоки неуправляемой памяти, TCP-порты и тому подобное. Т.е. когда в C# класс реализует IDisposable, то это обычно делается именно потому, что он инкапсулирует какие-то ограниченные ресурсы системы, которые нужно уметь освободить "по команде", как в случае с закрытием файла, а не полагаться на сборщик мусора CLR.

Последний раз редактировалось gl00mie; 20.01.2023 в 16:09.
Старый 20.01.2023, 16:17   #5  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от gl00mie Посмотреть сообщение
...Надо было разморозить курицу добавить параметров архиватору ...
Вот я это чувствовал!
Раз Total Commander мог файл просмотреть и скопировать, значит и архиватор должен был уметь. Не хватило терпения дочитать все описание ключей командной строки.

Но, вообще, мне кажется, что безопаснее использовать .net классы для создания файлов. Если блокировка с файла не снята, то фиг знает, что там еще не доделано. Может не сделан flush на диск последней порции записываемых данных (хотя я это не проверял).
Теги
7zip, finalize, garbage collector, gc, rar, textio, winrar, архивирование

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
D365 как получить список всех меточных файлов swr DAX: Программирование 1 10.08.2020 10:45
Как посмотреть исходные имена файлов в MSP-пакете gl00mie DAX: Администрирование 2 19.11.2017 10:14
bojensen: Performing File IO with the TextIo Class [AX 2012] Blog bot DAX Blogs 0 04.12.2012 13:11
Хранение файлов AlexeyVS DAX: Программирование 6 03.09.2010 11:27
Мертвые блокировки при резерве Logger DAX: Программирование 36 19.11.2007 16:29

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 15:39.