Transactions de graphe d’objets à copie sur écriture

THotPDF fournit des points de sauvegarde imbriqués pour les graphes d’objets indirects chargés ou assemblés, sans cloner le document au début de la transaction

Cycle de vie d’une transaction

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

BeginGraphTransaction indexe les racines indirectes actuelles et installe des observateurs de mutation, sans créer d’instantané ; la première écriture dans une racine indirecte existante de ce cadre crée un instantané, réutilisé par les écritures suivantes dans cette même racine

CommitGraphTransaction conserve le graphe courant et abandonne ou transfère les instantanés sans le cloner ; RollbackGraphTransaction restaure les objets racine sur place, supprime les objets ajoutés après le point de sauvegarde et restaure l’allocation des numéros d’objet

Les transactions imbriquées sont des points de sauvegarde indépendants ; une annulation interne revient à l’état d’entrée interne, tandis qu’une validation interne conserve assez d’historique pour une annulation externe ultérieure

Préparation automatique et explicite des écritures

THPDFDictionaryObject.AddValue, ReplaceValue et DeleteValue, THPDFArrayObject.AddObject et SetIndexedItem, ainsi que les modifications de THPDFStreamObject.Length notifient automatiquement la racine indirecte englobante

Les champs scalaires publics et les octets bruts de flux ne peuvent pas intercepter une affectation ; appelez PrepareLoadedObjectForWrite avant d’affecter Value, de modifier des indicateurs d’objet publics, de remplacer des pointeurs de graphe ou d’écrire via 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;

Mémoire et performances

La mémoire des instantanés augmente avec les racines indirectes touchées plutôt qu’avec la taille totale du document ; les grandes charges de flux basculent vers des fichiers temporaires détenus après GraphTransactionMemoryThreshold, fixé par défaut à 16 Mio

L’annulation rétablit les entrées de dictionnaire, éléments de tableau et stockages de flux enregistrés dans la racine existante, évitant une seconde copie profonde ; le pointeur de racine reste stable, mais les pointeurs vers les descendants directs doivent être redemandés après l’annulation

GetGraphTransactionStatistics renvoie Active, la profondeur d’imbrication Depth, SnapshotCount, AddedObjectCount, les octets d’instantanés en mémoire et déversés, ainsi que le pic des octets en mémoire

THPDFBeforeMutationEvent est la signature d’observateur de bas niveau qui achemine les mutations de conteneur et de cycle de vie vers l’instantané de la racine indirecte englobante

Périmètre

Les transactions couvrent le graphe d’objets indirects, l’état du cycle de vie, les racines ajoutées et l’allocation des numéros d’objet ; les pointeurs appartenant à l’appelant, tableaux d’ordre des pages chargées, caches de rendu et autres états de façade ne sont pas journalisés

Ne supprimez, ne réordonnez ni ne remplacez les entrées existantes de GetLoadedIndirectObjects pendant qu’une transaction est active ; utilisez les méthodes de conteneur du graphe et redemandez les descendants directs après une annulation