[Dev] Shared transactions

Brett Wooldridge bwooldridge at alterpoint.com
Mon Aug 27 17:59:57 CDT 2007


I put the Elf in because code to test whether a transaction was in progress
and conditionally join or start was 14 recurring lines of code.  However I
must say that even adding the Elf made me queasy, and this discussion has me
reconsidering it's use at all.  In fact I'm virtually certain of the error
of my ways, now.  Here's why.

The fact that we have a beginOrJoinTransaction() semantic in our code is
itself indicative of a poor ownership model.  We really should know
explicitly who the owner of the transaction is -- everything "underneath"
should assume someone else is in control.  If the 'layers' of the
application are clear and apparent -- with transactions residing "above" a
certain layer -- the need to begin OR join should not arise.  There's an
exception to every rule, but it should be extremely rare to need to do so.

If I remember, the "need" first arose in either the createDevice() method of
DeviceProvider or createDirectoryEntry() of Directory.  CreateDevice()
initially assumed (correctly) that it was 'joining' a transaction -- whoever
was calling it, owned it.  At the time the one caller was Discovery.
However, as we added the ability of the client to directly call
createDevice() it introducted the possibility that a transaction DIDN'T
exist.  This occurred in several more spots of differing call chains, and
rather than examining more carefully where the ownership should reside and
getting annoyed by the 14 lines of code required to Begin or Join, I created
the Elf.  It has to be wrong.  I can smell it.  :-)  You smelled it without
even knowing the root cause.  Anything we do now to make it simpler or make
it symmetric is lip-stick on a pig.

In a "normal" application server, entry into the container from a client is
one place a transaction gets initiated and terminated (on exit).  This is
the client call to createDevice(), for example.  So, either in the SOAP
invocation servlet (preferred) -- ZwsServlet -- or in the Delegates (less
preferred) we should surround the invocation with a transaction.  This
covers all of the externally facing API cases.

I'll need to noodle on where to draw the line in the other services for
'cross-service' invocation, but clearly (for example) the Discovery callback
is an 'owner' of the transaction with respect to createDevice().  The
entirely of the DeviceProvider implementation is probably just a 'joiner' of
transactions but never an initiator.

I shouldn't have defended the Elf in the first place.  My gut was telling me
to resist making it any more complex because I was already queasy about it's
existence.  The Elf must die.  The code will be better for it.

-Brett


On 8/27/07 5:03 PM, "Leo Bayer" <lbayer at alterpoint.com> wrote:

> I'm not saying always use the reference counting.  But in those cases
> where we are explicitly 'or join'-ing it is implicitly what is happening
> but in the 'or join' scenario you have to conditionally commit.  Maybe
> just adding a method like "commitOrLetGuyWhoOwnsItDoIt()" on the elf
> would make me feel better.  It would be more symmetrical to the
> beginOrJoin() method.  Also, the extra three lines of code that the if
> statement requires make me feel uneasy.
> 
>  - Leo
> 
> Brett Wooldridge wrote:
>> I know it seems like an obvious pattern to use (reference counting) and
>> slightly simpler than what we have (only slightly), but it has some inherent
>> flaws which is why JTA (and no transaction manager that I'm aware of)
>> employs it.  Imagine how easy (code-wise) it would have been for JTA to
>> embed reference counting in the UserTransaction object.
>> 
>> The first issue is that the transaction may not be initiated by our code.
>> It could, for example, be initiated inside of Quartz (which has the ability
>> to run jobs as transactions) or some other third-party library.  Or Bundles
>> from our codebase could ultimately be run inside of an application server
>> such has JBoss which itself is managing the transaction boundaries.
>> 
>> A reference counting model could also interfere with Distributed
>> Transactions which are supported by JTA.  I wouldn't want to close the door
>> on ZipTie in the future deploying in a multiple-server model and possibly
>> needing distributed transactions between physical machines (
>> http://archive.devx.com/java/free/articles/dd_jta/jta-1.asp).
>> 
>> Lastly, two minor nits I would have with a reference counting pattern
>> (besides those above) is that 1) it would elevate the Elf to being a
>> Manager, because now it becomes stateful in tracking threads->counters, and
>> 2) I don't like that when debugging and "stepping over" a commit() you don't
>> really know if that was THE commit or just a dummy commit().  Meaning an
>> explicit call to commit() from application code is not an explict commit of
>> the transaction.
>> 
>> -Brett
>> 
>> On 8/27/07 4:01 PM, "Leo Bayer" <lbayer at alterpoint.com> wrote:
>> 
>>   
>>> Brett,
>>>   Instead of doing a beginOrJoin for transactions would it make sense to
>>> use some sort of "re-entrant" transaction.  Doing so would allow the
>>> usage of a transaction to not care if it is the owner or not and would
>>> call commit with the assumption that the last commit in the stack
>>> performs the actual commit.
>>> 
>>> For example:
>>>   begin(); // begins the transaction
>>>      begin(); // increments the begin count, does not begin a new
>>> transaction
>>>      commit(); // decrements begin count, does not commit
>>>   commit(); // performs the commit
>>> 
>>> Just a thought,
>>>  - Leo
>>> 
>>> _______________________________________________
>>> Dev mailing list
>>> Dev at ziptie.org
>>> http://mailman.ziptie.org/listinfo/dev
>>> 
>>>     
>> 
>> _______________________________________________
>> Dev mailing list
>> Dev at ziptie.org
>> http://mailman.ziptie.org/listinfo/dev
>>   
> _______________________________________________
> Dev mailing list
> Dev at ziptie.org
> http://mailman.ziptie.org/listinfo/dev
> 



More information about the Dev mailing list