Transacciones copy-on-write del grafo de objetos

THotPDF proporciona savepoints anidados para grafos de indirect objects cargados o ensamblados, sin clonar el documento al iniciar la transacción

Ciclo de vida de la transacción

PDF.BeginGraphTransaction('metadata edit');
try
  Info.AddStringValue('Producer', 'HotPDF');
  PDF.CommitGraphTransaction;
except
  PDF.RollbackGraphTransaction;
  raise;
end;

BeginGraphTransaction indexa las raíces indirectas actuales e instala observers de mutación, pero no crea snapshots; la primera escritura sobre una raíz indirecta existente en ese frame crea un snapshot, y las escrituras posteriores sobre la misma raíz lo reutilizan

CommitGraphTransaction conserva el grafo actual y descarta o transfiere los snapshots sin clonarlo; RollbackGraphTransaction restaura los objetos raíz in situ, elimina los objetos añadidos después del savepoint y restaura la asignación de números de objeto

El rollback invalida el cache de relaciones de formulario cargado antes de restaurar los objetos, así que las búsquedas de campos posteriores se reconstruyen desde el grafo restaurado en lugar de retener referencias a campos o widgets eliminados

Las transacciones anidadas son savepoints independientes; un rollback interno vuelve al estado de entrada interno, mientras que un commit interno conserva historial suficiente para un rollback externo posterior

Preparación automática y explícita de escrituras

THPDFDictionaryObject.AddValue, ReplaceValue y DeleteValue, THPDFArrayObject.AddObject y SetIndexedItem, y los cambios de THPDFStreamObject.Length notifican automáticamente a la raíz indirecta que los envuelve

Los campos escalares públicos y los bytes crudos del stream no pueden interceptar la asignación; llame a PrepareLoadedObjectForWrite antes de asignar Value, cambiar flags públicos del objeto, reemplazar punteros del grafo o escribir a través de 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;

Memoria y rendimiento

La memoria de snapshots crece con las raíces indirectas tocadas, no con el tamaño total del documento; los payloads grandes de stream se derraman a archivos temporales propios después de GraphTransactionMemoryThreshold, cuyo valor por defecto es 16 MiB

El rollback intercambia de vuelta las entradas de diccionario, los elementos de array y el almacenamiento de stream guardados dentro de la raíz existente, evitando una segunda copia profunda; el puntero de la raíz permanece estable, pero los punteros a descendientes directos deben readquirirse después del rollback

GetGraphTransactionStatistics devuelve Active, la Depth de anidamiento, SnapshotCount, AddedObjectCount, los bytes residentes y derramados de snapshots, y el pico de bytes residentes de snapshots

THPDFBeforeMutationEvent es la firma de observer de bajo nivel usada para enrutar las mutaciones de contenedores y de ciclo de vida hacia el snapshot de la raíz indirecta que envuelve

Alcance

Las transacciones cubren el grafo de indirect objects, el estado de ciclo de vida, las raíces añadidas y la asignación de números de objeto; los punteros propiedad del caller, los arrays de orden de páginas cargadas, las cachés renderizadas y demás estado lateral del facade no se journalean

No elimine, reordene ni reemplace entradas existentes en GetLoadedIndirectObjects mientras haya una transacción activa; use los métodos de contenedor del grafo y readquiera los descendientes directos después del rollback