Концептуальная информация про файловую систему Win.
При открытии файла ему назначается ключ - произвольное целое число (оно растёт).
При повторном открытии файла с таким же именем файловая система пытается найти уже открытый дескриптор файла.
и возвращает его, если он есть.
Файл кладётся в коллекцию финализируемых объектов и закрывается финализатором.
При создании резервной копии в редакторе файл переименовывается в .bak
При переименовании происходит поиск уже открытого описателя файла с основным именем (возвращается его ключ),
если он находится, то помечается как временный. Временный файл в финализаторе пытаемся удалить.
Проблема с резервными копиями
Проблема с резервными копиями
Последний раз редактировалось БудДен 24.09.22 18:32, всего редактировалось 3 раза.
Re: Проблема с резервными копиями
Крокодил не ловится, не растёт кокос. Нужно найти место, где временный файл превращается обратно в обычный. Как вариант, включить трассировку файловой системы. ИЛи же найти прямо в коде, где это происходит именно для сохранения файла в ИСР. Но уже не сегодня.
Re: Проблема с резервными копиями
Удалось включить трассировку (заодно нашлась проблема с литералами множеств, завёл задачу про это).
Похоже, что дело как-то связано с финализацией, потому что падает после неё.
Но странно, раньше-то всё работало. Либо на новом компьютере (более медленном)
срабатывают какие-то гонки, которые раньше не срабатывали, либо я что-то сломал. Попробую ещё попродвигаться
в направлении поиска гонок, но потом, видимо, придётся отступать в прошлое и искать момент поломки.
В плане гонок вызывает подозрение поиск объекта в множестве объектов, которые могут финализироваться.
Проблема в том, что поиск проводится процедурой, которая может возвращать даже те объекты, которые
уже приговорены к финализации. Как бы не получилось, что мы тем самым воскрешаем финализируемый объект.
Это не так сложно проверить, но странно, почему раньше такой беды никогда не случалось.
Похоже, что дело как-то связано с финализацией, потому что падает после неё.
Но странно, раньше-то всё работало. Либо на новом компьютере (более медленном)
срабатывают какие-то гонки, которые раньше не срабатывали, либо я что-то сломал. Попробую ещё попродвигаться
в направлении поиска гонок, но потом, видимо, придётся отступать в прошлое и искать момент поломки.
В плане гонок вызывает подозрение поиск объекта в множестве объектов, которые могут финализироваться.
Проблема в том, что поиск проводится процедурой, которая может возвращать даже те объекты, которые
уже приговорены к финализации. Как бы не получилось, что мы тем самым воскрешаем финализируемый объект.
Это не так сложно проверить, но странно, почему раньше такой беды никогда не случалось.
Re: Проблема с резервными копиями
Ура, версия от 15.02 (SHA 6c1561acf1) тоже так падает. Т.е. если это и я что-то сломал, то не в последнее время. А на тот момент мой старый компьютер ещё работал. Значит, дело в переходе на новый компьютер. Видимо, нужно более внимательно посмотреть на статусы возврата и поискать гонки между операциями над файлами.
Re: Проблема с резервными копиями
Шапками не закидать. Попробую проследить жизненный путь файла. Window.LoadВнутр:
Код: Выделить всё
file := Files.Old(name);
если (file # НУЛЬ) то
file.GetName(fullname);
readonly := readonly или (Files.ReadOnly в file.flags);
иначе (* эта ветка неинтересна *) всё;
(* определяем формат файла, при этом открываем его ещё раз *)
decoder := TextUtilities.DecodeAutoJQ(Ю32.Ю8_вСвежуюСтроку(fullname)^, autoCodecFormat);
(* 3-й раз открываем файл *)
in := Codecs.OpenInputStream(fullname);
(* file - локальная переменная внтури LoadВнутр, она бросается *)
Что происходит при сохранении?
Window.Store:
Код: Выделить всё
oldFile := Files.Old(nameA); (* это сам файл, со старым содержимым пока что *)
если (Files.ReadOnly в oldFile.flags) то ошибка и возврат всё;
CreateBackupFile
Строки32.Склей(filename, Лит32(".Bak"), backName);
Files.Rename(Ю32.СтрокуВСвежуюЮ8(filename)^, Ю32.СтрокуВСвежуюЮ8(backName)^, res);
key := nfs.FileKey(fold);
если key # 0 то f := FindOpenFile(seacher, nfs, key) иначе f := НУЛЬ всё;
nfs.Rename0(fold, fnew, f, res)
Код: Выделить всё
Fn := collection.ByNameNotGC( Ю16.Ю16_вСвежуюЮ8(fnnewU2)^ );
если Fn # НУЛЬ то
если ~Fn.ToTemp() то
трассируй("Rename0: не удалось превратить мешающий новый файл во временный");
возврат всё всё;
если fold # НУЛЬ то
Fo := fold( File );
если ~Fo.ToTemp() то
трассируй("Rename0: не удалось превратить старый новый файл во временный"); возврат всё;
трассируй(Fo.tfname^);
ret := Kernel32.CopyFileW( Fo.tfName^, fnnewU2, 0 )
иначе ret := Kernel32.MoveFileExW( fnoldU2, fnnewU2, {MoveFileReplaceExisting, MoveFileCopyAllowed} )
Код: Выделить всё
oldFile := НУЛЬ;
file := Files.New(nameA);
file.GetName(fullnameA);
w := Codecs.OpenOutputStream(fullnameA);
encoder.Open(w);
encoder.WriteText(currentPage.редакторТекстаДокумента.text, res);
w.ПротолкниБуферВПоток; (w бросается)
Re: Проблема с резервными копиями
Поставил вывод ключа файла в финализаторе, далее открыл файл и начал добавлять и удалять пробел, чтобы он много раз парсился. Вижу странное:
Ключ, равный нулю, возникает в процедуре Windows.WinFs.Mod/.../Unregister.Mod, а она вызывается только из ToTemp, а также в процедуре Windows.WinFs...New0, для нового файла.
Плюс к тому, дважды вызывается финализатор с одинаковым ключём. Это "жжж" явно неспроста.
Код: Выделить всё
Collections.FinalizeFile C:\ob\jaos\source\Archives.Mod, key = 0
File.Finalize C:\ob\jaos\source\Archives.Mod
Collections.FinalizeFile C:\ob\jaos\source\Archives.Mod, key = -315
File.Finalize C:\ob\jaos\source\Archives.Mod
Collections.FinalizeFile C:\ob\jaos\source\Archives.Mod, key = -315
File.Finalize C:\ob\jaos\source\Archives.Mod
Плюс к тому, дважды вызывается финализатор с одинаковым ключём. Это "жжж" явно неспроста.
Re: Проблема с резервными копиями
Уфф. Проблема была в Windows Defender. При многократном копировании он внедряет какой-то свой перехватчик копирования. Не знаю уж, что там дальше идёт не так, но если его отключить или добавить oberon.exe в список исключений Защитника Windows, то проблема исчезает.
MpDetoursCopyAccelerator.dll
Из проблем других людей:
Но понятно, что придётся заняться файловой системой вплотную. Обероновская идея о монопольном владении файлом не работает, когда мы находимся внутри другой ОС. Значит тут даже на идейном уровне нужно что-то переделывать, и эта переделка будет большой и затронет всю работу с файлами. Т.к. закрывать файлы тут не принято, принято их бросать и это носит тотальный характер.
Кроме того, работа в условиях монопольного владения файловой системой кардинально отличается от работы во внешнем мире, когда нужно учитывать существование других игроков. Т.е. и прикладная логика усложняется. Короче, это фундаментальная проблема, если мы хотим не только режим ОС, но и режим приложения. Получается, что код и бизнес-логика должны нести издержки за немонопольность, даже если мы работаем в режиме ОС. Ого-го.
MpDetoursCopyAccelerator.dll
Из проблем других людей:
Не знаю, что они понимают под своей "виртуальной файловой системой", но, по всей вероятности, копирование падает по той причине, что файл всё ещё открыт в нашем процессе oberon.exe. В этом случае можно было бы попробовать закрывать файл, однако в общем случае неясно, как это сделать. Там построена хрупкая конструкция, позволяющая нескольким клиентам пользоваться одним и тем же файловым дескриптором от ОС. Для новых файлов это не работает. Файлу нужно по идее делать Register, но некоторые файлы бросаются с одним только New, но без Register. Короче говоря, там всё в таком состоянии, что "работает - не трогай".Когда CopyFile вызывается игрой несколько раз (по нашему опыту, от 5 до 7 раз), игра внезапно загружает MpDetoursCopyAccelerator.dll, а другой процесс (я полагаю, процесс Defender) заботится о фактической копии. Поскольку этот другой процесс не работает в контексте нашей виртуальной файловой системы, операция копирования завершится неудачно
Но понятно, что придётся заняться файловой системой вплотную. Обероновская идея о монопольном владении файлом не работает, когда мы находимся внутри другой ОС. Значит тут даже на идейном уровне нужно что-то переделывать, и эта переделка будет большой и затронет всю работу с файлами. Т.к. закрывать файлы тут не принято, принято их бросать и это носит тотальный характер.
Кроме того, работа в условиях монопольного владения файловой системой кардинально отличается от работы во внешнем мире, когда нужно учитывать существование других игроков. Т.е. и прикладная логика усложняется. Короче, это фундаментальная проблема, если мы хотим не только режим ОС, но и режим приложения. Получается, что код и бизнес-логика должны нести издержки за немонопольность, даже если мы работаем в режиме ОС. Ого-го.