diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java index 7c3d744b0..4488a3ba7 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java @@ -29,6 +29,7 @@ import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.event.RemoteCommitProvider; import org.apache.openjpa.kernel.AutoClear; import org.apache.openjpa.kernel.AutoDetach; +import org.apache.openjpa.kernel.Broker; import org.apache.openjpa.kernel.BrokerFactory; import org.apache.openjpa.kernel.BrokerImpl; import org.apache.openjpa.kernel.ConnectionRetainModes; @@ -330,7 +331,37 @@ public interface OpenJPAConfiguration * @since 0.2.5 */ public void setDataCacheTimeout(Integer timeout); - + + /** + * Gets whether entity state is to be refreshed from {@link DataCache}. + * The entities are never refreshed from DataCache if lock is being applied + * (e.g. in a pessimistic transaction) and hence this setting only refers + * to behavior when not locking. + * + * @since 1.1.1 + */ + public boolean getRefreshFromDataCache(); + + /** + * Sets whether entity state is to be refreshed from {@link DataCache}. + * The entities are never refreshed from DataCache if lock is being applied + * (e.g. in a pessimistic transaction) and hence this setting only refers + * to behavior when not locking. + * + * @since 1.1. + */ + public void setRefreshFromDataCache(boolean refreshFromDataCache); + + /** + * Sets whether entity state is to be refreshed from {@link DataCache}. + * The entities are never refreshed from DataCache if lock is being applied + * (e.g. in a pessimistic transaction) and hence this setting only refers + * to behavior when not locking. + * + * @since 1.1.1 + */ + public void setRefreshFromDataCache(Boolean refreshFromDataCache); + /** * The plugin to use for level-2 data store query caching. * diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java index 817005680..e7fd3d2e4 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java @@ -122,6 +122,7 @@ public class OpenJPAConfigurationImpl public BooleanValue ignoreChanges; public BooleanValue nontransactionalRead; public BooleanValue nontransactionalWrite; + public BooleanValue refreshFromDataCache; public BooleanValue multithreaded; public StringValue mapping; public PluginValue metaFactoryPlugin; @@ -222,7 +223,12 @@ public class OpenJPAConfigurationImpl queryCachePlugin.setAliases(aliases); queryCachePlugin.setDefault(aliases[0]); queryCachePlugin.setString(aliases[0]); - + + refreshFromDataCache = addBoolean("RefreshFromDataCache"); + refreshFromDataCache.setDefault("false"); + refreshFromDataCache.set(false); + refreshFromDataCache.setDynamic(true); + dynamicDataStructs = addBoolean("DynamicDataStructs"); dynamicDataStructs.setDefault("false"); dynamicDataStructs.set(false); @@ -644,6 +650,20 @@ public class OpenJPAConfigurationImpl public String getQueryCache() { return queryCachePlugin.getString(); } + + public boolean getRefreshFromDataCache() { + return refreshFromDataCache.get(); + } + + public void setRefreshFromDataCache(boolean flag) { + refreshFromDataCache.set(flag); + } + + public void setRefreshFromDataCache(Boolean flag) { + if (flag != null) { + refreshFromDataCache.set(flag.booleanValue()); + } + } public boolean getDynamicDataStructs() { return dynamicDataStructs.get(); diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java index f71add065..999129ec1 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java @@ -423,8 +423,12 @@ public class DataCacheStoreManager public Collection loadAll(Collection sms, PCState state, int load, FetchConfiguration fetch, Object edata) { - if (load == StoreManager.FORCE_LOAD_REFRESH || isLocking(fetch)) - return super.loadAll(sms, state, load, fetch, edata); + if (isLocking(fetch) || + (!isLocking(fetch) && + (load == StoreManager.FORCE_LOAD_REFRESH) + && !_ctx.getConfiguration().getRefreshFromDataCache())) { + return super.loadAll(sms, state, load, fetch, edata); + } Map unloaded = null; List smList = null; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java index 4f1121ca1..e791df985 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java @@ -286,10 +286,11 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase { */ public void verifyRefresh(boolean useDataCache, LockModeType lock, - boolean makeDirtyBeforeRefresh, String expected) { + boolean makeDirtyBeforeRefresh, boolean refreshFromDataCache, + String expected) { OpenJPAEntityManagerFactorySPI emf = (useDataCache) ? emfWithDataCache : emfWithoutDataCache; - + emf.getConfiguration().setRefreshFromDataCache(refreshFromDataCache); OpenJPAEntityManagerSPI em = emf.createEntityManager(); em.getTransaction().begin(); @@ -364,39 +365,59 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase { } public void testDirtyRefreshWithNoLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, false, MARKER_DATABASE); + } + + public void testDirtyRefreshWithNoLockHitsDataCache() { + verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, true, MARKER_DATACACHE); } public void testCleanRefreshWithNoLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, false, MARKER_DATABASE); + } + + public void testCleanRefreshWithNoLockHitsDataCache() { + verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, true, MARKER_DATACACHE); } public void testDirtyRefreshWithReadLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, true, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, false, MARKER_DATABASE); } public void testCleanRefreshWithReadLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, true, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, false, MARKER_DATABASE); } public void testDirtyRefreshWithWriteLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, true, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, false, MARKER_DATABASE); } public void testCleanRefreshWithWriteLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, true, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, false, MARKER_DATABASE); } public void testDirtyRefreshWithoutDataCacheAlwaysHitsDatabase() { - verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, true, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, true, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, true, MARKER_DATABASE); + + verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, false, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, false, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, false, MARKER_DATABASE); } public void testCleanRefreshWithoutDataCacheAlwaysHitsDatabase() { - verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, true, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, true, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, true, MARKER_DATABASE); + + verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, false, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, false, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, false, MARKER_DATABASE); } /**