thinkaurelius/titan — pull request #390 by batali (2013-09-26 21:47:29+00:00)
Title: Added saveModifiedRelations and beginBackendTransaction

Here is a description of the two changes I made to Titan and
why we need them.

1. added method saveModifiedRelations to StandardTitanTx.

This method takes two arguments: the collections of added, and
deleted, internal relations from the transaction. It is used in the
commit() method of StandardTitanTx before calling the commit() method
of the backendTransaction handle of the StandardTitanTx.

The default implementation of this method calls the save() method of
the transaction's graph, which creates and collects all of the
required mutations required for the backend transaction to persist the
modifications represented in the added and deleted relations
collections.

Making this a separate, override-able method, allows different
subclasses of StandardTitanTx more control over how the modifications
of the transaction are persisted.

In particular, we want to be able to collect the transaction's
modifications so that they can be stored to record the "delta" this
transaction would inflict on the graph. The delta is recorded, so
that we can keep track of the history of modifications to the graph,
and is actually applied to the graph, and the changes committed, by a
different process (after using a message queue to collect impose an
ordering on deltas from different threads).

2. added method beginBackendTransaction to StandardTitanGraph.

This method simply calls the beginTransaction() method of the graph's
backend, wrapped in a try/catch block to convert StorageExceptions
into RunTime exceptions.

This method is needed to make it possible for subclasses of
StandardTitanGraph to be able to use subclasses of StandardTitanTx.

All transactions created by a StandardTitanGraph are created in the
method newTransaction.

The original version of this method creates and returns a new instance
of StandardTitanTx, passing the graph, an instance of a
transactionConfig, and a newly created backend transaction (created by
calling backend.beginTransaction()) to the StandardTitanTx constructor
method.

The only constructor for StandardTitanTx requires three arguments: a
graph, a transaction config, and a new BackendTransaction. The
constructor for any subclasses of StandardTitanTx must therefore
provide these arguments. The graph and TransactionConfig are easily
obtained from a StandardTitanGraph, however is private.

One solution would have been to make the backend field of a
StandardTitanGraph protected, however this is more than we really
need.

By adding beginBackendTransaction as a protected method, the third
required argument to the StandardTitanTx constructor can be created,
making it possible to override newTransaction to create and return a
subclass of StandardTitanTx.

How we used the changes:

We create a subclass of StandardTitanTx that overrides the
saveModifiedRelations method (discussed above), to collect the "delta"
represented by the modified relations and send them to a message queue
(which is stored in the transaction instance), instead of turning them
into mutations for the backend to execute.

Our subclass of StandardTitanGraph is created with the message queue
for posting the deltas collected by the new Transaction instances.
The newTransaction method of this graph creates an instance of our new
Transaction class with the graph, the transaction configuration, the
new backend transaction, and the message queue.

Nothing else needs to be changed. When the graph's commit() method
called, its current transaction's commit() method is called. This
method calls our override of the saveModifiedRelations method, which
collects the delta represented by the modified relations and sends it
to the message queue. Since no mutations are recorded in the backend
transaction handle of our modified transaction instance, the call to
the backendTransaction's commit() method has no effect other than to
clear any caches created for the transaction.