openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Pinaki Poddar <>
Subject Re: Is the implementation of lock(LockModeType.READ) correct?
Date Thu, 12 Feb 2009 17:43:23 GMT

The expressed view relates to Philip's use case by his own observation:
> It "works" if I run with non-enhanced classes, since then there is no
> change detection and all rows get > written and version checked.

The point is the way OpenJPA decides what is flushed in a commit is not the
entire set {A,B,C} but only {B,C} that are dirty. So 'transaction
consistency' is ensured but not 'database consistency' because another
transaction may have committed {A,B}. And that breaks the parity invariance
of the entire set {A,B,C}. 

dezzio wrote:
> Hi Pinaki,
> Actually, much as I like your concepts, I don't yet see how they 
> illuminate the issue.
> Cheers,
> David
> Pinaki Poddar wrote:
>> Hi David & Philip,
>>    I have not had the time to pay attention to the use case it deserves
>> --
>> but reading the case brings up certain aspects that I will like to share
>> with your experience.
>>   This interesting use case can fail and is failing. But the issue it
>> reveals goes beyond locking semantics. 
>> Behavior of lock is described at datum level -- the levels of warranty
>> for 
>> shared access/mutation to a *single datum* in a consistent way. 
>> Transaction goes to the next stage and describes the level of warranty of
>> a
>> set of datum as an atomic 'unit of work'. 
>> But this test case demands a even higher level of warranty -- consistency
>> or
>> invariance of a set-based property (in this case the odd-even parity of 3
>> instances), which is neither the property of an individual datum nor the
>> property of a unit of work.
>> Of course, optimism of optimistic transaction model results in weaker
>> warranty of set-based invariance. To ensure set-based property
>> invariance, a
>> transaction must commit all 3 instances (with consistent odd-even parity)
>> as
>> a unit of work, but what it does is that it reads {A,B,C} and writes only
>> {B, C}.  
>> I will refrain from describing what flags of which OpenJPA configuration
>> property can be tweaked to get there because let me first hear your
>> comments
>> on the expressed views in this posts.  
>> Philip Aston wrote:
>>> Hi David,
>>> Thanks for confirming this. So to summarise where we are, we have:
>>>  1. A reasonable use case that can fail with some unlucky timing.
>>>  2. A technical test case demonstrating the problem that does not rely
>>> on unlucky timing.
>>>  3. A disagreement in our readings of whether 1 and 2 are spec.
>>> compliant. Personally, I don't share your reading of the spec. In my
>>> reading, read locks are safe and provide a concrete guarantee that if
>>> locked entity is changed by another transaction, the locking transaction
>>> will not complete.
>>> (This is a different QoS compared to a write lock - if a write lock is
>>> obtained and the pc flushed, the transaction knows that it will not fail
>>> due to another transaction updating the locked entity. Read locks are
>>> "more optimistic" and can support higher concurrency if there is minimal
>>> contention - many transactions can hold read locks, only one can hold
>>> right locks.).
>>> How can I convince you to change your interpretation of the spec? Anyone
>>> else have an opinion?
>>> FWIW, EclipseLink passes the test case.
>>> - Phil
>>> dezzio (via Nabble) wrote:
>>>> Hi Philip,
>>>> Let's take a closer look.
>>>> We have two bank accounts, Account[1] and Account[2], shared
>>>> jointly by customers Innocent[1] and Innocent[2]. The bank's
>>>> business rule is that no withdrawal can be made the draws
>>>> the combined total of the accounts below zero. This rule is
>>>> enforced in the server side Java application that customer's
>>>> use.
>>>> At the start of the banking day, the accounts stand at:
>>>>      Account[1] balance 100.
>>>>      Account[2] balance 50.
>>>> Innocent[1] wants to draw out all the money, and asks the
>>>> application to take 150 from Account[1]. Innocent[2] also
>>>> wants to draw out all the money, and asks the application to
>>>> take 150 from Account[2]. By itself, either transaction
>>>> would conform to the bank's business rule.
>>>> The application implements the withdrawal logic by doing the
>>>> following for each transaction.
>>>> For Innocent[1], read Account[1] and Account[2]. Obtain a
>>>> read lock on Account[2]. Refresh Account[2]. Deduct 150 from
>>>> Account[1]. Verify business rule, result, sum of balances =
>>>> 0. Call JPA commit.
>>>> For Innocent[2], read Account[1] and Account[2]. Obtain a
>>>> read lock on Account[1]. Refresh Account[1]. Deduct 150 from
>>>> Account[2]. Verify business rule, result, sum of balances =
>>>> 0. Call JPA commit.
>>>> Within JPA commit, as seen over the JDBC connections, the
>>>> following time sequence occurs. (Other time sequences can
>>>> yield the same result.)
>>>> Innocent[1]: Check version of Account[2]: passes.
>>>> Innocent[2]: Check version of Account[1]: passes.
>>>> Innocent[2]: Update balance of Account[2], withdraw 150,
>>>>                  setting balance to -100: does not block.
>>>> Innocent[2]: commit: successful
>>>> Innocent[2]: Receives 150.
>>>> Innocent[1]: Update balance of Account[1], withdraw 150,
>>>>                  setting balance to -50: does not block.
>>>> Innocent[1]: commit: successful.
>>>> Innocent[1]: Receives 150.
>>>> After the two transactions:
>>>> Account[1]: balance -50
>>>> Account[2]: balance -100
>>>> Clearly the bank would not be happy. What's a developer to
>>>> do?
>>>> I think the developer needs an education about what is meant
>>>> by the JPA spec. What JPA is guaranteeing is that when JPA
>>>> commit is called, the objects with read locks will have
>>>> their versions checked. The objects with write locks will
>>>> have their versions checked and changed. The objects that
>>>> have been modified will have their versions checked, their
>>>> information updated, and their versions changed. Clearly all
>>>> of these rules were enforced in the above example.
>>>> If the developer had used write locks, both transactions
>>>> would not have succeeded. In fact, for the above example and
>>>> a similar time sequence, if write locks had been used in
>>>> place of read locks, there would have been deadlock.
>>>> Now, if in fact, I'm wrong about my interpretation of the
>>>> JPA spec (and it wouldn't be the first time) then you have a
>>>> case. I'd be curious to know whether other JPA
>>>> implementations pass your elegant test case, and what they
>>>> are doing differently that makes it so.
>>>> Also, if I am wrong about my interpretation, then the JPA
>>>> TCK needs a test case that will snag this failure, because
>>>> OpenJPA passes the current JPA TCK.
>>>> Cheers,
>>>> David
>>>> Philip Aston wrote:
>>>>> Oh yeah - my bad. Try this one instead:
>>>>> Suppose there are a set of Accounts, and a business rule that says
>>>>> that the net balance must be positive.
>>>>> Innocent wants to draw down on Account 1 as far as possible. It read
>>>>> locks the of Accounts, sums up the value, and and subtracts the
>>>>> positive total from Account 1. Innocent begins its commit, and its
>>>>> read locks are validated.
>>>>> Meanwhile InnocentToo does the same for Account 2, and commits.
>>>>> Innocent updates Account 1 and finishes its commit.
>>>>> The total in account summary is now negative, violating the business
>>>>> rule. If read locks worked as I think they should, Innocent would have
>>>>> received an OptimisticLockException.
>>>>> dezzio wrote:
>>>>>> Hi Philip,
>>>>>> When two transactions read the same version of AccountSummary, both
>>>>>> cannot successfully update its sum.  Only one will successfully
>>>>>> commit.
>>>>>> David

View this message in context:
Sent from the OpenJPA Users mailing list archive at

View raw message