You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2008/09/11 06:38:25 UTC
svn commit: r694111 - in /openjpa/branches/sql-cache:
openjpa-kernel/src/main/java/org/apache/openjpa/conf/
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/
ope...
Author: ppoddar
Date: Wed Sep 10 21:38:24 2008
New Revision: 694111
URL: http://svn.apache.org/viewvc?rev=694111&view=rev
Log:
Define PreparedQueryCache and capability to invalidate and ignore PreparedQuery via Query hints when context changes
Modified:
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java
openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java
openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java
openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java Wed Sep 10 21:38:24 2008
@@ -46,6 +46,7 @@
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.meta.MetaDataFactory;
import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.persistence.PreparedQueryCache;
import org.apache.openjpa.util.ClassResolver;
import org.apache.openjpa.util.ProxyManager;
import org.apache.openjpa.util.StoreFacadeTypeRegistry;
@@ -1528,22 +1529,22 @@
public void setInitializeEagerly(boolean flag);
/**
- * Configuration settings for the Prepared Query Cache to use.
- * @see PreparedQueryCacheValue
+ * Affirms if Prepared Query Cache is activated.
+ *
* @since 1.3.0
*/
- public String getPreparedQueryCache();
+ public boolean getPreparedQueryCache();
/**
- * Configuration settings for the Prepared Query Cache to use.
- * @see PreparedQueryCacheValue
+ * Sets whether Prepared Query Cache is activated.
+ *
* @since 1.3.0
*/
- public void setPreparedQueryCache(String cache);
+ public void setPreparedQueryCache(boolean flag);
/**
- * Gets the modifable map of the cached prepared query indexed by query
+ * Gets the modifable view of the cached prepared query indexed by query
* String.
*/
- public Map getPreparedQueryCacheInstance();
+ public PreparedQueryCache getPreparedQueryCacheInstance();
}
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java Wed Sep 10 21:38:24 2008
@@ -49,6 +49,7 @@
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.MetaDataFactory;
import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.persistence.PreparedQueryCache;
import org.apache.openjpa.util.ClassResolver;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.ProxyManager;
@@ -1403,18 +1404,19 @@
return (Map) queryCompilationCachePlugin.get();
}
- public String getPreparedQueryCache() {
- return preparedQueryCachePlugin.getString();
+ public boolean getPreparedQueryCache() {
+ String str = preparedQueryCachePlugin.getString();
+ return str != null && str.toLowerCase().startsWith("true");
}
- public void setPreparedQueryCache(String queryCompilationCache) {
- preparedQueryCachePlugin.setString(queryCompilationCache);
+ public void setPreparedQueryCache(boolean flag) {
+ preparedQueryCachePlugin.setString(""+flag);
}
- public Map getPreparedQueryCacheInstance() {
+ public PreparedQueryCache getPreparedQueryCacheInstance() {
if (preparedQueryCachePlugin.get() == null)
- preparedQueryCachePlugin.instantiate(Map.class, this);
- return (Map) preparedQueryCachePlugin.get();
+ preparedQueryCachePlugin.instantiate(PreparedQueryCache.class, this);
+ return (PreparedQueryCache) preparedQueryCachePlugin.get();
}
public StoreFacadeTypeRegistry getStoreFacadeTypeRegistry() {
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java Wed Sep 10 21:38:24 2008
@@ -18,15 +18,8 @@
*/
package org.apache.openjpa.conf;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.Map;
-
-import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.conf.PluginValue;
-import java.util.concurrent.ConcurrentHashMap;
-import org.apache.openjpa.lib.util.ParseException;
-import org.apache.openjpa.util.CacheMap;
+import org.apache.openjpa.persistence.PreparedQueryCache;
/**
* A cache of prepared queries indexed by an identifier.
@@ -39,40 +32,19 @@
extends PluginValue {
public static final String[] ALIASES = {
- "true", CacheMap.class.getName(),
- "all", ConcurrentHashMap.class.getName(),
- "false", null,
+ "true", PreparedQueryCache.class.getName(),
+ "false", null,
};
-
+
public PreparedQueryCacheValue(String prop) {
super(prop, true);
setAliases(ALIASES);
setDefault(ALIASES[0]);
setClassName(ALIASES[1]);
}
-
- public Object newInstance(String clsName, Class type,
- Configuration conf, boolean fatal) {
- // make sure map handles concurrency
- Map map;
-
- try {
- map = (Map) super.newInstance(clsName, type, conf, fatal);
- } catch (ParseException pe) {
- // For comment on special classloading see QueryCompilationCacheValue
- map = (Map) super.newInstance(clsName,
- PreparedQueryCacheValue.class, conf, fatal);
- } catch (IllegalArgumentException iae) {
- map = (Map) super.newInstance(clsName,
- PreparedQueryCacheValue.class, conf, fatal);
- }
-
- if (map != null && !(map instanceof Hashtable)
- && !(map instanceof CacheMap)
- && !(map instanceof
- org.apache.openjpa.lib.util.concurrent.ConcurrentMap)
- && !(map instanceof java.util.concurrent.ConcurrentMap))
- map = Collections.synchronizedMap(map);
- return map;
- }
+
+ @Override
+ public boolean isAliasListComprehensive() {
+ return true;
+ }
}
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java Wed Sep 10 21:38:24 2008
@@ -52,6 +52,14 @@
*/
public void setImplicitBehavior(OpCallbacks call,
RuntimeExceptionTranslator ex);
+
+ /**
+ * Gets the translator for runtime exceptions.
+ *
+ * @see #setImplicitBehavior(OpCallbacks, RuntimeExceptionTranslator)
+ * @since 1.3.0
+ */
+ public RuntimeExceptionTranslator getInstanceExceptionTranslator();
/**
* Return the factory that produced this broker.
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Wed Sep 10 21:38:24 2008
@@ -370,7 +370,7 @@
_extrans = ex;
}
- RuntimeExceptionTranslator getInstanceExceptionTranslator() {
+ public RuntimeExceptionTranslator getInstanceExceptionTranslator() {
return (_operationCount == 0) ? _extrans : null;
}
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java Wed Sep 10 21:38:24 2008
@@ -495,6 +495,15 @@
throw translate(re);
}
}
+
+ public RuntimeExceptionTranslator getInstanceExceptionTranslator() {
+ try {
+ return _broker.getInstanceExceptionTranslator();
+ } catch (RuntimeException re) {
+ throw translate(re);
+ }
+ }
+
public BrokerFactory getBrokerFactory() {
try {
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java Wed Sep 10 21:38:24 2008
@@ -158,11 +158,24 @@
addFetchGroups(fetch.getFetchGroups());
clearFields();
addFields(fetch.getFields());
-
+ copyHints(fetch);
// don't use setters because require active transaction
_state.readLockLevel = fetch.getReadLockLevel();
_state.writeLockLevel = fetch.getWriteLockLevel();
}
+
+ void copyHints(FetchConfiguration fetch) {
+ if (fetch instanceof FetchConfigurationImpl == false)
+ return;
+ FetchConfigurationImpl from = (FetchConfigurationImpl)fetch;
+ if (from._state == null || from._state.hints == null)
+ return;
+ if (this._state == null)
+ return;
+ if (this._state.hints == null)
+ this._state.hints = new HashMap();
+ this._state.hints.putAll(from._state.hints);
+ }
public int getFetchBatchSize() {
return _state.fetchBatchSize;
Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java (original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java Wed Sep 10 21:38:24 2008
@@ -50,7 +50,29 @@
* has a constant performance penalty for the frequent use case where a
* query is repeatedly executed in different persistent context with the
* same fetch plan or locking.
+ *
+ * @see #HINT_IGNORE_PREPARED_QUERY
*/
public static final String HINT_INVALIDATE_PREPARED_QUERY =
"openjpa.hint.InvalidatePreparedQuery";
+
+ /**
+ * A directive to ignore any prepared SQL that might have been cached
+ * against a JPQL query. The target SQL corresponding to a JPQL depends on
+ * several context parameters such as fetch configuration, lock mode etc.
+ * If a query is executed repeatedly and hence its SQL is cached for faster
+ * execution then if any of the contextual parameters change across query
+ * execution then the user must supply this hint to ignore the cached
+ * SQL query for the current execution.
+ * This is in contrast with invalidation hint that removes the cached
+ * version from cache altogether.
+ *
+ * The cached SQL is retained and subsequent execution of the same query
+ * string without this hint will reuse the cached SQL.
+ *
+ * @see #HINT_INVALIDATE_PREPARED_QUERY
+ */
+ public static final String HINT_IGNORE_PREPARED_QUERY =
+ "openjpa.hint.IgnorePreparedQuery";
+
}
Modified: openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java (original)
+++ openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java Wed Sep 10 21:38:24 2008
@@ -23,10 +23,16 @@
import java.util.List;
import java.util.Map;
+import javax.persistence.EntityManager;
+
import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.kernel.QueryHints;
+import org.apache.openjpa.kernel.QueryLanguages;
+import org.apache.openjpa.kernel.jpql.JPQLParser;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAQuery;
import org.apache.openjpa.persistence.PreparedQuery;
+import org.apache.openjpa.persistence.PreparedQueryCache;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
@@ -44,30 +50,176 @@
public static final String[] DEPARTMENT_NAMES = { "Marketing", "Sales",
"Engineering" };
public static final String[] EMPLOYEE_NAMES = { "Tom", "Dick", "Harray" };
-
+ public static final String EXCLUDED_QUERY_1 = "select count(p) from Company p";
+ public static final String EXCLUDED_QUERY_2 = "select count(p) from Department p";
+ public static final String INCLUDED_QUERY = "select count(p) from Address p";
+
public void setUp() throws Exception {
super.setUp(Company.class, Department.class, Employee.class,
- Address.class, "openjpa.Log", "SQL=WARN");
+ Address.class,
+ "openjpa.Log", "SQL=WARN",
+ "openjpa.PreparedQueryCache",
+ "true(excludes='select count(p) from Company p;select count(p) from Department p')");
}
public void tearDown() throws Exception {
super.tearDown();
}
+
+ PreparedQueryCache getCache() {
+ return emf.getConfiguration().getPreparedQueryCacheInstance();
+ }
public void testPreparedQueryCacheIsActiveByDefault() {
OpenJPAConfiguration conf = emf.getConfiguration();
- assertEquals("true", conf.getPreparedQueryCache());
- assertNotNull(conf.getPreparedQueryCacheInstance());
+ assertEquals(true, conf.getPreparedQueryCache());
+ assertNotNull(getCache());
}
public void testPreparedQueryCacheCanBeDeactivatedDynamically() {
OpenJPAConfiguration conf = emf.getConfiguration();
- assertNotNull(conf.getPreparedQueryCacheInstance());
- conf.setPreparedQueryCache("false");
- assertNull(conf.getPreparedQueryCacheInstance());
+ assertNotNull(getCache());
+ conf.setPreparedQueryCache(false);
+ assertNull(getCache());
+ }
+
+ public void testPreparedQueryCacheIsPerUnitSingleton() {
+ PreparedQueryCache c1 = getCache();
+ PreparedQueryCache c2 = getCache();
+ assertSame(c1, c2);
+ }
+
+ public void testExclusionPattern() {
+ List<String> patterns = getCache().getExcludes();
+ OpenJPAEntityManager em = emf.createEntityManager();
+ OpenJPAQuery q1 = em.createQuery(EXCLUDED_QUERY_1);
+ q1.getResultList();
+ assertNotCached(EXCLUDED_QUERY_1);
+
+ OpenJPAQuery q2 = em.createQuery(EXCLUDED_QUERY_2);
+ q2.getResultList();
+ assertNotCached(EXCLUDED_QUERY_2);
+
+ OpenJPAQuery q3 = em.createQuery(INCLUDED_QUERY);
+ q3.getResultList();
+ assertCached(INCLUDED_QUERY);
}
+
+ void assertLanguage(OpenJPAQuery q, String lang) {
+ assertEquals(lang, q.getLanguage());
+ }
+
+ void assertCached(String id) {
+ PreparedQuery cached = getCache().get(id);
+ assertNotNull(getCache() + ": " + getCache().getMapView() +
+ " does not contain " + id, cached);
+ }
+
+ void assertNotCached(String id) {
+ PreparedQueryCache cache = getCache();
+ if (cache != null) {
+ assertNull(cache.get(id));
+ }
+ }
+
+ public void testPreparedQueryIsCachedOnExecution() {
+ String jpql = "select p from Company p";
+ OpenJPAEntityManager em = emf.createEntityManager();
+ OpenJPAQuery q1 = em.createQuery(jpql);
+ assertNotCached(jpql);
+ assertLanguage(q1, JPQLParser.LANG_JPQL);
+
+ List result = q1.getResultList();
+ assertCached(jpql);
+ assertLanguage(q1, JPQLParser.LANG_JPQL);
+
+ PreparedQuery cached = getCache().get(jpql);
+ assertEquals(jpql, cached.getIdentifier());
+ assertNotEquals(jpql, cached.getSQL());
+ }
+
+ public void testPreparedQueryIsCachedAcrossExecution() {
+ String jpql = "select p from Company p";
+ OpenJPAEntityManager em = emf.createEntityManager();
+ OpenJPAQuery q1 = em.createQuery(jpql);
+ assertNotCached(jpql);
+ assertLanguage(q1, JPQLParser.LANG_JPQL);
+
+
+ List result = q1.getResultList();
+ assertCached(jpql);
+ assertLanguage(q1, JPQLParser.LANG_JPQL);
+
+ // Create a new query with the same JPQL
+ // This is not only cached, its language is different too
+ OpenJPAQuery q2 = em.createQuery(jpql);
+ assertCached(jpql);
+ assertLanguage(q2, QueryLanguages.LANG_PREPARED_SQL);
+ }
+
+ public void testInvalidatePreparedQueryWithHint() {
+ String jpql = "select p from Company p";
+ OpenJPAEntityManager em = emf.createEntityManager();
+ OpenJPAQuery q1 = em.createQuery(jpql);
+ assertNotCached(jpql);
+ List result = q1.getResultList();
+ assertCached(jpql);
+ assertLanguage(q1, JPQLParser.LANG_JPQL);
+
+ // Create a new query with the same JPQL
+ // This is cached on creation, its language is Prepared SQL
+ OpenJPAQuery q2 = em.createQuery(jpql);
+ assertCached(jpql);
+ assertLanguage(q2, QueryLanguages.LANG_PREPARED_SQL);
+ q2.getResultList();
+
+ // Now execute with hints to invalidate.
+ q2.setHint(QueryHints.HINT_INVALIDATE_PREPARED_QUERY, true);
+ // Immediately it should be removed from the cache
+ assertNotCached(jpql);
+ assertEquals(JPQLParser.LANG_JPQL, q2.getLanguage());
+ q2.getResultList();
+
+ // Create a new query with the same JPQL
+ // This is not cached on creation, its language is JPQL
+ OpenJPAQuery q3 = em.createQuery(jpql);
+ assertNotCached(jpql);
+ assertLanguage(q3, JPQLParser.LANG_JPQL);
+ }
+
+ public void testIgnorePreparedQueryWithHint() {
+ String jpql = "select p from Company p";
+ OpenJPAEntityManager em = emf.createEntityManager();
+ OpenJPAQuery q1 = em.createQuery(jpql);
+ assertNotCached(jpql);
+ List result = q1.getResultList();
+ assertCached(jpql);
+ assertLanguage(q1, JPQLParser.LANG_JPQL);
+
+ // Create a new query with the same JPQL
+ // This is cached on creation, its language is PREPARED SQL
+ OpenJPAQuery q2 = em.createQuery(jpql);
+ assertCached(jpql);
+ assertLanguage(q2, QueryLanguages.LANG_PREPARED_SQL);
+ q2.getResultList();
+
+ // Now execute with hints to ignore.
+ q2.setHint(QueryHints.HINT_IGNORE_PREPARED_QUERY, true);
+ // It should remain in the cache
+ assertCached(jpql);
+ // But its language should be JPQL and not PREPARED SQL
+ assertEquals(JPQLParser.LANG_JPQL, q2.getLanguage());
+ q2.getResultList();
+
+ // Create a new query with the same JPQL
+ // This is cached on creation, its language is PREPARED SQL
+ OpenJPAQuery q3 = em.createQuery(jpql);
+ assertCached(jpql);
+ assertLanguage(q3, QueryLanguages.LANG_PREPARED_SQL);
+ }
+
- public void testSimpleQueryCache() {
+ public void testQueryWithNoParameter() {
compare("select p from Company p");
}
@@ -80,7 +232,7 @@
"param", "x");
}
- public void testJoins() {
+ public void testQueryWithJoinsAndParameters() {
compare("select e from Employee e " + "where e.name = :emp "
+ "and e.department.name = :dept " +
"and e.department.company.name = :company " +
@@ -98,19 +250,22 @@
*
*/
void compare(String jpql, Object... params) {
+// if (true) return;
// run the query once for warming up
run(jpql, params, !QUERY_CACHE, 1);
// run N times without cache
long without = run(jpql, params, !QUERY_CACHE, SAMPLE_SIZE);
+ assertNotCached(jpql);
// run N times with cache
long with = run(jpql, params, QUERY_CACHE, SAMPLE_SIZE);
+ assertCached(jpql);
long delta = (without == 0) ? 0 : (without - with) * 100 / without;
String sql = getSQL(jpql);
- System.err.println("Execution time in millis for " + SAMPLE_SIZE
+ System.err.println("Execution time in nanos for " + SAMPLE_SIZE
+ " query execution with and without SQL cache:" + with + " "
+ without + " (" + delta + "%)");
System.err.println("JPQL: " + jpql);
@@ -120,14 +275,14 @@
/**
* Create and run a query N times with the given parameters. The time for
- * each query execution is measured in nanosecond precision) and finally
- * median time taken in N observation is returned in nanosecond.
+ * each query execution is measured in nanosecond precision and
+ * median time taken in N observation is returned.
*
* returns median time taken for single execution.
*/
long run(String jpql, Object[] params, boolean cache, int N) {
OpenJPAEntityManager em = emf.createEntityManager();
- em.getConfiguration().setPreparedQueryCache("" + cache);
+ em.getConfiguration().setPreparedQueryCache(cache);
List<Long> stats = new ArrayList<Long>();
for (int i = 0; i < N; i++) {
@@ -153,15 +308,13 @@
return stats.get(N/2);
}
- public boolean isCached(String jpql) {
- Map cache = emf.getConfiguration().getPreparedQueryCacheInstance();
- return cache != null && cache.get(jpql) != null
- && cache.get(jpql) != PreparedQuery.NOT_CACHABLE;
- }
-
String getSQL(String jpql) {
- Map cache = emf.getConfiguration().getPreparedQueryCacheInstance();
- return cache == null ? null : ((PreparedQuery)cache.get(jpql)).getSQL();
+ PreparedQueryCache cache = emf.getConfiguration().getPreparedQueryCacheInstance();
+ if (cache == null)
+ return "null";
+ if (cache.get(jpql) != null)
+ return cache.get(jpql).getSQL();
+ return "null";
}
@@ -174,7 +327,13 @@
+ "e.department.company.name = :company and e.address.zip = :zip";
Object[] params = { "emp", "John", "dept", "Engineering", "company",
"acme.org", "zip", 12345 };
+ System.err.println("Executing 100 times [" + jpql + "]");
+ System.err.println("Press return to continue...");
+// System.in.read();
+ long start = System.nanoTime();
_this.run(jpql, params, true, 100);
+ long end = System.nanoTime();
+ System.err.println("Time taken " + (end-start) + "ns");
}
}
Modified: openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java (original)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java Wed Sep 10 21:38:24 2008
@@ -32,7 +32,6 @@
import java.util.Collection;
import java.util.EnumSet;
import java.util.Map;
-import java.util.HashMap;
import java.util.IdentityHashMap;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
@@ -64,7 +63,6 @@
import org.apache.openjpa.meta.SequenceMetaData;
import org.apache.openjpa.util.Exceptions;
import org.apache.openjpa.util.ImplHelper;
-import org.apache.openjpa.util.ParameterMap;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
import org.apache.openjpa.util.UserException;
@@ -947,14 +945,15 @@
throw new ArgumentException(_loc.get("no-sql"), null, null, false);
}
- private PreparedQuery getPreparedQuery(String id) {
- Map cache = getConfiguration().getPreparedQueryCacheInstance();
- if (cache == null)
- return null;
- Object val = cache.get(id);
- if (val == PreparedQuery.NOT_CACHABLE)
- return null;
- return (PreparedQuery)val;
+ /**
+ * Gets the prepared query cached by the given key.
+ *
+ * @return the cached PreparedQuery or null if none exists.
+ */
+ PreparedQuery getPreparedQuery(String id) {
+ PreparedQueryCache cache = getConfiguration()
+ .getPreparedQueryCacheInstance();
+ return (cache == null) ? null : cache.get(id);
}
public void setFlushMode(FlushModeType flushMode) {
Modified: openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java (original)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java Wed Sep 10 21:38:24 2008
@@ -44,7 +44,6 @@
* @nojavadoc
*/
public class PreparedQuery {
- public static final PreparedQuery NOT_CACHABLE = new PreparedQuery();
private final String _sql;
private final String _id;
@@ -53,14 +52,6 @@
boolean _subclasses = true;
boolean _isProjection = false;
- /**
- * Private constructor to designate a null marker.
- */
- private PreparedQuery() {
- _sql = null;
- _id = null;
- }
-
public PreparedQuery(String id, String sql, Query compiled) {
this._id = id;
this._sql = sql;
Modified: openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java?rev=694111&r1=694110&r2=694111&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java (original)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java Wed Sep 10 21:38:24 2008
@@ -35,6 +35,7 @@
import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.enhance.Reflection;
+import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.kernel.DelegatingQuery;
import org.apache.openjpa.kernel.DelegatingResultList;
import org.apache.openjpa.kernel.Filters;
@@ -43,6 +44,7 @@
import org.apache.openjpa.kernel.QueryOperations;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.FilterListener;
+import org.apache.openjpa.kernel.jpql.JPQLParser;
import org.apache.openjpa.lib.rop.ResultList;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.ImplHelper;
@@ -64,7 +66,7 @@
private static final Localizer _loc = Localizer.forPackage(QueryImpl.class);
- private final DelegatingQuery _query;
+ private DelegatingQuery _query;
private transient EntityManagerImpl _em;
private transient FetchPlan _fetch;
private ParameterMap _params;
@@ -359,10 +361,15 @@
throw new ArgumentException(_loc.get(
"bad-query-hint-value", key, value), null,
null, false);
- } else if (QueryHints.HINT_INVALIDATE_PREPARED_QUERY.equals(key)) {
- invalidatePreparedQueryCache();
- } else
+ } else if (QueryHints.HINT_INVALIDATE_PREPARED_QUERY.equals
+ (key)) {
_query.getFetchConfiguration().setHint(key, value);
+ invalidatePreparedQuery();
+ } else if (QueryHints.HINT_IGNORE_PREPARED_QUERY.equals(key)) {
+ _query.getFetchConfiguration().setHint(key, (Boolean)value);
+ ignorePreparedQuery();
+ } else
+ _query.getFetchConfiguration().setHint(key, (Boolean)value);
} else
throw new ArgumentException(_loc.get("bad-query-hint", key),
null, null, false);
@@ -559,41 +566,74 @@
}
/**
- * Cache this query with its identifier as key and SQL as value if this
- * query is amenable to caching and has not already been cached.
+ * Cache this query if this query is amenable to caching and has not
+ * already been cached. If the query can not be cached, then mark it as such
+ * to avoid computing for the same key again.
*
* @return non-null if this query has already been cached. null if it can
- * not be cached or cached in this call.
+ * not be cached or cached in this call or hint is set to ignore the cached
+ * version.
*/
PreparedQuery cache() {
- if (_id == null)
+ if (_id == null
+ || !_em.getConfiguration().getPreparedQueryCache()
+ || isHinted(QueryHints.HINT_IGNORE_PREPARED_QUERY)
+ || isHinted(QueryHints.HINT_INVALIDATE_PREPARED_QUERY))
return null;
- Map cache = _em.getConfiguration().getPreparedQueryCacheInstance();
- if (cache == null)
- return null;
- PreparedQuery cached = (PreparedQuery)cache.get(_id);
- if (cached == PreparedQuery.NOT_CACHABLE)
+ PreparedQueryCache cache = _em.getConfiguration()
+ .getPreparedQueryCacheInstance();
+ if (cache.isCachable(_id) == Boolean.FALSE)
return null;
+ PreparedQuery cached = cache.get(_id);
if (cached == null) {
String[] sqls = _query.getDataStoreActions(getParameterMap(true));
- boolean cacheable = sqls.length == 1;
+ boolean cacheable = (sqls.length == 1);
if (!cacheable) {
- cache.put(_id, PreparedQuery.NOT_CACHABLE);
+ cache.markUncachable(_id);
return null;
}
cached = new PreparedQuery(_id, sqls[0], _query);
- cache.put(_id, cached);
- return null;
+ // Attempt to cache may fail if query matches exclusion pattern
+ if (!cache.cache(cached)) {
+ cached = null;
+ }
}
return cached;
}
+ boolean isHinted(String hint) {
+ Object result = _query.getFetchConfiguration().getHint(hint);
+ return result != null && "true".equalsIgnoreCase(result.toString());
+ }
+
/**
* Remove this query from PreparedQueryCache.
*/
- public boolean invalidatePreparedQueryCache() {
- Map cache = _em.getConfiguration().getPreparedQueryCacheInstance();
- return cache != null && cache.remove(_id) != null;
+ private boolean invalidatePreparedQuery() {
+ if (!_em.getConfiguration().getPreparedQueryCache())
+ return false;
+ ignorePreparedQuery();
+ PreparedQueryCache cache = _em.getConfiguration()
+ .getPreparedQueryCacheInstance();
+ return cache.invalidate(_id);
+ }
+
+ /**
+ * Ignores this query from PreparedQueryCache by recreating the original
+ * query if it has been cached.
+ */
+ private void ignorePreparedQuery() {
+ PreparedQuery cached = _em.getPreparedQuery(_id);
+ if (cached == null)
+ return;
+ Broker broker = _em.getBroker();
+ String JPQL = JPQLParser.LANG_JPQL;
+ String jpql = _id;
+ org.apache.openjpa.kernel.Query newQuery = broker.newQuery(JPQL, jpql);
+ newQuery.getFetchConfiguration().copy(_query.getFetchConfiguration());
+ newQuery.compile();
+ _query = new DelegatingQuery(newQuery,
+ broker.getInstanceExceptionTranslator());
}
public int hashCode() {