diff --git a/src/java/com/samskivert/depot/CacheAdapter.java b/src/java/com/samskivert/depot/CacheAdapter.java index 3d01776..aaef5de 100644 --- a/src/java/com/samskivert/depot/CacheAdapter.java +++ b/src/java/com/samskivert/depot/CacheAdapter.java @@ -23,7 +23,6 @@ package com.samskivert.depot; import java.io.Serializable; import com.samskivert.depot.impl.FindAllQuery; -import com.samskivert.util.Tuple; /** * Implementations of this interface are responsible for all the caching needs of Depot. @@ -31,14 +30,14 @@ import com.samskivert.util.Tuple; * From the point of view of this interface, there are a potentially very large number of * caches available, each idenfided by a unique cacheId. Currently Depot creates up to three * caches for each record type: - * + * * Any record type with a primary key has a {@link CacheCategory#RECORD} cache, for storing * record instances by primary key. - * + * * Record types with primary keys may also have a {@link CacheCategory#KEYSET} cache wherein * {@link KeySet} instances are stored, identified by query strings. See {@link FindAllQuery} * for more on this. - * + * * Finally, clients may request {@link CacheCategory#RESULT} caching of entire result sets of * some record type -- which does not need to have a primary key, in contrast to the other two * categories. These are also identified by query strings, and end up in a third cache. @@ -73,7 +72,7 @@ public interface CacheAdapter /** * Provides a way to enumerate the currently cached entries for the given cache. */ - public Iterable>> enumerate (String cacheId); + public Iterable enumerate (String cacheId); /** * Shut down all operations, e.g. persisting memory contents to disk. diff --git a/src/java/com/samskivert/depot/EHCacheAdapter.java b/src/java/com/samskivert/depot/EHCacheAdapter.java index 535ad2a..1a14318 100644 --- a/src/java/com/samskivert/depot/EHCacheAdapter.java +++ b/src/java/com/samskivert/depot/EHCacheAdapter.java @@ -27,7 +27,6 @@ import java.util.Set; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.samskivert.util.Tuple; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Ehcache; @@ -122,34 +121,14 @@ public class EHCacheAdapter } // from CacheAdapter - public Iterable>> enumerate (final String cacheId) + public Iterable enumerate (final String cacheId) { - if (_slowEnumerations > 5) { - return Collections.emptySet(); - } - long now = System.currentTimeMillis(); - EHCacheBin bin = _bins.get(cacheId); if (bin == null) { return Collections.emptySet(); } - Set>> result = Sets.newHashSet(); - Ehcache cache = bin.getCache(); - - for (Serializable key : bin.getKeys()) { - CachedValue value = lookup(cache, cacheId, key); - if (value != null) { - result.add(Tuple.newTuple(key, value)); - } - } - long dT = System.currentTimeMillis() - now; - if (dT > 50) { - _slowEnumerations ++; - log.warning("Aii! Enumerating cache took a long time!", "cacheId", cacheId, "dT", dT, - "cacheSize", result.size(), "disabled", _slowEnumerations > 5); - } - return result; + return Sets.newHashSet(bin.getKeys()); } // from CacheAdapter @@ -190,9 +169,6 @@ public class EHCacheAdapter return cache; } - // TODO: To be removed when we're done investigating potential sluggishness - protected int _slowEnumerations = 0; - protected Map _categories = Collections.synchronizedMap(Maps.newHashMap()); protected Map> _bins = @@ -278,7 +254,8 @@ public class EHCacheAdapter protected Ehcache _cache; protected String _id; - protected Set _keys = Sets.newConcurrentHashSet(); + protected Set _keys = Collections.synchronizedSet( + Sets.newHashSet()); } // this is just for convenience and memory use; we don't rely on pointer equality anywhere diff --git a/src/java/com/samskivert/depot/OldEHCacheAdapter.java b/src/java/com/samskivert/depot/OldEHCacheAdapter.java new file mode 100644 index 0000000..97d0903 --- /dev/null +++ b/src/java/com/samskivert/depot/OldEHCacheAdapter.java @@ -0,0 +1,192 @@ +// +// $Id: EHCacheAdapter.java 325 2008-11-16 08:03:33Z samskivert $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell +// +// This library 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 2.1 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, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot; + +import java.io.Serializable; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Element; +import net.sf.ehcache.distribution.CacheManagerPeerListener; +import net.sf.ehcache.distribution.CacheManagerPeerProvider; +import net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator; + +import static com.samskivert.depot.Log.log; + +/** + * An implementation of {@link CacheAdapter} for ehcache. + */ +public class OldEHCacheAdapter + implements CacheAdapter +{ + /** + * Creates an adapter using the supplied cache manager. Note: this adapter does not shut down + * the supplied manager when it is shutdown. The caller is responsible for shutting down the + * cache manager when it knows that Depot and any other clients no longer need it. + */ + public OldEHCacheAdapter (CacheManager cachemgr) + { + _cachemgr = cachemgr; + + CacheManagerPeerListener listener = _cachemgr.getCachePeerListener(); + CacheManagerPeerProvider provider = _cachemgr.getCachePeerProvider(); + if ((provider != null) != (listener != null)) { + // we want either both listener and provider, or neither + log.warning("EHCache misconfigured, distributed mode disabled [listener =" + + listener + ", provider=" + provider); + _distributed = false; + + } else { + _distributed = (listener != null); + } + } + + public EHCacheBin getCache (String id) + { + return new EHCacheBin(id); + } + + /** + * The main ehcache-bridging class, a {@link CacheBin} interface against {@link Cache}. + */ + protected class EHCacheBin + { + // from CacheBin + public CachedValue lookup (Serializable key) + { + Element hit = _cache.get(key); + if (hit == null) { + return null; + } + + Serializable rawValue = hit.getValue(); + @SuppressWarnings("unchecked") + final T value = (T) (rawValue instanceof NullValue ? null : rawValue); + return new CachedValue() { + public T getValue () { + return value; + } + @Override public String toString () { + return String.valueOf(value); + } + }; + } + + // from CacheBin + public void store (Serializable key, T value) + { + _cache.put(new Element(key, value != null ? value : NULL)); + } + + // from CacheBin + public void remove (Serializable key) + { + _cache.remove(key); + } + + // from CacheBin + public Iterable enumerateKeys () + { + @SuppressWarnings("unchecked") Iterable keys = _cache.getKeys(); + return keys; + } + + protected EHCacheBin (String id) + { + synchronized (_cachemgr) { + _cache = _cachemgr.getCache(id); + if (_cache == null) { + // create the cache programatically with reasonable settings + // TODO: we will eventually need this to be configurable in .properties + _cache = new Cache(id, + 3000, // keep 3000 elements in RAM + false, // overflow the rest to disk + false, // don't keep records around eternally + 300, // keep them for 5 minutes after they're created + 60); // or 60 seconds after last access + + if (_distributed) { + // a programatically created cache has to have its replicator event + // listener programatically added. + _cache.getCacheEventNotificationService().registerListener( + new RMIAsynchronousCacheReplicator(false, true, false, true, 1000)); + } + _cachemgr.addCache(_cache); + } + } + } + + protected Cache _cache; + } + + // from CacheAdapter + public void shutdown () + { + } + + protected boolean _distributed; + protected CacheManager _cachemgr; + + // this is just for convenience and memory use; we don't rely on pointer equality anywhere + protected static Serializable NULL = new NullValue() {}; + + /** A class to represent an explicitly Serializable concept of null for EHCache. */ + protected static class NullValue implements Serializable + { + @Override public String toString () + { + return ""; + } + + @Override public boolean equals (Object other) + { + return other != null && other.getClass().equals(NullValue.class); + } + + @Override public int hashCode () + { + return 1; + } + } + + public Iterable enumerate (String cacheId) + { + return getCache(cacheId).enumerateKeys(); + } + + public CachedValue lookup (String cacheId, Serializable key) + { + // TODO Auto-generated method stub + return null; + } + + public void remove (String cacheId, Serializable key) + { + // TODO Auto-generated method stub + + } + + public void store (CacheCategory category, String cacheId, Serializable key, T value) + { + // TODO Auto-generated method stub + + } +} diff --git a/src/java/com/samskivert/depot/PersistenceContext.java b/src/java/com/samskivert/depot/PersistenceContext.java index 2564789..5e3f0a7 100644 --- a/src/java/com/samskivert/depot/PersistenceContext.java +++ b/src/java/com/samskivert/depot/PersistenceContext.java @@ -436,9 +436,11 @@ public class PersistenceContext return; } - Iterable>> entries = _cache.enumerate(cacheId); - for (Tuple> entry : entries) { - filter.visitCacheEntry(this, cacheId, entry.left, entry.right.getValue()); + for (Serializable key : _cache.enumerate(cacheId)) { + CachedValue result = _cache.lookup(cacheId, key); + if (result != null && result.getValue() != null) { + filter.visitCacheEntry(this, cacheId, key, result.getValue()); + } } }