Hi David, EL does an update for each read lock at commit time, setting its version column to the same value. See my other post - I agree that SELECT FOR UPDATE is not appropriate for read locks, and I instead suggest a third approach; that is to do the optimistic lock checks for read locks after the INSERT, DELETE, and UPDATES for the transaction.
- Phil dezzio wrote: > > Hi Philip, > > But why does EclipseLink pass the test? > > Clearly the implementation could use SELECT FOR UPDATE when it checks > the READ lock's state prior to commit. If it did that, then both > transactions would not succeed, and in fact, due to the likelihood of > deadlock in our example case, they both might fail. > > These kind of issues do not get sorted by argument. They are settled by > test cases in the TCK. For this issue, there is no TCK test case, and > thus, ipso facto, OpenJPA complies with the spec. You can still argue > that it doesn't comply with the spec in the best way, and you may be > right. I could be persuaded by understanding the behavior of competing > implementations. > > Cheers, > > David > > 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: http://n2.nabble.com/Is-the-implementation-of-lock%28LockModeType.READ%29-correct--tp2272546p2329205.html Sent from the OpenJPA Users mailing list archive at Nabble.com.
