diff options
| author | Andrew Branson <andrew.branson@cern.ch> | 2012-12-18 17:02:17 +0100 |
|---|---|---|
| committer | Andrew Branson <andrew.branson@cern.ch> | 2012-12-18 17:02:17 +0100 |
| commit | 31746638f0a7d99093f9348e14436c3b7aea28db (patch) | |
| tree | 40f3f215f72974287e0a057d6fe4547a9d81963c | |
| parent | 82a3a75cf8045a638e0dcd90dcff39a67609bc68 (diff) | |
Added optional WeakCache to hold fewer ClusterStorage objects in memory.
Enabled with Storage.useWeakCache property. Useful for large imports and
other operations that involve accessing a large number of items over a
short period.
4 files changed, 193 insertions, 10 deletions
diff --git a/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java b/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java index 70fb46d..c49b41f 100644 --- a/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java +++ b/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java @@ -16,7 +16,9 @@ import com.c2kernel.persistency.outcome.Outcome; import com.c2kernel.persistency.outcome.Viewpoint;
import com.c2kernel.process.Gateway;
import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.NonStrongRefCache;
import com.c2kernel.utils.SoftCache;
+import com.c2kernel.utils.WeakCache;
/**
* instantiates ClusterStorages listed in properties file All read/write requests to storage pass through this object, which
@@ -31,7 +33,7 @@ public class ClusterStorageManager { HashMap<String, ArrayList<ClusterStorage>> clusterWriters = new HashMap<String, ArrayList<ClusterStorage>>();
HashMap<String, ArrayList<ClusterStorage>> clusterReaders = new HashMap<String, ArrayList<ClusterStorage>>();
// we don't need a soft cache for the top level cache - the proxies and entities clear that when reaped
- HashMap<Integer, SoftCache<String, C2KLocalObject>> memoryCache = new HashMap<Integer, SoftCache<String, C2KLocalObject>>();
+ HashMap<Integer, NonStrongRefCache<String, C2KLocalObject>> memoryCache = new HashMap<Integer, NonStrongRefCache<String, C2KLocalObject>>();
/**
* Initialises all ClusterStorage handlers listed by class name in the property "ClusterStorages"
@@ -159,7 +161,7 @@ public class ClusterStorageManager { public C2KLocalObject get(Integer sysKeyIntObj, String path) throws ClusterStorageException, ObjectNotFoundException {
C2KLocalObject result = null;
// check cache first
- SoftCache<String, C2KLocalObject> sysKeyMemCache = null;
+ NonStrongRefCache<String, C2KLocalObject> sysKeyMemCache = null;
if (memoryCache.containsKey(sysKeyIntObj)) {
sysKeyMemCache = memoryCache.get(sysKeyIntObj);
synchronized(sysKeyMemCache) {
@@ -208,7 +210,9 @@ public class ClusterStorageManager { if (result != null) { // got it!
// store it in the cache
if (sysKeyMemCache == null) { // create cache if needed
- sysKeyMemCache = new SoftCache<String, C2KLocalObject>(0);
+ boolean useWeak = Gateway.getProperty("Storage.useWeakCache","false").equals("true");
+ Logger.msg(7,"ClusterStorageManager.put() - Creating "+(useWeak?"Weak":"Strong")+" cache for entity "+sysKeyIntObj);
+ sysKeyMemCache = useWeak?new WeakCache<String, C2KLocalObject>():new SoftCache<String, C2KLocalObject>(0);
synchronized (memoryCache) {
memoryCache.put(sysKeyIntObj, sysKeyMemCache);
}
@@ -242,11 +246,13 @@ public class ClusterStorageManager { }
}
// put in mem cache if that worked
- SoftCache<String, C2KLocalObject> sysKeyMemCache;
+ NonStrongRefCache<String, C2KLocalObject> sysKeyMemCache;
if (memoryCache.containsKey(sysKeyIntObj))
sysKeyMemCache = memoryCache.get(sysKeyIntObj);
else {
- sysKeyMemCache = new SoftCache<String, C2KLocalObject>();
+ boolean useWeak = Gateway.getProperty("Storage.useWeakCache","false").equals("true");
+ Logger.msg(7,"ClusterStorageManager.put() - Creating "+(useWeak?"Weak":"Strong")+" cache for entity "+sysKeyIntObj);
+ sysKeyMemCache = useWeak?new WeakCache<String, C2KLocalObject>():new SoftCache<String, C2KLocalObject>(0);
synchronized (memoryCache) {
memoryCache.put(sysKeyIntObj, sysKeyMemCache);
}
@@ -277,7 +283,7 @@ public class ClusterStorageManager { }
if (memoryCache.containsKey(sysKeyIntObj)) {
- SoftCache<?, ?> sysKeyMemCache = memoryCache.get(sysKeyIntObj);
+ NonStrongRefCache<?, ?> sysKeyMemCache = memoryCache.get(sysKeyIntObj);
synchronized (sysKeyMemCache) {
sysKeyMemCache.remove(path);
}
@@ -292,7 +298,7 @@ public class ClusterStorageManager { Logger.msg(7, "CSM.clearCache() - removing "+sysKeyIntObj+"/"+path);
if (memoryCache.containsKey(sysKeyIntObj)) {
- SoftCache<String, C2KLocalObject> sysKeyMemCache = memoryCache.get(sysKeyIntObj);
+ NonStrongRefCache<String, C2KLocalObject> sysKeyMemCache = memoryCache.get(sysKeyIntObj);
synchronized(sysKeyMemCache) {
for (Iterator<String> iter = sysKeyMemCache.keySet().iterator(); iter.hasNext();) {
String thisPath = iter.next();
@@ -312,7 +318,7 @@ public class ClusterStorageManager { if (memoryCache.containsKey(sysKeyIntObj)) {
synchronized (memoryCache) {
if (Logger.doLog(6)) {
- SoftCache<?, ?> sysKeyMemCache = memoryCache.get(sysKeyIntObj);
+ NonStrongRefCache<?, ?> sysKeyMemCache = memoryCache.get(sysKeyIntObj);
int size = sysKeyMemCache.size();
Logger.msg(6, "CSM.clearCache() - "+size+" objects to remove.");
}
@@ -335,7 +341,7 @@ public class ClusterStorageManager { synchronized(memoryCache) {
for (Integer sysKey : memoryCache.keySet()) {
Logger.msg(logLevel, "Cached Objects of Entity "+sysKey);
- SoftCache<?, ?> sysKeyMemCache = memoryCache.get(sysKey);
+ NonStrongRefCache<?, ?> sysKeyMemCache = memoryCache.get(sysKey);
try {
synchronized(sysKeyMemCache) {
for (Object name : sysKeyMemCache.keySet()) {
diff --git a/src/main/java/com/c2kernel/utils/NonStrongRefCache.java b/src/main/java/com/c2kernel/utils/NonStrongRefCache.java new file mode 100644 index 0000000..400f587 --- /dev/null +++ b/src/main/java/com/c2kernel/utils/NonStrongRefCache.java @@ -0,0 +1,43 @@ +/*
+ * NonStrongRefCache.java
+ *
+ * Copyright (c) 2012, The CRISTAL Consortium. All rights reserved.
+ *
+ * CRISTAL kernel is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see:
+ * http://www.gnu.org/licenses/
+ */
+
+package com.c2kernel.utils;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+public interface NonStrongRefCache<K, V> {
+
+ public abstract V get(Object key);
+
+ public abstract V put(K key, V value);
+
+ public abstract V remove(Object key);
+
+ public abstract void clear();
+
+ public abstract int size();
+
+ public abstract Set<K> keySet();
+
+ public abstract Set<Map.Entry<K, V>> entrySet();
+
+}
\ No newline at end of file diff --git a/src/main/java/com/c2kernel/utils/SoftCache.java b/src/main/java/com/c2kernel/utils/SoftCache.java index 2fd79f1..da58c87 100644 --- a/src/main/java/com/c2kernel/utils/SoftCache.java +++ b/src/main/java/com/c2kernel/utils/SoftCache.java @@ -14,7 +14,7 @@ import java.util.Set; *
* $Revision: 1.5 $ $Date: 2004/10/29 13:29:09 $
******************************************************************************/
-public class SoftCache<K, V> extends AbstractMap<K, V> {
+public class SoftCache<K, V> extends AbstractMap<K, V> implements NonStrongRefCache<K, V> {
private final Map<K, SoftValue<V>> hash = new HashMap<K, SoftValue<V>>();
private final int minSize;
diff --git a/src/main/java/com/c2kernel/utils/WeakCache.java b/src/main/java/com/c2kernel/utils/WeakCache.java new file mode 100644 index 0000000..e7ec105 --- /dev/null +++ b/src/main/java/com/c2kernel/utils/WeakCache.java @@ -0,0 +1,134 @@ +package com.c2kernel.utils;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.AbstractMap;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+/*******************************************************************************
+ * WeakReferences are reaped if no strong references are left next time the gc has a chance.
+ * The ClusterStorageManager caches can optionally use this one, for high volume imports etc
+ *
+ * $Revision: 1.5 $ $Date: 2004/10/29 13:29:09 $
+ ******************************************************************************/
+public class WeakCache<K, V> extends AbstractMap<K, V> implements NonStrongRefCache<K, V> {
+
+ private final Map<K, WeakValue<V>> hash = new HashMap<K, WeakValue<V>>();
+ private final int minSize;
+ private final LinkedList<V> hardCache = new LinkedList<V>();
+ private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
+
+ public WeakCache() {
+ this(0);
+ }
+
+ public WeakCache(int minSize) {
+ this.minSize = minSize;
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#get(java.lang.Object)
+ */
+ @Override
+ public V get(Object key) {
+ V result = null;
+ WeakValue<V> weak_ref = hash.get(key);
+ if (weak_ref != null) {
+ result = weak_ref.get();
+ if (result == null)
+ hash.remove(key);
+ else
+ if (minSize > 0) { // add to hard cache so it's not reaped for a while
+ hardCache.addFirst(result);
+ if (hardCache.size() > minSize) // trim last one off
+ hardCache.removeLast();
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#put(K, V)
+ */
+ @Override
+ public V put(K key, V value) {
+ processQueue();
+ if (minSize > 0) {
+ hardCache.addFirst(value);
+ if (hardCache.size() > minSize)
+ hardCache.removeLast();
+ }
+ hash.put(key, new WeakValue<V>(key, value, queue));
+ return value;
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#remove(java.lang.Object)
+ */
+ @Override
+ public V remove(Object key) {
+ processQueue();
+ if (hash.containsKey(key)) return hash.remove(key).get();
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#clear()
+ */
+ @Override
+ public void clear() {
+ hardCache.clear();
+ while(queue.poll()!=null);
+ hash.clear();
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#size()
+ */
+ @Override
+ public int size() {
+ processQueue();
+ return hash.size();
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#keySet()
+ */
+ @Override
+ public Set<K> keySet() {
+ processQueue();
+ return hash.keySet();
+ }
+
+ /* (non-Javadoc)
+ * @see com.c2kernel.utils.NonStrongRefCache#entrySet()
+ */
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ // Would have to create another Map to do this - too expensive
+ // Throwing runtime expensive is dangerous, but better than nulls
+ throw new UnsupportedOperationException();
+ }
+
+ private static class WeakValue<V> extends WeakReference<V> {
+ private final Object key;
+ private WeakValue(Object key, V value, ReferenceQueue<V> q) {
+ super(value, q);
+ this.key = key;
+ }
+ }
+
+ /**
+ * Look for values that have been reaped, and remove their keys from the cache
+ */
+ private void processQueue() {
+ WeakValue<V> sv;
+ while ((sv = (WeakValue<V>) queue.poll()) != null) {
+ hash.remove(sv.key);
+ }
+ }
+
+}
|
