From e876ff08321bb6fad2879eb2fd5744fd1814ac6f Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Thu, 30 Jul 2009 22:06:18 +0000 Subject: [PATCH] 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. --- src/java/com/samskivert/depot/Key.java | 27 ++---- src/java/com/samskivert/depot/KeySet.java | 7 +- .../samskivert/depot/PersistenceContext.java | 25 ++--- .../samskivert/depot/impl/FindAllQuery.java | 5 +- .../samskivert/depot/impl/FindOneQuery.java | 2 +- .../samskivert/depot/impl/KeyCacheKey.java | 94 +++++++++++++++++++ .../com/samskivert/depot/impl/Modifier.java | 17 ++-- .../depot/{ => impl}/SimpleCacheKey.java | 24 +---- 8 files changed, 129 insertions(+), 72 deletions(-) create mode 100644 src/java/com/samskivert/depot/impl/KeyCacheKey.java rename src/java/com/samskivert/depot/{ => impl}/SimpleCacheKey.java (80%) diff --git a/src/java/com/samskivert/depot/Key.java b/src/java/com/samskivert/depot/Key.java index d8cde03..46ff283 100644 --- a/src/java/com/samskivert/depot/Key.java +++ b/src/java/com/samskivert/depot/Key.java @@ -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 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 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 extends WhereClause // from CacheInvalidator public void invalidate (PersistenceContext ctx) { - ctx.cacheInvalidate(this); + ctx.cacheInvalidate(new KeyCacheKey(this)); } /** diff --git a/src/java/com/samskivert/depot/KeySet.java b/src/java/com/samskivert/depot/KeySet.java index 31c9891..fd17a34 100644 --- a/src/java/com/samskivert/depot/KeySet.java +++ b/src/java/com/samskivert/depot/KeySet.java @@ -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 extends WhereClause // from ValidatingCacheInvalidator public void invalidate (PersistenceContext ctx) { for (Key key : this) { - ctx.cacheInvalidate(key); + ctx.cacheInvalidate(new KeyCacheKey(key)); } } diff --git a/src/java/com/samskivert/depot/PersistenceContext.java b/src/java/com/samskivert/depot/PersistenceContext.java index 7bff8e3..65d905d 100644 --- a/src/java/com/samskivert/depot/PersistenceContext.java +++ b/src/java/com/samskivert/depot/PersistenceContext.java @@ -74,22 +74,21 @@ public class PersistenceContext public static interface CacheListener { /** - * 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 casted = (CacheListener)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 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> 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 casted = (CacheListener)listener; - casted.entryInvalidated(key, oldEntry); + casted.entryInvalidated(oldEntry); } } } diff --git a/src/java/com/samskivert/depot/impl/FindAllQuery.java b/src/java/com/samskivert/depot/impl/FindAllQuery.java index 7b26222..5cee113 100644 --- a/src/java/com/samskivert/depot/impl/FindAllQuery.java +++ b/src/java/com/samskivert/depot/impl/FindAllQuery.java @@ -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 extends Query> fetchKeys = Sets.newHashSet(); for (Key key : allKeys) { - T value = ctx.cacheLookup(key); + T value = ctx.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 extends Query extends Query 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) { diff --git a/src/java/com/samskivert/depot/impl/KeyCacheKey.java b/src/java/com/samskivert/depot/impl/KeyCacheKey.java new file mode 100644 index 0000000..77e21c5 --- /dev/null +++ b/src/java/com/samskivert/depot/impl/KeyCacheKey.java @@ -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; +} diff --git a/src/java/com/samskivert/depot/impl/Modifier.java b/src/java/com/samskivert/depot/impl/Modifier.java index 5f6aff8..4e305d3 100644 --- a/src/java/com/samskivert/depot/impl/Modifier.java +++ b/src/java/com/samskivert/depot/impl/Modifier.java @@ -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 * 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 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 key) { if (key != null) { - _key = key; + _key = new KeyCacheKey(key); } } @@ -98,7 +99,7 @@ public abstract class Modifier implements Operation 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; } diff --git a/src/java/com/samskivert/depot/SimpleCacheKey.java b/src/java/com/samskivert/depot/impl/SimpleCacheKey.java similarity index 80% rename from src/java/com/samskivert/depot/SimpleCacheKey.java rename to src/java/com/samskivert/depot/impl/SimpleCacheKey.java index 2cf519e..bbf2881 100644 --- a/src/java/com/samskivert/depot/SimpleCacheKey.java +++ b/src/java/com/samskivert/depot/impl/SimpleCacheKey.java @@ -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; }