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.
This commit is contained in:
@@ -44,7 +44,7 @@ import com.samskivert.depot.impl.FindAllQuery;
|
|||||||
*/
|
*/
|
||||||
public interface CacheAdapter
|
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. */
|
/** The encapsulated result of a cache lookup. */
|
||||||
public interface CachedValue<T>
|
public interface CachedValue<T>
|
||||||
|
|||||||
@@ -93,10 +93,25 @@ public abstract class DepotRepository
|
|||||||
* there is no invalidation of the keyset query: If records are inserted, deleted or
|
* there is no invalidation of the keyset query: If records are inserted, deleted or
|
||||||
* modified, cached keysets will not be updated.
|
* 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
|
* 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.
|
* 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
|
* This cache strategy is direct and explicit, eschewing the dual phases of the
|
||||||
@@ -363,7 +378,7 @@ public abstract class DepotRepository
|
|||||||
DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||||
|
|
||||||
switch (cache) {
|
switch (cache) {
|
||||||
case KEYS: case BEST: case RECORDS:
|
case LONG_KEYS: case SHORT_KEYS: case BEST: case RECORDS:
|
||||||
String reason = null;
|
String reason = null;
|
||||||
if (marsh.getTableName() == null) {
|
if (marsh.getTableName() == null) {
|
||||||
reason = type + " is computed";
|
reason = type + " is computed";
|
||||||
@@ -380,7 +395,7 @@ public abstract class DepotRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cache == CacheStrategy.BEST) {
|
if (cache == CacheStrategy.BEST) {
|
||||||
cache = (reason != null) ? CacheStrategy.NONE : CacheStrategy.KEYS;
|
cache = (reason != null) ? CacheStrategy.NONE : CacheStrategy.SHORT_KEYS;
|
||||||
|
|
||||||
} else if (reason != null) {
|
} else if (reason != null) {
|
||||||
// if user explicitly asked for a strategy we can't do, protest
|
// if user explicitly asked for a strategy we can't do, protest
|
||||||
@@ -393,12 +408,14 @@ public abstract class DepotRepository
|
|||||||
cache = CacheStrategy.NONE;
|
cache = CacheStrategy.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache == CacheStrategy.KEYS || cache == CacheStrategy.RECORDS) {
|
switch(cache) {
|
||||||
return _ctx.invoke(new FindAllQuery.WithCache<T>(
|
case SHORT_KEYS: case LONG_KEYS: case RECORDS:
|
||||||
_ctx, type, clauses, cache == CacheStrategy.KEYS));
|
return _ctx.invoke(new FindAllQuery.WithCache<T>(_ctx, type, clauses, cache));
|
||||||
|
|
||||||
|
default:
|
||||||
|
return _ctx.invoke(new FindAllQuery.Explicitly<T>(
|
||||||
|
_ctx, type, clauses, cache == CacheStrategy.CONTENTS));
|
||||||
}
|
}
|
||||||
return _ctx.invoke(new FindAllQuery.Explicitly<T>(
|
|
||||||
_ctx, type, clauses, cache == CacheStrategy.CONTENTS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
* 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.
|
* cached under {@link EHCacheKey}, which basically wraps just such a tuple.
|
||||||
*
|
*
|
||||||
* Thus there are currently only three Ehcaches in play, called 'depotRecord', 'depotKeyset', and
|
* Thus there are currently only four Ehcaches in play, called 'depotRecord', 'depotLongKeyset',
|
||||||
* 'depotResult'. These must be defined in your ehcache.xml configuration. If you use distributed
|
* 'depotShortKeyset' and 'depotResult'. These must be defined in your ehcache.xml configuration.
|
||||||
* replication/invalidation, you should replicate updates and removes but not puts nor
|
* If you use distributed replication/invalidation, you should replicate updates and removes but
|
||||||
* updates-via-copy.
|
* not puts nor updates-via-copy.
|
||||||
*/
|
*/
|
||||||
public class EHCacheAdapter
|
public class EHCacheAdapter
|
||||||
implements CacheAdapter
|
implements CacheAdapter
|
||||||
{
|
{
|
||||||
public static final String EHCACHE_RECORD_CACHE = "depotRecord";
|
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 final String EHCACHE_RESULT_CACHE = "depotResult";
|
||||||
|
|
||||||
public static class EHCachePerformance
|
public static class EHCachePerformance
|
||||||
@@ -70,7 +71,8 @@ public class EHCacheAdapter
|
|||||||
public EHCacheAdapter (CacheManager cachemgr)
|
public EHCacheAdapter (CacheManager cachemgr)
|
||||||
{
|
{
|
||||||
bindEHCache(cachemgr, CacheCategory.RECORD, EHCACHE_RECORD_CACHE);
|
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);
|
bindEHCache(cachemgr, CacheCategory.RESULT, EHCACHE_RESULT_CACHE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import com.samskivert.depot.PersistentRecord;
|
|||||||
import com.samskivert.depot.SimpleCacheKey;
|
import com.samskivert.depot.SimpleCacheKey;
|
||||||
import com.samskivert.depot.Stats;
|
import com.samskivert.depot.Stats;
|
||||||
import com.samskivert.depot.CacheAdapter.CacheCategory;
|
import com.samskivert.depot.CacheAdapter.CacheCategory;
|
||||||
|
import com.samskivert.depot.DepotRepository.CacheStrategy;
|
||||||
import com.samskivert.depot.clause.FieldOverride;
|
import com.samskivert.depot.clause.FieldOverride;
|
||||||
import com.samskivert.depot.clause.QueryClause;
|
import com.samskivert.depot.clause.QueryClause;
|
||||||
import com.samskivert.depot.clause.SelectClause;
|
import com.samskivert.depot.clause.SelectClause;
|
||||||
@@ -67,7 +68,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
|
|||||||
public static class WithCache<T extends PersistentRecord> extends FindAllQuery<T>
|
public static class WithCache<T extends PersistentRecord> extends FindAllQuery<T>
|
||||||
{
|
{
|
||||||
public WithCache (PersistenceContext ctx, Class<T> type,
|
public WithCache (PersistenceContext ctx, Class<T> type,
|
||||||
Collection<? extends QueryClause> clauses, boolean cacheKeys)
|
Collection<? extends QueryClause> clauses, CacheStrategy strategy)
|
||||||
throws DatabaseException
|
throws DatabaseException
|
||||||
{
|
{
|
||||||
super(ctx, type);
|
super(ctx, type);
|
||||||
@@ -84,11 +85,21 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
_select = new SelectClause<T>(_type, _marsh.getPrimaryKeyFields(), clauses);
|
_select = new SelectClause<T>(_type, _marsh.getPrimaryKeyFields(), clauses);
|
||||||
if (cacheKeys) {
|
switch(strategy) {
|
||||||
|
case SHORT_KEYS: case LONG_KEYS:
|
||||||
_qkey = new SimpleCacheKey(_marsh.getTableName() + "Keys", _select.toString());
|
_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;
|
_qkey = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected cache strategy: " + strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // from Query
|
@Override // from Query
|
||||||
@@ -136,7 +147,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
|
|||||||
}
|
}
|
||||||
if (_qkey != null) {
|
if (_qkey != null) {
|
||||||
// cache the resulting key set
|
// cache the resulting key set
|
||||||
ctx.cacheStore(CacheCategory.KEYSET, _qkey, _keys);
|
ctx.cacheStore(_category, _qkey, _keys);
|
||||||
}
|
}
|
||||||
// and fetch any records we can from the cache
|
// and fetch any records we can from the cache
|
||||||
_fetchKeys = loadFromCache(ctx, _keys, _entities);
|
_fetchKeys = loadFromCache(ctx, _keys, _entities);
|
||||||
@@ -147,6 +158,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected SimpleCacheKey _qkey;
|
protected SimpleCacheKey _qkey;
|
||||||
|
protected CacheCategory _category;
|
||||||
protected SelectClause<T> _select;
|
protected SelectClause<T> _select;
|
||||||
protected KeySet<T> _keys;
|
protected KeySet<T> _keys;
|
||||||
protected Set<Key<T>> _fetchKeys;
|
protected Set<Key<T>> _fetchKeys;
|
||||||
|
|||||||
Reference in New Issue
Block a user