Transaction isn't even quite that, it is the controller for the
'current' transaction and also a builder for thread independent
transactions. Current transaction may or may not refer to a thread local
graph.
I agree that this is confusing, mostly because it bucks the trend of
using the connection factory to handle shared state between connections.
Matt is correct that it would be much simpler if every thread that
access to a graph should just obtain a new Graph instance from a
GraphFactory instance. Creating a GraphFactory should be expensive, but
creating multiple graphs from that factory should be cheap. You could
then get rid of the Transaction interface altogether and move commit()
and rollback() back on to the graph, all thread local stuff can go and
every graph becomes thread independent.
//The graph factory instance will handle sharing resources. The concrete
implementation of the factory will be provided by the graph provider.
GraphFactory gf = GraphFactory.open(props);
//These graphs will all point to the same underlying data.
Graph g1 = gf.create();
Graph g2 = gf.create();
Graph g3 = gf.create();
g1.commit();
g2.commit();
g3.commit();
This way if the client wants to stash a graph in a thread local then
they are free to do it under their own terms. We don't interfere with
the application threading model.
However, it would be such a major change..... Perhaps this could be
considered for TP4?
On 10/10/15 16:53, Matt Frantz wrote:
If the threading model is well-defined, then ThreadLocal can be a
convenient way to inject state. For example, if you have a pool of
long-lived worker threads, then each worker thread can store state related
to shared objects in ThreadLocal. However, if the threading model is less
well-defined or there is no clear affinity between threads and the shared
objects, then ThreadLocal can be awkward for some situations, such as the
ones you point out where multiple threads collaborate on a Transaction.
I'm trying to uncover the requirements here, and understand why the
Transaction.onReadWrite state cannot simply manifest in the Transaction
object itself, as it appears to do in my read of the Transaction class.
When you call graph.tx().onReadWrite(X), is the intent to affect one
Transaction or all Transactions from that point onward [in the caller's
thread]?
[reads code]
Ah, now that I see Graph.tx()'s Javadoc, it appears I misunderstood what
Transaction means. Transaction is not a transaction, but is something more
like a Transaction builder. Is there an interface that represents a single
transaction?
Graph might therefore be better understood as a conflation of the graph
itself and a way of (==set of options for) interacting with the graph.
Could a client simply instantiate multiple Graph objects to maintain
different ways of interacting with the underlying graph?
Could we cleave the two aspects of Graph into Graph and TransactionBuilder?
On Sat, Oct 10, 2015 at 4:36 AM, Stephen Mallette <[email protected]>
wrote:
It sounds like you're proposing a bigger picture change to transactions
than just what this particular issue is about. Just to be clear, Dylan and
I were trying to come to conclusion on a specific problem with Transactions
within our existing model. For that, I'm not sure I see a way outside of
ThreadLocal for that issue. If i'm wrong in understanding your proposal
perhaps you need to add more details.
More generally speaking, in terms of the bigger picture, ThreadLocal has a
convenience for transactions but also is a genuine pain for a lot of
applications (server applications). Perhaps you could expand your thoughts
a bit as you might bring a new perspective on how to do this stuff. Of
course, i would imagine it pretty hard to change our flow on that at this
point, but I suppose it doesn't hurt to talk about it.
On Fri, Oct 9, 2015 at 5:58 PM, Matt Frantz <[email protected]>
wrote:
Sometimes, use of thread-local storage is a code smell. It's a "global"
variable from the standpoint of the thread. Assuming in this case that
the
Transaction object itself is not the appropriate place for this state,
then
is there something like a TransactionFactory abstraction that could
encapsulate the context that is being stored in ThreadLocal, and then
provided explicitly to the txn?
On Fri, Oct 9, 2015 at 10:54 AM, Stephen Mallette <[email protected]>
wrote:
Graphs that support transactions in TinkerPop (going back to
Blueprints)
have always implemented as ThreadLocal, meaning the transaction is
bound
to
the thread it is executed in. Some graphs, those that can support it,
can
break out of that model with a "threaded transaction":
http://tinkerpop.incubator.apache.org/docs/3.0.1-incubating/#_threaded_transactions
In this case multiple threads can operate on the same transaction.
On Fri, Oct 9, 2015 at 1:43 PM, Matt Frantz <
[email protected]>
wrote:
This is the first time I've noticed a reference to ThreadLocal in a
TP
discussion, so if you could share a bit of background, I'd appreciate
it.
What is the concurrency model for TP from the client standpoint?
When
you
say "thread local", do you mean the client thread? Does this
behavior
port
across other client libraries, especially threadless environments
like
JavaScript?
I understand API's that affect transactions, but not ones that affect
threads. Can't this be a Transaction API?
On Fri, Oct 9, 2015 at 7:32 AM, Stephen Mallette <
[email protected]
wrote:
Not sure why, but from the beginning I'd thought of this settings
as
being
global to the Graph instance, but framed in this context, it
doesn't
seem
right (in any context). I agree with Dylan that this setting
should
be
ThreadLocal.
On Fri, Oct 9, 2015 at 8:58 AM, Dylan Millikin <
[email protected]
wrote:
Hey guys,
It's become apparent from the discussion in the following issue
that
there
are some limitations with making the transactional
READ_WRITE_BEHAVIOR
global to all graph operations (
https://issues.apache.org/jira/browse/TINKERPOP3-875 )
With gremlin-server as an example this implies that:
If you issue
graph.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL)
(as is automatic when you use the sessionOpProcessor) every
subsequent
request will need to handle transactions manually. I think this
also
includes other clients that have no idea this operation was
performed.
The side effect of this is that sessionless requests
(StandardOpProcessor)
that should be automatically committed, break.
Seeing as fixing this would be a breaking change, let's discuss
pros
and
cons and depending on how things go, create another JIRA ticket
(the
one
linked earlier is being used for another issue)
Best,
Dylan