Transações de grafo de objetos com cópia na escrita
THotPDF provides nested savepoints for loaded or assembled indirect-object graphs without cloning the document at transaction start
Transaction lifecycle
PDF.BeginGraphTransaction('metadata edit');
try
Info.AddStringValue('Producer', 'HotPDF');
PDF.CommitGraphTransaction;
except
PDF.RollbackGraphTransaction;
raise;
end;
BeginGraphTransaction indexes the current indirect roots and installs mutation observers but creates no snapshots; the first write to an existing indirect root in that frame creates one snapshot, and later writes to the same root reuse it
CommitGraphTransaction keeps the current graph and discards or transfers snapshots without cloning it; RollbackGraphTransaction restores root objects in place, removes objects appended after the savepoint, and restores object-number allocation
Nested transactions are independent savepoints; an inner rollback returns to the inner entry state, while an inner commit retains enough history for a later outer rollback
Automatic and explicit write preparation
THPDFDictionaryObject.AddValue, ReplaceValue, and DeleteValue, THPDFArrayObject.AddObject e SetIndexedItem, and THPDFStreamObject.Length changes notify the enclosing indirect root automatically
Public scalar fields and raw stream bytes cannot intercept assignment; call PrepareLoadedObjectForWrite before assigning Value, changing public object flags, replacing graph pointers, or writing through 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;
Memory and performance
Snapshot memory grows with touched indirect roots rather than total document size; large stream payloads spill to owned temporary files after GraphTransactionMemoryThreshold, whose default is 16 MiB
Rollback swaps saved dictionary entries, array items, and stream storage back into the existing root, avoiding a second deep copy; the root pointer remains stable, but pointers to direct descendants must be reacquired after rollback
GetGraphTransactionStatistics devolve Active, nesting Depth, SnapshotCount, AddedObjectCount, resident and spilled snapshot bytes, and peak resident snapshot bytes
THPDFBeforeMutationEvent is the low-level observer signature used to route container and lifecycle mutations to the enclosing indirect-root snapshot
Scope
Transactions cover the indirect-object graph, lifecycle state, appended roots, and object-number allocation; caller-owned pointers, loaded-page ordering arrays, rendered caches, and other facade side state are not journalled
Do not remove, reorder, or replace existing entries in GetLoadedIndirectObjects while a transaction is active; use graph container methods and reacquire direct descendants after rollback