Step one in making Depot's caching classloader friendly: make the keys use only

system classes (not 100% done, if you use a ByteEnum in a key right now it
doesn't do the right thing). Also moved SimpleCacheKey into impl because it's
an implementation detail, not meant to be used by external parties.
This commit is contained in:
Michael Bayne
2009-07-30 22:06:18 +00:00
parent c0b031a36d
commit e876ff0832
8 changed files with 129 additions and 72 deletions
+8 -19
View File
@@ -28,23 +28,24 @@ import java.util.Map;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.impl.DepotMarshaller;
import com.samskivert.depot.impl.DepotUtil;
import com.samskivert.depot.impl.ExpressionVisitor;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.impl.KeyCacheKey;
/**
* A special form of {@link WhereClause} that uniquely specifies a single database row and thus
* also a single persistent object. Because it implements both {@link CacheKey} and {@link
* CacheInvalidator} it also uniquely indexes into the cache and knows how to invalidate itself
* upon modification. This class is created by many {@link DepotMarshaller} methods as a
* convenience, and may also be instantiated explicitly.
* also a single persistent object. It knows how to invalidate itself upon modification. This class
* is created by many {@link DepotMarshaller} methods as a convenience, and may also be
* instantiated explicitly.
*/
public class Key<T extends PersistentRecord> extends WhereClause
implements SQLExpression, CacheKey, ValidatingCacheInvalidator, Serializable
implements SQLExpression, ValidatingCacheInvalidator
{
/** Handles the matching of the key columns to its bound values. This is needed so that we can
* combine a bunch of keys into a {@link KeySet}. */
@@ -199,18 +200,6 @@ public class Key<T extends PersistentRecord> extends WhereClause
return builder.visit(this);
}
// from CacheKey
public String getCacheId ()
{
return _pClass.getName();
}
// from CacheKey
public Serializable getCacheKey ()
{
return this;
}
// from ValidatingCacheInvalidator
public void validateFlushType (Class<?> pClass)
{
@@ -225,7 +214,7 @@ public class Key<T extends PersistentRecord> extends WhereClause
// from CacheInvalidator
public void invalidate (PersistenceContext ctx)
{
ctx.cacheInvalidate(this);
ctx.cacheInvalidate(new KeyCacheKey(this));
}
/**
+4 -3
View File
@@ -34,13 +34,14 @@ import com.samskivert.util.Logger;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.operator.In;
import com.samskivert.depot.operator.Or;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.LiteralExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.impl.DepotUtil;
import com.samskivert.depot.impl.ExpressionVisitor;
import com.samskivert.depot.impl.KeyCacheKey;
import com.samskivert.depot.operator.In;
import com.samskivert.depot.operator.Or;
/**
* Contains a set of primary keys that match a set of persistent records. This is used internally
@@ -299,7 +300,7 @@ public abstract class KeySet<T extends PersistentRecord> extends WhereClause
// from ValidatingCacheInvalidator
public void invalidate (PersistenceContext ctx) {
for (Key<T> key : this) {
ctx.cacheInvalidate(key);
ctx.cacheInvalidate(new KeyCacheKey(key));
}
}
@@ -74,22 +74,21 @@ public class PersistenceContext
public static interface CacheListener<T>
{
/**
* The given entry (which is never null) has just been evicted from the cache slot
* indicated by the given key.
* The given entry (which is never null) has just been evicted from the cache.
*
* This method is most commonly used to trigger custom cache invalidation of records that
* depend on the one that was just invalidated.
*/
public void entryInvalidated (CacheKey key, T oldEntry);
public void entryInvalidated (T oldEntry);
/**
* The given entry, which may be an explicit null, has just been placed into the cache
* under the given key. The previous cache entry, if any, is also supplied.
* The given entry, which may be an explicit null, has just been placed into the cache. The
* previous cache entry, if any, is also supplied.
*
* This method is most likely used by repositories to index entries by attribute for quick
* cache invalidation when brute force is unrealistically time consuming.
*/
public void entryCached (CacheKey key, T newEntry, T oldEntry);
public void entryCached (T newEntry, T oldEntry);
}
/**
@@ -345,7 +344,7 @@ public class PersistenceContext
log.debug("cascading [listener=" + listener + "]");
@SuppressWarnings("unchecked")
CacheListener<T> casted = (CacheListener<T>)listener;
casted.entryCached(key, entry, oldEntry);
casted.entryCached(entry, oldEntry);
}
}
}
@@ -363,15 +362,6 @@ public class PersistenceContext
}
}
/**
* Evicts the cache entry indexed under the given class and cache key, if there is one. The
* eviction may trigger further cache invalidations.
*/
public void cacheInvalidate (Class<? extends PersistentRecord> pClass, Serializable cacheKey)
{
cacheInvalidate(pClass.getName(), cacheKey);
}
/**
* Evicts the cache entry indexed under the given cache id and cache key, if there is one. The
* eviction may trigger further cache invalidations.
@@ -393,12 +383,11 @@ public class PersistenceContext
// if there was one, do (possibly cascading) cache invalidations
Set<CacheListener<?>> listeners = _listenerSets.get(cacheId);
if (listeners != null && listeners.size() > 0) {
CacheKey key = new SimpleCacheKey(cacheId, cacheKey);
for (CacheListener<?> listener : listeners) {
log.debug("cascading [listener=" + listener + "]");
@SuppressWarnings("unchecked") CacheListener<T> casted =
(CacheListener<T>)listener;
casted.entryInvalidated(key, oldEntry);
casted.entryInvalidated(oldEntry);
}
}
}
@@ -46,7 +46,6 @@ import com.samskivert.depot.Key;
import com.samskivert.depot.KeySet;
import com.samskivert.depot.PersistenceContext;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.SimpleCacheKey;
import com.samskivert.depot.Stats;
import com.samskivert.depot.XArrayList;
import com.samskivert.depot.XList;
@@ -283,7 +282,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<XLi
{
Set<Key<T>> fetchKeys = Sets.newHashSet();
for (Key<T> key : allKeys) {
T value = ctx.<T>cacheLookup(key);
T value = ctx.<T>cacheLookup(new KeyCacheKey(key));
if (value != null) {
@SuppressWarnings("unchecked") T newValue = (T) value.clone();
entities.put(key, newValue);
@@ -360,7 +359,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<XLi
if (entities.put(key, obj) != null) {
dups++;
}
ctx.cacheStore(CacheCategory.RECORD, key, obj.clone()); // cache our result
ctx.cacheStore(CacheCategory.RECORD, new KeyCacheKey(key), obj.clone());
got.add(key);
cnt++;
}
@@ -98,7 +98,7 @@ public class FindOneQuery<T extends PersistentRecord> extends Query<T>
if (key == null) {
// no row-specific cache key was given, if we can, create a key from the record
if (result != null && _marsh.hasPrimaryKey()) {
key = _marsh.getPrimaryKey(result);
key = new KeyCacheKey(_marsh.getPrimaryKey(result));
}
}
if (PersistenceContext.CACHE_DEBUG) {
@@ -0,0 +1,94 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2009 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.impl;
import java.io.Serializable;
import java.util.Arrays;
import com.samskivert.depot.CacheKey;
import com.samskivert.depot.Key;
/**
* Converts a {@link CacheKey} to and from a {@link Key} in a way that eliminates references to
* non-Java classes (so that we don't have to deal with RMI classloader hell when replicating cache
* contents).
*/
public class KeyCacheKey
implements CacheKey, Serializable
{
public KeyCacheKey (Key<?> key)
{
_cacheId = key.getPersistentClass().getName();
Comparable<?>[] values = key.getValues();
_values = new Comparable<?>[values.length];
for (int ii = 0; ii < _values.length; ii++) {
_values[ii] = values[ii]; // TODO: check for non-system-class and serialize
}
}
// from CacheKey
public String getCacheId ()
{
return _cacheId;
}
// from CacheKey
public Serializable getCacheKey ()
{
return this;
}
@Override // from Object
public boolean equals (Object obj)
{
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return Arrays.equals(_values, ((KeyCacheKey) obj)._values);
}
@Override // from Object
public int hashCode ()
{
return Arrays.hashCode(_values);
}
@Override // from Object
public String toString ()
{
StringBuilder builder = new StringBuilder(_cacheId);
builder.append("(");
for (int ii = 0; ii < _values.length; ii++) {
if (ii > 0) {
builder.append(", ");
}
builder.append(_values[ii]);
}
builder.append(")");
return builder.toString();
}
protected String _cacheId;
protected Comparable<?>[] _values;
}
@@ -24,12 +24,13 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import com.samskivert.depot.CacheAdapter;
import com.samskivert.depot.CacheInvalidator;
import com.samskivert.depot.CacheKey;
import com.samskivert.depot.Key;
import com.samskivert.depot.PersistenceContext;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.Stats;
import com.samskivert.depot.CacheAdapter.CacheCategory;
import com.samskivert.jdbc.DatabaseLiaison;
/**
@@ -73,21 +74,21 @@ public abstract class Modifier implements Operation<Integer>
* Construct a new CachingModifier with the given result, cache key, and invalidator,
* all of which are optional, and may also be set during execution.
*/
protected CachingModifier (T result, CacheKey key, CacheInvalidator invalidator)
protected CachingModifier (T result, Key<T> key, CacheInvalidator invalidator)
{
super(invalidator);
_result = result;
_key = key;
_key = (key == null) ? null : new KeyCacheKey(key);
}
/**
* Update this {@link CachingModifier}'s cache key, e.g. during insertion when a
* persistent object first receives a generated key.
* Update this {@link CachingModifier}'s cache key, e.g. during insertion when a persistent
* object first receives a generated key.
*/
protected void updateKey (CacheKey key)
protected void updateKey (Key<T> key)
{
if (key != null) {
_key = key;
_key = new KeyCacheKey(key);
}
}
@@ -98,7 +99,7 @@ public abstract class Modifier implements Operation<Integer>
Integer rows = super.invoke(ctx, conn, liaison);
// if we have both a key and a record, cache
if (_key != null && _result != null) {
ctx.cacheStore(CacheCategory.RECORD, _key, _result.clone());
ctx.cacheStore(CacheAdapter.CacheCategory.RECORD, _key, _result.clone());
}
return rows;
}
@@ -18,10 +18,11 @@
// 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;
package com.samskivert.depot.impl;
import java.io.Serializable;
import com.samskivert.depot.CacheKey;
import com.samskivert.util.ObjectUtil;
/**
@@ -32,27 +33,10 @@ import com.samskivert.util.ObjectUtil;
public class SimpleCacheKey
implements CacheKey
{
/**
* Construct a {@link SimpleCacheKey} for a query that has no parameters whatsoever.
*/
public SimpleCacheKey (String cacheId)
{
this(cacheId, Boolean.TRUE);
}
/**
* Construct a {@link SimpleCacheKey} associated with the given persistent class with
* the given cache key.
*/
public SimpleCacheKey (Class<?> cacheClass, Serializable cacheKey)
{
this(cacheClass.getName(), cacheKey);
}
/**
* Construct a {@link SimpleCacheKey} for the given cache id with the given cache key.
*/
public SimpleCacheKey (String cacheId, Serializable cacheKey)
public SimpleCacheKey (String cacheId, String cacheKey)
{
_cacheId = cacheId;
_cacheKey = cacheKey;
@@ -98,5 +82,5 @@ public class SimpleCacheKey
}
protected String _cacheId;
protected Serializable _cacheKey;
protected String _cacheKey;
}