Update of /var/cvs/src/org/mmbase/cache
In directory james.mmbase.org:/tmp/cvs-serv10057
Modified Files:
Cache.java CacheImplementationInterface.java
QueryResultCache.java
Log Message:
MMB-1667, changed locking object, and made it explicit
See also: http://cvs.mmbase.org/viewcvs/src/org/mmbase/cache
See also: http://www.mmbase.org/jira/browse/MMB-1667
Index: Cache.java
===================================================================
RCS file: /var/cvs/src/org/mmbase/cache/Cache.java,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -b -r1.49 -r1.50
--- Cache.java 3 Feb 2008 17:33:56 -0000 1.49
+++ Cache.java 24 Jun 2008 09:54:44 -0000 1.50
@@ -20,7 +20,7 @@
* A base class for all Caches. Extend this class for other caches.
*
* @author Michiel Meeuwissen
- * @version $Id: Cache.java,v 1.49 2008/02/03 17:33:56 nklasens Exp $
+ * @version $Id: Cache.java,v 1.50 2008/06/24 09:54:44 michiel Exp $
*/
abstract public class Cache<K, V> implements SizeMeasurable, Map<K, V> {
@@ -33,6 +33,7 @@
* @since MMBase-1.8
*/
private CacheImplementationInterface<K, V> implementation;
+ protected Object lock;
/**
* The number of times an element was succesfully retrieved from this
cache.
@@ -52,6 +53,7 @@
public Cache(int size) {
// See: http://www.mmbase.org/jira/browse/MMB-1486
implementation = new LRUCache<K, V>(size);
+ lock = = implementation.getLock();
//implementation = new LRUHashtable<K, V>(size);
log.service("Creating cache " + getName() + ": " + getDescription());
@@ -63,6 +65,7 @@
if (implementation == null || (!
clas.equals(implementation.getClass()))) {
implementation = (CacheImplementationInterface<K,V>)
clas.newInstance();
implementation.config(configValues);
+ lock = implementation.getLock();
}
} catch (ClassNotFoundException cnfe) {
log.error("For cache " + this + " " + cnfe.getClass().getName() +
": " + cnfe.getMessage());
@@ -118,6 +121,13 @@
}
/**
+ * @since MMBase-1.8.6
+ */
+ public Class getImplementation() {
+ return implementation.getClass();
+ }
+
+ /**
* Checks whether the key object should be cached.
* This method returns <code>false</code> if either the current cache is
inactive, or the object to cache
* has a cache policy associated that prohibits caching of the object.
Index: CacheImplementationInterface.java
===================================================================
RCS file: /var/cvs/src/org/mmbase/cache/CacheImplementationInterface.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- CacheImplementationInterface.java 10 Aug 2007 07:53:52 -0000 1.9
+++ CacheImplementationInterface.java 24 Jun 2008 09:54:44 -0000 1.10
@@ -17,7 +17,7 @@
* An implementation of this interface has to be thread-safe to guarantee
correctness.
*
* @author Michiel Meeuwissen
- * @version $Id: CacheImplementationInterface.java,v 1.9 2007/08/10 07:53:52
michiel Exp $
+ * @version $Id: CacheImplementationInterface.java,v 1.10 2008/06/24 09:54:44
michiel Exp $
* @since MMBase-1.8
*/
public interface CacheImplementationInterface<K, V> extends Map<K, V> {
@@ -42,4 +42,10 @@
*/
void config(Map<String, String> configuration);
+ /**
+ * The cache implementation must be somehow thread-safe. This method should
+ * return the object on which to synchronize, e.g. when looping over
entrySet.
+ * @since MMBase-1.8.6
+ */
+ Object getLock();
}
Index: QueryResultCache.java
===================================================================
RCS file: /var/cvs/src/org/mmbase/cache/QueryResultCache.java,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -b -r1.45 -r1.46
--- QueryResultCache.java 17 Sep 2007 16:53:01 -0000 1.45
+++ QueryResultCache.java 24 Jun 2008 09:54:44 -0000 1.46
@@ -27,14 +27,15 @@
* one of the types present in the SearchQuery is changed (,created or
deleted).
* This mechanism is not very subtle but it is garanteed to be correct. It
means
* though that your cache can be considerably less effective for queries
- * containing node types from which often node are edited.
+ * containing node types from which often nodes are edited.
*
* @author Daniel Ockeloen
* @author Michiel Meeuwissen
* @author Bunst Eunders
- * @version $Id: QueryResultCache.java,v 1.45 2007/09/17 16:53:01 pierre Exp $
+ * @version $Id: QueryResultCache.java,v 1.46 2008/06/24 09:54:44 michiel Exp $
* @since MMBase-1.7
* @see org.mmbase.storage.search.SearchQuery
+ * @todo Perhaps we could put the 'typeCounter' stuff in a sub-class.
*/
abstract public class QueryResultCache extends Cache<SearchQuery,
List<MMObjectNode>> implements NodeEventListener, RelationEventListener {
@@ -47,6 +48,8 @@
* A relation role name is considered a type
* This cache will not invalidate when an event does not mention one of
these types
* The cache will be evaluated when a parent type is in this map.
+ * @todo I think that nearly all query result caches contain queries with
quite generic or
+ * oftenly changed types. I doubt that the gain is worth the hassle.
*/
private Map<String, Integer> typeCounters = new HashMap<String, Integer>();
@@ -100,14 +103,16 @@
/**
* Puts a search result in this cache.
*/
- public synchronized List<MMObjectNode> put(SearchQuery query,
List<MMObjectNode> queryResult) {
+ public List<MMObjectNode> put(SearchQuery query, List<MMObjectNode>
queryResult) {
if (!checkCachePolicy(query)) return null;
if (query instanceof BasicQuery) {
query = ((BasicQuery) query).getQuery();
}
+ synchronized(lock) {
increaseCounters(query, typeCounters);
return super.put(query, queryResult);
}
+ }
/**
* Removes an object from the cache. It alsos remove the watch from the
@@ -115,14 +120,16 @@
*
* @param key A SearchQuery object.
*/
- public synchronized List<MMObjectNode> remove(SearchQuery key) {
+ public List<MMObjectNode> remove(SearchQuery key) {
if (key instanceof BasicQuery) {
key = ((BasicQuery) key).getQuery();
}
+ synchronized(lock) {
List<MMObjectNode> result = super.remove(key);
- decreaseCounters(key, typeCounters);
+ if (result != null) decreaseCounters(key, typeCounters);
return result;
}
+ }
private void increaseCounters(SearchQuery query, Map<String, Integer>
counters) {
for (Step step : query.getSteps()) {
@@ -130,8 +137,7 @@
if (counters.containsKey(stepName)) {
int count = counters.get(stepName);
counters.put(stepName, count + 1);
- }
- else {
+ } else {
counters.put(stepName, 1);
}
}
@@ -144,8 +150,7 @@
int count = counters.get(stepName);
if (count > 1) {
counters.put(stepName, count - 1);
- }
- else {
+ } else {
counters.remove(stepName);
}
}
@@ -165,7 +170,12 @@
}
}
+ /**
+ *
+ * @todo Is the lock necessary?
+ */
private boolean containsType(RelationEvent event) {
+ synchronized(lock) {
if (typeCounters.containsKey("object")) {
return true;
}
@@ -198,6 +208,8 @@
}
return false;
}
+ }
+
/**
* @see
org.mmbase.core.event.NodeEventListener#notify(org.mmbase.core.event.NodeEvent)
@@ -209,6 +221,7 @@
}
private boolean containsType(NodeEvent event) {
+ synchronized(lock) {
if (typeCounters.containsKey("object")) {
return true;
}
@@ -227,6 +240,7 @@
}
return false;
}
+ }
protected int nodeChanged(Event event) throws IllegalArgumentException{
if (log.isDebugEnabled()) {
@@ -234,7 +248,7 @@
}
Set<SearchQuery> cacheKeys;
Map<String, Integer> oldTypeCounters;
- synchronized(this) {
+ synchronized(lock) {
cacheKeys = new HashSet<SearchQuery>(keySet());
oldTypeCounters = new HashMap<String, Integer>(typeCounters);
}
@@ -244,7 +258,7 @@
evaluate(event, cacheKeys, removeKeys, foundTypeCounters);
- synchronized(this) {
+ synchronized(lock) {
for (SearchQuery q : removeKeys) {
remove(q);
}
@@ -275,7 +289,9 @@
}
return removeKeys.size();
}
-
+ /**
+ * @javadoc
+ */
private void evaluate(Event event, Set<SearchQuery> cacheKeys,
Set<SearchQuery> removeKeys, Map<String, Integer> foundTypeCounters) {
int evaluatedResults = cacheKeys.size();
long startTime = System.currentTimeMillis();
_______________________________________________
Cvs mailing list
[email protected]
http://lists.mmbase.org/mailman/listinfo/cvs