[
https://issues.apache.org/jira/browse/OPENJPA-891?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12675510#action_12675510
]
Albert Lee commented on OPENJPA-891:
------------------------------------
The JIRA implements the new JPA2 LockModeType features.
The following is a summary of the design points and considerations in the
OpenJPA implementation:
Support the following new LockModeType and property map combination for find,
lock and refresh methods in the EntityManager interface:
Optimistic (Same as Read)
Optimistic_Force_Increment (Same as Write)
Pessimistic_Read
Pessimistic_Write
Pessimistic_Force_Increment
Since OpenJPA already support both optimistic and pessimistic lock managers,
the basic design goal is to "reuse" as much as possible to ensure stability,
compatibility and semantics of existing lock managers behaviors as well as the
new JPA 2 support..
A new JPA2LockManager is introduced to support the new lock mode semantics.
"jpa2" is the alias name for the openjpa.LockManager properties. This will be
the default for OpenJPA 2.0.0.
There are 3 aspects in supporting the new features:
The front end - EntityManagerImpl:
The EntityManagerImpl needs to implement the new interface methods.
Since the em method's LockMode and properties Map arguments are transient and
only apply during the method call, the front end code needs to save, apply the
setting for the current method call and restore the previous values when the
method exit.
Translate the relevant property values and apply to the fetch configuration for
use downstream. Only the following properties will be processed
javax.persistence.lock.timeout
openjpa.LockTimeout
openjpa.ReadLockMode
openjpa.WriteLockMode
public <T> T find(Class<T> cls, Object oid, LockModeType mode,
Map<String, Object> properties) {
assertNotCloseInvoked();
if (mode != LockModeType.NONE)
_broker.assertActiveTransaction();
boolean fcPushed = pushLockProperties(mode, properties);
try {
oid = _broker.newObjectId(cls, oid);
return (T) _broker.find(oid, true, this);
} finally {
popLockProperties(fcPushed);
}
}
The back end - Lock Manager
The role of the JPA2LockManager is to route the requested LockMode to the lock
manager and set the version check options to be processed by the delegated lock
manager:
protected void lockInternal(OpenJPAStateManager sm, int level, int timeout,
Object sdata) {
if (level >= LOCK_PESSIMISTIC_FORCE_INCREMENT) {
setVersionCheckOnReadLock(true);
setVersionUpdateOnWriteLock(true);
super.lockInternal(sm, level, timeout, sdata);
} else if (level >= LOCK_PESSIMISTIC_READ) {
setVersionCheckOnReadLock(true);
setVersionUpdateOnWriteLock(false);
super.lockInternal(sm, level, timeout, sdata);
} else if (level >= LOCK_READ) {
setVersionCheckOnReadLock(true);
setVersionUpdateOnWriteLock(true);
optimisticLockInternal(sm, level, timeout, sdata);
}
}
Exception handling
New LockTimeoutException and PessimisticLockException require differentiation
its statement-level and transaction-level rollback semantics respectively.
Application may recover and re-try when the former exception is received.
Since detecting these conditions is very database specific. the
DBDictionary.narrow() method will delegate to the associated Dictionary
subclass to examine the SQLException (SQLState, SQLCode and message text etc.)
thrown by the database and to compute if the exception is a recoverable
exception. The existing sqlstate mapping to StoreException's subtype remains
unchanged (except a few corrections). The StoreException is used to encapsulate
the recoverable attribute of the SQLException and will be processed during
exception translation.. The only subtype that is affected is
StoreException.LOCK type.
OpenJPAException narrow(String msg, SQLException ex) {
Boolean recoverable = null;
int errorType = StoreException.GENERAL;
for (Integer type : sqlStateCodes.keySet()) {
Set<String> errorStates = sqlStateCodes.get(type);
if (errorStates != null) {
recoverable = matchErrorState(type, errorStates, ex);
if (recoverable != null) {
errorType = type;
break;
}
}
}
StoreException storeEx;
switch (errorType) {
case StoreException.LOCK:
storeEx = new LockException(msg);
break;
E.g.
DB2:
@Override
protected Boolean matchErrorState(int subtype, Set<String> errorStates,
SQLException ex) {
Boolean recoverable = null;
if (errorStates.contains(errorState)) {
recoverable = Boolean.FALSE;
if (subtype == StoreException.LOCK && errorState.equals("57033")
&& ex.getMessage().indexOf("80") != -1) {
recoverable = Boolean.TRUE;
}
}
return recoverable;
}
Derby:
@Override
protected Boolean matchErrorState(int subtype, Set<String> errorStates,
SQLException ex) {
Boolean recoverable = null;
String errorState = ex.getSQLState();
int errorCode = ex.getErrorCode();
if (errorStates.contains(errorState)) {
recoverable = Boolean.FALSE;
if (subtype == StoreException.LOCK && errorCode < 30000) {
recoverable = Boolean.TRUE;
}
}
return recoverable;
}
The LockException will be translated to the proper em method exception as in :
private static Throwable translateStoreException(OpenJPAException ke) {
.......
} else if (ke.getSubtype() == StoreException.LOCK || cause instanceof
LockException) {
LockException lockEx = (LockException)(ke instanceof
LockException ? ke : cause);
if( lockEx != null && lockEx.isPessimistic()) {
if( lockEx.isRecoverable()) {
e = new org.apache.openjpa.persistence
.LockTimeoutException(ke.getMessage(),
getNestedThrowables(ke), getFailedObject(ke), ke.isFatal());
} else {
e = new org.apache.openjpa.persistence
.PessimisticLockException(ke.getMessage(),
getNestedThrowables(ke), getFailedObject(ke), ke.isFatal());
}
} else {
e = new org.apache.openjpa.persistence
.OptimisticLockException(ke.getMessage(),
getNestedThrowables(ke), getFailedObject(ke), ke.isFatal());
}
} else if (ke.getSubtype() == StoreException.OBJECT_EXISTS
The LockTimeoutException and QueryTimeoutException will be exempted from being
marked RolledbackOnly in PersistenceExceptions
public static RuntimeExceptionTranslator getRollbackTranslator(
final OpenJPAEntityManager em) {
return new RuntimeExceptionTranslator() {
private boolean throwing = false;
public RuntimeException translate(RuntimeException re) {
RuntimeException ex = toPersistenceException(re);
if (!(ex instanceof NonUniqueResultException)
&& !(ex instanceof NoResultException)
&& !(ex instanceof LockTimeoutException)
&& !(ex instanceof QueryTimeoutException)
&& !throwing) {
try {
throwing = true;
openjpa.ReadLockLevel and WriteLockLevel are enhanced in parallel to the new
lock modes. (i.e.
5.53. openjpa.ReadLockLevel
Property name: openjpa.ReadLockLevel
Resource adaptor config-property: ReadLockLevel
Default: read
Possible values: none, read, write, optimistic, optimistic-force-increment,
pessimistic-read, pessimistic-write, pessimistic-force-increment, numeric
values for lock-manager specific lock levels
Description: The default level at which to lock objects retrieved during a
non-optimistic transaction. Note that for the default JDBC lock manager, read
and write lock levels are equivalent.
For the em methods that take both LockModeType and a property Map, we may run
into situation where "openjpa.ReadLockMode/WriteLockMode" are specified and
create a conflict with the LockModeType argument. Resolution: the LockModeType
argument takes a higher precedent than the *LockLevel values specified in the
Map argument.
If application specifies "version" or "pessimistic" as the openjpa.LockManager,
the old behavior is honored.
However if new lock mode is requested using the new EntityManager Interface,
the following behavior will be implemented:
"version" lock manager
All "Pessimistic_*" mode will be down grade to "Optimistic_Force_Increment"
(Write) and a warning message is logged.
"pessimistic" lock manager
All lock type uses the same existing pessimistic semantics.
Albert Lee.
> JPA2 LockTypeMode Support, part 1 - optimistic lock types
> ---------------------------------------------------------
>
> Key: OPENJPA-891
> URL: https://issues.apache.org/jira/browse/OPENJPA-891
> Project: OpenJPA
> Issue Type: Sub-task
> Components: jpa
> Affects Versions: 2.0.0
> Reporter: Albert Lee
> Assignee: Albert Lee
> Fix For: 2.0.0
>
>
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.