4.14.1.2 Impact of transactions
Transactions interact with other facilities that depend on changing dynamic predicates. This section discusses these interactions.
- Last modified generation
- Using the predicate_property/2
property
last_modified_generation(Generation)
we can determine whether a predicate was modified. When a predicate is changed inside a transaction this generation is not updated. The generation for dynamic predicates that are modified in the transaction is updated to the commit generation when the transaction is committed. Asking for the last modified generation inside the transaction examines the log of modified clauses and reports the generation as one of- The global modified generation if the predicate was not modified in
the transaction and not modified outside the transaction to beyond the
start generation of the transaction. If the modified generation is
higher than the transaction start generation, this generation is
reported.
bugNote that the above implies
that inside a transaction we observe a changing last modified generation
for predicates that have only been modified outside the transaction
while these changes are not visible.
- The transaction start generation plus the local generation of the last change if the predicate is modified inside the transaction.
- The global modified generation if the predicate was not modified in
the transaction and not modified outside the transaction to beyond the
start generation of the transaction. If the modified generation is
higher than the transaction start generation, this generation is
reported.
bugNote that the above implies
that inside a transaction we observe a changing last modified generation
for predicates that have only been modified outside the transaction
while these changes are not visible.
- Wait for database changes
- The predicate thread_wait/2 does not wakeup threads for changes inside a transaction. The wakeup is delayed until the transaction is committed. Note that thread_wait/2 cannot be meaningfully called from inside a transaction because no external entities can cause changes to the dynamic database inside the transaction.
- Incremental tabling
- Consistency of tables must be restored if the transaction is rolled
back. For local tables this is realised as follows:
- Tables are either marked to be invalidated on rollback or, for monotonic tabling individual answers are marked to be removed on rollback.
- A table is marked to be invalidated if, while it is created or reevaluated, at least one dependent dynamic predicate has been modified inside the transaction.
- Answers are marked to be retracted when they result from monotonic reevaluation based on changes inside the transaction.
In other words: tables being reevaluated inside a transaction that do not depend on predicates modified inside the transaction remain valid. Monotonic tables that get new answers due to asserts inside the transaction have these answers removed during the rollback while the table remains valid. Monotonic tables that are for some reason invalidated inside the transaction are invalidated during the rollback.
Correct interaction between tabling and transaction currently only deals with local tables. Shared tables should not be combined with transactions. Future versions may improve on that. A possible route is to make a local copy from a shared table when (re)evaluation is performed inside a transaction.
Status SWI-Prolog transaction basics and API are stable. Interaction with other parts of the system that depend on dynamic predicates is still unsettled. Future versions may support non-determinism through transactions and snapshots.