Processing Transactions

Processing transactions

After a transaction data structure is built, you must submit it to the transactor for processing. The transactor queues transactions and processes them serially. Since the transactor is not processing queries (they are handled in the peers), no locking is required and the processing is very fast.

Submitting transactions

Once a transaction data structure is built, you submit it to the transactor by calling the datomic.Connection.transact or transactAsync method. Both methods return a Future<Map>. Its get method returns a map with information about transaction if the transaction commits and throws an exception if the transaction aborts. In Clojure, you can also use the deref method or @ to get a transaction's result.

txResult = conn.transact(tx).get();

future = conn.transactAsync(tx);

... // do other work

txResult = future.get();

Transaction Timeouts

The transact method is synchronous, it waits until the transaction completes before returning. The transactAsync method is asynchronous, it submits the transaction to the transactor and returns immediately. A call to get on the Future<Map> returned from transactAsync will block until the transaction completes. Application code should use the overload for get that takes a timeout value expressed as a long and a java.util.concurrent.TimeUnit in order to ensure that the calling thread never blocks indefinitely.

When a transaction times out, the peer does not know whether the transaction succeeded, and will need to query a recent value of the database to discover what happened.

Monitoring transactions

Peers can monitor all transactions being processed by the system's transactor. The datomic.Connection.txReportQueue method provides a method to get a queue of transaction notifications.

The queue delivers a report for every transaction submitted while a peer is connected to the database, even those submitted by other peers. The reports are instances of the datomic.TxReport type, which provides access to the value of the database before and after the transaction was applied, and the set of facts added by the transaction.

Once your code gets the transaction report queue, reports will be added to it. It is the responsibility of your peer code to empty the queue. When you are done monitoring the queue, you must remove it by calling the datomic.Connection/removeTxReportQueue method so it doesn't continue to consume memory.

This example shows how to connect to the notification queue, and retrieve a transaction report from it.

queue = conn.txReportQueue();

report = (Map) queue.poll();

The report map contains the following keys, which are static members of the datomic.Connection class:

key usage
DB_BEFORE database value before the transaction
DB_AFTER database value after the transaction
TX_DATA datoms produced by the transaction
TEMPIDS used to resolve temporary ids

The TX_DATA member of a transaction report contains the set of datoms created by a transaction (both assertions and retractions). The TX_DATA can be used as an input source for a query. The query below uses the transaction data and the database value after the transaction was applied to show each datom of the transaction.

[:find ?e ?aname ?v ?added
 :in $ [[?e ?a ?v _ ?added]]
 [?e ?a ?v _ ?added]
 [?a :db/ident ?aname]]

The query expects the DB_AFTER and TX_DATA values of a transaction report as its two input sources, in that order.

See Query for more information on using sets of tuples as input sources in queries.