Hi Philip and Pinaki,
Since Philip brought his test case to me before coming here, I am
familiar with it. So, I'll try to elucidate.
The test case concerns the order of operations within the OpenJPA commit
method as seen over the two JDBC connections involved. (Philip actually
uses three transactions, but the third is just to make the timings of
the other two always come out the same.)
Time sequence:
Innocent: SELECT to check version of Flag1 (passes)
Evil: UPDATE to change Flag1 (does not block)
Evil: COMMIT (succeeds)
Innocent: UPDATE to change Flag2 (does not block)
Innocent: COMMIT (succeeds)
Philip's argument is that both transactions ought not to succeed since
Innocent holds a READ lock on Flag1 that ought to be enforced until his
transaction commits.
I believe that the implementor's argument is that optimistic
transactions ought to avoid deadlock, and READ locks ought not to
increase the chances of deadlock.
To accomplish this end, it is acceptable to allow evil to triumph,in
this test case, especially since Evil has not caused any harm.
Presumably, whatever information in the object Flag1 that Innocent
relied upon has already been used to modify the object Flag2, and the
net result is that image in the database is the same as it would be if
Evil has dallied until Innocent was done. On the other hand, if Evil had
been eager to accomplish his nefarious deed, Innocent's transaction
would not have succeeded.
In short, Philip, where is the harm?
Cheers,
David
Philip Aston wrote:
All understood and agreed.
The problem is not 1., and I'm using read committed. The problem is in the
implementation of the VersionLockManager itself. It does the check, then
leaves a gap where the data can be modified by a separate commit before the
update happens. Thus its actual behaviour is "verifying that the version of
all read-locked instances is unchanged at the start of the commit of the
transaction".
Pinaki Poddar wrote:
Hi Philip,
I did not execute the test case but reading it gave me the impression
that it is exercising/exposing the following known limitation. But may be
I should analyze the test case deeper to understand what is causing this
behavior.
1. "In order to maintain reasonable performance levels when loading object
state, OpenJPA can only guarantee that an object is locked at the proper
lock level after the state has been retrieved from the database. This
means that it is technically possible for another transaction to "sneak
in" and modify the database record after OpenJPA retrieves the state, but
before it locks the object. The only way to positively guarantee that the
object is locked and has the most recent state to refresh the object after
locking it."
2. On VersionLockManager (which is the default and being used in this
case): "This lock manager does not perform any exclusive locking, but
instead ensures read consistency by verifying that the version of all
read-locked instances is unchanged at the end of the transaction."
3. Another possibly relevant point: "In order for the version lock
manager to prevent the dirty read phenomenon, the underlying data store's
transaction isolation level must be set to the equivalent of "read
committed" or higher."
Philip Aston wrote:
Thanks Pinaki.
I don't think the documented known issues cover my case. The first bullet
point is about the pessimistic lock manager, which I'm not using. The
second bullet is about the read consistency of the locked object - this
isn't the problem either. The last paragraph is again about the
pessimistic lock manager. And I don't see any of the INFO level messages
referred to.
I find the documented issues to be reasonable, but I'm afraid I can't say
the same of the read locking implementation.
- Phil
Pinaki Poddar wrote:
Hi Philip,
The points you raise are valid, correct and known. Please refer to
[1].
By the way, the test case is very neat!
[1]
http://openjpa.apache.org/builds/latest/docs/manual/manual.html#ref_guide_locking_issues