OPENJPA-610: Restored refresh() behavior for clean/new instances.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@667312 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2008-06-13 01:58:49 +00:00
parent 514a4bb907
commit 71519b0808
2 changed files with 124 additions and 57 deletions

View File

@ -2742,10 +2742,14 @@ public class BrokerImpl
try { try {
assertNontransactionalRead(); assertNontransactionalRead();
for (Iterator itr = objs.iterator(); itr.hasNext();) { for (Iterator itr = objs.iterator(); itr.hasNext();)
gatherCascadeRefresh(itr.next(), call); gatherCascadeRefresh(itr.next(), call);
} if (_operating.isEmpty())
refreshInternal(_operating, call); return;
if (_operating.size() == 1)
refreshInternal(_operating.iterator().next(), call);
else
refreshInternal(_operating, call);
} finally { } finally {
endOperation(); endOperation();
} }
@ -2760,7 +2764,12 @@ public class BrokerImpl
assertNontransactionalRead(); assertNontransactionalRead();
gatherCascadeRefresh(obj, call); gatherCascadeRefresh(obj, call);
refreshInternal(_operating, call); if (_operating.isEmpty())
return;
if (_operating.size() == 1)
refreshInternal(_operating.iterator().next(), call);
else
refreshInternal(_operating, call);
} finally { } finally {
endOperation(); endOperation();
} }
@ -2797,7 +2806,7 @@ public class BrokerImpl
List exceps = null; List exceps = null;
try { try {
// collect instances that need a refresh // collect instances that need a refresh
Collection load = new ArrayList(objs.size()); Collection load = null;
StateManagerImpl sm; StateManagerImpl sm;
Object obj; Object obj;
for (Iterator itr = objs.iterator(); itr.hasNext();) { for (Iterator itr = objs.iterator(); itr.hasNext();) {
@ -2812,9 +2821,11 @@ public class BrokerImpl
continue; continue;
if (sm != null) { if (sm != null) {
if (sm.isDetached()) { if (sm.isDetached())
throw newDetachedException(obj, "refresh"); throw newDetachedException(obj, "refresh");
} else if (sm.beforeRefresh(true)) { else if (sm.beforeRefresh(true)) {
if (load == null)
load = new ArrayList(objs.size());
load.add(sm); load.add(sm);
} }
} else if (assertPersistenceCapable(obj).pcIsDetached() } else if (assertPersistenceCapable(obj).pcIsDetached()
@ -2826,7 +2837,7 @@ public class BrokerImpl
} }
// refresh all // refresh all
if (!load.isEmpty()) { if (load != null) {
Collection failed = _store.loadAll(load, null, Collection failed = _store.loadAll(load, null,
StoreManager.FORCE_LOAD_REFRESH, _fc, null); StoreManager.FORCE_LOAD_REFRESH, _fc, null);
if (failed != null && !failed.isEmpty()) if (failed != null && !failed.isEmpty())
@ -2868,6 +2879,36 @@ public class BrokerImpl
throwNestedExceptions(exceps, false); throwNestedExceptions(exceps, false);
} }
/**
* Optimization for single-object refresh.
*/
protected void refreshInternal(Object obj, OpCallbacks call) {
try {
StateManagerImpl sm = getStateManagerImpl(obj, true);
if ((processArgument(OpCallbacks.OP_REFRESH, obj, sm, call)
& OpCallbacks.ACT_RUN) == 0)
return;
if (sm != null) {
if (sm.isDetached())
throw newDetachedException(obj, "refresh");
else if (sm.beforeRefresh(false)) {
sm.load(_fc, StateManagerImpl.LOAD_FGS, null, null, false);
sm.afterRefresh();
}
fireLifecycleEvent(sm.getManagedInstance(), null,
sm.getMetaData(), LifecycleEvent.AFTER_REFRESH);
} else if (assertPersistenceCapable(obj).pcIsDetached()
== Boolean.TRUE)
throw newDetachedException(obj, "refresh");
} catch (OpenJPAException ke) {
throw ke;
} catch (RuntimeException re) {
throw new GeneralException(re);
}
}
public void retrieveAll(Collection objs, boolean dfgOnly, public void retrieveAll(Collection objs, boolean dfgOnly,
OpCallbacks call) { OpCallbacks call) {
if (objs == null || objs.isEmpty()) if (objs == null || objs.isEmpty())

View File

@ -19,10 +19,10 @@
package org.apache.openjpa.persistence.datacache; package org.apache.openjpa.persistence.datacache;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.LockModeType; import javax.persistence.LockModeType;
import org.apache.openjpa.persistence.EntityManagerImpl; import org.apache.openjpa.persistence.EntityManagerImpl;
import org.apache.openjpa.persistence.EntityNotFoundException;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
import org.apache.openjpa.persistence.StoreCache; import org.apache.openjpa.persistence.StoreCache;
@ -54,7 +54,10 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase {
private static final boolean WITH_DATACACHE = true; private static final boolean WITH_DATACACHE = true;
private static final boolean CONSISTENT = true; private static final boolean CONSISTENT = true;
private static final boolean DIRTY = true; private static final boolean DIRTY = true;
private static final boolean REFRESH_FROM_DATACACHE = true;
private static final LockModeType NOLOCK = null; private static final LockModeType NOLOCK = null;
private static final Class ENTITY_NOT_FOUND_ERROR = EntityNotFoundException.class;
private static final Class NO_ERROR = null;
private static final String MARKER_DATACACHE = "in DataCache"; private static final String MARKER_DATACACHE = "in DataCache";
private static final String MARKER_DATABASE = "in Database"; private static final String MARKER_DATABASE = "in Database";
@ -356,68 +359,66 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase {
String getExpectedMarker(boolean useDataCache, LockModeType lock, String getExpectedMarker(boolean useDataCache, LockModeType lock,
boolean makeDirtyBeforeRefresh) { boolean makeDirtyBeforeRefresh) {
if (useDataCache) { if (useDataCache) {
// return (lock != null && makeDirtyBeforeRefresh)
return (lock != null) ? MARKER_DATABASE : MARKER_DATACACHE; return (lock != null) ? MARKER_DATABASE : MARKER_DATACACHE;
} else { } else {
// return (makeDirtyBeforeRefresh) ? MARKER_DATABASE : MARKER_CACHE;
return MARKER_DATABASE; return MARKER_DATABASE;
} }
} }
public void testDirtyRefreshWithNoLockHitsDatabase() { public void testDirtyRefreshWithNoLockHitsDatabase() {
verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, false, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
} }
public void testDirtyRefreshWithNoLockHitsDataCache() { public void testDirtyRefreshWithNoLockHitsDataCache() {
verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, true, MARKER_DATACACHE); verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
} }
public void testCleanRefreshWithNoLockHitsDatabase() { public void testCleanRefreshWithNoLockDoesNotHitDatabase() {
verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, false, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
} }
public void testCleanRefreshWithNoLockHitsDataCache() { public void testCleanRefreshWithNoLockHitsDataCache() {
verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, true, MARKER_DATACACHE); verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
} }
public void testDirtyRefreshWithReadLockHitsDatabase() { public void testDirtyRefreshWithReadLockHitsDatabase() {
verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, true, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, false, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE);
} }
public void testCleanRefreshWithReadLockHitsDatabase() { public void testCleanRefreshWithReadLockDoesNotHitDatabase() {
verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, true, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, false, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
} }
public void testDirtyRefreshWithWriteLockHitsDatabase() { public void testDirtyRefreshWithWriteLockHitsDatabase() {
verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, true, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, false, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE);
} }
public void testCleanRefreshWithWriteLockHitsDatabase() { public void testCleanRefreshWithWriteLockDoesNotHitDatabase() {
verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, true, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, false, MARKER_DATABASE); verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE);
} }
public void testDirtyRefreshWithoutDataCacheAlwaysHitsDatabase() { public void testDirtyRefreshWithoutDataCacheAlwaysHitsDatabase() {
verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, true, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, true, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, true, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, false, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, false, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE);
verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, false, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE);
} }
public void testCleanRefreshWithoutDataCacheAlwaysHitsDatabase() { public void testCleanRefreshWithoutDataCacheDoesNotHitDatabase() {
verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, true, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_CACHE);
verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, true, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_CACHE);
verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, true, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_CACHE);
verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, false, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_CACHE);
verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, false, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_CACHE);
verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, false, MARKER_DATABASE); verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_CACHE);
} }
/** /**
@ -430,7 +431,7 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase {
* @param lock * @param lock
*/ */
public void verifyDeleteDetectionOnRefresh(boolean useDataCache, public void verifyDeleteDetectionOnRefresh(boolean useDataCache,
LockModeType lock) { boolean dirty, LockModeType lock, Class expectedExceptionType) {
OpenJPAEntityManagerFactorySPI emf = (useDataCache) OpenJPAEntityManagerFactorySPI emf = (useDataCache)
? emfWithDataCache : emfWithoutDataCache; ? emfWithDataCache : emfWithoutDataCache;
@ -465,34 +466,59 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase {
* *
*/ */
em.getTransaction().begin(); em.getTransaction().begin();
if (lock != null) em.getFetchPlan().setReadLockMode(lock);
em.getFetchPlan().setReadLockMode(lock); if (dirty)
pc.setName("Dirty Name");
try { try {
em.refresh(pc); em.refresh(pc);
fail("expected EntityNotFoundException for PObject:" + oid); if (expectedExceptionType != null) {
} catch (EntityNotFoundException ex) { fail("expected " + expectedExceptionType.getSimpleName() +
// we are good " for PObject:" + oid);
}
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); boolean expectedException = expectedExceptionType != null &&
fail("expected EntityNotFoundException for PObject:" + oid); expectedExceptionType.isAssignableFrom(ex.getClass());
if (!expectedException) {
ex.printStackTrace();
String error = (expectedExceptionType == null)
? "no exception" : expectedExceptionType.getName();
fail("expected " + error + " for PObject:" + oid);
}
} finally { } finally {
em.getTransaction().rollback(); em.getTransaction().rollback();
} }
} }
public void testDeleteIsDetectedOnRefreshWithLockWithActiveDataCache() { public void testDeleteIsNotDetectedOnCleanRefreshWithoutLockWithDataCache() {
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, LockModeType.READ); verifyDeleteDetectionOnRefresh(WITH_DATACACHE, !DIRTY, NOLOCK, NO_ERROR);
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, LockModeType.WRITE);
} }
public void testDeleteIsNotDetectedOnRefreshWithNoLockWithActiveDataCache() { public void testDeleteIsDetectedOnCleanRefreshWithLockWithDataCache() {
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, NOLOCK); verifyDeleteDetectionOnRefresh(WITH_DATACACHE, !DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR);
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, !DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR);
} }
public void testDeleteIsDetectedOnRefreshAlwaysWithoutDataCache() { public void testDeleteIsNotDetectedOnDirtyRefreshWithoutLockWithDataCache() {
verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, NOLOCK); verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, NOLOCK, NO_ERROR);
verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, LockModeType.READ); }
verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, LockModeType.WRITE);
public void testDeleteIsDetectedOnDirtyRefreshWithLockWithDataCache() {
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR);
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR);
}
public void testDeleteIsDetectedOnDirtyRefreshWitDataCache() {
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR);
verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR);
}
public void testDeleteIsDetectedOnCleanRefreshWithoutLockWithoutDataCache() {
verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, !DIRTY, NOLOCK, ENTITY_NOT_FOUND_ERROR);
}
public void testDeleteIsDetectedOnCleanRefreshWithLockWithoutDataCache() {
verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, !DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR);
verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, !DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR);
} }
} }