OberonCore
https://forum.oberoncore.ru/

Кажется, ошибка в TextModels
https://forum.oberoncore.ru/viewtopic.php?f=134&t=6811
Страница 1 из 1

Автор:  adimetrius [ Суббота, 23 Октябрь, 2021 21:50 ]
Заголовок сообщения:  Кажется, ошибка в TextModels

Коллеги,

у меня завелась ошибка: иногда после закрытия документа и повторного открытия (в рамках одного запуска ББ) сохраненные изменения пропадали. Т.е. открываешь, изменяешь, закрываешь, открываешь - бац! изменения пропали. При этом в файле - измененный документ (видно через odcread). Немало времени и ядреных слов я потратил на восстановление пропащих авторских правок.
В чем же дело?
ББ гарантирует, что одному файлу соответствует один и тот же Files.File; зная это, я предполагал, что где-то в системе нет-нет, да и притаится паразитный указатель на файл, который не ликвидируется после закрытия окна с документом. У меня в ББ много "примочек" к редактору, которые кэшируют читателей TextModels.Reader (а внутри них есть иногда указатель на файл, из которого прочитан текст) и сканеры TextMappers.Scanner (а внутри них есть читатель). Я перерыл свои модули, перепроверил кэши, все аккуратно очистил - безрезультатно.

Кажется, ошибка была в TextModels. Процедура PROCEDURE (text: TextModels.Model) NewReader (rd: TextModels.Reader) позволяет, для экономии памяти, передать rd, который будет переиспользован - т.е. можно взять чтеца, попользоваться, потом переподключить его к другому тексту и пользоваться дальше. Это описано в документации и немало используется в ББ. И вот я выяснил, что при переподключении важное поле Reader.run не переинициализируется. Это видно из анализа процедур TextModels.StdModel.NewReader и TextModels.StdReader.SetPos. А именно Reader.run после чтения текста из файла содержит указатель на TextModels.Piece, который содержит указатель на Files.File - это как раз и получается "фантомная" файловая переменная, которая незримо "висит" и не дает ББ видеть обновленную версию файла.

Вот проверочный модуль. Он пишет в журнал имя "зацепленного" файла, а также показывает стек вызовов, в котором можно также убедиться в сохранении лишнего указателя.
Код:
MODULE BugReaders;

   IMPORT SYSTEM, TextModels, Views, Models, Files, Services, Log;
   
   TYPE
      Reader = POINTER TO RECORD
         eot*: BOOLEAN;
         attr*: INTEGER;
         char*: CHAR;
         view*: Views.View;
         w*, h*: INTEGER;
         base: INTEGER;   (* base = Base() *)
         pos: INTEGER;   (* pos = Pos() *)
         era: INTEGER;
         run: ANYPTR;   (* era = base.era => Pos(run) + off = pos *)
         off: INTEGER;   (* era = base.era => 0 <= off < run.len *)
         reader: Files.Reader   (* file reader cache *)
      END;
      
      Piece = POINTER TO RECORD
         prev, next, len, attr: INTEGER;
         file: Files.File
      END;
      
      File = POINTER TO RECORD
         type-: Files.Type;
         init: BOOLEAN;
         state: INTEGER;
         name: ARRAY 256 OF CHAR;
      END;
   
   PROCEDURE Hack (rd: TextModels.Reader);
      VAR nm: ARRAY 64 OF CHAR; rdr: Reader; pc: Piece; f: File;
   BEGIN
      Services.GetTypeName(rd, nm);
      IF nm # "TextModels.StdReader" THEN Log.String("~(rd IS TextModels.StdReader"); Log.Ln
      ELSE
         rdr := SYSTEM.VAL(Reader, rd);
         IF rdr.run = NIL THEN Log.String(".run = NIL"); Log.Ln
         ELSE
            Services.GetTypeName(rdr.run, nm);
            IF nm # "TextModels.Piece" THEN Log.String("~(rd.run IS TextModels.Piece"); Log.Ln
            ELSE
               pc := SYSTEM.VAL(Piece, rdr.run);
               IF pc.file = NIL THEN Log.String("rd.run.file = NIL"); Log.Ln
               ELSE
                  f := SYSTEM.VAL(File, pc.file);
                  Log.String("rd.run.file.name = "); Log.String(f.name); Log.Ln
               END
            END
         END
      END
   END Hack;
      
   
   PROCEDURE Do*;
      VAR rd: TextModels.Reader; t: Models.Model; v: Views.View;
   BEGIN
      v := Views.OldView(Files.dir.This('System/Rsrc/'), 'Menus.odc');
      t := v.ThisModel();
      WITH t: TextModels.Model DO
         rd := TextModels.dir.New().NewReader(rd);
         Hack(rd);
         rd := t.NewReader(NIL); rd.Read;
         Hack(rd);
         rd := TextModels.dir.New().NewReader(rd);
         Hack(rd);
         HALT(0)
      END
   END Do;

END BugReaders.
(!) BugReaders.Do

После BugReaders.Do в журнале - дважды имя файла System/Rsrc/Menus.odc, хотя должно быть лишь один.

А вот поправка в TextModels.StdModel.NewReader, которая, кажется, должна и исправляет ошибку:
Код:
   PROCEDURE (t: StdModel) NewReader (old: Reader): Reader;
      VAR rd: StdReader;
   BEGIN
      StdInit(t);
      IF (old # NIL) & (old IS StdReader) THEN rd := old(StdReader) ELSE NEW(rd) END;
      IF rd.base # t THEN
         rd.base := t; rd.era := -1; (*==>*) rd.run := NIL; (*<==*) rd.SetPos(0)
      ELSIF rd.pos > t.len THEN
         rd.SetPos(t.len)
      END;
      rd.eot := FALSE;
      RETURN rd
   END NewReader;


С этой поправкой BugReaders.Do, как и ожидается, выдает имя файла System/Rsrc/Menus.odc только один раз. И у меня вроде пропали фантомные файлы.

Что скажете? Прошу поразмыслить, попробовать, и в конечном итоге - предлагаю включить поправку в ББ.

Автор:  Илья Ермаков [ Воскресенье, 24 Октябрь, 2021 01:58 ]
Заголовок сообщения:  Re: Кажется, ошибка в TextModels

Хм, на Wine периодически сталкиваемся с ошибкой, что нельзя сохранить документ (не удаётся записать файл). При повторном Ctrl-S, как правило, норм.
Похоже, это ноги оттуда же растут.

Автор:  Иван Денисов [ Воскресенье, 24 Октябрь, 2021 07:55 ]
Заголовок сообщения:  Re: Кажется, ошибка в TextModels

Аргументы выглядят убедительно.

Вот тут ещё есть некий буфер, судя по комментарию, который вероятно также лучше очищать во избежание проблем?
Вложение:
reader.png
reader.png [ 18.2 КБ | Просмотров: 1339 ]

Автор:  Борис Рюмшин [ Воскресенье, 24 Октябрь, 2021 11:41 ]
Заголовок сообщения:  Re: Кажется, ошибка в TextModels

Илья Ермаков писал(а):
Хм, на Wine периодически сталкиваемся с ошибкой, что нельзя сохранить документ (не удаётся записать файл). При повторном Ctrl-S, как правило, норм.
Похоже, это ноги оттуда же растут.

Нет, это связано, на сколько я помню, с особенностями работы самого Wine.

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/