mirror of
https://github.com/apache/openjpa.git
synced 2025-02-23 02:48:46 +00:00
OPENJPA-703: Beef up strong/weak exclusion of cache entries. Narrow down reason for exclusion.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@791971 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9f62d5ebfa
commit
dcaa13461e
@ -51,21 +51,21 @@ import org.apache.openjpa.lib.util.Localizer;
|
||||
*/
|
||||
public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
private static final String PATTERN_SEPARATOR = "\\;";
|
||||
private static final String EXLUDED_BY_USER = "Excluded by user";
|
||||
// Key: Query identifier
|
||||
private final Map<String, PreparedQuery> _delegate;
|
||||
// Key: Query identifier Value: Reason why excluded
|
||||
private final Map<String, String> _uncachables;
|
||||
private List<String> _exclusionPatterns;
|
||||
private final Map<String, Exclusion> _uncachables;
|
||||
private final List<Exclusion> _exclusionPatterns;
|
||||
private final QueryStatistics<String> _stats;
|
||||
private ReentrantLock _lock = new ReentrantLock();
|
||||
private Log _log;
|
||||
private Localizer _loc = Localizer.forPackage(PreparedQueryCacheImpl.class);
|
||||
|
||||
private static Localizer _loc = Localizer.forPackage(PreparedQueryCacheImpl.class);
|
||||
|
||||
public PreparedQueryCacheImpl() {
|
||||
_delegate = new HashMap<String, PreparedQuery>();
|
||||
_uncachables = new HashMap<String, String>();
|
||||
_uncachables = new HashMap<String, Exclusion>();
|
||||
_stats = new QueryStatistics.Default<String>();
|
||||
_exclusionPatterns = new ArrayList<Exclusion>();
|
||||
}
|
||||
|
||||
public Boolean register(String id, Query query, FetchConfiguration hints) {
|
||||
@ -113,9 +113,9 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
_log.warn(_loc.get("prepared-query-not-cachable", id));
|
||||
return false;
|
||||
}
|
||||
String pattern = getMatchedExclusionPattern(id);
|
||||
if (pattern != null) {
|
||||
markUncachable(id, pattern);
|
||||
Exclusion exclusion = getMatchedExclusionPattern(id);
|
||||
if (exclusion != null) {
|
||||
markUncachable(id, exclusion);
|
||||
return false;
|
||||
}
|
||||
_delegate.put(id, q);
|
||||
@ -133,9 +133,9 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
if (pq == null)
|
||||
return null;
|
||||
|
||||
boolean cacheable = pq.initialize(result);
|
||||
if (!cacheable) {
|
||||
markUncachable(key);
|
||||
Exclusion exclusion = pq.initialize(result);
|
||||
if (exclusion != null) {
|
||||
markUncachable(key, exclusion);
|
||||
return null;
|
||||
}
|
||||
return pq;
|
||||
@ -144,8 +144,8 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
public boolean invalidate(String id) {
|
||||
lock();
|
||||
try {
|
||||
if (_log.isTraceEnabled())
|
||||
_log.trace(_loc.get("prepared-query-invalidate", id));
|
||||
if (_log != null && _log.isInfoEnabled())
|
||||
_log.info(_loc.get("prepared-query-invalidate", id));
|
||||
return _delegate.remove(id) != null;
|
||||
} finally {
|
||||
unlock();
|
||||
@ -174,22 +174,12 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
}
|
||||
}
|
||||
|
||||
public PreparedQuery markUncachable(String id) {
|
||||
return markUncachable(id, EXLUDED_BY_USER);
|
||||
}
|
||||
|
||||
private PreparedQuery markUncachable(String id, String reason) {
|
||||
public PreparedQuery markUncachable(String id, Exclusion exclusion) {
|
||||
lock();
|
||||
try {
|
||||
boolean excludedByUser = _uncachables.get(id) == EXLUDED_BY_USER;
|
||||
if (!excludedByUser)
|
||||
_uncachables.put(id, reason);
|
||||
if (_log != null && _log.isInfoEnabled()) {
|
||||
if (excludedByUser)
|
||||
_log.info(_loc.get("prepared-query-uncache-strong", id));
|
||||
else
|
||||
_log.info(_loc.get("prepared-query-uncache-weak", id,
|
||||
reason));
|
||||
if (_uncachables.put(id, exclusion) == null) {
|
||||
if (_log != null && _log.isInfoEnabled())
|
||||
_log.info(_loc.get("prepared-query-uncache", id, exclusion));
|
||||
}
|
||||
return _delegate.remove(id);
|
||||
} finally {
|
||||
@ -197,8 +187,8 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExcluded(String id) {
|
||||
return getMatchedExclusionPattern(id) != null;
|
||||
public Exclusion isExcluded(String id) {
|
||||
return getMatchedExclusionPattern(id);
|
||||
}
|
||||
|
||||
public void setExcludes(String excludes) {
|
||||
@ -206,8 +196,6 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
try {
|
||||
if (StringUtils.isEmpty(excludes))
|
||||
return;
|
||||
if (_exclusionPatterns == null)
|
||||
_exclusionPatterns = new ArrayList<String>();
|
||||
String[] patterns = excludes.split(PATTERN_SEPARATOR);
|
||||
for (String pattern : patterns)
|
||||
addExclusionPattern(pattern);
|
||||
@ -216,9 +204,8 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getExcludes() {
|
||||
return _exclusionPatterns == null ? Collections.EMPTY_LIST :
|
||||
Collections.unmodifiableList(_exclusionPatterns);
|
||||
public List<Exclusion> getExcludes() {
|
||||
return Collections.unmodifiableList(_exclusionPatterns);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,16 +215,14 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
public void addExclusionPattern(String pattern) {
|
||||
lock();
|
||||
try {
|
||||
if (_exclusionPatterns == null)
|
||||
_exclusionPatterns = new ArrayList<String>();
|
||||
_exclusionPatterns.add(pattern);
|
||||
Collection<String> invalidKeys = getMatchedKeys(pattern,
|
||||
_delegate.keySet());
|
||||
if (!invalidKeys.isEmpty() && _log != null && _log.isInfoEnabled())
|
||||
_log.info(_loc.get("prepared-query-add-pattern", pattern,
|
||||
invalidKeys.size(), invalidKeys));
|
||||
for (String invalidKey : invalidKeys)
|
||||
markUncachable(invalidKey, pattern);
|
||||
String reason = _loc.get("prepared-query-excluded-by-user", pattern).getMessage();
|
||||
Exclusion exclusion = new WeakExclusion(pattern, reason);
|
||||
_exclusionPatterns.add(exclusion);
|
||||
Collection<String> invalidKeys = getMatchedKeys(pattern, _delegate.keySet());
|
||||
for (String invalidKey : invalidKeys) {
|
||||
Exclusion invalid = new WeakExclusion(invalidKey, reason);
|
||||
markUncachable(invalidKey, invalid);
|
||||
}
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
@ -251,15 +236,14 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
public void removeExclusionPattern(String pattern) {
|
||||
lock();
|
||||
try {
|
||||
if (_exclusionPatterns == null)
|
||||
return;
|
||||
_exclusionPatterns.remove(pattern);
|
||||
Exclusion exclusion = new WeakExclusion(pattern, null);
|
||||
_exclusionPatterns.remove(exclusion);
|
||||
Collection<String> reborns = getMatchedKeys(pattern, _uncachables);
|
||||
if (!reborns.isEmpty() && _log != null && _log.isInfoEnabled())
|
||||
_log.info(_loc.get("prepared-query-remove-pattern", pattern,
|
||||
reborns.size(), reborns));
|
||||
for (String rebornKey : reborns)
|
||||
_uncachables.remove(rebornKey);
|
||||
for (String rebornKey : reborns) {
|
||||
_uncachables.remove(rebornKey);
|
||||
if (_log != null && _log.isInfoEnabled())
|
||||
_log.info(_loc.get("prepared-query-remove-pattern", pattern, rebornKey));
|
||||
}
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
@ -272,11 +256,9 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
/**
|
||||
* Gets the pattern that matches the given identifier.
|
||||
*/
|
||||
private String getMatchedExclusionPattern(String id) {
|
||||
if (_exclusionPatterns == null || _exclusionPatterns.isEmpty())
|
||||
return null;
|
||||
for (String pattern : _exclusionPatterns)
|
||||
if (matches(pattern, id))
|
||||
private Exclusion getMatchedExclusionPattern(String id) {
|
||||
for (Exclusion pattern : _exclusionPatterns)
|
||||
if (pattern.matches(id))
|
||||
return pattern;
|
||||
return null;
|
||||
}
|
||||
@ -284,11 +266,11 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
/**
|
||||
* Gets the keys of the given map whose values match the given pattern.
|
||||
*/
|
||||
private Collection<String> getMatchedKeys(String pattern,
|
||||
Map<String,String> map) {
|
||||
private Collection<String> getMatchedKeys(String pattern, Map<String,Exclusion> map) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
if (matches(pattern, entry.getValue())) {
|
||||
for (Map.Entry<String, Exclusion> entry : map.entrySet()) {
|
||||
Exclusion exclusion = entry.getValue();
|
||||
if (!exclusion.isStrong() && exclusion.matches(pattern)) {
|
||||
result.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
@ -298,8 +280,7 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
/**
|
||||
* Gets the elements of the given list which match the given pattern.
|
||||
*/
|
||||
private Collection<String> getMatchedKeys(String pattern,
|
||||
Collection<String> coll) {
|
||||
private Collection<String> getMatchedKeys(String pattern, Collection<String> coll) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (String key : coll) {
|
||||
if (matches(pattern, key)) {
|
||||
@ -348,4 +329,91 @@ public class PreparedQueryCacheImpl implements PreparedQueryCache {
|
||||
|
||||
public void endConfiguration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* An immutable abstract pattern for exclusion.
|
||||
*
|
||||
*/
|
||||
private static abstract class ExclusionPattern implements PreparedQueryCache.Exclusion {
|
||||
private final boolean _strong;
|
||||
private final String _pattern;
|
||||
private final String _reason;
|
||||
|
||||
private static Localizer _loc = Localizer.forPackage(PreparedQueryCacheImpl.class);
|
||||
private static String STRONG = _loc.get("strong-exclusion").getMessage();
|
||||
private static String WEAK = _loc.get("weak-exclusion").getMessage();
|
||||
|
||||
public ExclusionPattern(boolean _strong, String _pattern, String _reason) {
|
||||
super();
|
||||
this._strong = _strong;
|
||||
this._pattern = _pattern;
|
||||
this._reason = _reason;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return _reason;
|
||||
}
|
||||
|
||||
public boolean isStrong() {
|
||||
return _strong;
|
||||
}
|
||||
|
||||
public boolean matches(String id) {
|
||||
return _pattern != null && (_pattern.equals(id) || _pattern.matches(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equals by strength and pattern (not by reason).
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(Object other) {
|
||||
if (other == this)
|
||||
return true;
|
||||
if (!(other instanceof Exclusion))
|
||||
return false;
|
||||
Exclusion that = (Exclusion)other;
|
||||
return this._strong == that.isStrong()
|
||||
&& StringUtils.equals(this._pattern, that.getPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (_strong ? 1 : 0)
|
||||
+ (_pattern == null ? 0 : _pattern.hashCode());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(_strong ? STRONG : WEAK);
|
||||
if (_reason != null)
|
||||
buf.append(_reason);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strong exclusion.
|
||||
*
|
||||
*/
|
||||
public static class StrongExclusion extends ExclusionPattern {
|
||||
|
||||
public StrongExclusion(String pattern, String reason) {
|
||||
super(true, pattern, reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Weak exclusion.
|
||||
*
|
||||
*/
|
||||
public static class WeakExclusion extends ExclusionPattern {
|
||||
|
||||
public WeakExclusion(String pattern, String reason) {
|
||||
super(false, pattern, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import org.apache.openjpa.kernel.Query;
|
||||
import org.apache.openjpa.kernel.QueryImpl;
|
||||
import org.apache.openjpa.kernel.QueryLanguages;
|
||||
import org.apache.openjpa.kernel.StoreQuery;
|
||||
import org.apache.openjpa.kernel.PreparedQueryCache.Exclusion;
|
||||
import org.apache.openjpa.kernel.exps.QueryExpressions;
|
||||
import org.apache.openjpa.lib.rop.ResultList;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
@ -153,42 +154,52 @@ public class PreparedQueryImpl implements PreparedQuery {
|
||||
* The input argument is processed only if it is a {@link ResultList} with
|
||||
* an attached {@link SelectResultObjectProvider} as its
|
||||
* {@link ResultList#getUserObject() user object}.
|
||||
*
|
||||
* @return an exclusion if can not be initialized for some reason.
|
||||
* null if initialization is successful.
|
||||
*/
|
||||
public boolean initialize(Object result) {
|
||||
public Exclusion initialize(Object result) {
|
||||
if (isInitialized())
|
||||
return true;
|
||||
SelectExecutor selector = extractSelectExecutor(result);
|
||||
return null;
|
||||
Object[] extract = extractSelectExecutor(result);
|
||||
SelectExecutor selector = (SelectExecutor)extract[0];
|
||||
if (selector == null)
|
||||
return new PreparedQueryCacheImpl.StrongExclusion(_id, ((Localizer.Message)extract[1]).getMessage());
|
||||
if (selector == null || selector.hasMultipleSelects()
|
||||
|| ((selector instanceof Union)
|
||||
&& (((Union)selector).getSelects().length != 1)))
|
||||
return false;
|
||||
return new PreparedQueryCacheImpl.StrongExclusion(_id, _loc.get("exclude-multi-select").getMessage());
|
||||
select = extractImplementation(selector);
|
||||
if (select == null)
|
||||
return false;
|
||||
return new PreparedQueryCacheImpl.StrongExclusion(_id, _loc.get("exclude-no-select").getMessage());
|
||||
SQLBuffer buffer = selector.getSQL();
|
||||
if (buffer == null)
|
||||
return false;
|
||||
return new PreparedQueryCacheImpl.StrongExclusion(_id, _loc.get("exclude-no-sql").getMessage());;
|
||||
setTargetQuery(buffer.getSQL());
|
||||
setParameters(buffer.getParameters());
|
||||
setUserParameterPositions(buffer.getUserParameters());
|
||||
_initialized = true;
|
||||
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the underlying SelectExecutor from the given argument, if possible.
|
||||
*
|
||||
* @return two objects in an array. The element at index 0 is SelectExecutor,
|
||||
* if it can be extracted. The element at index 1 is the reason why it can
|
||||
* not be extracted.
|
||||
*/
|
||||
private SelectExecutor extractSelectExecutor(Object result) {
|
||||
private Object[] extractSelectExecutor(Object result) {
|
||||
if (result instanceof ResultList == false)
|
||||
return null;
|
||||
return new Object[]{null, _loc.get("exclude-not-result")};
|
||||
Object userObject = ((ResultList<?>)result).getUserObject();
|
||||
if (userObject == null || !userObject.getClass().isArray() || ((Object[])userObject).length != 2)
|
||||
return null;
|
||||
return new Object[]{null, _loc.get("exclude-no-user-object")};
|
||||
Object provider = ((Object[])userObject)[0];
|
||||
Object executor = ((Object[])userObject)[1];
|
||||
if (executor instanceof StoreQuery.Executor == false)
|
||||
return null;
|
||||
return new Object[]{null, _loc.get("exclude-not-executor")};
|
||||
_exps = ((StoreQuery.Executor)executor).getQueryExpressions();
|
||||
if (_exps[0].projections.length == 0) {
|
||||
_projTypes = StoreQuery.EMPTY_CLASSES;
|
||||
@ -202,9 +213,9 @@ public class PreparedQueryImpl implements PreparedQuery {
|
||||
provider = ((QueryImpl.PackingResultObjectProvider)provider).getDelegate();
|
||||
}
|
||||
if (provider instanceof SelectResultObjectProvider) {
|
||||
return ((SelectResultObjectProvider)provider).getSelect();
|
||||
return new Object[]{((SelectResultObjectProvider)provider).getSelect(), null};
|
||||
}
|
||||
return null;
|
||||
return new Object[]{null, _loc.get("exclude-not-select-rop")};
|
||||
}
|
||||
|
||||
private SelectImpl extractImplementation(SelectExecutor selector) {
|
||||
|
@ -113,15 +113,16 @@ graph-not-cycle-free: A circular flush dependency has been found after all \
|
||||
batch_limit: The batch limit is set to {0}.
|
||||
batch_update_info: ExecuteBatch command returns update count {0} for \
|
||||
statement {1}.
|
||||
strong-exclusion: excluded permanently
|
||||
weak-exclusion: excluded temporarily
|
||||
prepared-query-excluded-by-user: because matches user specified exclusion \
|
||||
pattern "{0}"
|
||||
prepared-query-cached: Query "{0}" is cached as target query "{1}"
|
||||
prepared-query-not-cachable: Query "{0}" is not fit for caching.
|
||||
prepared-query-invalidate: Query "{0}" is invalidated and removed from cache.
|
||||
prepared-query-uncache-strong: Query "{0}" is permanently excluded from cache.
|
||||
prepared-query-uncache-weak: Query "{0}" is excluded temporarily due to "{1}".
|
||||
prepared-query-add-pattern: Adding a Query exclusion pattern "{0}" has caused \
|
||||
following {1} cached queries to be removed from the cache: "{2}".
|
||||
prepared-query-remove-pattern: Removing a Query exclusion pattern "{0}" caused \
|
||||
following {1} queries to be re-inserted in the cache: "{2}".
|
||||
prepared-query-uncache: Query "{0}" is removed from cache {1}.
|
||||
prepared-query-remove-pattern: Removing exclusion pattern "{0}" caused \
|
||||
query to be cacheable again.
|
||||
uparam-mismatch: Supplied user parameters "{1}" do not match expected \
|
||||
parameters "{0}" for the prepared query "{2}".
|
||||
uparam-null: No user parameter was given. Expected parameters "{0}" for the \
|
||||
@ -152,3 +153,16 @@ bad-lrs-size: Invalid LRS size. Valid values are \
|
||||
"unknown"(0), "last"(1) or "query"(2). Specified value: {0}.
|
||||
bad-join-syntax: Invalid join syntax. Valid values are \
|
||||
"sql92"(0), "tradition"(1) or "database"(2). Specified value: {0}.
|
||||
exclude-multi-select: because this query generates multiple SQL statements. \
|
||||
A query can be cached only when it corresponds to a single SQL statement.
|
||||
exclude-not-result: because this query returns a single value rather than \
|
||||
a list. A query that returns single value can not be cached.
|
||||
exclude-no-user-object: because post-execution data can not be extracted \
|
||||
from this query.
|
||||
exclude-no-sql: because target SQL statement can not be extracted \
|
||||
from this query.
|
||||
exclude-no-select: because internal select instance can not be extracted \
|
||||
from this query.
|
||||
exclude-no-select-rop: because the query result is not obtained by executing \
|
||||
a select statement. This can happen if the query was evaluated in-memory.
|
||||
exclude-not-executor: because this query was not executed on a data store.
|
||||
|
@ -20,6 +20,8 @@ package org.apache.openjpa.kernel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.kernel.PreparedQueryCache.Exclusion;
|
||||
|
||||
/**
|
||||
* A prepared query associates a compiled query to a <em>parsed state</em> that
|
||||
* can be executed possibly with more efficiency. An obvious example is to
|
||||
@ -86,10 +88,10 @@ public interface PreparedQuery {
|
||||
* @param o an opaque instance supposed to carry post-execution data such
|
||||
* as target database query, parameters of the query etc.
|
||||
*
|
||||
* @return true if this receiver can initialize itself from the given
|
||||
* @return Exclusion if this receiver can initialize itself from the given
|
||||
* argument. false otherwise.
|
||||
*/
|
||||
public boolean initialize(Object o);
|
||||
public Exclusion initialize(Object o);
|
||||
|
||||
/**
|
||||
* Affirms if this receiver has been initialized.
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -55,8 +56,8 @@ import org.apache.openjpa.lib.conf.Configurable;
|
||||
*
|
||||
* This cache allows customization of whether a query can be cached or not
|
||||
* via either explicit marking of certain keys as non-cachable (which is
|
||||
* irreversible) or addition/removal of exclusion patterns (which is
|
||||
* reversible).
|
||||
* irreversible or <em>strong</em>) or addition/removal of exclusion patterns
|
||||
* (which is reversible or <em>weak</em>).
|
||||
*
|
||||
* @see #markUncachable(String)
|
||||
* @see #addExclusionPattern(String)
|
||||
@ -143,25 +144,28 @@ public interface PreparedQueryCache extends Configurable {
|
||||
|
||||
/**
|
||||
* Marks the given key as not amenable to caching.
|
||||
* Explicit marking helps to avoid repeated computational cost of
|
||||
* determining whether a query can be cached or not.
|
||||
* Explicit marking helps to avoid repeated computational cost of
|
||||
* determining whether a query can be cached or not.
|
||||
*
|
||||
* Explicit marking can not be reversed by removal of exclusion patterns.
|
||||
* @param id is the key to be excluded
|
||||
* @param exclusion directs whether exclusion is irreversible or not.
|
||||
*
|
||||
* @return The value for the given key if it had been cached before. null
|
||||
* otherwise.
|
||||
*/
|
||||
public PreparedQuery markUncachable(String id);
|
||||
public PreparedQuery markUncachable(String id, Exclusion exclusion);
|
||||
|
||||
/**
|
||||
* Affirms if the given key matches any of the exclusion patterns.
|
||||
* Returns the exclusion status of if the given query key.
|
||||
*
|
||||
* @return null implies that the key is not excluded.
|
||||
*/
|
||||
public boolean isExcluded(String id);
|
||||
public Exclusion isExcluded(String id);
|
||||
|
||||
/**
|
||||
* Gets the exclusion patterns.
|
||||
*/
|
||||
public List<String> getExcludes();
|
||||
public List<Exclusion> getExcludes();
|
||||
|
||||
/**
|
||||
* Sets one or more exclusion regular expression patterns separated by
|
||||
@ -182,7 +186,7 @@ public interface PreparedQueryCache extends Configurable {
|
||||
* Any excluded key that matches the given pattern can now be cached
|
||||
* again, unless it has been marked non-cachable explicitly.
|
||||
*
|
||||
* @see #markUncachable(String)
|
||||
* @see #markUncachable(String, Exclusion)
|
||||
*/
|
||||
public void removeExclusionPattern(String pattern);
|
||||
|
||||
@ -195,4 +199,31 @@ public interface PreparedQueryCache extends Configurable {
|
||||
* Gets the simple statistics for executed queries.
|
||||
*/
|
||||
public QueryStatistics<String> getStatistics();
|
||||
|
||||
/**
|
||||
* A structure to describe the strength and reason for excluding a query from the cache.
|
||||
*
|
||||
*/
|
||||
public static interface Exclusion {
|
||||
/**
|
||||
* Affirms if this exclusion is strong i.e. can never be reversed.
|
||||
*/
|
||||
public boolean isStrong();
|
||||
|
||||
/**
|
||||
* Gets the human-readable reason for excluding this query from being cached.
|
||||
*/
|
||||
public String getReason();
|
||||
|
||||
/**
|
||||
* The pattern (either the exact query string or a regular expression) that
|
||||
* denotes this exclusion.
|
||||
*/
|
||||
public String getPattern();
|
||||
|
||||
/**
|
||||
* Affirms if this exclusion matches the given identifier.
|
||||
*/
|
||||
boolean matches(String id);
|
||||
}
|
||||
}
|
||||
|
@ -417,3 +417,7 @@ bad-lock-level: Invalid lock mode/level. Valid values are \
|
||||
"optimistic-force-increment"(25), "pessimistic-read"(30), \
|
||||
"pessimistic-write"(40) or "pessimistic-force-increment"(50). \
|
||||
Specified value: {0}.
|
||||
declared-unbound-params: User specified parameter "{1}" does not appear in \
|
||||
declared parameters "{2}" of the query "{0}".
|
||||
user-unbound-params: User has not bound parameter "{1}" for the query "{0}". \
|
||||
The declared parameters are "{2}", bound parameters are "{3}".
|
@ -59,7 +59,10 @@ public class TestFinderCache extends SQLListenerTestCase {
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
super.setUp(CLEAR_TABLES, Merchandise.class, Book.class, CD.class,
|
||||
super.setUp(CLEAR_TABLES,
|
||||
"openjpa.RuntimeUnenhancedClasses", "unsupported",
|
||||
"openjpa.DynamicEnhancementAgent", "false",
|
||||
Merchandise.class, Book.class, CD.class,
|
||||
Author.class, Person.class, Singer.class, Address.class);
|
||||
createTestData();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.openjpa.persistence.jdbc.sqlcache;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
@ -55,10 +56,14 @@ public class TestPreparedQueryCacheExclusion extends TestCase {
|
||||
String excludes = "a;b;c";
|
||||
cache.setExcludes(excludes);
|
||||
assertEquals(3, cache.getExcludes().size());
|
||||
assertTrue(cache.isExcluded("a"));
|
||||
assertTrue(cache.isExcluded("b"));
|
||||
assertTrue(cache.isExcluded("c"));
|
||||
assertFalse(cache.isExcluded("d"));
|
||||
assertNotNull(cache.isExcluded("a"));
|
||||
assertNotNull(cache.isExcluded("b"));
|
||||
assertNotNull(cache.isExcluded("c"));
|
||||
assertNull(cache.isExcluded("d"));
|
||||
|
||||
List<PreparedQueryCache.Exclusion> exclusions = cache.getExcludes();
|
||||
for (PreparedQueryCache.Exclusion e : exclusions)
|
||||
System.err.println(e);
|
||||
}
|
||||
|
||||
public void testCachePopulationSetUp() {
|
||||
@ -106,7 +111,8 @@ public class TestPreparedQueryCacheExclusion extends TestCase {
|
||||
|
||||
public void testRemoveExclusionPatternDoesNotRemoveUserProhbitedKeys() {
|
||||
String USER_MARKED_UNCACHABLE = "[user prohibited]";
|
||||
cache.markUncachable(USER_MARKED_UNCACHABLE);
|
||||
cache.markUncachable(USER_MARKED_UNCACHABLE,
|
||||
new PreparedQueryCacheImpl.StrongExclusion(USER_MARKED_UNCACHABLE,"for testing"));
|
||||
|
||||
PreparedQuery p = new PreparedQueryImpl(USER_MARKED_UNCACHABLE, "xyz",
|
||||
null);
|
||||
|
Loading…
x
Reference in New Issue
Block a user