From bb510ca506f6120126143afff56b29ce3680bc0f Mon Sep 17 00:00:00 2001 From: Par Winzell Date: Fri, 6 Feb 2009 16:09:10 +0000 Subject: [PATCH] Allow for distinguishing long-term caching from brief caching. For example, a public list of high scores may well lag 5 minutes behind database updates, whereas responses in a forum thread should perhaps never be more than 10 seconds out of date. The exact numbers are up to to the ehcache.xml configuration. --- .../com/samskivert/depot/CacheAdapter.java | 2 +- .../com/samskivert/depot/DepotRepository.java | 33 ++++++++++++++----- .../com/samskivert/depot/EHCacheAdapter.java | 14 ++++---- .../samskivert/depot/impl/FindAllQuery.java | 20 ++++++++--- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/java/com/samskivert/depot/CacheAdapter.java b/src/java/com/samskivert/depot/CacheAdapter.java index aaef5de..7946c72 100644 --- a/src/java/com/samskivert/depot/CacheAdapter.java +++ b/src/java/com/samskivert/depot/CacheAdapter.java @@ -44,7 +44,7 @@ import com.samskivert.depot.impl.FindAllQuery; */ public interface CacheAdapter { - public enum CacheCategory { RECORD, KEYSET, RESULT }; + public enum CacheCategory { RECORD, SHORT_KEYSET, LONG_KEYSET, RESULT }; /** The encapsulated result of a cache lookup. */ public interface CachedValue diff --git a/src/java/com/samskivert/depot/DepotRepository.java b/src/java/com/samskivert/depot/DepotRepository.java index 8ca7bb0..b022d6e 100644 --- a/src/java/com/samskivert/depot/DepotRepository.java +++ b/src/java/com/samskivert/depot/DepotRepository.java @@ -93,10 +93,25 @@ public abstract class DepotRepository * there is no invalidation of the keyset query: If records are inserted, deleted or * modified, cached keysets will not be updated. * + * Keysets cached using this strategy should have a short time-to-live. + * * Note: This strategy may not be used on @Computed records, for records that do not in * fact have a primary key, or for queries that use @FieldOverrides. */ - KEYS, + SHORT_KEYS, + + /** + * This strategy is identical to {@link #RECORDS}, but we also cache the keyset fetched + * in the first pass. This makes it much more efficient, but also less reliable because + * there is no invalidation of the keyset query: If records are inserted, deleted or + * modified, cached keysets will not be updated. + * + * Keysets cached using this strategy may have a long time-to-live. + * + * Note: This strategy may not be used on @Computed records, for records that do not in + * fact have a primary key, or for queries that use @FieldOverrides. + */ + LONG_KEYS, /** * This cache strategy is direct and explicit, eschewing the dual phases of the @@ -363,7 +378,7 @@ public abstract class DepotRepository DepotMarshaller marsh = _ctx.getMarshaller(type); switch (cache) { - case KEYS: case BEST: case RECORDS: + case LONG_KEYS: case SHORT_KEYS: case BEST: case RECORDS: String reason = null; if (marsh.getTableName() == null) { reason = type + " is computed"; @@ -380,7 +395,7 @@ public abstract class DepotRepository } } if (cache == CacheStrategy.BEST) { - cache = (reason != null) ? CacheStrategy.NONE : CacheStrategy.KEYS; + cache = (reason != null) ? CacheStrategy.NONE : CacheStrategy.SHORT_KEYS; } else if (reason != null) { // if user explicitly asked for a strategy we can't do, protest @@ -393,12 +408,14 @@ public abstract class DepotRepository cache = CacheStrategy.NONE; } - if (cache == CacheStrategy.KEYS || cache == CacheStrategy.RECORDS) { - return _ctx.invoke(new FindAllQuery.WithCache( - _ctx, type, clauses, cache == CacheStrategy.KEYS)); + switch(cache) { + case SHORT_KEYS: case LONG_KEYS: case RECORDS: + return _ctx.invoke(new FindAllQuery.WithCache(_ctx, type, clauses, cache)); + + default: + return _ctx.invoke(new FindAllQuery.Explicitly( + _ctx, type, clauses, cache == CacheStrategy.CONTENTS)); } - return _ctx.invoke(new FindAllQuery.Explicitly( - _ctx, type, clauses, cache == CacheStrategy.CONTENTS)); } /** diff --git a/src/java/com/samskivert/depot/EHCacheAdapter.java b/src/java/com/samskivert/depot/EHCacheAdapter.java index 867a9f2..d8e9e45 100644 --- a/src/java/com/samskivert/depot/EHCacheAdapter.java +++ b/src/java/com/samskivert/depot/EHCacheAdapter.java @@ -42,16 +42,17 @@ import static com.samskivert.depot.Log.log; * combinations within one category is stuffed into the same {@link Ehcache}, and all elements are * cached under {@link EHCacheKey}, which basically wraps just such a tuple. * - * Thus there are currently only three Ehcaches in play, called 'depotRecord', 'depotKeyset', and - * 'depotResult'. These must be defined in your ehcache.xml configuration. If you use distributed - * replication/invalidation, you should replicate updates and removes but not puts nor - * updates-via-copy. + * Thus there are currently only four Ehcaches in play, called 'depotRecord', 'depotLongKeyset', + * 'depotShortKeyset' and 'depotResult'. These must be defined in your ehcache.xml configuration. + * If you use distributed replication/invalidation, you should replicate updates and removes but + * not puts nor updates-via-copy. */ public class EHCacheAdapter implements CacheAdapter { public static final String EHCACHE_RECORD_CACHE = "depotRecord"; - public static final String EHCACHE_KEYSET_CACHE = "depotKeyset"; + public static final String EHCACHE_SHORT_KEYSET_CACHE = "depotShortKeyset"; + public static final String EHCACHE_LONG_KEYSET_CACHE = "depotLongKeyset"; public static final String EHCACHE_RESULT_CACHE = "depotResult"; public static class EHCachePerformance @@ -70,7 +71,8 @@ public class EHCacheAdapter public EHCacheAdapter (CacheManager cachemgr) { bindEHCache(cachemgr, CacheCategory.RECORD, EHCACHE_RECORD_CACHE); - bindEHCache(cachemgr, CacheCategory.KEYSET, EHCACHE_KEYSET_CACHE); + bindEHCache(cachemgr, CacheCategory.SHORT_KEYSET, EHCACHE_SHORT_KEYSET_CACHE); + bindEHCache(cachemgr, CacheCategory.LONG_KEYSET, EHCACHE_LONG_KEYSET_CACHE); bindEHCache(cachemgr, CacheCategory.RESULT, EHCACHE_RESULT_CACHE); } diff --git a/src/java/com/samskivert/depot/impl/FindAllQuery.java b/src/java/com/samskivert/depot/impl/FindAllQuery.java index 3fc04a4..91e5423 100644 --- a/src/java/com/samskivert/depot/impl/FindAllQuery.java +++ b/src/java/com/samskivert/depot/impl/FindAllQuery.java @@ -47,6 +47,7 @@ import com.samskivert.depot.PersistentRecord; import com.samskivert.depot.SimpleCacheKey; import com.samskivert.depot.Stats; import com.samskivert.depot.CacheAdapter.CacheCategory; +import com.samskivert.depot.DepotRepository.CacheStrategy; import com.samskivert.depot.clause.FieldOverride; import com.samskivert.depot.clause.QueryClause; import com.samskivert.depot.clause.SelectClause; @@ -67,7 +68,7 @@ public abstract class FindAllQuery extends Query extends FindAllQuery { public WithCache (PersistenceContext ctx, Class type, - Collection clauses, boolean cacheKeys) + Collection clauses, CacheStrategy strategy) throws DatabaseException { super(ctx, type); @@ -84,11 +85,21 @@ public abstract class FindAllQuery extends Query(_type, _marsh.getPrimaryKeyFields(), clauses); - if (cacheKeys) { + switch(strategy) { + case SHORT_KEYS: case LONG_KEYS: _qkey = new SimpleCacheKey(_marsh.getTableName() + "Keys", _select.toString()); - } else { + _category = (strategy == CacheStrategy.SHORT_KEYS) ? + CacheCategory.SHORT_KEYSET : CacheCategory.LONG_KEYSET; + break; + + case RECORDS: _qkey = null; + break; + + default: + throw new IllegalArgumentException("Unexpected cache strategy: " + strategy); } + } @Override // from Query @@ -136,7 +147,7 @@ public abstract class FindAllQuery extends Query extends Query _select; protected KeySet _keys; protected Set> _fetchKeys;