Транзакции графа объектов copy-on-write
THotPDF даёт вложенные savepoint для загруженных или собранных графов косвенных объектов без клонирования документа на старте транзакции
Жизненный цикл транзакции
PDF.BeginGraphTransaction('metadata edit');
try
Info.AddStringValue('Producer', 'HotPDF');
PDF.CommitGraphTransaction;
except
PDF.RollbackGraphTransaction;
raise;
end;
BeginGraphTransaction индексирует текущие косвенные корни и ставит наблюдателей мутаций, но не создаёт снимков; первая запись в существующий косвенный корень в этом кадре создаёт один снимок, а последующие записи в тот же корень переиспользуют его
CommitGraphTransaction оставляет текущий граф и отбрасывает или передаёт снимки без клонирования; RollbackGraphTransaction восстанавливает корневые объекты на месте, удаляет объекты, добавленные после savepoint, и восстанавливает выделение номеров объектов
Вложенные транзакции — независимые savepoint; внутренний откат возвращает к состоянию на входе во внутреннюю, а внутренний commit сохраняет достаточно истории для последующего внешнего отката
Автоматическая и явная подготовка к записи
THPDFDictionaryObject.AddValue, ReplaceValue и DeleteValue, THPDFArrayObject.AddObject и SetIndexedItem, а также изменения THPDFStreamObject.Length сами уведомляют объемлющий косвенный корень
Публичные скалярные поля и сырые байты stream не могут перехватить присваивание; вызывайте PrepareLoadedObjectForWrite перед записью в Value, изменением публичных флагов объекта, заменой указателей графа или записью через THPDFStreamObject.Stream
PDF.BeginGraphTransaction('raw stream edit');
try
PDF.PrepareLoadedObjectForWrite(StreamObject);
StreamObject.Stream.Size:= 0;
StreamObject.Stream.WriteBuffer(Bytes[0], Length(Bytes));
StreamObject.Length:= Length(Bytes);
PDF.CommitGraphTransaction;
except
PDF.RollbackGraphTransaction;
raise;
end;
Память и производительность
Память снимков растёт по числу затронутых косвенных корней, а не по общему размеру документа; крупные payload stream после GraphTransactionMemoryThreshold (по умолчанию 16 MiB) вытесняются в собственные временные файлы
Откат подменяет сохранённые записи словарей, элементы массивов и хранилище stream обратно в существующий корень, избегая второго глубокого копирования; указатель корня остаётся стабильным, но указатели на прямых потомков после отката нужно получить заново
GetGraphTransactionStatistics возвращает Active, глубину вложенности Depth, SnapshotCount, AddedObjectCount, резидентные и вытесненные байты снимков и пиковые резидентные байты снимков
THPDFBeforeMutationEvent — низкоуровневая сигнатура наблюдателя, через которую мутации контейнеров и жизненного цикла маршрутизируются в снимок объемлющего косвенного корня
Область действия
Транзакции покрывают граф косвенных объектов, состояние жизненного цикла, добавленные корни и выделение номеров объектов; указатели вызывающего, массивы порядка загруженных страниц, кэши рендеринга и прочее побочное состояние фасада не журналируются
Пока транзакция активна, не удаляйте, не переставляйте и не заменяйте существующие записи в GetLoadedIndirectObjects; используйте методы графовых контейнеров и после отката заново получите прямых потомков