* somewhat tolerant of such behavior, in that the cache will be cleaned
* up as failures occur.
*/
private void notifyOptimisticLockFailure(OptimisticException e) {
Object o = e.getFailedObject();
OpenJPAStateManager sm = _ctx.getStateManager(o);
if (sm == null)
return;
Object oid = sm.getId();
boolean remove;
// this logic could be more efficient -- we could aggregate
// all the cache->oid changes, and then use DataCache.removeAll()
// and less write locks to do the mutation.
DataCache cache = _mgr.selectCache(sm);
if (cache == null)
return;
cache.writeLock();
try {
DataCachePCData data = cache.get(oid);
if (data == null)
return;
switch (compareVersion(sm, sm.getVersion(), data.getVersion())) {
case StoreManager.VERSION_LATER:
case StoreManager.VERSION_SAME:
// This tx's current version is later than or the same as
// the data cache version. In this case, the commit should
// have succeeded from the standpoint of the cache. Remove
// the instance from cache in the hopes that the cache is
// out of sync.
remove = true;
break;
case StoreManager.VERSION_EARLIER:
// This tx's current version is earlier than the data
// cache version. This is a normal optimistic lock failure.
// Do not clean up the cache; it probably already has the
// right values, and if not, it'll get cleaned up by a tx
// that fails in one of the other case statements.
remove = false;
break;
case StoreManager.VERSION_DIFFERENT:
// The version strategy for the failed object does not
// store enough information to optimize for expected
// failures. Clean up the cache.
remove = true;
break;
default:
// Unexpected return value. Remove to be future-proof.
remove = true;
break;
}
if (remove)
// remove directly instead of via the RemoteCommitListener
// since we have a write lock here already, so this is more
// efficient than read-locking and then write-locking later.
cache.remove(sm.getId());
} finally {
cache.writeUnlock();
}
// fire off a remote commit stalenesss detection event.