JBoss Cache SVN: r7683 - in core/branches/flat/src: main/java/org/horizon/container and 13 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2009-02-11 12:13:41 -0500 (Wed, 11 Feb 2009)
New Revision: 7683
Added:
core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStoreConfig.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/PurgeExpired.java
core/branches/flat/src/test/java/org/horizon/loader/AsyncTest.java
Modified:
core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java
core/branches/flat/src/main/java/org/horizon/container/CachedValue.java
core/branches/flat/src/main/java/org/horizon/container/DataContainer.java
core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java
core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java
core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java
core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java
core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java
core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java
core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java
core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java
core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java
core/branches/flat/src/main/resources/config-samples/all.xml
core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java
core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java
Log:
more loader work in progress
Modified: core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -27,6 +27,7 @@
import org.horizon.config.parsing.XmlParserBase;
import org.horizon.loader.CacheLoader;
import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.decorators.AsyncStoreConfig;
import org.horizon.loader.decorators.SingletonStoreConfig;
import org.horizon.util.Util;
import org.w3c.dom.Element;
@@ -69,13 +70,11 @@
CacheLoaderConfig clc;
try {
cl = (CacheLoader) Util.getInstance(clClass);
- clc = (CacheLoaderConfig) Util.getInstance(cl.getConfigurationClass());
+ clc = Util.getInstance(cl.getConfigurationClass());
} catch (Exception e) {
throw new ConfigurationException("Unable to instantiate cache loader or configuration", e);
}
- String async = getAttributeValue(indivElement, "async");
- if (existsAttribute(async)) clc.setAsync(getBoolean(async));
String fetchPersistentState = getAttributeValue(indivElement, "fetchPersistentState");
if (existsAttribute(fetchPersistentState)) clc.setFetchPersistentState(getBoolean(fetchPersistentState));
String ignoreModifications = getAttributeValue(indivElement, "ignoreModifications");
@@ -85,8 +84,8 @@
clc.setClassName(clClass);
XmlConfigHelper.setValues(clc, XmlConfigHelper.readPropertiesContents(indivElement), false, true);
- SingletonStoreConfig ssc = parseSingletonStoreConfig(getSingleElementInCoreNS("singletonStore", indivElement));
- if (ssc != null) clc.setSingletonStoreConfig(ssc);
+ clc.setSingletonStoreConfig(parseSingletonStoreConfig(getSingleElementInCoreNS("singletonStore", indivElement)));
+ clc.setAsyncStoreConfig(parseAsyncStoreConfig(getSingleElementInCoreNS("async", indivElement)));
return clc;
}
@@ -106,4 +105,29 @@
}
return ssc;
}
+
+ public AsyncStoreConfig parseAsyncStoreConfig(Element element) {
+ AsyncStoreConfig asc = new AsyncStoreConfig();
+ if (element == null) {
+ asc.setEnabled(false);
+ } else {
+ boolean async = getBoolean(getAttributeValue(element, "enabled"));
+ asc.setEnabled(async);
+
+ if (async) {
+ String tmp = getAttributeValue(element, "batchSize");
+ if (existsAttribute(tmp)) asc.setBatchSize(getInt(tmp));
+
+ tmp = getAttributeValue(element, "pollWait");
+ if (existsAttribute(tmp)) asc.setPollWait(getLong(tmp));
+
+ tmp = getAttributeValue(element, "queueSize");
+ if (existsAttribute(tmp)) asc.setQueueSize(getInt(tmp));
+
+ tmp = getAttributeValue(element, "threadPoolSize");
+ if (existsAttribute(tmp)) asc.setThreadPoolSize(getInt(tmp));
+ }
+ }
+ return asc;
+ }
}
Modified: core/branches/flat/src/main/java/org/horizon/container/CachedValue.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/CachedValue.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/container/CachedValue.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,13 +1,13 @@
package org.horizon.container;
-public class CachedValue<V> {
- protected V value;
+public class CachedValue {
+ protected Object value;
protected long modifiedTime;
protected CachedValue() {
}
- public CachedValue(V value) {
+ public CachedValue(Object value) {
this.value = value;
touch();
}
@@ -20,11 +20,11 @@
return modifiedTime;
}
- public final V getValue() {
+ public final Object getValue() {
return value;
}
- public final void setValue(V value) {
+ public final void setValue(Object value) {
this.value = value;
}
}
\ No newline at end of file
Modified: core/branches/flat/src/main/java/org/horizon/container/DataContainer.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/DataContainer.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/container/DataContainer.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -34,29 +34,29 @@
* @since 1.0
*/
@Scope(Scopes.NAMED_CACHE)
-public interface DataContainer<K, V> {
- V get(K k);
+public interface DataContainer {
+ Object get(Object k);
- void put(K k, V v, long lifespan);
+ void put(Object k, Object v, long lifespan);
- boolean containsKey(K k);
+ boolean containsKey(Object k);
- V remove(K k);
+ Object remove(Object k);
int size();
void clear();
- Set<K> keySet();
+ Set<Object> keySet();
- long getModifiedTimestamp(K key);
+ long getModifiedTimestamp(Object key);
/**
* Purges entries that have passed their expiry time, returning a set of keys that have been purged.
*
* @return set of keys that have been purged.
*/
- Set<K> purgeExpiredEntries();
+ Set<Object> purgeExpiredEntries();
- StoredEntry<K, V> createEntryForStorage(K key);
+ StoredEntry createEntryForStorage(Object key);
}
Modified: core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,19 +1,19 @@
package org.horizon.container;
-public class ExpirableCachedValue<V> extends CachedValue<V> {
+public class ExpirableCachedValue extends CachedValue {
protected long createdTime;
protected long expiryTime;
protected ExpirableCachedValue() {
}
- public ExpirableCachedValue(V value, long createdTime, long expiryTime) {
+ public ExpirableCachedValue(Object value, long createdTime, long expiryTime) {
super(value);
this.createdTime = createdTime;
this.expiryTime = expiryTime;
}
- public ExpirableCachedValue(V value, long lifespan) {
+ public ExpirableCachedValue(Object value, long lifespan) {
super(value);
createdTime = getModifiedTime();
setLifespan(lifespan);
Modified: core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -42,11 +42,11 @@
* @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
* @since 1.0
*/
-public class UnsortedDataContainer<K, V> implements DataContainer<K, V> {
+public class UnsortedDataContainer implements DataContainer {
// data with expiry and without expiry are stored in different maps, for efficiency. E.g., so that when purging expired
// stuff, we don't need to iterate through immortal data.
- final ConcurrentMap<K, CachedValue<V>> immortalData = new ConcurrentHashMap<K, CachedValue<V>>();
- final ConcurrentMap<K, ExpirableCachedValue<V>> expirableData = new ConcurrentHashMap<K, ExpirableCachedValue<V>>();
+ final ConcurrentMap<Object, CachedValue> immortalData = new ConcurrentHashMap<Object, CachedValue>();
+ final ConcurrentMap<Object, ExpirableCachedValue> expirableData = new ConcurrentHashMap<Object, ExpirableCachedValue>();
private static final Object NULL = new Object();
private CacheLoaderManager clm;
private CacheStore cacheStore;
@@ -56,36 +56,34 @@
this.clm = clm;
}
- private void expire(K key) {
+ private void expire(Object key) {
expirableData.remove(key);
expireOnCacheLoader(key);
}
- private void expireOnCacheLoader(K key) {
+ private void expireOnCacheLoader(Object key) {
if (cacheStore == null && clm != null) cacheStore = clm.getCacheStore();
if (cacheStore != null) {
cacheStore.remove(key);
}
}
- @SuppressWarnings("unchecked")
- private K maskNullKey(K o) {
- return o == null ? (K) NULL : o;
+ private Object maskNullKey(Object o) {
+ return o == null ? NULL : o;
}
- private K unmaskNullKey(K o) {
+ private Object unmaskNullKey(Object o) {
return (o == NULL) ? null : o;
}
- @SuppressWarnings("unchecked")
- public V get(K k) {
- K maskedKey = maskNullKey(k);
- CachedValue<V> cv = immortalData.get(maskedKey);
+ public Object get(Object k) {
+ Object maskedKey = maskNullKey(k);
+ CachedValue cv = immortalData.get(maskedKey);
if (cv != null) {
cv.touch();
return cv.getValue();
} else {
- ExpirableCachedValue<V> ecv = expirableData.get(maskedKey);
+ ExpirableCachedValue ecv = expirableData.get(maskedKey);
if (ecv != null) {
if (ecv.isExpired()) {
expire(maskedKey);
@@ -99,11 +97,11 @@
return null;
}
- public void put(K k, V v, long lifespan) {
- K maskedKey = maskNullKey(k);
+ public void put(Object k, Object v, long lifespan) {
+ Object maskedKey = maskNullKey(k);
- CachedValue<V> cv = immortalData.get(maskedKey);
- ExpirableCachedValue<V> ecv;
+ CachedValue cv = immortalData.get(maskedKey);
+ ExpirableCachedValue ecv;
if (cv != null) {
// do we need to move this to expirable?
if (lifespan < 0) {
@@ -111,7 +109,7 @@
cv.setValue(v);
cv.touch();
} else {
- ecv = new ExpirableCachedValue<V>(v, lifespan);
+ ecv = new ExpirableCachedValue(v, lifespan);
immortalData.remove(maskedKey);
expirableData.put(maskedKey, ecv);
}
@@ -119,7 +117,7 @@
// do we need to move this to immortal?
if (lifespan < 0) {
// yes.
- cv = new CachedValue<V>(v);
+ cv = new CachedValue(v);
expirableData.remove(maskedKey);
immortalData.put(maskedKey, cv);
} else {
@@ -129,19 +127,19 @@
} else {
// does not exist anywhere!
if (lifespan < 0) {
- cv = new CachedValue<V>(v);
+ cv = new CachedValue(v);
immortalData.put(maskedKey, cv);
} else {
- ecv = new ExpirableCachedValue<V>(v, lifespan);
+ ecv = new ExpirableCachedValue(v, lifespan);
expirableData.put(maskedKey, ecv);
}
}
}
- public boolean containsKey(K k) {
- K maskedKey = maskNullKey(k);
+ public boolean containsKey(Object k) {
+ Object maskedKey = maskNullKey(k);
if (!immortalData.containsKey(maskedKey)) {
- ExpirableCachedValue<V> ecv = expirableData.get(maskedKey);
+ ExpirableCachedValue ecv = expirableData.get(maskedKey);
if (ecv == null) return false;
if (ecv.isExpired()) {
expire(maskedKey);
@@ -151,17 +149,16 @@
return true;
}
- public long getModifiedTimestamp(K key) {
- K maskedKey = maskNullKey(key);
- CachedValue<V> cv = immortalData.get(maskedKey);
+ public long getModifiedTimestamp(Object key) {
+ Object maskedKey = maskNullKey(key);
+ CachedValue cv = immortalData.get(maskedKey);
if (cv == null) cv = expirableData.get(maskedKey);
return cv == null ? -1 : cv.getModifiedTime();
}
- @SuppressWarnings("unchecked")
- public V remove(K k) {
- K maskedKey = maskNullKey(k);
- CachedValue<V> cv = immortalData.remove(maskedKey);
+ public Object remove(Object k) {
+ Object maskedKey = maskNullKey(k);
+ CachedValue cv = immortalData.remove(maskedKey);
if (cv == null) cv = expirableData.remove(maskedKey);
if (cv == null) {
@@ -180,7 +177,7 @@
expirableData.clear();
}
- public Set<K> keySet() {
+ public Set<Object> keySet() {
return new KeySet();
}
@@ -188,11 +185,11 @@
return "Immortal Data: " + immortalData.toString() + "\n" + "Expirable Data: " + expirableData.toString();
}
- public Set<K> purgeExpiredEntries() {
- Set<K> purged = new HashSet<K>();
- for (Iterator<Map.Entry<K, ExpirableCachedValue<V>>> iter = expirableData.entrySet().iterator(); iter.hasNext();) {
- Map.Entry<K, ExpirableCachedValue<V>> entry = iter.next();
- ExpirableCachedValue<V> cv = entry.getValue();
+ public Set<Object> purgeExpiredEntries() {
+ Set<Object> purged = new HashSet<Object>();
+ for (Iterator<Map.Entry<Object, ExpirableCachedValue>> iter = expirableData.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry<Object, ExpirableCachedValue> entry = iter.next();
+ ExpirableCachedValue cv = entry.getValue();
if (cv.isExpired()) {
expireOnCacheLoader(entry.getKey());
purged.add(entry.getKey());
@@ -202,25 +199,25 @@
return purged;
}
- public StoredEntry<K, V> createEntryForStorage(K key) {
- CachedValue<V> immortal = immortalData.get(key);
+ public StoredEntry createEntryForStorage(Object key) {
+ CachedValue immortal = immortalData.get(key);
if (immortal != null)
- return new StoredEntry<K, V>(key, immortal.getValue(), -1, -1);
- ExpirableCachedValue<V> ecv = expirableData.get(key);
+ return new StoredEntry(key, immortal.getValue());
+ ExpirableCachedValue ecv = expirableData.get(key);
if (ecv == null) return null;
- return new StoredEntry<K, V>(key, ecv.getValue(), ecv.getCreatedTime(), ecv.getExpiryTime());
+ return new StoredEntry(key, ecv.getValue(), ecv.getCreatedTime(), ecv.getExpiryTime());
}
- private class KeySet extends AbstractSet<K> {
- Set<K> immortalKeys;
- Set<K> expirableKeys;
+ private class KeySet extends AbstractSet<Object> {
+ Set<Object> immortalKeys;
+ Set<Object> expirableKeys;
public KeySet() {
immortalKeys = immortalData.keySet();
expirableKeys = expirableData.keySet();
}
- public Iterator<K> iterator() {
+ public Iterator<Object> iterator() {
return new KeyIterator(immortalKeys.iterator(), expirableKeys.iterator());
}
@@ -229,7 +226,7 @@
}
public boolean contains(Object o) {
- K maskedKey = maskNullKey((K) o);
+ Object maskedKey = maskNullKey((Object) o);
return immortalKeys.contains(maskedKey) || expirableKeys.contains(maskedKey);
}
@@ -242,14 +239,14 @@
}
}
- private class KeyIterator implements Iterator<K> {
- Iterator<Iterator<K>> metaIterator;
- Iterator<K> immortalIterator;
- Iterator<K> expirableIterator;
- Iterator<K> currentIterator;
+ private class KeyIterator implements Iterator<Object> {
+ Iterator<Iterator<Object>> metaIterator;
+ Iterator<Object> immortalIterator;
+ Iterator<Object> expirableIterator;
+ Iterator<Object> currentIterator;
- private KeyIterator(Iterator<K> immortalIterator, Iterator<K> expirableIterator) {
- List<Iterator<K>> iterators = new ArrayList<Iterator<K>>(2);
+ private KeyIterator(Iterator<Object> immortalIterator, Iterator<Object> expirableIterator) {
+ List<Iterator<Object>> iterators = new ArrayList<Iterator<Object>>(2);
iterators.add(immortalIterator);
iterators.add(expirableIterator);
metaIterator = iterators.iterator();
@@ -267,7 +264,7 @@
}
@SuppressWarnings("unchecked")
- public K next() {
+ public Object next() {
return unmaskNullKey(currentIterator.next());
}
Modified: core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -66,7 +66,7 @@
* @param dataContiner the cache's data container
* @param evictionAlgorithmConfig algorithm configuration to use
*/
- void init(Cache<?, ?> cache, DataContainer<?, ?> dataContiner,
+ void init(Cache<?, ?> cache, DataContainer dataContiner,
EvictionAlgorithmConfig evictionAlgorithmConfig);
/**
Modified: core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -46,7 +46,7 @@
ScheduledExecutorService executor;
Configuration configuration;
Cache cache;
- private DataContainer<?, ?> dataContainer;
+ private DataContainer dataContainer;
@Inject
public void initialize((a)ComponentName(KnownComponentNames.EVICTION_SCHEDULED_EXECUTOR) ScheduledExecutorService executor,
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -116,7 +116,7 @@
this.action = evictionAction;
}
- public void init(Cache<?, ?> cache, DataContainer<?, ?> dataContainer, EvictionAlgorithmConfig evictionAlgorithmConfig) {
+ public void init(Cache<?, ?> cache, DataContainer dataContainer, EvictionAlgorithmConfig evictionAlgorithmConfig) {
this.cache = cache;
this.dataContainer = dataContainer;
this.config = (BaseEvictionAlgorithmConfig) evictionAlgorithmConfig;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -66,7 +66,7 @@
// no-op
}
- public void init(Cache<?, ?> cache, DataContainer<?, ?> dataContainer, EvictionAlgorithmConfig evictionAlgorithmConfig) {
+ public void init(Cache<?, ?> cache, DataContainer dataContainer, EvictionAlgorithmConfig evictionAlgorithmConfig) {
// no-op
}
Modified: core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -56,7 +56,7 @@
protected TransactionTable txTable = null;
protected CacheLoader loader;
- protected DataContainer<Object, Object> dataContainer;
+ protected DataContainer dataContainer;
protected CacheNotifier notifier;
protected EntryFactory entryFactory;
@@ -71,7 +71,7 @@
@Inject
protected void injectDependencies(TransactionTable txTable, CacheLoaderManager clm,
- DataContainer<Object, Object> dataContainer, EntryFactory entryFactory, CacheNotifier notifier) {
+ DataContainer dataContainer, EntryFactory entryFactory, CacheNotifier notifier) {
this.txTable = txTable;
this.clm = clm;
this.dataContainer = dataContainer;
Modified: core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -6,5 +6,5 @@
* @author Manik Surtani
* @since 1.0
*/
-public abstract class AbstractCacheLoader<K, V> implements CacheLoader<K, V> {
+public abstract class AbstractCacheLoader implements CacheLoader {
}
Modified: core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,27 +1,17 @@
package org.horizon.loader;
import org.horizon.config.PluggableConfigurationComponent;
+import org.horizon.loader.decorators.AsyncStoreConfig;
import org.horizon.loader.decorators.SingletonStoreConfig;
import org.horizon.util.Util;
public class AbstractCacheLoaderConfig extends PluggableConfigurationComponent implements CacheLoaderConfig {
- private boolean async;
private boolean ignoreModifications;
private boolean fetchPersistentState;
private boolean purgeOnStartup;
private SingletonStoreConfig singletonStoreConfig;
+ private AsyncStoreConfig asyncStoreConfig;
-// protected void populateFromBaseConfig(CacheLoaderManagerConfig.IndividualCacheLoaderConfig base) {
-// if (base != null) {
-// setAsync(base.isAsync());
-// setIgnoreModifications(base.isIgnoreModifications());
-// setFetchPersistentState(base.isFetchPersistentState());
-// setSingletonStoreConfig(base.getSingletonStoreConfig());
-// setPurgeOnStartup(base.isPurgeOnStartup());
-// setProperties(base.getProperties());
-// }
-// }
-
public boolean isPurgeOnStartup() {
return purgeOnStartup;
}
@@ -35,15 +25,6 @@
this.fetchPersistentState = fetchPersistentState;
}
- public void setAsync(boolean async) {
- testImmutability("async");
- this.async = async;
- }
-
- public boolean isAsync() {
- return async;
- }
-
public void setIgnoreModifications(boolean ignoreModifications) {
testImmutability("ignoreModifications");
this.ignoreModifications = ignoreModifications;
@@ -67,6 +48,15 @@
this.singletonStoreConfig = singletonStoreConfig;
}
+ public AsyncStoreConfig getAsyncStoreConfig() {
+ return asyncStoreConfig;
+ }
+
+ public void setAsyncStoreConfig(AsyncStoreConfig asyncStoreConfig) {
+ testImmutability("asyncStoreConfig");
+ this.asyncStoreConfig = asyncStoreConfig;
+ }
+
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
@@ -81,10 +71,10 @@
AbstractCacheLoaderConfig other = (AbstractCacheLoaderConfig) obj;
return Util.safeEquals(this.className, other.className)
- && (this.async == other.async)
&& (this.ignoreModifications == other.ignoreModifications)
&& (this.fetchPersistentState == other.fetchPersistentState)
- && Util.safeEquals(this.singletonStoreConfig, other.singletonStoreConfig);
+ && Util.safeEquals(this.singletonStoreConfig, other.singletonStoreConfig)
+ && Util.safeEquals(this.asyncStoreConfig, other.asyncStoreConfig);
}
@Override
@@ -95,10 +85,10 @@
protected int hashCodeExcludingProperties() {
int result = 17;
result = 31 * result + (className == null ? 0 : className.hashCode());
- result = 31 * result + (async ? 0 : 1);
result = 31 * result + (ignoreModifications ? 0 : 1);
result = 31 * result + (fetchPersistentState ? 0 : 1);
result = 31 * result + (singletonStoreConfig == null ? 0 : singletonStoreConfig.hashCode());
+ result = 31 * result + (asyncStoreConfig == null ? 0 : asyncStoreConfig.hashCode());
result = 31 * result + (purgeOnStartup ? 0 : 1);
return result;
}
@@ -106,7 +96,6 @@
@Override
public String toString() {
return new StringBuilder().append("IndividualCacheLoaderConfig{").append("className='").append(className).append('\'')
- .append(", async=").append(async)
.append(", ignoreModifications=").append(ignoreModifications)
.append(", fetchPersistentState=").append(fetchPersistentState)
.append(", properties=").append(properties)
Modified: core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -4,7 +4,10 @@
import org.horizon.loader.modifications.Remove;
import org.horizon.loader.modifications.Store;
+import javax.transaction.Transaction;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* // TODO: Manik: Document this!
@@ -12,21 +15,22 @@
* @author Manik Surtani
* @since 1.0
*/
-public abstract class AbstractCacheStore<K, V> extends AbstractCacheLoader<K, V> implements CacheStore<K, V> {
+public abstract class AbstractCacheStore extends AbstractCacheLoader implements CacheStore {
- @SuppressWarnings("unchecked")
+ private final Map<Transaction, List<Modification>> transactions = new ConcurrentHashMap<Transaction, List<Modification>>();
+
protected void applyModifications(List<Modification> mods) {
for (Modification m : mods) {
switch (m.getType()) {
case STORE:
- Store<K, V> s = (Store<K, V>) m;
+ Store s = (Store) m;
store(s.getStoredEntry());
break;
case CLEAR:
clear();
break;
case REMOVE:
- Remove<K> r = (Remove<K>) m;
+ Remove r = (Remove) m;
remove(r.getKey());
break;
default:
@@ -35,4 +39,20 @@
}
}
+ public void prepare(List<Modification> mods, Transaction tx, boolean isOnePhase) {
+ if (isOnePhase) {
+ applyModifications(mods);
+ } else {
+ transactions.put(tx, mods);
+ }
+ }
+
+ public void rollback(Transaction tx) {
+ transactions.remove(tx);
+ }
+
+ public void commit(Transaction tx) {
+ List<Modification> list = transactions.remove(tx);
+ if (list != null && !list.isEmpty()) applyModifications(list);
+ }
}
Modified: core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -12,7 +12,7 @@
* @author Manik Surtani
* @since 1.0
*/
-public interface CacheLoader<K, V> extends Lifecycle {
+public interface CacheLoader extends Lifecycle {
/**
* Used to initialize a cache loader. Typically invoked by the {@link org.horizon.loader.CacheLoaderManager} when
@@ -32,20 +32,20 @@
* @param key key
* @return an entry
*/
- StoredEntry<K, V> load(K key);
+ StoredEntry load(Object key);
/**
* Loads all entries in the loader. Expired entries are not returned.
*
* @return a set of entries, or an empty set if the loader is emptied.
*/
- Set<StoredEntry<K, V>> loadAll();
+ Set<StoredEntry> loadAll();
/**
* @param key key to test
* @return true if the key exists, false otherwise
*/
- boolean containsKey(K key);
+ boolean containsKey(Object key);
/**
Modified: core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,5 +1,6 @@
package org.horizon.loader;
+import org.horizon.loader.decorators.AsyncStoreConfig;
import org.horizon.loader.decorators.SingletonStoreConfig;
/**
@@ -15,10 +16,6 @@
void setFetchPersistentState(boolean fetchPersistentState);
- void setAsync(boolean async);
-
- boolean isAsync();
-
void setIgnoreModifications(boolean ignoreModifications);
boolean isIgnoreModifications();
@@ -29,6 +26,10 @@
void setSingletonStoreConfig(SingletonStoreConfig singletonStoreConfig);
+ AsyncStoreConfig getAsyncStoreConfig();
+
+ void setAsyncStoreConfig(AsyncStoreConfig asyncStoreConfig);
+
CacheLoaderConfig clone();
String getClassName();
Modified: core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -167,8 +167,8 @@
if (tmpLoader instanceof CacheStore) {
CacheStore tmpStore = (CacheStore) tmpLoader;
// async?
- if (cfg.isAsync()) {
- tmpStore = new AsyncStore(tmpStore);
+ if (cfg.getAsyncStoreConfig().isEnabled()) {
+ tmpStore = new AsyncStore(tmpStore, cfg.getAsyncStoreConfig());
tmpLoader = tmpStore;
}
Modified: core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -14,14 +14,14 @@
* @author Manik Surtani
* @since 1.0
*/
-public interface CacheStore<K, V> extends CacheLoader<K, V> {
+public interface CacheStore extends CacheLoader {
/**
* Stores an entry
*
* @param ed entry to store
*/
- void store(StoredEntry<K, V> ed);
+ void store(StoredEntry ed);
/**
* Writes contents of the stream to the store. Implementations should expect that the stream contains data in an
@@ -30,6 +30,8 @@
* dealing with the stream to make use of efficient marshalling.
*
* @param inputStream stream to read from
+ * @throws java.io.IOException in case of IO problems
+ * @throws ClassNotFoundException in case of not being able to read the stream
*/
void store(InputStream inputStream) throws IOException, ClassNotFoundException;
@@ -56,7 +58,7 @@
* @param key key to remove
* @return true if the entry was removed; false if the entry wasn't found.
*/
- boolean remove(K key);
+ boolean remove(Object key);
/**
* Purges expired entries from the store.
Modified: core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -12,18 +12,23 @@
*
* @author Manik Surtani
*/
-public class StoredEntry<K, V> extends ExpirableCachedValue<V> implements Externalizable {
- private K key;
+public class StoredEntry extends ExpirableCachedValue implements Externalizable {
+ private Object key;
public StoredEntry() {
}
- public StoredEntry(K key, V value, long created, long expiry) {
+ public StoredEntry(Object key, Object value) {
+ super(value, -1, -1);
+ this.key = key;
+ }
+
+ public StoredEntry(Object key, Object value, long created, long expiry) {
super(value, created, expiry);
this.key = key;
}
- public final K getKey() {
+ public final Object getKey() {
return key;
}
@@ -65,8 +70,8 @@
@SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
- key = (K) in.readObject();
- value = (V) in.readObject();
+ key = in.readObject();
+ value = in.readObject();
createdTime = in.readLong();
expiryTime = in.readLong();
modifiedTime = System.currentTimeMillis();
Modified: core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,21 +1,103 @@
package org.horizon.loader.decorators;
+import org.horizon.Cache;
+import org.horizon.loader.AbstractCacheStore;
+import org.horizon.loader.CacheLoaderConfig;
import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.marshall.Marshaller;
+import javax.transaction.Transaction;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Set;
+
/**
- * // TODO: Manik: Document this!
+ * Simple delegate that delegates all calls. This is intended as a building block for other decorators who wish to add
+ * behavior to certain calls only.
*
* @author Manik Surtani
+ * @since 1.0
*/
-public abstract class AbstractDelegatingStore implements CacheStore {
+public class AbstractDelegatingStore extends AbstractCacheStore {
CacheStore delegate;
- public void setDelegate(CacheStore cacheStore) {
- this.delegate = cacheStore;
+ public AbstractDelegatingStore(CacheStore delegate) {
+ this.delegate = delegate;
}
+ public void setDelegate(CacheStore delegate) {
+ this.delegate = delegate;
+ }
+
public CacheStore getDelegate() {
return delegate;
}
+
+ public void store(StoredEntry ed) {
+ delegate.store(ed);
+ }
+
+ public void store(InputStream inputStream) throws IOException, ClassNotFoundException {
+ delegate.store(inputStream);
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ delegate.load(outputStream);
+ }
+
+ public void clear() {
+ delegate.clear();
+ }
+
+ public boolean remove(Object key) {
+ return delegate.remove(key);
+ }
+
+ public void purgeExpired() {
+ delegate.purgeExpired();
+ }
+
+ public void commit(Transaction tx) {
+ delegate.commit(tx);
+ }
+
+ public void rollback(Transaction tx) {
+ delegate.rollback(tx);
+ }
+
+ public void prepare(List list, Transaction tx, boolean isOnePhase) {
+ delegate.prepare(list, tx, isOnePhase);
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ delegate.init(config, cache, m);
+ }
+
+ public StoredEntry load(Object key) {
+ return delegate.load(key);
+ }
+
+ public Set loadAll() {
+ return delegate.loadAll();
+ }
+
+ public boolean containsKey(Object key) {
+ return delegate.containsKey(key);
+ }
+
+ public Class getConfigurationClass() {
+ return delegate.getConfigurationClass();
+ }
+
+ public void start() {
+ delegate.start();
+ }
+
+ public void stop() {
+ delegate.stop();
+ }
}
Modified: core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,107 +1,208 @@
package org.horizon.loader.decorators;
-import org.horizon.Cache;
-import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.CacheException;
import org.horizon.loader.CacheStore;
import org.horizon.loader.StoredEntry;
-import org.horizon.marshall.Marshaller;
+import org.horizon.loader.modifications.Clear;
+import org.horizon.loader.modifications.Modification;
+import org.horizon.loader.modifications.PurgeExpired;
+import org.horizon.loader.modifications.Remove;
+import org.horizon.loader.modifications.Store;
+import org.horizon.logging.Log;
+import org.horizon.logging.LogFactory;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
/**
- * An asynchronous wrapper around a cache store
+ * The AsyncStore is a delegating CacheStore that extends AbstractDelegatingStore, overriding methods to that should not
+ * just delegate the operation to the underlying store.
+ * <p/>
+ * Read operations are done synchronously, while write operations are done asynchronously. There is no provision for
+ * exception handling for problems encountered with the underlying store during a write operation, and the exception is
+ * just logged.
+ * <p/>
+ * When configuring the loader, use the following element:
+ * <p/>
+ * <code> <async enabled="true" /> </code>
+ * <p/>
+ * to define whether cache loader operations are to be asynchronous. If not specified, a cache loader operation is
+ * assumed synchronous and this decorator is not applied.
+ * <p/>
*
* @author Manik Surtani
* @since 1.0
*/
-public class AsyncStore implements CacheStore {
+public class AsyncStore extends AbstractDelegatingStore {
- CacheStore delegate;
+ private static final Log log = LogFactory.getLog(AsyncStore.class);
+ private static final boolean trace = log.isTraceEnabled();
- public AsyncStore(CacheStore delegate) {
- this.delegate = delegate;
- }
+ private static AtomicInteger threadId = new AtomicInteger(0);
- public void store(StoredEntry ed) {
- // TODO: Manik: Customise this generated block
- }
+ private ExecutorService executor;
+ private AtomicBoolean stopped = new AtomicBoolean(true);
+ private BlockingQueue<Modification> queue;
+ private List<Future> processorFutures;
+ private AsyncStoreConfig asyncStoreConfig;
- public void storeAll(Collection ed) {
- // TODO: Manik: Customise this generated block
+ public AsyncStore(CacheStore cacheStore, AsyncStoreConfig asyncStoreConfig) {
+ super(cacheStore);
+ this.asyncStoreConfig = asyncStoreConfig;
}
- public void store(InputStream inputStream) {
- // TODO: Manik: Customise this generated block
+ public void store(StoredEntry ed) {
+ enqueue(new Store(ed));
}
- public void load(OutputStream outputStream) throws IOException {
- // TODO: Manik: Customise this generated block
- }
-
public void clear() {
- // TODO: Manik: Customise this generated block
+ enqueue(new Clear());
}
public boolean remove(Object key) {
- return false; // TODO: Manik: Customise this generated block
+ enqueue(new Remove(key));
+ return true;
}
public void purgeExpired() {
- // TODO: Manik: Customise this generated block
+ enqueue(new PurgeExpired());
}
- public void commit(Transaction tx) {
- // TODO: Manik: Customise this generated block
+ private void enqueue(final Modification mod) {
+ try {
+ if (stopped.get()) {
+ throw new CacheException("AsyncStore stopped; no longer accepting more entries.");
+ }
+ log.trace("Enqueuing modification {0}", mod);
+ queue.put(mod);
+ } catch (Exception e) {
+ throw new CacheException("Unable to enqueue asynchronous task", e);
+ }
}
- public void rollback(Transaction tx) {
- // TODO: Manik: Customise this generated block
+ @Override
+ public void start() {
+ queue = new LinkedBlockingQueue<Modification>(asyncStoreConfig.getQueueSize());
+ log.info("Async cache loader starting {0}", this);
+ stopped.set(false);
+ super.start();
+ int poolSize = asyncStoreConfig.getThreadPoolSize();
+ executor = Executors.newFixedThreadPool(poolSize, new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "AsyncStore-" + threadId.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ }
+ });
+ processorFutures = new ArrayList<Future>(poolSize);
+ for (int i = 0; i < poolSize; i++) processorFutures.add(executor.submit(new AsyncProcessor()));
}
- public void prepare(List list, Transaction tx, boolean isOnePhase) {
- // TODO: Manik: Customise this generated block
+ @Override
+ public void stop() {
+ stopped.set(true);
+ if (executor != null) {
+ for (Future f : processorFutures) f.cancel(true);
+ executor.shutdown();
+ try {
+ boolean terminated = executor.isTerminated();
+ while (!terminated) {
+ terminated = executor.awaitTermination(60, TimeUnit.SECONDS);
+ }
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ executor = null;
+ super.stop();
}
- public void init(CacheLoaderConfig config, Cache cache, TransactionManager tm, Marshaller m) {
- // TODO: Manik: Customise this generated block
+ protected void applyModificationsSync(List<Modification> mods) {
+ for (Modification m : mods) {
+ switch (m.getType()) {
+ case STORE:
+ Store s = (Store) m;
+ super.store(s.getStoredEntry());
+ break;
+ case CLEAR:
+ super.clear();
+ break;
+ case REMOVE:
+ Remove r = (Remove) m;
+ super.remove(r.getKey());
+ break;
+ case PURGE_EXPIRED:
+ super.purgeExpired();
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown modification type " + m.getType());
+ }
+ }
}
- public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
- // TODO: Manik: Customise this generated block
- }
- public StoredEntry load(Object key) {
- return null; // TODO: Manik: Customise this generated block
- }
+ /**
+ * Processes (by batch if possible) a queue of {@link Modification}s.
+ *
+ * @author manik surtani
+ */
+ private class AsyncProcessor implements Runnable {
+ // Modifications to invoke as a single put
+ private final List<Modification> mods = new ArrayList<Modification>(asyncStoreConfig.getBatchSize());
- public Set loadAll(Collection keys) {
- return null; // TODO: Manik: Customise this generated block
- }
+ public void run() {
+ while (!Thread.interrupted()) {
+ try {
+ run0();
+ }
+ catch (InterruptedException e) {
+ break;
+ }
+ }
- public Set loadAll() {
- return null; // TODO: Manik: Customise this generated block
- }
+ try {
+ if (trace) log.trace("Process remaining batch {0}", mods.size());
+ put(mods);
+ if (trace) log.trace("Process remaining queued {0}", queue.size());
+ while (!queue.isEmpty()) run0();
+ }
+ catch (InterruptedException e) {
+ log.trace("remaining interrupted");
+ }
+ }
- public boolean containsKey(Object key) {
- return false; // TODO: Manik: Customise this generated block
- }
+ private void run0() throws InterruptedException {
+ log.trace("Checking for modifications");
+ int i = queue.drainTo(mods, asyncStoreConfig.getBatchSize());
+ if (i == 0) {
+ Modification m = queue.take();
+ mods.add(m);
+ }
- public Class getConfigurationClass() {
- return null; // TODO: Manik: Customise this generated block
- }
+ if (trace) log.trace("Calling put(List) with {0} modifications", mods.size());
+ put(mods);
+ mods.clear();
+ }
- public void start() {
- // TODO: Manik: Customise this generated block
+ private void put(List<Modification> mods) {
+ try {
+ AsyncStore.this.applyModificationsSync(mods);
+ }
+ catch (Exception e) {
+ if (log.isWarnEnabled()) log.warn("Failed to process async modifications: " + e);
+ if (log.isDebugEnabled()) log.debug("Exception: ", e);
+ }
+ }
}
- public void stop() {
- // TODO: Manik: Customise this generated block
- }
}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStoreConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStoreConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStoreConfig.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -0,0 +1,63 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.config.AbstractNamedCacheConfigurationBean;
+
+/**
+ * Configuration for the async cache loader
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class AsyncStoreConfig extends AbstractNamedCacheConfigurationBean {
+ boolean enabled;
+ int batchSize = 100;
+ long pollWait = 100;
+ int queueSize = 10000;
+ int threadPoolSize = 1;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ testImmutability("enabled");
+ this.enabled = enabled;
+ }
+
+ public int getBatchSize() {
+ return batchSize;
+ }
+
+ public void setBatchSize(int batchSize) {
+ testImmutability("batchSize");
+ this.batchSize = batchSize;
+ }
+
+ public long getPollWait() {
+ return pollWait;
+ }
+
+ public void setPollWait(long pollWait) {
+ testImmutability("pollWait");
+ this.pollWait = pollWait;
+ }
+
+ public int getQueueSize() {
+ return queueSize;
+ }
+
+ public void setQueueSize(int queueSize) {
+ testImmutability("queueSize");
+ this.queueSize = queueSize;
+ }
+
+ public int getThreadPoolSize() {
+ return threadPoolSize;
+ }
+
+ public void setThreadPoolSize(int threadPoolSize) {
+ testImmutability("threadPoolSize");
+ this.threadPoolSize = threadPoolSize;
+ }
+
+}
Modified: core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -1,106 +1,62 @@
package org.horizon.loader.decorators;
-import org.horizon.Cache;
-import org.horizon.loader.CacheLoaderConfig;
import org.horizon.loader.CacheStore;
import org.horizon.loader.StoredEntry;
-import org.horizon.marshall.Marshaller;
import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collection;
import java.util.List;
-import java.util.Set;
/**
- * // TODO: Manik: Document this!
+ * A decorator that makes the underlying store a {@link org.horizon.loader.CacheLoader}, i.e., suppressing all write
+ * methods.
*
* @author Manik Surtani
+ * @since 1.0
*/
-public class ReadOnlyStore implements CacheStore {
+public class ReadOnlyStore extends AbstractDelegatingStore {
- CacheStore delegate;
-
public ReadOnlyStore(CacheStore delegate) {
- this.delegate = delegate;
+ super(delegate);
}
+ @Override
public void store(StoredEntry ed) {
- // TODO: Manik: Customise this generated block
+ // no-op
}
- public void storeAll(Collection ed) {
- // TODO: Manik: Customise this generated block
- }
-
+ @Override
public void store(InputStream inputStream) {
- // TODO: Manik: Customise this generated block
+ // no-op
}
- public void load(OutputStream outputStream) throws IOException {
- // TODO: Manik: Customise this generated block
- }
-
+ @Override
public void clear() {
- // TODO: Manik: Customise this generated block
+ // no-op
}
+ @Override
public boolean remove(Object key) {
- return false; // TODO: Manik: Customise this generated block
+ return false; // no-op
}
+ @Override
public void purgeExpired() {
- // TODO: Manik: Customise this generated block
+ // no-op
}
+ @Override
public void commit(Transaction tx) {
- // TODO: Manik: Customise this generated block
+ // no-op
}
+ @Override
public void rollback(Transaction tx) {
- // TODO: Manik: Customise this generated block
+ // no-op
}
+ @Override
public void prepare(List list, Transaction tx, boolean isOnePhase) {
- // TODO: Manik: Customise this generated block
+ // no-op
}
-
- public void init(CacheLoaderConfig config, Cache cache, TransactionManager tm, Marshaller m) {
- // TODO: Manik: Customise this generated block
- }
-
- public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
- // TODO: Manik: Customise this generated block
- }
-
- public StoredEntry load(Object key) {
- return null; // TODO: Manik: Customise this generated block
- }
-
- public Set loadAll(Collection keys) {
- return null; // TODO: Manik: Customise this generated block
- }
-
- public Set loadAll() {
- return null; // TODO: Manik: Customise this generated block
- }
-
- public boolean containsKey(Object key) {
- return false; // TODO: Manik: Customise this generated block
- }
-
- public Class getConfigurationClass() {
- return null; // TODO: Manik: Customise this generated block
- }
-
- public void start() {
- // TODO: Manik: Customise this generated block
- }
-
- public void stop() {
- // TODO: Manik: Customise this generated block
- }
}
Modified: core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -20,8 +20,8 @@
* @author Manik Surtani
*/
public class SingletonStore extends AbstractDelegatingStore {
- public SingletonStore(CacheStore tmpStore) {
- setDelegate(tmpStore);
+ public SingletonStore(CacheStore delegate) {
+ super(delegate);
}
public void store(StoredEntry ed) {
Modified: core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -7,10 +7,8 @@
* @since 1.0
*/
public class Clear implements Modification {
- final Type type = Type.CLEAR;
-
public Type getType() {
- return type;
+ return Type.CLEAR;
}
@Override
Modified: core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -8,7 +8,7 @@
*/
public interface Modification {
public static enum Type {
- STORE, REMOVE, CLEAR
+ STORE, REMOVE, CLEAR, PURGE_EXPIRED;
}
Type getType();
Added: core/branches/flat/src/main/java/org/horizon/loader/modifications/PurgeExpired.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/PurgeExpired.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/PurgeExpired.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -0,0 +1,7 @@
+package org.horizon.loader.modifications;
+
+public class PurgeExpired implements Modification {
+ public Type getType() {
+ return Type.PURGE_EXPIRED;
+ }
+}
Modified: core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -6,20 +6,19 @@
* @author Manik Surtani
* @since 1.0
*/
-public class Remove<K> implements Modification {
+public class Remove implements Modification {
- final Type type = Type.REMOVE;
- final K key;
+ final Object key;
- public Remove(K key) {
+ public Remove(Object key) {
this.key = key;
}
public Type getType() {
- return type;
+ return Type.REMOVE;
}
- public K getKey() {
+ public Object getKey() {
return key;
}
@@ -31,15 +30,13 @@
Remove remove = (Remove) o;
if (key != null ? !key.equals(remove.key) : remove.key != null) return false;
- if (type != remove.type) return false;
return true;
}
@Override
public int hashCode() {
- int result = type != null ? type.hashCode() : 0;
- result = 31 * result + (key != null ? key.hashCode() : 0);
+ int result = key != null ? key.hashCode() : 0;
return result;
}
Modified: core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -8,20 +8,19 @@
* @author Manik Surtani
* @since 1.0
*/
-public class Store<K, V> implements Modification {
+public class Store implements Modification {
- final Type type = Type.STORE;
- final StoredEntry<K, V> storedEntry;
+ final StoredEntry storedEntry;
- public Store(StoredEntry<K, V> storedEntry) {
+ public Store(StoredEntry storedEntry) {
this.storedEntry = storedEntry;
}
public Type getType() {
- return type;
+ return Type.STORE;
}
- public StoredEntry<K, V> getStoredEntry() {
+ public StoredEntry getStoredEntry() {
return storedEntry;
}
@@ -33,15 +32,13 @@
Store store = (Store) o;
if (storedEntry != null ? !storedEntry.equals(store.storedEntry) : store.storedEntry != null) return false;
- if (type != store.type) return false;
return true;
}
@Override
public int hashCode() {
- int result = type != null ? type.hashCode() : 0;
- result = 31 * result + (storedEntry != null ? storedEntry.hashCode() : 0);
+ int result = storedEntry != null ? storedEntry.hashCode() : 0;
return result;
}
Modified: core/branches/flat/src/main/resources/config-samples/all.xml
===================================================================
--- core/branches/flat/src/main/resources/config-samples/all.xml 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/resources/config-samples/all.xml 2009-02-11 17:13:41 UTC (rev 7683)
@@ -145,7 +145,7 @@
<!--
We can have multiple cache loaders, which get chained
-->
- <loader class="org.horizon.loader.JDBCCacheLoader" async="true" fetchPersistentState="true"
+ <loader class="org.horizon.loader.JDBCCacheLoader" fetchPersistentState="true"
ignoreModifications="true" purgeOnStartup="true">
<!-- See the documentation for more configuration examples and options. -->
@@ -157,6 +157,7 @@
</properties>
<singletonStore enabled="true" pushStateWhenCoordinator="true" pushStateTimeout="20000"/>
+ <async enabled="true" batchSize="1000" threadPoolSize="5"/>
</loader>
</loaders>
Modified: core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
===================================================================
--- core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd 2009-02-11 17:13:41 UTC (rev 7683)
@@ -177,9 +177,17 @@
<xs:attribute name="pushStateTimeout" type="xs:positiveInteger"/>
</xs:complexType>
</xs:element>
+ <xs:element name="async" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:attribute name="enabled" type="tns:booleanType"/>
+ <xs:attribute name="batchSize" type="xs:positiveInteger"/>
+ <xs:attribute name="pollWait" type="xs:positiveInteger"/>
+ <xs:attribute name="queueSize" type="xs:positiveInteger"/>
+ <xs:attribute name="threadPoolSize" type="xs:positiveInteger"/>
+ </xs:complexType>
+ </xs:element>
</xs:all>
<xs:attribute name="class" type="xs:string"/>
- <xs:attribute name="async" type="tns:booleanType"/>
<xs:attribute name="fetchPersistentState" type="tns:booleanType"/>
<xs:attribute name="ignoreModifications" type="tns:booleanType"/>
<xs:attribute name="purgeOnStartup" type="tns:booleanType"/>
Modified: core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -155,7 +155,7 @@
public void testCacheLoaders() throws Exception {
XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
String xml = "<loaders passivation=\"true\" shared=\"true\" preload=\"true\">\n" +
- " <loader class=\"org.horizon.loader.jdbc.JDBCCacheLoader\" async=\"true\" fetchPersistentState=\"true\"\n" +
+ " <loader class=\"org.horizon.loader.jdbc.JDBCCacheLoader\" fetchPersistentState=\"true\"\n" +
" ignoreModifications=\"false\" purgeOnStartup=\"false\">\n" +
" <properties>\n" +
" dataSource=HorizonDS\n" +
@@ -164,6 +164,7 @@
" dropTable=false\n" +
" </properties>\n" +
" <singletonStore enabled=\"true\" pushStateWhenCoordinator=\"true\" pushStateTimeout=\"20000\" />\n" +
+ " <async enabled=\"true\" batchSize=\"15\" />\n" +
" </loader>\n" +
" </loaders>";
Element e = XmlConfigHelper.stringToElement(xml);
@@ -180,7 +181,11 @@
CacheLoaderConfig iclc = clc.getFirstCacheLoaderConfig();
assert iclc.getClassName().equals("org.horizon.loader.jdbc.JDBCCacheLoader");
- assert iclc.isAsync();
+ assert iclc.getAsyncStoreConfig().isEnabled();
+ assert iclc.getAsyncStoreConfig().getBatchSize() == 15;
+ assert iclc.getAsyncStoreConfig().getPollWait() == 100;
+ assert iclc.getAsyncStoreConfig().getQueueSize() == 10000;
+ assert iclc.getAsyncStoreConfig().getThreadPoolSize() == 1;
assert iclc.isFetchPersistentState();
assert !iclc.isIgnoreModifications();
assert !iclc.isPurgeOnStartup();
@@ -218,7 +223,7 @@
CacheLoaderConfig iclc = clc.getFirstCacheLoaderConfig();
assert iclc.getClassName().equals("org.horizon.loader.jdbc.JDBCCacheLoader");
- assert !iclc.isAsync();
+ assert !iclc.getAsyncStoreConfig().isEnabled();
assert !iclc.isFetchPersistentState();
assert !iclc.isIgnoreModifications();
assert !iclc.isPurgeOnStartup();
Modified: core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -99,7 +99,7 @@
delegate.setEvictionAction(evictionAction);
}
- public void init(Cache<?, ?> cache, DataContainer<?, ?> dataContiner, EvictionAlgorithmConfig evictionAlgorithmConfig) {
+ public void init(Cache<?, ?> cache, DataContainer dataContiner, EvictionAlgorithmConfig evictionAlgorithmConfig) {
delegate.init(cache, dataContiner, evictionAlgorithmConfig);
}
Added: core/branches/flat/src/test/java/org/horizon/loader/AsyncTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/AsyncTest.java (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/loader/AsyncTest.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -0,0 +1,62 @@
+package org.horizon.loader;
+
+import org.horizon.CacheException;
+import org.horizon.loader.decorators.AsyncStore;
+import org.horizon.loader.decorators.AsyncStoreConfig;
+import org.horizon.loader.dummy.DummyInMemoryCacheLoader;
+import org.horizon.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.ExecutorService;
+
+@Test(groups = "unit", sequential = true)
+public class AsyncTest {
+
+ AsyncStore store;
+ ExecutorService asyncExecutor;
+
+
+ @BeforeTest
+ public void setUp() {
+ store = new AsyncStore(new DummyInMemoryCacheLoader(), new AsyncStoreConfig());
+ DummyInMemoryCacheLoader.Cfg cfg = new DummyInMemoryCacheLoader.Cfg();
+ cfg.setStore(AsyncTest.class.getName());
+ store.init(cfg, null, null);
+ store.start();
+ asyncExecutor = (ExecutorService) TestingUtil.extractField(store, "executor");
+ }
+
+ @AfterTest
+ public void tearDown() {
+ if (store != null) store.stop();
+ }
+
+ @AfterMethod
+ public void clearStore() {
+ if (store != null) store.clear();
+ }
+
+ public void testRestrictionOnAddingToAsyncQueue() throws Exception {
+ store.remove("blah");
+
+ store.store(new StoredEntry("one", "value"));
+ store.store(new StoredEntry("two", "value"));
+ store.store(new StoredEntry("three", "value"));
+ store.store(new StoredEntry("four", "value"));
+
+ // stop the cache store
+ store.stop();
+ try {
+ store.remove("blah");
+ assert false : "Should have restricted this entry from being made";
+ }
+ catch (CacheException expected) {
+ }
+
+ // clean up
+ store.start();
+ }
+}
Modified: core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java 2009-02-11 12:53:09 UTC (rev 7682)
+++ core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java 2009-02-11 17:13:41 UTC (rev 7683)
@@ -5,10 +5,8 @@
import org.horizon.loader.AbstractCacheStore;
import org.horizon.loader.CacheLoaderConfig;
import org.horizon.loader.StoredEntry;
-import org.horizon.loader.modifications.Modification;
import org.horizon.marshall.Marshaller;
-import javax.transaction.Transaction;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
@@ -16,22 +14,19 @@
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-public class DummyInMemoryCacheLoader<K, V> extends AbstractCacheStore<K, V> {
+public class DummyInMemoryCacheLoader extends AbstractCacheStore {
static final ConcurrentMap<String, Map> stores = new ConcurrentHashMap<String, Map>();
String storeName = "__DEFAULT_STORES__";
- Map<K, StoredEntry<K, V>> store;
+ Map<Object, StoredEntry> store;
Cfg config;
- ConcurrentMap<Transaction, List<Modification>> txs = new ConcurrentHashMap<Transaction, List<Modification>>();
-
- public void store(StoredEntry<K, V> ed) {
+ public void store(StoredEntry ed) {
store.put(ed.getKey(), ed);
}
@@ -42,7 +37,7 @@
int numEntries = ois.readInt();
store.clear();
for (int i = 0; i < numEntries; i++) {
- StoredEntry<K, V> e = (StoredEntry<K, V>) ois.readObject();
+ StoredEntry e = (StoredEntry) ois.readObject();
store.put(e.getKey(), e);
}
}
@@ -51,47 +46,31 @@
ObjectOutputStream oos = outputStream instanceof ObjectOutputStream ? (ObjectOutputStream) outputStream :
new ObjectOutputStream(outputStream);
oos.writeInt(store.size());
- for (StoredEntry<K, V> se : store.values()) oos.writeObject(se);
+ for (StoredEntry se : store.values()) oos.writeObject(se);
}
public void clear() {
store.clear();
}
- public boolean remove(K key) {
+ public boolean remove(Object key) {
return store.remove(key) != null;
}
public void purgeExpired() {
- for (Iterator<StoredEntry<K, V>> i = store.values().iterator(); i.hasNext();) {
- StoredEntry<K, V> se = i.next();
+ for (Iterator<StoredEntry> i = store.values().iterator(); i.hasNext();) {
+ StoredEntry se = i.next();
if (se.isExpired()) i.remove();
}
}
- public void commit(Transaction tx) {
- List<Modification> mods = txs.remove(tx);
- if (mods != null) applyModifications(mods);
- }
-
- public void rollback(Transaction tx) {
- txs.remove(tx);
- }
-
- public void prepare(List<Modification> list, Transaction tx, boolean isOnePhase) {
- if (isOnePhase)
- applyModifications(list);
- else
- txs.put(tx, list);
- }
-
public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
this.config = (Cfg) config;
}
- public StoredEntry<K, V> load(K key) {
+ public StoredEntry load(Object key) {
if (key == null) return null;
- StoredEntry<K, V> se = store.get(key);
+ StoredEntry se = store.get(key);
if (se == null) return null;
if (se.isExpired()) {
store.remove(key);
@@ -101,10 +80,10 @@
return se;
}
- public Set<StoredEntry<K, V>> loadAll() {
- Set<StoredEntry<K, V>> s = new HashSet<StoredEntry<K, V>>();
- for (Iterator<StoredEntry<K, V>> i = store.values().iterator(); i.hasNext();) {
- StoredEntry<K, V> se = i.next();
+ public Set<StoredEntry> loadAll() {
+ Set<StoredEntry> s = new HashSet<StoredEntry>();
+ for (Iterator<StoredEntry> i = store.values().iterator(); i.hasNext();) {
+ StoredEntry se = i.next();
if (se.isExpired())
i.remove();
else
@@ -113,7 +92,7 @@
return s;
}
- public boolean containsKey(K key) {
+ public boolean containsKey(Object key) {
return load(key) != null;
}
15 years, 11 months
JBoss Cache SVN: r7682 - in core/branches/flat/src: main/java/org/horizon/config and 10 other directories.
by jbosscache-commits@lists.jboss.org
Author: mircea.markus
Date: 2009-02-11 07:53:09 -0500 (Wed, 11 Feb 2009)
New Revision: 7682
Added:
core/branches/flat/src/test/java/org/horizon/interceptors/
core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java
core/branches/flat/src/test/java/org/horizon/marshall/
core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java
Removed:
core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java
core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java
Modified:
core/branches/flat/src/main/java/org/horizon/Cache.java
core/branches/flat/src/main/java/org/horizon/CacheDelegate.java
core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java
core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java
core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java
core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java
core/branches/flat/src/main/resources/config-samples/all.xml
core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java
core/branches/flat/src/test/resources/configs/named-cache-test.xml
Log:
added support for lazy deserialization
Modified: core/branches/flat/src/main/java/org/horizon/Cache.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/Cache.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/Cache.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -140,5 +140,14 @@
AdvancedCache<K, V> getAdvancedCache();
+ /**
+ * Method that releases object references of cached objects held in the cache by serializing them to byte buffers.
+ * Cached objects are lazily deserialized when accessed again, based on the calling thread's context class loader.
+ * <p/>
+ * This can be expensive, based on the effort required to serialize cached objects.
+ * <p/>
+ */
+ void compact();
+
ComponentStatus getStatus();
}
Modified: core/branches/flat/src/main/java/org/horizon/CacheDelegate.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/CacheDelegate.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/CacheDelegate.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -50,6 +50,7 @@
import org.horizon.logging.Log;
import org.horizon.logging.LogFactory;
import org.horizon.manager.CacheManager;
+import org.horizon.marshall.MarshalledValue;
import org.horizon.marshall.Marshaller;
import org.horizon.notifications.cachelistener.CacheNotifier;
import org.horizon.remoting.RPCManager;
@@ -432,4 +433,23 @@
public AdvancedCache<K, V> getAdvancedCache() {
return this;
}
+
+ public void compact() {
+ for (Object key : dataContainer.keySet())
+ {
+ // get the key first, before attempting to serialize stuff since data.get() may deserialize the key if doing
+ // a hashcode() or equals().
+
+ Object value = dataContainer.get(key);
+ if (key instanceof MarshalledValue)
+ {
+ ((MarshalledValue) key).compact(true, true);
+ }
+
+ if (value instanceof MarshalledValue)
+ {
+ ((MarshalledValue) value).compact(true, true);
+ }
+ }
+ }
}
Modified: core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -31,23 +31,23 @@
*/
public static final short DEFAULT_MARSHALL_VERSION = Version.getVersionShort();
- String asyncListenerExecutorFactoryClass = DefaultExecutorFactory.class.getName();
- TypedProperties asyncListenerExecutorProperties = EMPTY_PROPERTIES;
- String asyncSerializationExecutorFactoryClass = DefaultExecutorFactory.class.getName();
- TypedProperties asyncSerializationExecutorProperties = EMPTY_PROPERTIES;
- String evictionScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
- TypedProperties evictionScheduledExecutorProperties = EMPTY_PROPERTIES;
- String replicationQueueScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
- TypedProperties replicationQueueScheduledExecutorProperties = EMPTY_PROPERTIES;
- String marshallerClass = VersionAwareMarshaller.class.getName(); // the default
- int objectInputStreamPoolSize = 50; // defaults
- int objectOutputStreamPoolSize = 50; // defaults
- String transportClass = null; // this defaults to a non-clustered cache.
- TypedProperties transportProperties = EMPTY_PROPERTIES;
- Configuration defaultConfiguration;
- String clusterName = "Horizon-Cluster";
- ShutdownHookBehavior shutdownHookBehavior = ShutdownHookBehavior.DEFAULT;
- short marshallVersion = DEFAULT_MARSHALL_VERSION;
+ private String asyncListenerExecutorFactoryClass = DefaultExecutorFactory.class.getName();
+ private TypedProperties asyncListenerExecutorProperties = EMPTY_PROPERTIES;
+ private String asyncSerializationExecutorFactoryClass = DefaultExecutorFactory.class.getName();
+ private TypedProperties asyncSerializationExecutorProperties = EMPTY_PROPERTIES;
+ private String evictionScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
+ private TypedProperties evictionScheduledExecutorProperties = EMPTY_PROPERTIES;
+ private String replicationQueueScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
+ private TypedProperties replicationQueueScheduledExecutorProperties = EMPTY_PROPERTIES;
+ private String marshallerClass = VersionAwareMarshaller.class.getName(); // the default
+ private int objectInputStreamPoolSize = 50; // defaults
+ private int objectOutputStreamPoolSize = 50; // defaults
+ private String transportClass = null; // this defaults to a non-clustered cache.
+ private TypedProperties transportProperties = EMPTY_PROPERTIES;
+ private Configuration defaultConfiguration;
+ private String clusterName = "Horizon-Cluster";
+ private ShutdownHookBehavior shutdownHookBehavior = ShutdownHookBehavior.DEFAULT;
+ private short marshallVersion = DEFAULT_MARSHALL_VERSION;
private GlobalComponentRegistry gcr;
Modified: core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -151,6 +151,7 @@
configureLocking(getSingleElementInCoreNS("locking", e), c);
configureTransaction(getSingleElementInCoreNS("transaction", e), c);
configureJmxStatistics(getSingleElementInCoreNS("jmxStatistics", e), c);
+ configureLazyDeserialization(getSingleElementInCoreNS("lazyDeserialization", e), c);
configureInvocationBatching(getSingleElementInCoreNS("invocationBatching", e), c);
configureClustering(getSingleElementInCoreNS("clustering", e), c);
configureEviction(getSingleElementInCoreNS("eviction", e), c);
@@ -293,6 +294,15 @@
}
}
+ void configureLazyDeserialization(Element element, Configuration config) {
+ if (element != null) {
+ String enabled = getAttributeValue(element, "enabled");
+ if (existsAttribute(enabled)) {
+ config.setUseLazyDeserialization(getBoolean(enabled));
+ }
+ }
+ }
+
void configureInvalidation(Element element, Configuration config) {
if (element == null) return; //might be replication
Element async = getSingleElement("async");
Modified: core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -28,7 +28,6 @@
import org.horizon.context.InvocationContext;
import org.horizon.interceptors.base.CommandInterceptor;
import org.horizon.marshall.MarshalledValue;
-import org.horizon.marshall.MarshalledValueHelper;
import java.io.IOException;
import java.io.NotSerializableException;
@@ -47,6 +46,7 @@
* representations.
*
* @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @author Mircea.Markus(a)jboss.com
* @see org.horizon.marshall.MarshalledValue
* @since 1.0
*/
@@ -54,59 +54,68 @@
@Override
public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable {
Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
-
- command.setMap(wrapMap(command.getMap(), marshalledValues, ctx));
+ Map map = wrapMap(command.getMap(), marshalledValues, ctx);
+ command.setMap(map);
Object retVal = invokeNextInterceptor(ctx, command);
return compactAndProcessRetVal(marshalledValues, retVal);
}
@Override
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
- Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
- if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass())) {
- Object newKey = createAndAddMarshalledValue(command.getKey(), marshalledValues, ctx);
- command.setKey(newKey);
+ MarshalledValue key = null;
+ MarshalledValue value = null;
+ if (!MarshalledValue.isTypeExcluded(command.getKey().getClass())) {
+ key = createMarshalledValue(command.getKey(), ctx);
+ command.setKey(key);
}
- if (!MarshalledValueHelper.isTypeExcluded(command.getValue().getClass())) {
- Object value = createAndAddMarshalledValue(command.getValue(), marshalledValues, ctx);
+ if (!MarshalledValue.isTypeExcluded(command.getValue().getClass())) {
+ value = createMarshalledValue(command.getValue(), ctx);
command.setValue(value);
}
Object retVal = invokeNextInterceptor(ctx, command);
- return compactAndProcessRetVal(marshalledValues, retVal);
+ compact(key);
+ compact(value);
+ return processRetVal(retVal);
}
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
- Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
- if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass())) {
- Object value = createAndAddMarshalledValue(command.getKey(), marshalledValues, ctx);
+ MarshalledValue value = null;
+ if (!MarshalledValue.isTypeExcluded(command.getKey().getClass())) {
+ value = createMarshalledValue(command.getKey(), ctx);
command.setKey(value);
}
Object retVal = invokeNextInterceptor(ctx, command);
- return compactAndProcessRetVal(marshalledValues, retVal);
+ compact(value);
+ return processRetVal(retVal);
}
@Override
public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable {
- Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
- if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass())) {
- Object value = createAndAddMarshalledValue(command.getKey(), marshalledValues, ctx);
- command.setKey(value);
+ MarshalledValue mv = null;
+ if (!MarshalledValue.isTypeExcluded(command.getKey().getClass())) {
+ mv = createMarshalledValue(command.getKey(), ctx);
+ command.setKey(mv);
+ compact(mv);
}
Object retVal = invokeNextInterceptor(ctx, command);
- return compactAndProcessRetVal(marshalledValues, retVal);
+ compact(mv);
+ return processRetVal(retVal);
}
private Object compactAndProcessRetVal(Set<MarshalledValue> marshalledValues, Object retVal)
throws IOException, ClassNotFoundException {
if (trace) log.trace("Compacting MarshalledValues created");
- for (MarshalledValue mv : marshalledValues) mv.compact(false, false);
-
+ for (MarshalledValue mv : marshalledValues) compact(mv);
return processRetVal(retVal);
}
- private Object processRetVal(Object retVal)
- throws IOException, ClassNotFoundException {
+ private void compact(MarshalledValue mv) {
+ if (mv == null) return;
+ mv.compact(false, false);
+ }
+
+ private Object processRetVal(Object retVal) throws IOException, ClassNotFoundException {
if (retVal instanceof MarshalledValue) {
if (trace) log.trace("Return value is a MarshalledValue. Unwrapping.");
retVal = ((MarshalledValue) retVal).get();
@@ -125,16 +134,16 @@
for (Map.Entry me : m.entrySet()) {
Object key = me.getKey();
Object value = me.getValue();
- copy.put((key == null || MarshalledValueHelper.isTypeExcluded(key.getClass())) ? key : createAndAddMarshalledValue(key, marshalledValues, ctx),
- (value == null || MarshalledValueHelper.isTypeExcluded(value.getClass())) ? value : createAndAddMarshalledValue(value, marshalledValues, ctx));
+ Object newKey = (key == null || MarshalledValue.isTypeExcluded(key.getClass())) ? key : createMarshalledValue(key, ctx);
+ Object newValue = (value == null || MarshalledValue.isTypeExcluded(value.getClass())) ? value : createMarshalledValue(value, ctx);
+ if (newKey instanceof MarshalledValue) marshalledValues.add((MarshalledValue) newKey);
+ if (newValue instanceof MarshalledValue) marshalledValues.add((MarshalledValue) newValue);
+ copy.put(newKey, newValue);
}
return copy;
}
- protected MarshalledValue createAndAddMarshalledValue(Object toWrap, Set<MarshalledValue> marshalledValues, InvocationContext ctx) throws NotSerializableException {
- MarshalledValue mv = new MarshalledValue(toWrap);
- marshalledValues.add(mv);
- if (!ctx.isOriginLocal()) mv.setEqualityPreferenceForInstance(false);
- return mv;
+ protected MarshalledValue createMarshalledValue(Object toWrap, InvocationContext ctx) throws NotSerializableException {
+ return new MarshalledValue(toWrap, ctx.isOriginLocal());
}
}
Modified: core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -22,6 +22,9 @@
package org.horizon.marshall;
import org.horizon.CacheException;
+import org.horizon.commands.ReplicableCommand;
+import org.horizon.remoting.transport.Address;
+import org.horizon.transaction.GlobalTransaction;
import org.jboss.util.stream.MarshalledValueInputStream;
import java.io.*;
@@ -35,6 +38,7 @@
* <p/>
*
* @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @author Mircea.Markus(a)jboss.com
* @see org.horizon.interceptors.MarshalledValueInterceptor
* @since 1.0
*/
@@ -45,23 +49,20 @@
// by default equals() will test on the istance rather than the byte array if conversion is required.
private transient boolean equalityPreferenceForInstance = true;
- public MarshalledValue(Object instance) throws NotSerializableException {
+ public MarshalledValue(Object instance, boolean equalityPreferenceForInstance) throws NotSerializableException {
if (instance == null) throw new NullPointerException("Null values cannot be wrapped as MarshalledValues!");
if (instance instanceof Serializable)
this.instance = instance;
else
throw new NotSerializableException("Marshalled values can only wrap Objects that are serializable! Instance of " + instance.getClass() + " won't Serialize.");
+ this.equalityPreferenceForInstance = equalityPreferenceForInstance;
}
public MarshalledValue() {
// empty ctor for serialization
}
- public void setEqualityPreferenceForInstance(boolean equalityPreferenceForInstance) {
- this.equalityPreferenceForInstance = equalityPreferenceForInstance;
- }
-
public synchronized void serialize() {
if (raw == null) {
try {
@@ -72,7 +73,6 @@
baos.close();
// Do NOT set instance to null over here, since it may be used elsewhere (e.g., in a cache listener).
// this will be compacted by the MarshalledValueInterceptor when the call returns.
-// instance = null;
raw = baos.toByteArray();
}
catch (Exception e) {
@@ -90,7 +90,6 @@
instance = ois.readObject();
ois.close();
bais.close();
-// raw = null;
}
catch (Exception e) {
throw new CacheException("Unable to unmarshall value", e);
@@ -123,13 +122,17 @@
// need to lose one representation!
if (preferSerializedRepresentation) {
- instance = null;
+ nullifyInstance();
} else {
raw = null;
}
}
}
+ private synchronized void nullifyInstance() {
+ instance = null;
+ }
+
public void writeExternal(ObjectOutput out) throws IOException {
if (raw == null) serialize();
out.writeInt(raw.length);
@@ -145,7 +148,13 @@
cachedHashCode = in.readInt();
}
- public Object get() throws IOException, ClassNotFoundException {
+ /**
+ * Returns the 'cached' instance.
+ * Impl note: this method is synchronized so that it synchronizez with the code that nullifies the instance.
+ *
+ * @see #nullifyInstance()
+ */
+ public synchronized Object get() throws IOException, ClassNotFoundException {
if (instance == null) deserialize();
return instance;
}
@@ -191,4 +200,19 @@
public String toString() {
return "MarshalledValue(cachedHashCode=" + cachedHashCode + "; serialized=" + (raw != null) + ")";
}
+
+ /**
+ * Tests whether the type should be excluded from MarshalledValue wrapping.
+ *
+ * @param type type to test. Should not be null.
+ * @return true if it should be excluded from MarshalledValue wrapping.
+ */
+ public static boolean isTypeExcluded(Class type) {
+ return type.equals(String.class) || type.isPrimitive() ||
+ type.equals(Void.class) || type.equals(Boolean.class) || type.equals(Character.class) ||
+ type.equals(Byte.class) || type.equals(Short.class) || type.equals(Integer.class) ||
+ type.equals(Long.class) || type.equals(Float.class) || type.equals(Double.class) ||
+ (type.isArray() && isTypeExcluded(type.getComponentType())) || type.equals(GlobalTransaction.class) || Address.class.isAssignableFrom(type) ||
+ ReplicableCommand.class.isAssignableFrom(type) || type.equals(MarshalledValue.class);
+ }
}
Deleted: core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -1,53 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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 software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.marshall;
-
-import org.horizon.commands.ReplicableCommand;
-import org.horizon.remoting.transport.Address;
-import org.horizon.transaction.GlobalTransaction;
-
-/**
- * Common functionality used by the {@link org.horizon.interceptors.MarshalledValueInterceptor} and the {@link
- * MarshalledValueMap}.
- *
- * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
- * @see MarshalledValue
- * @see org.horizon.interceptors.MarshalledValueInterceptor
- * @see MarshalledValueMap
- * @since 1.0
- */
-public class MarshalledValueHelper {
- /**
- * Tests whether the type should be excluded from MarshalledValue wrapping.
- *
- * @param type type to test. Should not be null.
- * @return true if it should be excluded from MarshalledValue wrapping.
- */
- public static boolean isTypeExcluded(Class type) {
- return type.equals(String.class) || type.isPrimitive() ||
- type.equals(Void.class) || type.equals(Boolean.class) || type.equals(Character.class) ||
- type.equals(Byte.class) || type.equals(Short.class) || type.equals(Integer.class) ||
- type.equals(Long.class) || type.equals(Float.class) || type.equals(Double.class) ||
- (type.isArray() && isTypeExcluded(type.getComponentType())) || type.equals(GlobalTransaction.class) || Address.class.isAssignableFrom(type) ||
- ReplicableCommand.class.isAssignableFrom(type) || type.equals(MarshalledValue.class);
- }
-}
Deleted: core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -1,155 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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 software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.marshall;
-
-import net.jcip.annotations.Immutable;
-import org.horizon.CacheException;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A Map that is able to wrap/unwrap MarshalledValues in keys or values. Note that calling keySet(), entrySet() or
- * values() could be expensive if this map is large!!
- * <p/>
- * Also note that this is an immutable Map.
- * <p/>
- *
- * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
- * @see MarshalledValue
- * @since 1.0
- */
-@Immutable
-public class MarshalledValueMap implements Map, Externalizable {
- Map delegate;
- Map<Object, Object> unmarshalled;
-
- public MarshalledValueMap() {
- // for externalization
- }
-
- public MarshalledValueMap(Map delegate) {
- this.delegate = delegate;
- }
-
- @SuppressWarnings("unchecked")
- protected synchronized Map getUnmarshalledMap() {
- if (unmarshalled == null) unmarshalled = unmarshalledMap(delegate.entrySet());
- return unmarshalled;
- }
-
- public int size() {
- return delegate.size();
- }
-
- public boolean isEmpty() {
- return delegate.isEmpty();
- }
-
- public boolean containsKey(Object key) {
- return getUnmarshalledMap().containsKey(key);
- }
-
- public boolean containsValue(Object value) {
- return getUnmarshalledMap().containsValue(value);
- }
-
- public Object get(Object key) {
- return getUnmarshalledMap().get(key);
- }
-
- public Object put(Object key, Object value) {
- throw new UnsupportedOperationException("This is an immutable map!");
- }
-
- public Object remove(Object key) {
- throw new UnsupportedOperationException("This is an immutable map!");
- }
-
- public void putAll(Map t) {
- throw new UnsupportedOperationException("This is an immutable map!");
- }
-
- public void clear() {
- throw new UnsupportedOperationException("This is an immutable map!");
- }
-
- public Set keySet() {
- return getUnmarshalledMap().keySet();
- }
-
- public Collection values() {
- return getUnmarshalledMap().values();
- }
-
- public Set entrySet() {
- return getUnmarshalledMap().entrySet();
- }
-
- @SuppressWarnings("unchecked")
- protected Map unmarshalledMap(Set entries) {
- if (entries == null || entries.isEmpty()) return Collections.emptyMap();
- Map map = new HashMap(entries.size());
- for (Object e : entries) {
- Map.Entry entry = (Map.Entry) e;
- map.put(getUnmarshalledValue(entry.getKey()), getUnmarshalledValue(entry.getValue()));
- }
- return map;
- }
-
- private Object getUnmarshalledValue(Object o) {
- try {
- return o instanceof MarshalledValue ? ((MarshalledValue) o).get() : o;
- }
- catch (Exception e) {
- throw new CacheException("Unable to unmarshall value", e);
- }
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof Map) {
- return getUnmarshalledMap().equals(other);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return getUnmarshalledMap().hashCode();
- }
-
- public void writeExternal(ObjectOutput out) throws IOException {
- out.writeObject(delegate);
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
- delegate = (Map) in.readObject();
- }
-}
Modified: core/branches/flat/src/main/resources/config-samples/all.xml
===================================================================
--- core/branches/flat/src/main/resources/config-samples/all.xml 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/resources/config-samples/all.xml 2009-02-11 12:53:09 UTC (rev 7682)
@@ -77,6 +77,8 @@
-->
<jmxStatistics enabled="false"/>
+ <lazyDeserialization enabled="false"/>
+
<!--
Used to enable invocation batching and allow the use of Cache.startBatch()/endBatch() methods.
-->
Modified: core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
===================================================================
--- core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd 2009-02-11 12:53:09 UTC (rev 7682)
@@ -47,6 +47,7 @@
<xs:element name="locking" type="tns:lockingType" minOccurs="0" maxOccurs="1"/>
<xs:element name="transaction" type="tns:transactionType" minOccurs="0" maxOccurs="1"/>
<xs:element name="jmxStatistics" type="tns:jmxStatisticsType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="lazyDeserialization" type="tns:lazyDeserialization" minOccurs="0" maxOccurs="1"/>
<xs:element name="invocationBatching" type="tns:invocationBatchingType" minOccurs="0" maxOccurs="1"/>
<xs:element name="eviction" type="tns:evictionType" minOccurs="0" maxOccurs="1"/>
<xs:element name="loaders" type="tns:loadersType" minOccurs="0" maxOccurs="1"/>
@@ -108,10 +109,6 @@
</xs:attribute>
</xs:complexType>
- <xs:complexType name="serializationType">
- <xs:attribute name="useLazyDeserialization" type="tns:booleanType"/>
- </xs:complexType>
-
<xs:simpleType name="booleanType">
<xs:restriction base="xs:string">
<xs:pattern value="\$\{.*\}|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]"/>
@@ -128,6 +125,10 @@
<xs:attribute name="enabled" type="tns:booleanType"/>
</xs:complexType>
+ <xs:complexType name="lazyDeserialization">
+ <xs:attribute name="enabled" type="tns:booleanType"/>
+ </xs:complexType>
+
<xs:complexType name="invocationBatchingType">
<xs:attribute name="enabled" type="tns:booleanType"/>
</xs:complexType>
Modified: core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -75,6 +75,17 @@
assert c.isExposeManagementStatistics();
}
+ public void testLazyDeserialization() throws Exception {
+ XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
+ String xml = "<lazyDeserialization enabled=\"true\"/>";
+ Element e = XmlConfigHelper.stringToElement(xml);
+
+ Configuration c = new Configuration();
+ parser.configureLazyDeserialization(e, c);
+
+ assert c.isExposeManagementStatistics();
+ }
+
public void testJmxStatisticsDefaults() throws Exception {
XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
String xml = "<jmxStatistics />";
Modified: core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -87,6 +87,10 @@
assert c.getLockAcquisitionTimeout() == 20000;
assert c.getConcurrencyLevel() == 1000;
assert c.getIsolationLevel() == IsolationLevel.REPEATABLE_READ;
+ assert !c.isUseLazyDeserialization();
+
+ c = namedCaches.get("lazyDeserialization");
+ assert c.isUseLazyDeserialization();
}
public void testConfigurationMerging() throws IOException {
Added: core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -0,0 +1,135 @@
+package org.horizon.interceptors;
+
+import org.horizon.Cache;
+import org.horizon.config.Configuration;
+import org.horizon.config.GlobalConfiguration;
+import org.horizon.manager.CacheManager;
+import org.horizon.manager.DefaultCacheManager;
+import org.horizon.marshall.MarshalledValue;
+import org.horizon.util.TestingUtil;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik AT jboss DOT org</a>)
+ * @author Mircea.Markus(a)jboss.com
+ * @since 1.0
+ */
+@Test(groups = "functional", sequential = true, testName = "interceptors.MarshalledValueInterceptorTest")
+public class MarshalledValueInterceptorTest {
+ CacheManager cm;
+
+ @BeforeTest
+ public void setUp() {
+ cm = new DefaultCacheManager(GlobalConfiguration.getNonClusteredDefault());
+ }
+
+ @AfterTest
+ public void tearDown() {
+ TestingUtil.killCacheManagers(cm);
+ }
+
+ public void testDefaultInterceptorStack() {
+ assert TestingUtil.findInterceptor(cm.getCache(), MarshalledValueInterceptor.class) == null;
+
+ Configuration configuration = new Configuration();
+ configuration.setUseLazyDeserialization(true);
+ cm.defineCache("someCache", configuration);
+ Cache c = cm.getCache("someCache");
+
+ assert TestingUtil.findInterceptor(c, MarshalledValueInterceptor.class) != null;
+ TestingUtil.killCaches(c);
+ }
+
+ public void testDisabledInterceptorStack() {
+ Configuration cfg = new Configuration();
+ cfg.setUseLazyDeserialization(false);
+ cm.defineCache("a", cfg);
+ Cache c = cm.getCache("a");
+ assert TestingUtil.findInterceptor(c, MarshalledValueInterceptor.class) == null;
+ }
+
+ public void testExcludedTypes() {
+ // Strings
+ assert MarshalledValue.isTypeExcluded(String.class);
+ assert MarshalledValue.isTypeExcluded(String[].class);
+ assert MarshalledValue.isTypeExcluded(String[][].class);
+ assert MarshalledValue.isTypeExcluded(String[][][].class);
+
+ // primitives
+ assert MarshalledValue.isTypeExcluded(void.class);
+ assert MarshalledValue.isTypeExcluded(boolean.class);
+ assert MarshalledValue.isTypeExcluded(char.class);
+ assert MarshalledValue.isTypeExcluded(byte.class);
+ assert MarshalledValue.isTypeExcluded(short.class);
+ assert MarshalledValue.isTypeExcluded(int.class);
+ assert MarshalledValue.isTypeExcluded(long.class);
+ assert MarshalledValue.isTypeExcluded(float.class);
+ assert MarshalledValue.isTypeExcluded(double.class);
+
+ assert MarshalledValue.isTypeExcluded(boolean[].class);
+ assert MarshalledValue.isTypeExcluded(char[].class);
+ assert MarshalledValue.isTypeExcluded(byte[].class);
+ assert MarshalledValue.isTypeExcluded(short[].class);
+ assert MarshalledValue.isTypeExcluded(int[].class);
+ assert MarshalledValue.isTypeExcluded(long[].class);
+ assert MarshalledValue.isTypeExcluded(float[].class);
+ assert MarshalledValue.isTypeExcluded(double[].class);
+
+ assert MarshalledValue.isTypeExcluded(boolean[][].class);
+ assert MarshalledValue.isTypeExcluded(char[][].class);
+ assert MarshalledValue.isTypeExcluded(byte[][].class);
+ assert MarshalledValue.isTypeExcluded(short[][].class);
+ assert MarshalledValue.isTypeExcluded(int[][].class);
+ assert MarshalledValue.isTypeExcluded(long[][].class);
+ assert MarshalledValue.isTypeExcluded(float[][].class);
+ assert MarshalledValue.isTypeExcluded(double[][].class);
+
+ assert MarshalledValue.isTypeExcluded(Void.class);
+ assert MarshalledValue.isTypeExcluded(Boolean.class);
+ assert MarshalledValue.isTypeExcluded(Character.class);
+ assert MarshalledValue.isTypeExcluded(Byte.class);
+ assert MarshalledValue.isTypeExcluded(Short.class);
+ assert MarshalledValue.isTypeExcluded(Integer.class);
+ assert MarshalledValue.isTypeExcluded(Long.class);
+ assert MarshalledValue.isTypeExcluded(Float.class);
+ assert MarshalledValue.isTypeExcluded(Double.class);
+
+ assert MarshalledValue.isTypeExcluded(Boolean[].class);
+ assert MarshalledValue.isTypeExcluded(Character[].class);
+ assert MarshalledValue.isTypeExcluded(Byte[].class);
+ assert MarshalledValue.isTypeExcluded(Short[].class);
+ assert MarshalledValue.isTypeExcluded(Integer[].class);
+ assert MarshalledValue.isTypeExcluded(Long[].class);
+ assert MarshalledValue.isTypeExcluded(Float[].class);
+ assert MarshalledValue.isTypeExcluded(Double[].class);
+
+ assert MarshalledValue.isTypeExcluded(Boolean[][].class);
+ assert MarshalledValue.isTypeExcluded(Character[][].class);
+ assert MarshalledValue.isTypeExcluded(Byte[][].class);
+ assert MarshalledValue.isTypeExcluded(Short[][].class);
+ assert MarshalledValue.isTypeExcluded(Integer[][].class);
+ assert MarshalledValue.isTypeExcluded(Long[][].class);
+ assert MarshalledValue.isTypeExcluded(Float[][].class);
+ assert MarshalledValue.isTypeExcluded(Double[][].class);
+ }
+
+ public void testNonExcludedTypes() {
+ assert !MarshalledValue.isTypeExcluded(Object.class);
+ assert !MarshalledValue.isTypeExcluded(List.class);
+ assert !MarshalledValue.isTypeExcluded(Collection.class);
+ assert !MarshalledValue.isTypeExcluded(Map.class);
+ assert !MarshalledValue.isTypeExcluded(Date.class);
+ assert !MarshalledValue.isTypeExcluded(Thread.class);
+ assert !MarshalledValue.isTypeExcluded(Collection.class);
+ assert !MarshalledValue.isTypeExcluded(new Object() {
+ String blah;
+ }.getClass());
+ }
+}
Property changes on: core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java 2009-02-11 12:53:09 UTC (rev 7682)
@@ -0,0 +1,373 @@
+package org.horizon.marshall;
+
+import org.horizon.AdvancedCache;
+import org.horizon.BaseClusteredTest;
+import org.horizon.Cache;
+import org.horizon.CacheException;
+import org.horizon.commands.write.PutKeyValueCommand;
+import org.horizon.config.CacheLoaderManagerConfig;
+import org.horizon.config.Configuration;
+import org.horizon.container.DataContainer;
+import org.horizon.context.InvocationContext;
+import org.horizon.interceptors.InterceptorChain;
+import org.horizon.interceptors.MarshalledValueInterceptor;
+import org.horizon.interceptors.base.CommandInterceptor;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.dummy.DummyInMemoryCacheLoader;
+import org.horizon.manager.CacheManager;
+import org.horizon.notifications.Listener;
+import org.horizon.notifications.cachelistener.annotation.CacheEntryModified;
+import org.horizon.notifications.cachelistener.event.CacheEntryModifiedEvent;
+import org.horizon.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+
+/**
+ * Tests implicit marshalled values
+ *
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik AT jboss DOT org</a>)
+ * @author Mircea.Markus(a)jboss.com
+ * @since 1.0
+ */
+@Test(groups = "functional", testName = "marshall.MarshalledValueTest")
+public class MarshalledValueTest extends BaseClusteredTest {
+ private Cache cache1, cache2;
+ private MarshalledValueListenerInterceptor mvli;
+ String k = "key", v = "value";
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() {
+ CacheManager cm1 = addClusterEnabledCacheManager();
+ CacheManager cm2 = addClusterEnabledCacheManager();
+
+ Configuration replSync = new Configuration();
+ replSync.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+ replSync.setUseLazyDeserialization(true);
+
+ defineCacheOnAllManagers("replSync", replSync);
+
+ cache1 = cm1.getCache("replSync");
+ cache2 = cm2.getCache("replSync");
+
+ assertMarshalledValueInterceptorPresent(cache1);
+ assertMarshalledValueInterceptorPresent(cache2);
+
+ mvli = new MarshalledValueListenerInterceptor();
+ ((AdvancedCache)cache1).addInterceptorAfter(mvli, MarshalledValueInterceptor.class);
+
+ TestingUtil.blockUntilViewsReceived(60000, true, cm1, cm2);
+ }
+
+ private void assertMarshalledValueInterceptorPresent(Cache c) {
+ InterceptorChain ic1 = TestingUtil.extractComponent(c, InterceptorChain.class);
+ assert ic1.containsInterceptorType(MarshalledValueInterceptor.class);
+ }
+
+ @AfterMethod
+ public void tearDown() {
+ TestingUtil.killCaches(cache1, cache2);
+ Pojo.serializationCount = 0;
+ Pojo.deserializationCount = 0;
+ }
+
+ private void assertOnlyOneRepresentationExists(MarshalledValue mv) {
+ assert (mv.instance != null && mv.raw == null) || (mv.instance == null && mv.raw != null) : "Only instance or raw representations should exist in a MarshalledValue; never both";
+ }
+
+ private void assertSerialized(MarshalledValue mv) {
+ assert mv.raw != null : "Should be serialized";
+ }
+
+ private void assertDeserialized(MarshalledValue mv) {
+ assert mv.instance != null : "Should be deserialized";
+ }
+
+ private void assertSerializationCounts(int serializationCount, int deserializationCount) {
+ assert Pojo.serializationCount == serializationCount : "Serialization count: expected " + serializationCount + " but was " + Pojo.serializationCount;
+ assert Pojo.deserializationCount == deserializationCount : "Deserialization count: expected " + deserializationCount + " but was " + Pojo.deserializationCount;
+ }
+
+ public void testNonSerializable() {
+ try {
+ cache1.put("Hello", new Object());
+ assert false : "Should have failed";
+ }
+ catch (CacheException expected) {
+
+ }
+
+ assert mvli.invocationCount == 0 : "Call should not have gone beyond the MarshalledValueInterceptor";
+
+ try {
+ cache1.put(new Object(), "Hello");
+ assert false : "Should have failed";
+ }
+ catch (CacheException expected) {
+
+ }
+
+ assert mvli.invocationCount == 0 : "Call should not have gone beyond the MarshalledValueInterceptor";
+ }
+
+ public void testNodeReleaseObjectValueReferences() {
+ Pojo value = new Pojo();
+ cache1.put("key", value);
+ assertSerializationCounts(1, 0);
+
+ DataContainer dc1 = TestingUtil.extractComponent(cache1, DataContainer.class);
+
+ Object o = dc1.get("key");
+ assert o instanceof MarshalledValue;
+ MarshalledValue mv = (MarshalledValue) o;
+ assertDeserialized(mv);
+ assert cache1.get("key").equals(value);
+ assertDeserialized(mv);
+ assertSerializationCounts(1, 0);
+ cache1.compact();
+ assertSerializationCounts(2, 0);
+ assertOnlyOneRepresentationExists(mv);
+ assertSerialized(mv);
+
+ // now on cache 2
+ DataContainer dc2 = TestingUtil.extractComponent(cache2, DataContainer.class);
+ o = dc2.get("key");
+ assert o instanceof MarshalledValue;
+ mv = (MarshalledValue) o;
+ assertSerialized(mv); // this proves that unmarshalling on the recipient cache instance is lazy
+
+ assert cache2.get("key").equals(value);
+ assertDeserialized(mv);
+ assertSerializationCounts(2, 1);
+ cache2.compact();
+ assertSerializationCounts(2, 1);
+ assertOnlyOneRepresentationExists(mv);
+ assertSerialized(mv);
+ }
+
+ public void testNodeReleaseObjectKeyReferences() throws IOException, ClassNotFoundException {
+ Pojo key = new Pojo();
+ cache1.put(key, "value");
+
+ assertSerializationCounts(1, 0);
+
+ DataContainer dc1 = TestingUtil.extractComponent(cache1, DataContainer.class);
+
+ Object o = dc1.keySet().iterator().next();
+ assert o instanceof MarshalledValue;
+ MarshalledValue mv = (MarshalledValue) o;
+ assertDeserialized(mv);
+
+ assert cache1.get(key).equals("value");
+ assertDeserialized(mv);
+ assertSerializationCounts(1, 0);
+
+ cache1.compact();
+ assertSerializationCounts(2, 0);
+ assertOnlyOneRepresentationExists(mv);
+ assertSerialized(mv);
+
+
+ // now on cache 2
+ DataContainer dc2 = TestingUtil.extractComponent(cache2, DataContainer.class);
+ o = dc2.keySet().iterator().next();
+ assert o instanceof MarshalledValue;
+ mv = (MarshalledValue) o;
+ assertSerialized(mv);
+ assert cache2.get(key).equals("value");
+ assertSerializationCounts(2, 1);
+ assertDeserialized(mv);
+ cache2.compact();
+
+ assertOnlyOneRepresentationExists(mv);
+ assertSerialized(mv);
+ assertSerializationCounts(2, 1);
+ }
+
+ public void testEqualsAndHashCode() throws Exception {
+ Pojo pojo = new Pojo();
+ MarshalledValue mv = new MarshalledValue(pojo, true);
+ assertDeserialized(mv);
+ int oldHashCode = mv.hashCode();
+
+ mv.serialize();
+ assertSerialized(mv);
+ assert oldHashCode == mv.hashCode();
+
+ MarshalledValue mv2 = new MarshalledValue(pojo, true);
+ assertSerialized(mv);
+ assertDeserialized(mv2);
+
+ assert mv2.hashCode() == oldHashCode;
+ assert mv.equals(mv2);
+ }
+
+ public void assertUseOfMagicNumbers() throws Exception {
+ Pojo pojo = new Pojo();
+ MarshalledValue mv = new MarshalledValue(pojo, true);
+
+ Configuration c = new Configuration();
+// ComponentRegistry cr = new ComponentRegistry(c, new CacheDelegate("aaa"));
+
+ HorizonMarshaller marshaller = new HorizonMarshaller();
+// cr.registerComponent(marshaller, Marshaller.class);
+
+ // Wire the marshaller
+// cr.start();
+
+ // start the test
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bout);
+ marshaller.objectToObjectStream(mv, out);
+ out.close();
+ bout.close();
+
+ // check that the rest just contains a byte stream which a MarshalledValue will be able to deserialize.
+ ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+ ObjectInputStream in = new ObjectInputStream(bin);
+
+ assert in.read() == HorizonMarshaller.MAGICNUMBER_MARSHALLEDVALUE;
+ MarshalledValue recreated = new MarshalledValue();
+ recreated.readExternal(in);
+
+ // there should be nothing more
+ assert in.available() == 0;
+ in.close();
+ bin.close();
+
+ assertSerialized(recreated);
+ assert recreated.equals(mv);
+
+ // since both objects being compared are serialized, the equals() above should just compare byte arrays.
+ assertSerialized(recreated);
+ assertOnlyOneRepresentationExists(recreated);
+ }
+
+ public void testCacheLoaders() throws CloneNotSupportedException {
+ tearDown();
+
+ Configuration cacheCofig = new Configuration();
+ cacheCofig.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+ cacheCofig.setUseLazyDeserialization(true);
+ CacheLoaderManagerConfig clmc = new CacheLoaderManagerConfig();
+ DummyInMemoryCacheLoader.Cfg clc = new DummyInMemoryCacheLoader.Cfg();
+ clc.setStore(getClass().getSimpleName());
+ clmc.setIndividualCacheLoaderConfigs(Collections.singletonList((CacheLoaderConfig)clc));
+ cacheCofig.setCacheLoaderConfig(clmc);
+
+ defineCacheOnAllManagers("replSync2", cacheCofig);
+ cache1 = getCacheManagers().get(0).getCache("replSync2");
+ cache2 = getCacheManagers().get(1).getCache("replSync2");
+
+ TestingUtil.blockUntilViewsReceived(60000, cache1, cache2);
+
+ Pojo pojo = new Pojo();
+ cache1.put("key", pojo);
+
+ assertMarshalledValueInterceptorPresent(cache1);
+ assertMarshalledValueInterceptorPresent(cache2);
+ assertSerializationCounts(1, 0);
+
+ cache2.get("key");
+
+ assertSerializationCounts(1, 1);
+ }
+
+ public void testCallbackValues() {
+ MockListener l = new MockListener();
+ cache1.addListener(l);
+ Pojo pojo = new Pojo();
+ cache1.put("key", pojo);
+
+ assert l.newValue != null;
+ assert l.newValue instanceof MarshalledValue;
+ MarshalledValue mv = (MarshalledValue) l.newValue;
+ assert mv.instance instanceof Pojo;
+ assertSerializationCounts(1, 0);
+ }
+
+ public void testRemoteCallbackValues() throws Exception {
+ MockListener l = new MockListener();
+ cache2.addListener(l);
+ Pojo pojo = new Pojo();
+ cache1.put("key", pojo);
+
+ assert l.newValue != null;
+ assert l.newValue instanceof MarshalledValue;
+ MarshalledValue mv = (MarshalledValue) l.newValue;
+ assert mv.get() instanceof Pojo;
+ assertSerializationCounts(1, 1);
+ }
+
+ @Listener
+ public static class MockListener {
+ Object newValue;
+
+ @CacheEntryModified
+ public void nodeModified(CacheEntryModifiedEvent e) {
+ if (!e.isPre()) newValue = e.getValue();
+ }
+ }
+
+ class MarshalledValueListenerInterceptor extends CommandInterceptor {
+ int invocationCount = 0;
+ public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
+ invocationCount++;
+ if (command.getKey() instanceof MarshalledValue)
+ assertOnlyOneRepresentationExists((MarshalledValue) command.getKey());
+ if (command.getValue() instanceof MarshalledValue)
+ assertOnlyOneRepresentationExists((MarshalledValue) command.getValue());
+ Object retval = invokeNextInterceptor(ctx, command);
+ if (retval instanceof MarshalledValue) assertOnlyOneRepresentationExists((MarshalledValue) retval);
+ return retval;
+ }
+
+ }
+
+ public static class Pojo implements Externalizable {
+ int i;
+ boolean b;
+ static int serializationCount, deserializationCount;
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Pojo pojo = (Pojo) o;
+
+ if (b != pojo.b) return false;
+ if (i != pojo.i) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = i;
+ result = 31 * result + (b ? 1 : 0);
+ return result;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(i);
+ out.writeBoolean(b);
+ serializationCount++;
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ i = in.readInt();
+ b = in.readBoolean();
+ deserializationCount++;
+ }
+ }
+}
Property changes on: core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: core/branches/flat/src/test/resources/configs/named-cache-test.xml
===================================================================
--- core/branches/flat/src/test/resources/configs/named-cache-test.xml 2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/test/resources/configs/named-cache-test.xml 2009-02-11 12:53:09 UTC (rev 7682)
@@ -69,4 +69,9 @@
<locking isolationLevel="REPEATABLE_READ" concurrencyLevel="1000" lockAcquisitionTimeout="20000" />
</namedCache>
+ <namedCache name="lazyDeserialization">
+ <locking isolationLevel="REPEATABLE_READ" concurrencyLevel="1000" lockAcquisitionTimeout="20000" />
+ <lazyDeserialization enabled="true"/>
+ </namedCache>
+
</horizon>
15 years, 11 months
JBoss Cache SVN: r7681 - core/trunk/src/test/java/org/jboss/cache.
by jbosscache-commits@lists.jboss.org
Author: mircea.markus
Date: 2009-02-11 06:09:31 -0500 (Wed, 11 Feb 2009)
New Revision: 7681
Modified:
core/trunk/src/test/java/org/jboss/cache/ResourceCleanupTest.java
Log:
enhanced logginig
Modified: core/trunk/src/test/java/org/jboss/cache/ResourceCleanupTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/ResourceCleanupTest.java 2009-02-11 09:55:04 UTC (rev 7680)
+++ core/trunk/src/test/java/org/jboss/cache/ResourceCleanupTest.java 2009-02-11 11:09:31 UTC (rev 7681)
@@ -42,6 +42,8 @@
System.out.println("Setting bind.address to 127.0.0.1 as it is missing!!!");
System.setProperty("bind.address","127.0.0.1");
}
+ System.out.println("java.runtime.version = " + System.getProperty("java.runtime.version"));
+ System.out.println("java.runtime.name =" + System.getProperty("java.runtime.name"));
System.out.println("java.vm.version = " + System.getProperty("java.vm.version"));
System.out.println("java.vm.vendor = " + System.getProperty("java.vm.vendor"));
System.out.println("os.name = " + System.getProperty("os.name"));
15 years, 11 months
JBoss Cache SVN: r7680 - core/branches/flat.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2009-02-11 04:55:04 -0500 (Wed, 11 Feb 2009)
New Revision: 7680
Modified:
core/branches/flat/pom.xml
Log:
By default, run all fuctional and unit tests
Modified: core/branches/flat/pom.xml
===================================================================
--- core/branches/flat/pom.xml 2009-02-11 09:52:13 UTC (rev 7679)
+++ core/branches/flat/pom.xml 2009-02-11 09:55:04 UTC (rev 7680)
@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<horizon-version>1.0.0-SNAPSHOT</horizon-version>
- <defaultTestGroup>functional</defaultTestGroup>
+ <defaultTestGroup>functional,unit</defaultTestGroup>
<!-- By default only generate Javadocs when we install the module. -->
<javadocPhase>install</javadocPhase>
</properties>
15 years, 11 months
JBoss Cache SVN: r7679 - in core/branches/flat/src: main/java/org/horizon/config and 28 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2009-02-11 04:52:13 -0500 (Wed, 11 Feb 2009)
New Revision: 7679
Added:
core/branches/flat/src/main/java/org/horizon/config/CacheLoaderManagerConfig.java
core/branches/flat/src/main/java/org/horizon/container/CachedValue.java
core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java
core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/loader/
core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java
core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java
core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManager.java
core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java
core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java
core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/
core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/ChainingCacheLoader.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java
core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStoreConfig.java
core/branches/flat/src/main/java/org/horizon/loader/jdbc/
core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoader.java
core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoaderConfig.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/
core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java
core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java
core/branches/flat/src/test/java/org/horizon/loader/
core/branches/flat/src/test/java/org/horizon/loader/BaseCacheLoaderTest.java
core/branches/flat/src/test/java/org/horizon/loader/dummy/
core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java
core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoaderTest.java
Removed:
core/branches/flat/src/main/java/org/horizon/config/CacheLoaderConfig.java
core/branches/flat/src/main/java/org/horizon/config/EvictionAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/container/CachedEntry.java
core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfigBase.java
core/branches/flat/src/main/java/org/horizon/loaderold/
Modified:
core/branches/flat/src/main/java/org/horizon/config/Configuration.java
core/branches/flat/src/main/java/org/horizon/config/EvictionConfig.java
core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigHelper.java
core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java
core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java
core/branches/flat/src/main/java/org/horizon/container/DataContainer.java
core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java
core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java
core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithmConfig.java
core/branches/flat/src/main/java/org/horizon/factories/EmptyConstructorNamedCacheFactory.java
core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java
core/branches/flat/src/main/java/org/horizon/interceptors/CacheStoreInterceptor.java
core/branches/flat/src/main/java/org/horizon/statetransfer/DefaultStateTransferManager.java
core/branches/flat/src/main/resources/config-samples/all.xml
core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
core/branches/flat/src/test/java/org/horizon/api/tree/NodeMoveAPITest.java
core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java
core/branches/flat/src/test/java/org/horizon/eviction/algorithms/BaseAlgorithmTest.java
core/branches/flat/src/test/java/org/horizon/manager/CacheManagerComponentRegistryTest.java
core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerCacheLoaderTest.java
core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerPassivationTest.java
Log:
Loaders - work in progress
Deleted: core/branches/flat/src/main/java/org/horizon/config/CacheLoaderConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/CacheLoaderConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/CacheLoaderConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,384 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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 software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.config;
-
-import org.horizon.loaderold.CacheLoaderOld;
-import org.horizon.loaderold.SingletonStoreCacheLoaderOld;
-import org.horizon.util.Util;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Holds the configuration of the cache loader chain. ALL cache loaders should be defined using this class, adding
- * individual cache loaders to the chain by calling {@link CacheLoaderConfig#addIndividualCacheLoaderConfig}
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @author Brian Stansberry
- * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
- * @since 1.0
- */
-public class CacheLoaderConfig extends AbstractNamedCacheConfigurationBean {
- private static final long serialVersionUID = 2210349340378984424L;
-
- private boolean passivation;
- private boolean preload;
- private List<IndividualCacheLoaderConfig> cacheLoaderConfigs = new ArrayList<IndividualCacheLoaderConfig>();
-
- private boolean shared;
-
- public void setPreload(boolean preload) {
- testImmutability("preload");
- this.preload = preload;
- }
-
- public void setPassivation(boolean passivation) {
- testImmutability("passivation");
- this.passivation = passivation;
- }
-
- public boolean isPassivation() {
- return passivation;
- }
-
- public void addIndividualCacheLoaderConfig(IndividualCacheLoaderConfig clc) {
- testImmutability("cacheLoaderConfigs");
- cacheLoaderConfigs.add(clc);
- }
-
- public List<IndividualCacheLoaderConfig> getIndividualCacheLoaderConfigs() {
- return cacheLoaderConfigs;
- }
-
- public void setIndividualCacheLoaderConfigs(List<IndividualCacheLoaderConfig> configs) {
- testImmutability("cacheLoaderConfigs");
- this.cacheLoaderConfigs = configs == null ? new ArrayList<IndividualCacheLoaderConfig>() : configs;
- }
-
- public IndividualCacheLoaderConfig getFirstCacheLoaderConfig() {
- if (cacheLoaderConfigs.size() == 0) return null;
- return cacheLoaderConfigs.get(0);
- }
-
- public boolean useChainingCacheLoader() {
- return !isPassivation() && cacheLoaderConfigs.size() > 1;
- }
-
- @Override
- public String toString() {
- return new StringBuilder().append("CacheLoaderConfig{").append("shared=").append(shared).append(", passivation=").append(passivation).append(", preload='").append(preload).append('\'').append(", cacheLoaderConfigs.size()=").append(cacheLoaderConfigs.size()).append('}').toString();
- }
-
- public void setShared(boolean shared) {
- testImmutability("shared");
- this.shared = shared;
- }
-
- public boolean isShared() {
- return shared;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
-
- if (obj instanceof CacheLoaderConfig) {
- CacheLoaderConfig other = (CacheLoaderConfig) obj;
- return (this.passivation == other.passivation)
- && (this.shared == other.shared)
- && Util.safeEquals(this.preload, other.preload)
- && Util.safeEquals(this.cacheLoaderConfigs, other.cacheLoaderConfigs);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int result = 19;
- result = 51 * result + (passivation ? 0 : 1);
- result = 51 * result + (shared ? 0 : 1);
- result = 51 * result + (preload ? 0 : 1);
- result = 51 * result + (cacheLoaderConfigs == null ? 0 : cacheLoaderConfigs.hashCode());
- return result;
- }
-
-
- @Override
- public CacheLoaderConfig clone() throws CloneNotSupportedException {
- CacheLoaderConfig clone = (CacheLoaderConfig) super.clone();
- if (cacheLoaderConfigs != null) {
- List<IndividualCacheLoaderConfig> clcs = new ArrayList<IndividualCacheLoaderConfig>(cacheLoaderConfigs.size());
- for (IndividualCacheLoaderConfig clc : cacheLoaderConfigs) {
- clcs.add(clc.clone());
- }
- clone.setIndividualCacheLoaderConfigs(clcs);
- }
- return clone;
- }
-
- /**
- * Loops through all individual cache loader configs and checks if fetchPersistentState is set on any of them
- */
- public boolean isFetchPersistentState() {
- for (IndividualCacheLoaderConfig iclc : cacheLoaderConfigs) {
- if (iclc.isFetchPersistentState()) return true;
- }
- return false;
- }
-
- public boolean isPreload() {
- return preload;
- }
-
-
- /**
- * Configuration object that holds the confguration of an individual cache loader.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
- */
- public static class IndividualCacheLoaderConfig extends PluggableConfigurationComponent {
- private static final long serialVersionUID = -2282396799100828593L;
-
- private boolean async;
- private boolean ignoreModifications;
- private boolean fetchPersistentState;
-
- private boolean purgeOnStartup;
-
- private SingletonStoreConfig singletonStoreConfig;
- private transient CacheLoaderOld<Object, Object> cacheLoader;
-
- protected void populateFromBaseConfig(IndividualCacheLoaderConfig base) {
- if (base != null) {
- setAsync(base.isAsync());
- setIgnoreModifications(base.isIgnoreModifications());
- setFetchPersistentState(base.isFetchPersistentState());
- setSingletonStoreConfig(base.getSingletonStoreConfig());
- setPurgeOnStartup(base.isPurgeOnStartup());
- setProperties(base.getProperties());
- }
- }
-
- public boolean isPurgeOnStartup() {
- return purgeOnStartup;
- }
-
- public boolean isFetchPersistentState() {
- return fetchPersistentState;
- }
-
- public void setFetchPersistentState(boolean fetchPersistentState) {
- testImmutability("fetchPersistentState");
- this.fetchPersistentState = fetchPersistentState;
- }
-
- public void setAsync(boolean async) {
- testImmutability("async");
- this.async = async;
- }
-
- public boolean isAsync() {
- return async;
- }
-
- public void setIgnoreModifications(boolean ignoreModifications) {
- testImmutability("ignoreModifications");
- this.ignoreModifications = ignoreModifications;
- }
-
- public boolean isIgnoreModifications() {
- return ignoreModifications;
- }
-
- public void setPurgeOnStartup(boolean purgeOnStartup) {
- testImmutability("purgeOnStartup");
- this.purgeOnStartup = purgeOnStartup;
- }
-
- public SingletonStoreConfig getSingletonStoreConfig() {
- return singletonStoreConfig;
- }
-
- public void setSingletonStoreConfig(SingletonStoreConfig singletonStoreConfig) {
- testImmutability("singletonStoreConfig");
- this.singletonStoreConfig = singletonStoreConfig;
- }
-
- /**
- * Provides the ability to get and set a running cache loader, which, if exists, will be used rather than
- * constructing a new one. Primarily to facilitate testing with mock objects.
- *
- * @return cache loader, if one exists
- * @since 1.0
- */
- public CacheLoaderOld<Object, Object> getCacheLoader() {
- return cacheLoader;
- }
-
- /**
- * Provides the ability to get and set a running cache loader, which, if exists, will be used rather than
- * constructing a new one. Primarily to facilitate testing with mock objects.
- *
- * @param cacheLoader cacheLoader to set
- * @since 1.0
- */
- public void setCacheLoader(CacheLoaderOld<Object, Object> cacheLoader) {
- this.cacheLoader = cacheLoader;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (super.equals(obj)) {
- IndividualCacheLoaderConfig i = (IndividualCacheLoaderConfig) obj;
- return equalsExcludingProperties(i);
- }
- return false;
- }
-
- protected boolean equalsExcludingProperties(Object obj) {
- if (!(obj instanceof IndividualCacheLoaderConfig))
- return false;
- IndividualCacheLoaderConfig other = (IndividualCacheLoaderConfig) obj;
-
- return Util.safeEquals(this.className, other.className)
- && (this.async == other.async)
- && (this.ignoreModifications == other.ignoreModifications)
- && (this.fetchPersistentState == other.fetchPersistentState)
- && Util.safeEquals(this.singletonStoreConfig, other.singletonStoreConfig);
-
- }
-
- @Override
- public int hashCode() {
- return 31 * hashCodeExcludingProperties() + (properties == null ? 0 : properties.hashCode());
- }
-
- protected int hashCodeExcludingProperties() {
- int result = 17;
- result = 31 * result + (className == null ? 0 : className.hashCode());
- result = 31 * result + (async ? 0 : 1);
- result = 31 * result + (ignoreModifications ? 0 : 1);
- result = 31 * result + (fetchPersistentState ? 0 : 1);
- result = 31 * result + (singletonStoreConfig == null ? 0 : singletonStoreConfig.hashCode());
- result = 31 * result + (purgeOnStartup ? 0 : 1);
- return result;
- }
-
- @Override
- public String toString() {
- return new StringBuilder().append("IndividualCacheLoaderConfig{").append("className='").append(className).append('\'')
- .append(", async=").append(async)
- .append(", ignoreModifications=").append(ignoreModifications)
- .append(", fetchPersistentState=").append(fetchPersistentState)
- .append(", properties=").append(properties)
- .append(", purgeOnStartup=").append(purgeOnStartup).append("},")
- .append("SingletonStoreConfig{").append(singletonStoreConfig).append('}')
- .toString();
- }
-
- @Override
- public IndividualCacheLoaderConfig clone() throws CloneNotSupportedException {
- IndividualCacheLoaderConfig clone = (IndividualCacheLoaderConfig) super.clone();
- if (singletonStoreConfig != null)
- clone.setSingletonStoreConfig(singletonStoreConfig.clone());
- clone.cacheLoader = cacheLoader;
- return clone;
- }
-
- /**
- * Configuration for a SingletonStoreCacheLoader
- */
- public static class SingletonStoreConfig extends PluggableConfigurationComponent {
- private static final long serialVersionUID = 824251894176131850L;
-
- /**
- * Indicates whether the singleton store functionality is enabled or not.
- */
- private boolean singletonStoreEnabled;
-
- public SingletonStoreConfig() {
- // default value
- className = SingletonStoreCacheLoaderOld.class.getName();
- }
-
- public boolean isSingletonStoreEnabled() {
- return singletonStoreEnabled;
- }
-
- public void setSingletonStoreEnabled(boolean singletonStoreEnabled) {
- testImmutability("singletonStoreEnabled");
- this.singletonStoreEnabled = singletonStoreEnabled;
- }
-
- public String getSingletonStoreClass() {
- return className;
- }
-
- public void setSingletonStoreClass(String className) {
- setClassName(className);
- }
-
- public Properties getSingletonStoreProperties() {
- return properties;
- }
-
- public void setSingletonStoreProperties(Properties properties) {
- setProperties(properties);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
-
- if (super.equals(obj)) {
- SingletonStoreConfig other = (SingletonStoreConfig) obj;
- return this.singletonStoreEnabled == other.singletonStoreEnabled;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int result = 19;
- result = 41 * result + super.hashCode();
- result = 41 * result + (singletonStoreEnabled ? 0 : 1);
- return result;
- }
-
- @Override
- public String toString() {
- return super.toString() + " enabled=" + singletonStoreEnabled +
- " class=" + className +
- " properties=" + properties;
- }
-
- @Override
- public SingletonStoreConfig clone() throws CloneNotSupportedException {
- return (SingletonStoreConfig) super.clone();
- }
- }
- }
-}
Copied: core/branches/flat/src/main/java/org/horizon/config/CacheLoaderManagerConfig.java (from rev 7675, core/branches/flat/src/main/java/org/horizon/config/CacheLoaderConfig.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/CacheLoaderManagerConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/config/CacheLoaderManagerConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,151 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.horizon.config;
+
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.util.Util;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Holds the configuration of the cache loader chain. ALL cache loaders should be defined using this class, adding
+ * individual cache loaders to the chain by calling {@link CacheLoaderManagerConfig#addIndividualCacheLoaderConfig}
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @author Brian Stansberry
+ * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
+ * @since 1.0
+ */
+public class CacheLoaderManagerConfig extends AbstractNamedCacheConfigurationBean {
+ private static final long serialVersionUID = 2210349340378984424L;
+
+ private boolean passivation;
+ private boolean preload;
+ private List<CacheLoaderConfig> cacheLoaderConfigs = new LinkedList<CacheLoaderConfig>();
+
+ private boolean shared;
+
+ public void setPreload(boolean preload) {
+ testImmutability("preload");
+ this.preload = preload;
+ }
+
+ public void setPassivation(boolean passivation) {
+ testImmutability("passivation");
+ this.passivation = passivation;
+ }
+
+ public boolean isPassivation() {
+ return passivation;
+ }
+
+ public void addIndividualCacheLoaderConfig(CacheLoaderConfig clc) {
+ testImmutability("cacheLoaderConfigs");
+ cacheLoaderConfigs.add(clc);
+ }
+
+ public List<CacheLoaderConfig> getIndividualCacheLoaderConfigs() {
+ return cacheLoaderConfigs;
+ }
+
+ public void setIndividualCacheLoaderConfigs(List<CacheLoaderConfig> configs) {
+ testImmutability("cacheLoaderConfigs");
+ this.cacheLoaderConfigs = configs == null ? new LinkedList<CacheLoaderConfig>() : configs;
+ }
+
+ public CacheLoaderConfig getFirstCacheLoaderConfig() {
+ if (cacheLoaderConfigs.size() == 0) return null;
+ return cacheLoaderConfigs.get(0);
+ }
+
+ public boolean useChainingCacheLoader() {
+ return !isPassivation() && cacheLoaderConfigs.size() > 1;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder().append("CacheLoaderManagerConfig{").append("shared=").append(shared).append(", passivation=").append(passivation).append(", preload='").append(preload).append('\'').append(", cacheLoaderConfigs.size()=").append(cacheLoaderConfigs.size()).append('}').toString();
+ }
+
+ public void setShared(boolean shared) {
+ testImmutability("shared");
+ this.shared = shared;
+ }
+
+ public boolean isShared() {
+ return shared;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+
+ if (obj instanceof CacheLoaderManagerConfig) {
+ CacheLoaderManagerConfig other = (CacheLoaderManagerConfig) obj;
+ return (this.passivation == other.passivation)
+ && (this.shared == other.shared)
+ && Util.safeEquals(this.preload, other.preload)
+ && Util.safeEquals(this.cacheLoaderConfigs, other.cacheLoaderConfigs);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 19;
+ result = 51 * result + (passivation ? 0 : 1);
+ result = 51 * result + (shared ? 0 : 1);
+ result = 51 * result + (preload ? 0 : 1);
+ result = 51 * result + (cacheLoaderConfigs == null ? 0 : cacheLoaderConfigs.hashCode());
+ return result;
+ }
+
+
+ @Override
+ public CacheLoaderManagerConfig clone() throws CloneNotSupportedException {
+ CacheLoaderManagerConfig clone = (CacheLoaderManagerConfig) super.clone();
+ if (cacheLoaderConfigs != null) {
+ List<CacheLoaderConfig> clcs = new LinkedList<CacheLoaderConfig>();
+ for (CacheLoaderConfig clc : cacheLoaderConfigs) {
+ clcs.add(clc.clone());
+ }
+ clone.setIndividualCacheLoaderConfigs(clcs);
+ }
+ return clone;
+ }
+
+ /**
+ * Loops through all individual cache loader configs and checks if fetchPersistentState is set on any of them
+ */
+ public boolean isFetchPersistentState() {
+ for (CacheLoaderConfig iclc : cacheLoaderConfigs) {
+ if (iclc.isFetchPersistentState()) return true;
+ }
+ return false;
+ }
+
+ public boolean isPreload() {
+ return preload;
+ }
+}
Property changes on: core/branches/flat/src/main/java/org/horizon/config/CacheLoaderManagerConfig.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: core/branches/flat/src/main/java/org/horizon/config/Configuration.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/Configuration.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/Configuration.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -120,7 +120,7 @@
private IsolationLevel isolationLevel = IsolationLevel.READ_COMMITTED;
private EvictionConfig evictionConfig = null;
private String transactionManagerLookupClass = null;
- private CacheLoaderConfig cacheLoaderConfig = null;
+ private CacheLoaderManagerConfig cacheLoaderConfig = null;
@Dynamic
private boolean syncCommitPhase = false;
@Dynamic
@@ -260,7 +260,7 @@
this.transactionManagerLookupClass = transactionManagerLookupClass;
}
- public void setCacheLoaderConfig(CacheLoaderConfig config) {
+ public void setCacheLoaderConfig(CacheLoaderManagerConfig config) {
testImmutability("cacheLoaderConfig");
this.cacheLoaderConfig = config;
}
@@ -367,7 +367,7 @@
return transactionManagerLookupClass;
}
- public CacheLoaderConfig getCacheLoaderConfig() {
+ public CacheLoaderManagerConfig getCacheLoaderConfig() {
return cacheLoaderConfig;
}
Deleted: core/branches/flat/src/main/java/org/horizon/config/EvictionAlgorithmConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/EvictionAlgorithmConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/EvictionAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,61 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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 software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.config;
-
-/**
- * An interface used to configure an eviction algorithm. Replaces the deprecated {@link EvictionCacheConfig}.
- * <p/>
- * In its most basic form, it is implemented by {@link org.horizon.eviction.EvictionAlgorithmConfigBase}, but more
- * specific eviction policies may subclass {@link org.horizon.eviction.EvictionAlgorithmConfigBase} or re-implement this
- * interface to provide access to more config variables.
- *
- * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
- * @since 1.0
- */
-public interface EvictionAlgorithmConfig extends CloneableConfigurationComponent {
- /**
- * Gets the class name of the {@link org.horizon.eviction.EvictionAlgorithm} implementation this object will
- * configure.
- *
- * @return fully qualified class name
- */
- String getEvictionAlgorithmClassName();
-
- /**
- * Validate the configuration. Will be called after any configuration properties are set.
- *
- * @throws ConfigurationException if any values for the configuration properties are invalid
- */
- void validate() throws ConfigurationException;
-
- /**
- * Resets the values to their defaults.
- */
- void reset();
-
- /**
- * @return a clone of the EvictionAlgorithmConfig.
- */
- EvictionAlgorithmConfig clone();
-
-
-}
Modified: core/branches/flat/src/main/java/org/horizon/config/EvictionConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/EvictionConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/EvictionConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,6 +22,7 @@
package org.horizon.config;
import org.horizon.eviction.DefaultEvictionAction;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import java.util.concurrent.TimeUnit;
Modified: core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigHelper.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigHelper.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigHelper.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -291,6 +291,10 @@
return properties;
}
+ public static Properties readPropertiesContents(Element element) {
+ return readPropertiesContents(element, "properties");
+ }
+
/**
* Similar to {@link #readStringContents(org.w3c.dom.Element,String)} except that it returns a boolean.
*
Modified: core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,16 +1,16 @@
package org.horizon.config.parsing;
-import org.horizon.config.CacheLoaderConfig;
+import org.horizon.config.CacheLoaderManagerConfig;
import org.horizon.config.Configuration;
import org.horizon.config.ConfigurationException;
import org.horizon.config.CustomInterceptorConfig;
import org.horizon.config.DuplicateCacheNameException;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.config.EvictionConfig;
import org.horizon.config.GlobalConfiguration;
import org.horizon.config.parsing.element.CustomInterceptorsElementParser;
import org.horizon.config.parsing.element.LoadersElementParser;
import org.horizon.eviction.EvictionAlgorithm;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.lock.IsolationLevel;
import org.horizon.transaction.GenericTransactionManagerLookup;
import org.horizon.util.FileLookup;
@@ -241,7 +241,7 @@
void configureCacheLoaders(Element element, Configuration config) {
if (element == null) return; //null cache loaders are allowed
LoadersElementParser clElementParser = new LoadersElementParser();
- CacheLoaderConfig cacheLoaderConfig = clElementParser.parseLoadersElement(element);
+ CacheLoaderManagerConfig cacheLoaderConfig = clElementParser.parseLoadersElement(element);
config.setCacheLoaderConfig(cacheLoaderConfig);
}
Modified: core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/config/parsing/element/LoadersElementParser.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -21,15 +21,17 @@
*/
package org.horizon.config.parsing.element;
-import org.horizon.config.CacheLoaderConfig;
+import org.horizon.config.CacheLoaderManagerConfig;
import org.horizon.config.ConfigurationException;
import org.horizon.config.parsing.XmlConfigHelper;
import org.horizon.config.parsing.XmlParserBase;
+import org.horizon.loader.CacheLoader;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.decorators.SingletonStoreConfig;
+import org.horizon.util.Util;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
-import java.util.Properties;
-
/**
* Utility class for parsing the 'loaders' element in the .xml configuration file.
* <pre>
@@ -41,8 +43,8 @@
* @since 1.0
*/
public class LoadersElementParser extends XmlParserBase {
- public CacheLoaderConfig parseLoadersElement(Element element) {
- CacheLoaderConfig cacheLoaderConfig = new CacheLoaderConfig();
+ public CacheLoaderManagerConfig parseLoadersElement(Element element) {
+ CacheLoaderManagerConfig cacheLoaderConfig = new CacheLoaderManagerConfig();
String passivation = getAttributeValue(element, "passivation");
if (existsAttribute(passivation)) cacheLoaderConfig.setPassivation(getBoolean(passivation));
String shared = getAttributeValue(element, "shared");
@@ -53,45 +55,55 @@
NodeList cacheLoaderNodes = element.getElementsByTagName("loader");
for (int i = 0; i < cacheLoaderNodes.getLength(); i++) {
Element indivElement = (Element) cacheLoaderNodes.item(i);
- CacheLoaderConfig.IndividualCacheLoaderConfig iclc = parseIndividualCacheLoaderConfig(indivElement);
+ CacheLoaderConfig iclc = parseIndividualCacheLoaderConfig(indivElement);
cacheLoaderConfig.addIndividualCacheLoaderConfig(iclc);
}
return cacheLoaderConfig;
}
- private CacheLoaderConfig.IndividualCacheLoaderConfig parseIndividualCacheLoaderConfig(Element indivElement) {
- CacheLoaderConfig.IndividualCacheLoaderConfig iclc = new CacheLoaderConfig.IndividualCacheLoaderConfig();
+ private CacheLoaderConfig parseIndividualCacheLoaderConfig(Element indivElement) {
+ String clClass = getAttributeValue(indivElement, "class");
+ if (!existsAttribute(clClass))
+ throw new ConfigurationException("Missing 'class' attribute for cache loader configuration");
+ CacheLoader cl;
+ CacheLoaderConfig clc;
+ try {
+ cl = (CacheLoader) Util.getInstance(clClass);
+ clc = (CacheLoaderConfig) Util.getInstance(cl.getConfigurationClass());
+ } catch (Exception e) {
+ throw new ConfigurationException("Unable to instantiate cache loader or configuration", e);
+ }
String async = getAttributeValue(indivElement, "async");
- if (existsAttribute(async)) iclc.setAsync(getBoolean(async));
+ if (existsAttribute(async)) clc.setAsync(getBoolean(async));
String fetchPersistentState = getAttributeValue(indivElement, "fetchPersistentState");
- if (existsAttribute(fetchPersistentState)) iclc.setFetchPersistentState(getBoolean(fetchPersistentState));
+ if (existsAttribute(fetchPersistentState)) clc.setFetchPersistentState(getBoolean(fetchPersistentState));
String ignoreModifications = getAttributeValue(indivElement, "ignoreModifications");
- if (existsAttribute(ignoreModifications)) iclc.setIgnoreModifications(getBoolean(ignoreModifications));
+ if (existsAttribute(ignoreModifications)) clc.setIgnoreModifications(getBoolean(ignoreModifications));
String purgeOnStartup = getAttributeValue(indivElement, "purgeOnStartup");
- if (existsAttribute(purgeOnStartup)) iclc.setPurgeOnStartup(getBoolean(purgeOnStartup));
- String clClass = getAttributeValue(indivElement, "class");
- if (!existsAttribute(clClass))
- throw new ConfigurationException("Missing 'class' attribute for cache loader configuration");
- iclc.setClassName(clClass);
- iclc.setProperties(XmlConfigHelper.readPropertiesContents(indivElement, "properties"));
- CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig ssc = parseSingletonStoreConfig(getSingleElementInCoreNS("singletonStore", indivElement));
- if (ssc != null) {
- iclc.setSingletonStoreConfig(ssc);
- }
- return iclc;
+ if (existsAttribute(purgeOnStartup)) clc.setPurgeOnStartup(getBoolean(purgeOnStartup));
+
+ clc.setClassName(clClass);
+ XmlConfigHelper.setValues(clc, XmlConfigHelper.readPropertiesContents(indivElement), false, true);
+ SingletonStoreConfig ssc = parseSingletonStoreConfig(getSingleElementInCoreNS("singletonStore", indivElement));
+ if (ssc != null) clc.setSingletonStoreConfig(ssc);
+ return clc;
}
- public CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig parseSingletonStoreConfig(Element element) {
- if (element == null) return null; //might happen, this config option is not mandatory
- boolean singletonStoreEnabled = getBoolean(getAttributeValue(element, "enabled"));
- String singletonStoreClass = getAttributeValue(element, "class");
- CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig ssc = new CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig();
- if (existsAttribute(singletonStoreClass)) ssc.setSingletonStoreClass(singletonStoreClass);
- Properties singletonStoreproperties = XmlConfigHelper.readPropertiesContents(element, "properties");
- ssc.setSingletonStoreEnabled(singletonStoreEnabled);
- ssc.setSingletonStoreClass(singletonStoreClass);
- ssc.setSingletonStoreProperties(singletonStoreproperties);
+ public SingletonStoreConfig parseSingletonStoreConfig(Element element) {
+ SingletonStoreConfig ssc = new SingletonStoreConfig();
+ if (element == null) {
+ ssc.setSingletonStoreEnabled(false);
+ } else {
+ boolean singletonStoreEnabled = getBoolean(getAttributeValue(element, "enabled"));
+ ssc.setSingletonStoreEnabled(singletonStoreEnabled);
+
+ String tmp = getAttributeValue(element, "pushStateWhenCoordinator");
+ if (existsAttribute(tmp)) ssc.setPushStateWhenCoordinator(getBoolean(tmp));
+
+ tmp = getAttributeValue(element, "pushStateTimeout");
+ if (existsAttribute(tmp)) ssc.setPushStateTimeout(getLong(tmp));
+ }
return ssc;
}
}
Deleted: core/branches/flat/src/main/java/org/horizon/container/CachedEntry.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/CachedEntry.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/container/CachedEntry.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,9 +0,0 @@
-package org.horizon.container;
-
-/**
- * This is a wrapper for a cached entry, containing a reference to key, value and metadata.
- *
- * @author Manik Surtani
- * @since 1.0
- */
-
Added: core/branches/flat/src/main/java/org/horizon/container/CachedValue.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/CachedValue.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/container/CachedValue.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,30 @@
+package org.horizon.container;
+
+public class CachedValue<V> {
+ protected V value;
+ protected long modifiedTime;
+
+ protected CachedValue() {
+ }
+
+ public CachedValue(V value) {
+ this.value = value;
+ touch();
+ }
+
+ public final void touch() {
+ modifiedTime = System.currentTimeMillis();
+ }
+
+ public final long getModifiedTime() {
+ return modifiedTime;
+ }
+
+ public final V getValue() {
+ return value;
+ }
+
+ public final void setValue(V value) {
+ this.value = value;
+ }
+}
\ No newline at end of file
Modified: core/branches/flat/src/main/java/org/horizon/container/DataContainer.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/DataContainer.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/container/DataContainer.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -23,6 +23,7 @@
import org.horizon.factories.scopes.Scope;
import org.horizon.factories.scopes.Scopes;
+import org.horizon.loader.StoredEntry;
import java.util.Set;
@@ -56,4 +57,6 @@
* @return set of keys that have been purged.
*/
Set<K> purgeExpiredEntries();
+
+ StoredEntry<K, V> createEntryForStorage(K key);
}
Added: core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/container/ExpirableCachedValue.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,37 @@
+package org.horizon.container;
+
+public class ExpirableCachedValue<V> extends CachedValue<V> {
+ protected long createdTime;
+ protected long expiryTime;
+
+ protected ExpirableCachedValue() {
+ }
+
+ public ExpirableCachedValue(V value, long createdTime, long expiryTime) {
+ super(value);
+ this.createdTime = createdTime;
+ this.expiryTime = expiryTime;
+ }
+
+ public ExpirableCachedValue(V value, long lifespan) {
+ super(value);
+ createdTime = getModifiedTime();
+ setLifespan(lifespan);
+ }
+
+ public final boolean isExpired() {
+ return expiryTime >= 0 && System.currentTimeMillis() > expiryTime;
+ }
+
+ public final long getCreatedTime() {
+ return createdTime;
+ }
+
+ public final long getExpiryTime() {
+ return expiryTime;
+ }
+
+ public final void setLifespan(long lifespan) {
+ expiryTime = lifespan < 0 ? -1 : lifespan + createdTime;
+ }
+}
\ No newline at end of file
Modified: core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/container/UnsortedDataContainer.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,8 +22,9 @@
package org.horizon.container;
import org.horizon.factories.annotations.Inject;
-import org.horizon.loaderold.CacheLoaderManager;
-import org.horizon.loaderold.CacheLoaderOld;
+import org.horizon.loader.CacheLoaderManager;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
import java.util.AbstractSet;
import java.util.ArrayList;
@@ -48,7 +49,7 @@
final ConcurrentMap<K, ExpirableCachedValue<V>> expirableData = new ConcurrentHashMap<K, ExpirableCachedValue<V>>();
private static final Object NULL = new Object();
private CacheLoaderManager clm;
- private CacheLoaderOld cacheLoader;
+ private CacheStore cacheStore;
@Inject
public void injectDependencies(CacheLoaderManager clm) {
@@ -61,9 +62,9 @@
}
private void expireOnCacheLoader(K key) {
- if (cacheLoader == null && clm != null) cacheLoader = clm.getCacheLoader();
- if (cacheLoader != null) {
- cacheLoader.remove(key);
+ if (cacheStore == null && clm != null) cacheStore = clm.getCacheStore();
+ if (cacheStore != null) {
+ cacheStore.remove(key);
}
}
@@ -82,15 +83,15 @@
CachedValue<V> cv = immortalData.get(maskedKey);
if (cv != null) {
cv.touch();
- return cv.value;
+ return cv.getValue();
} else {
ExpirableCachedValue<V> ecv = expirableData.get(maskedKey);
if (ecv != null) {
- if (ecv.expired()) {
+ if (ecv.isExpired()) {
expire(maskedKey);
} else {
ecv.touch();
- return ecv.value;
+ return ecv.getValue();
}
}
}
@@ -107,7 +108,7 @@
// do we need to move this to expirable?
if (lifespan < 0) {
// no.
- cv.value = v;
+ cv.setValue(v);
cv.touch();
} else {
ecv = new ExpirableCachedValue<V>(v, lifespan);
@@ -122,7 +123,7 @@
expirableData.remove(maskedKey);
immortalData.put(maskedKey, cv);
} else {
- ecv.value = v;
+ ecv.setValue(v);
ecv.touch();
}
} else {
@@ -142,7 +143,7 @@
if (!immortalData.containsKey(maskedKey)) {
ExpirableCachedValue<V> ecv = expirableData.get(maskedKey);
if (ecv == null) return false;
- if (ecv.expired()) {
+ if (ecv.isExpired()) {
expire(maskedKey);
return false;
}
@@ -152,9 +153,9 @@
public long getModifiedTimestamp(K key) {
K maskedKey = maskNullKey(key);
- CachedValue cv = immortalData.get(maskedKey);
+ CachedValue<V> cv = immortalData.get(maskedKey);
if (cv == null) cv = expirableData.get(maskedKey);
- return cv == null ? -1 : cv.modified;
+ return cv == null ? -1 : cv.getModifiedTime();
}
@SuppressWarnings("unchecked")
@@ -166,7 +167,7 @@
if (cv == null) {
return null;
} else {
- return cv.value;
+ return cv.getValue();
}
}
@@ -191,8 +192,8 @@
Set<K> purged = new HashSet<K>();
for (Iterator<Map.Entry<K, ExpirableCachedValue<V>>> iter = expirableData.entrySet().iterator(); iter.hasNext();) {
Map.Entry<K, ExpirableCachedValue<V>> entry = iter.next();
- ExpirableCachedValue<?> cv = entry.getValue();
- if (cv.expired()) {
+ ExpirableCachedValue<V> cv = entry.getValue();
+ if (cv.isExpired()) {
expireOnCacheLoader(entry.getKey());
purged.add(entry.getKey());
iter.remove();
@@ -201,6 +202,15 @@
return purged;
}
+ public StoredEntry<K, V> createEntryForStorage(K key) {
+ CachedValue<V> immortal = immortalData.get(key);
+ if (immortal != null)
+ return new StoredEntry<K, V>(key, immortal.getValue(), -1, -1);
+ ExpirableCachedValue<V> ecv = expirableData.get(key);
+ if (ecv == null) return null;
+ return new StoredEntry<K, V>(key, ecv.getValue(), ecv.getCreatedTime(), ecv.getExpiryTime());
+ }
+
private class KeySet extends AbstractSet<K> {
Set<K> immortalKeys;
Set<K> expirableKeys;
@@ -265,37 +275,4 @@
throw new UnsupportedOperationException();
}
}
-
- private static class CachedValue<V> {
- V value;
- long modified;
-
- private CachedValue(V value) {
- this.value = value;
- modified = System.currentTimeMillis();
- }
-
- void touch() {
- modified = System.currentTimeMillis();
- }
- }
-
- private static class ExpirableCachedValue<V> extends CachedValue<V> {
- long created;
- long expiryTime;
-
- private ExpirableCachedValue(V value, long lifespan) {
- super(value);
- created = modified;
- setLifespan(lifespan);
- }
-
- private boolean expired() {
- return expiryTime >= 0 && System.currentTimeMillis() > expiryTime;
- }
-
- private void setLifespan(long lifespan) {
- expiryTime = lifespan < 0 ? -1 : lifespan + created;
- }
- }
}
\ No newline at end of file
Modified: core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,7 +22,6 @@
package org.horizon.eviction;
import org.horizon.Cache;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.container.DataContainer;
import org.horizon.eviction.events.EvictionEvent;
import org.horizon.eviction.events.EvictionEvent.Type;
@@ -82,8 +81,8 @@
boolean canIgnoreEvent(Type eventType);
/**
- * @return the type of the {@link org.horizon.config.EvictionAlgorithmConfig} bean used to configure this
- * implementation of {@link org.horizon.eviction.EvictionAlgorithm}
+ * @return the type of the {@link EvictionAlgorithmConfig} bean used to configure this implementation of {@link
+ * org.horizon.eviction.EvictionAlgorithm}
*/
Class<? extends EvictionAlgorithmConfig> getConfigurationClass();
}
Copied: core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfig.java (from rev 7673, core/branches/flat/src/main/java/org/horizon/config/EvictionAlgorithmConfig.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.horizon.eviction;
+
+import org.horizon.config.CloneableConfigurationComponent;
+import org.horizon.config.ConfigurationException;
+
+/**
+ * An interface used to configure an eviction algorithm. Replaces the deprecated {@link EvictionCacheConfig}.
+ * <p/>
+ * In its most basic form, it is implemented by {@link org.horizon.eviction.algorithms.BaseEvictionAlgorithmConfig}, but
+ * more specific eviction policies may subclass {@link org.horizon.eviction.algorithms.BaseEvictionAlgorithmConfig} or
+ * re-implement this interface to provide access to more config variables.
+ *
+ * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @since 1.0
+ */
+public interface EvictionAlgorithmConfig extends CloneableConfigurationComponent {
+ /**
+ * Gets the class name of the {@link org.horizon.eviction.EvictionAlgorithm} implementation this object will
+ * configure.
+ *
+ * @return fully qualified class name
+ */
+ String getEvictionAlgorithmClassName();
+
+ /**
+ * Validate the configuration. Will be called after any configuration properties are set.
+ *
+ * @throws org.horizon.config.ConfigurationException
+ * if any values for the configuration properties are invalid
+ */
+ void validate() throws ConfigurationException;
+
+ /**
+ * Resets the values to their defaults.
+ */
+ void reset();
+
+ /**
+ * @return a clone of the EvictionAlgorithmConfig.
+ */
+ EvictionAlgorithmConfig clone();
+}
Property changes on: core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfig.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfigBase.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfigBase.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfigBase.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,163 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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 software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.eviction;
-
-import org.horizon.config.AbstractNamedCacheConfigurationBean;
-import org.horizon.config.ConfigurationException;
-import org.horizon.config.Dynamic;
-import org.horizon.config.EvictionAlgorithmConfig;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * A base class used for configuring eviction algorithms.
- *
- * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
- * @since 1.0
- */
-public abstract class EvictionAlgorithmConfigBase extends AbstractNamedCacheConfigurationBean implements EvictionAlgorithmConfig {
- private static final long serialVersionUID = 4591691674370188932L;
-
- protected String evictionAlgorithmClassName;
- @Dynamic
- protected int maxEntries = -1;
- @Dynamic
- protected int minEntries = -1;
- @Dynamic
- protected long minTimeToLive = -1;
-
- /**
- * Can only be instantiated by a subclass.
- */
- protected EvictionAlgorithmConfigBase() {
- }
-
- public String getEvictionAlgorithmClassName() {
- return evictionAlgorithmClassName;
- }
-
- public int getMaxEntries() {
- return maxEntries;
- }
-
- /**
- * @param maxEntries max entries to hold in the cache. 0 denotes immediate expiry and -1 denotes unlimited entries.
- * -1 is the default
- */
- public void setMaxEntries(int maxEntries) {
- testImmutability("maxEntries");
- this.maxEntries = maxEntries;
- }
-
- public int getMinEntries() {
- return minEntries;
- }
-
- /**
- * This specifies the minimum entries to prune down to when maxExtries has been hit. -1 is the default value, which
- * means this feature is effectively unset, and eviction algorithms would be expected to evict until the cache
- * contains no more than maxEntries. Any other value means that if a pruning process starts, it will not stop until
- * minEntries has been reached. So, for example, minEntries of 0 would mean that the cache is emptied the moment
- * maxEntries is exceeded.
- *
- * @param minEntries minEntries value
- */
- public void setMinEntries(int minEntries) {
- testImmutability("minEntries");
- this.minEntries = minEntries;
- }
-
- /**
- * @return The minimum time to live, in milliseconds.
- */
- public long getMinTimeToLive() {
- return minTimeToLive;
- }
-
- /**
- * @param minTimeToLive time to live, in milliseconds. This defaults to -1, meaning that it is excluded from
- * calculations.
- */
- public void setMinTimeToLive(long minTimeToLive) {
- testImmutability("minTimeToLive");
- this.minTimeToLive = minTimeToLive;
- }
-
- public void setMinTimeToLive(long time, TimeUnit timeUnit) {
- testImmutability("minTimeToLive");
- minTimeToLive = timeUnit.toMillis(time);
- }
-
- public void validate() throws ConfigurationException {
- if (evictionAlgorithmClassName == null)
- throw new ConfigurationException("Eviction algorithm class name cannot be null!");
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- EvictionAlgorithmConfigBase that = (EvictionAlgorithmConfigBase) o;
-
- if (maxEntries != that.maxEntries) return false;
- if (minEntries != that.minEntries) return false;
- if (minTimeToLive != that.minTimeToLive) return false;
- if (evictionAlgorithmClassName != null ? !evictionAlgorithmClassName.equals(that.evictionAlgorithmClassName) : that.evictionAlgorithmClassName != null)
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = evictionAlgorithmClassName != null ? evictionAlgorithmClassName.hashCode() : 0;
- result = 31 * result + maxEntries;
- result = 31 * result + minEntries;
- result = 31 * result + (int) (minTimeToLive ^ (minTimeToLive >>> 32));
- return result;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{" +
- "evictionAlgorithmClassName='" + evictionAlgorithmClassName + '\'' +
- ", maxEntries=" + maxEntries +
- ", minEntries=" + minEntries +
- ", minTimeToLive=" + minTimeToLive +
- '}';
- }
-
- public void reset() {
- maxEntries = -1;
- minEntries = -1;
- minTimeToLive = -1;
- }
-
- public EvictionAlgorithmConfigBase clone() {
- try {
- return (EvictionAlgorithmConfigBase) super.clone();
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException("Should never happen", e);
- }
- }
-}
Modified: core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/EvictionManagerImpl.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -3,7 +3,6 @@
import net.jcip.annotations.ThreadSafe;
import org.horizon.Cache;
import org.horizon.config.Configuration;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.config.EvictionConfig;
import org.horizon.container.DataContainer;
import org.horizon.eviction.events.EvictionEvent;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,11 +22,10 @@
package org.horizon.eviction.algorithms;
import org.horizon.Cache;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.container.DataContainer;
import org.horizon.eviction.EvictionAction;
import org.horizon.eviction.EvictionAlgorithm;
-import org.horizon.eviction.EvictionAlgorithmConfigBase;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.EvictionException;
import org.horizon.eviction.EvictionQueue;
import org.horizon.eviction.events.EvictionEvent;
@@ -57,7 +56,7 @@
private static final boolean trace = log.isTraceEnabled();
protected EvictionAction action;
- protected EvictionAlgorithmConfigBase config;
+ protected BaseEvictionAlgorithmConfig config;
// blocking queue of cache keys
protected BlockingQueue<Object> recycleQueue;
protected EvictionQueue evictionQueue;
@@ -120,7 +119,7 @@
public void init(Cache<?, ?> cache, DataContainer<?, ?> dataContainer, EvictionAlgorithmConfig evictionAlgorithmConfig) {
this.cache = cache;
this.dataContainer = dataContainer;
- this.config = (EvictionAlgorithmConfigBase) evictionAlgorithmConfig;
+ this.config = (BaseEvictionAlgorithmConfig) evictionAlgorithmConfig;
}
public boolean canIgnoreEvent(Type eventType) {
Copied: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithmConfig.java (from rev 7673, core/branches/flat/src/main/java/org/horizon/eviction/EvictionAlgorithmConfigBase.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithmConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,163 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.horizon.eviction.algorithms;
+
+import org.horizon.config.AbstractNamedCacheConfigurationBean;
+import org.horizon.config.ConfigurationException;
+import org.horizon.config.Dynamic;
+import org.horizon.eviction.EvictionAlgorithmConfig;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A base class used for configuring eviction algorithms.
+ *
+ * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @since 1.0
+ */
+public abstract class BaseEvictionAlgorithmConfig extends AbstractNamedCacheConfigurationBean implements EvictionAlgorithmConfig {
+ private static final long serialVersionUID = 4591691674370188932L;
+
+ protected String evictionAlgorithmClassName;
+ @Dynamic
+ protected int maxEntries = -1;
+ @Dynamic
+ protected int minEntries = -1;
+ @Dynamic
+ protected long minTimeToLive = -1;
+
+ /**
+ * Can only be instantiated by a subclass.
+ */
+ protected BaseEvictionAlgorithmConfig() {
+ }
+
+ public String getEvictionAlgorithmClassName() {
+ return evictionAlgorithmClassName;
+ }
+
+ public int getMaxEntries() {
+ return maxEntries;
+ }
+
+ /**
+ * @param maxEntries max entries to hold in the cache. 0 denotes immediate expiry and -1 denotes unlimited entries.
+ * -1 is the default
+ */
+ public void setMaxEntries(int maxEntries) {
+ testImmutability("maxEntries");
+ this.maxEntries = maxEntries;
+ }
+
+ public int getMinEntries() {
+ return minEntries;
+ }
+
+ /**
+ * This specifies the minimum entries to prune down to when maxExtries has been hit. -1 is the default value, which
+ * means this feature is effectively unset, and eviction algorithms would be expected to evict until the cache
+ * contains no more than maxEntries. Any other value means that if a pruning process starts, it will not stop until
+ * minEntries has been reached. So, for example, minEntries of 0 would mean that the cache is emptied the moment
+ * maxEntries is exceeded.
+ *
+ * @param minEntries minEntries value
+ */
+ public void setMinEntries(int minEntries) {
+ testImmutability("minEntries");
+ this.minEntries = minEntries;
+ }
+
+ /**
+ * @return The minimum time to live, in milliseconds.
+ */
+ public long getMinTimeToLive() {
+ return minTimeToLive;
+ }
+
+ /**
+ * @param minTimeToLive time to live, in milliseconds. This defaults to -1, meaning that it is excluded from
+ * calculations.
+ */
+ public void setMinTimeToLive(long minTimeToLive) {
+ testImmutability("minTimeToLive");
+ this.minTimeToLive = minTimeToLive;
+ }
+
+ public void setMinTimeToLive(long time, TimeUnit timeUnit) {
+ testImmutability("minTimeToLive");
+ minTimeToLive = timeUnit.toMillis(time);
+ }
+
+ public void validate() throws ConfigurationException {
+ if (evictionAlgorithmClassName == null)
+ throw new ConfigurationException("Eviction algorithm class name cannot be null!");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ BaseEvictionAlgorithmConfig that = (BaseEvictionAlgorithmConfig) o;
+
+ if (maxEntries != that.maxEntries) return false;
+ if (minEntries != that.minEntries) return false;
+ if (minTimeToLive != that.minTimeToLive) return false;
+ if (evictionAlgorithmClassName != null ? !evictionAlgorithmClassName.equals(that.evictionAlgorithmClassName) : that.evictionAlgorithmClassName != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = evictionAlgorithmClassName != null ? evictionAlgorithmClassName.hashCode() : 0;
+ result = 31 * result + maxEntries;
+ result = 31 * result + minEntries;
+ result = 31 * result + (int) (minTimeToLive ^ (minTimeToLive >>> 32));
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" +
+ "evictionAlgorithmClassName='" + evictionAlgorithmClassName + '\'' +
+ ", maxEntries=" + maxEntries +
+ ", minEntries=" + minEntries +
+ ", minTimeToLive=" + minTimeToLive +
+ '}';
+ }
+
+ public void reset() {
+ maxEntries = -1;
+ minEntries = -1;
+ minTimeToLive = -1;
+ }
+
+ public BaseEvictionAlgorithmConfig clone() {
+ try {
+ return (BaseEvictionAlgorithmConfig) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Should never happen", e);
+ }
+ }
+}
Property changes on: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/BaseEvictionAlgorithmConfig.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,7 +22,7 @@
package org.horizon.eviction.algorithms.fifo;
import net.jcip.annotations.NotThreadSafe;
-import org.horizon.config.EvictionAlgorithmConfig;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.EvictionException;
import org.horizon.eviction.EvictionQueue;
import org.horizon.eviction.algorithms.BaseEvictionAlgorithm;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithmConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithmConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/fifo/FIFOAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -21,7 +21,7 @@
*/
package org.horizon.eviction.algorithms.fifo;
-import org.horizon.eviction.EvictionAlgorithmConfigBase;
+import org.horizon.eviction.algorithms.BaseEvictionAlgorithmConfig;
/**
* Configuration for {@link FIFOAlgorithm}.
@@ -29,7 +29,7 @@
* @author Manik Surtani
* @since 1.0
*/
-public class FIFOAlgorithmConfig extends EvictionAlgorithmConfigBase {
+public class FIFOAlgorithmConfig extends BaseEvictionAlgorithmConfig {
/**
* The serialVersionUID
*/
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,7 +22,7 @@
package org.horizon.eviction.algorithms.lfu;
import net.jcip.annotations.NotThreadSafe;
-import org.horizon.config.EvictionAlgorithmConfig;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.EvictionException;
import org.horizon.eviction.EvictionQueue;
import org.horizon.eviction.algorithms.BaseEvictionAlgorithm;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithmConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithmConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lfu/LFUAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -21,7 +21,7 @@
*/
package org.horizon.eviction.algorithms.lfu;
-import org.horizon.eviction.EvictionAlgorithmConfigBase;
+import org.horizon.eviction.algorithms.BaseEvictionAlgorithmConfig;
/**
* Configuration implementation for {@link LFUAlgorithm}.
@@ -29,7 +29,7 @@
* @author Manik Surtani
* @since 1.0
*/
-public class LFUAlgorithmConfig extends EvictionAlgorithmConfigBase {
+public class LFUAlgorithmConfig extends BaseEvictionAlgorithmConfig {
/**
* The serialVersionUID
*/
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,7 +22,7 @@
package org.horizon.eviction.algorithms.lru;
import net.jcip.annotations.NotThreadSafe;
-import org.horizon.config.EvictionAlgorithmConfig;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.EvictionException;
import org.horizon.eviction.EvictionQueue;
import org.horizon.eviction.algorithms.BaseEvictionAlgorithm;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithmConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithmConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/lru/LRUAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -21,7 +21,7 @@
*/
package org.horizon.eviction.algorithms.lru;
-import org.horizon.eviction.EvictionAlgorithmConfigBase;
+import org.horizon.eviction.algorithms.BaseEvictionAlgorithmConfig;
/**
* Configuration implementation for {@link LRUAlgorithm}.
@@ -30,7 +30,7 @@
* @author Manik Surtani
* @since 1.0
*/
-public class LRUAlgorithmConfig extends EvictionAlgorithmConfigBase {
+public class LRUAlgorithmConfig extends BaseEvictionAlgorithmConfig {
/**
* The serialVersionUID
*/
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,7 +22,7 @@
package org.horizon.eviction.algorithms.mru;
import net.jcip.annotations.NotThreadSafe;
-import org.horizon.config.EvictionAlgorithmConfig;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.EvictionException;
import org.horizon.eviction.EvictionQueue;
import org.horizon.eviction.algorithms.BaseEvictionAlgorithm;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithmConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithmConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/mru/MRUAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -21,7 +21,7 @@
*/
package org.horizon.eviction.algorithms.mru;
-import org.horizon.eviction.EvictionAlgorithmConfigBase;
+import org.horizon.eviction.algorithms.BaseEvictionAlgorithmConfig;
/**
* Configuration for {@link MRUAlgorithm}.
@@ -29,7 +29,7 @@
* @author Manik Surtani
* @since 1.0
*/
-public class MRUAlgorithmConfig extends EvictionAlgorithmConfigBase {
+public class MRUAlgorithmConfig extends BaseEvictionAlgorithmConfig {
/**
* The serialVersionUID
*/
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithm.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -22,10 +22,10 @@
package org.horizon.eviction.algorithms.nullalgo;
import org.horizon.Cache;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.container.DataContainer;
import org.horizon.eviction.EvictionAction;
import org.horizon.eviction.EvictionAlgorithm;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.EvictionException;
import org.horizon.eviction.EvictionQueue;
import org.horizon.eviction.events.EvictionEvent;
Modified: core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithmConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithmConfig.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/eviction/algorithms/nullalgo/NullEvictionAlgorithmConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -23,7 +23,7 @@
import org.horizon.config.AbstractNamedCacheConfigurationBean;
import org.horizon.config.ConfigurationException;
-import org.horizon.config.EvictionAlgorithmConfig;
+import org.horizon.eviction.EvictionAlgorithmConfig;
/**
* Configuration class for {@link NullEvictionAlgorithm}.
Modified: core/branches/flat/src/main/java/org/horizon/factories/EmptyConstructorNamedCacheFactory.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/factories/EmptyConstructorNamedCacheFactory.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/factories/EmptyConstructorNamedCacheFactory.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -28,7 +28,7 @@
import org.horizon.factories.annotations.DefaultFactoryFor;
import org.horizon.factories.context.ContextFactory;
import org.horizon.invocation.InvocationContextContainer;
-import org.horizon.loaderold.CacheLoaderManager;
+import org.horizon.loader.CacheLoaderManager;
import org.horizon.marshall.Marshaller;
import org.horizon.marshall.VersionAwareMarshaller;
import org.horizon.notifications.cachelistener.CacheNotifier;
Modified: core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/interceptors/CacheLoaderInterceptor.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -35,8 +35,8 @@
import org.horizon.factories.annotations.Inject;
import org.horizon.factories.annotations.Start;
import org.horizon.interceptors.base.JmxStatsCommandInterceptor;
-import org.horizon.loaderold.CacheLoaderManager;
-import org.horizon.loaderold.CacheLoaderOld;
+import org.horizon.loader.CacheLoader;
+import org.horizon.loader.CacheLoaderManager;
import org.horizon.notifications.cachelistener.CacheNotifier;
import org.horizon.transaction.TransactionTable;
@@ -55,7 +55,7 @@
private CacheLoaderManager clm;
protected TransactionTable txTable = null;
- protected CacheLoaderOld<Object, Object> loader;
+ protected CacheLoader loader;
protected DataContainer<Object, Object> dataContainer;
protected CacheNotifier notifier;
protected EntryFactory entryFactory;
@@ -126,7 +126,7 @@
}
private void loadIfNeeded(InvocationContext ctx, Object key) throws Throwable {
- if (dataContainer.containsKey(key) || !loader.exists(key))
+ if (dataContainer.containsKey(key) || !loader.containsKey(key))
return;
// Obtain a temporary lock to verify the key is not being concurrently added
@@ -149,7 +149,7 @@
private MVCCEntry loadEntry(InvocationContext ctx, Object key, MVCCEntry entry) throws Exception {
if (trace) log.trace("loading entry " + key + " entry is " + entry);
- Object value = loader.get(key);
+ Object value = loader.load(key);
boolean nodeExists = (value != null);
if (trace) log.trace("nodeExists " + nodeExists);
Modified: core/branches/flat/src/main/java/org/horizon/interceptors/CacheStoreInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/interceptors/CacheStoreInterceptor.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/interceptors/CacheStoreInterceptor.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -30,7 +30,8 @@
import org.horizon.commands.write.PutKeyValueCommand;
import org.horizon.commands.write.PutMapCommand;
import org.horizon.commands.write.RemoveCommand;
-import org.horizon.config.CacheLoaderConfig;
+import org.horizon.config.CacheLoaderManagerConfig;
+import org.horizon.container.DataContainer;
import org.horizon.context.InvocationContext;
import org.horizon.context.TransactionContext;
import org.horizon.factories.annotations.Inject;
@@ -39,10 +40,13 @@
import org.horizon.invocation.Options;
import org.horizon.jmx.annotations.ManagedAttribute;
import org.horizon.jmx.annotations.ManagedOperation;
-import org.horizon.loaderold.CacheLoaderManager;
-import org.horizon.loaderold.CacheLoaderOld;
-import org.horizon.loaderold.Modification;
-import org.horizon.loaderold.Modification.ModificationType;
+import org.horizon.loader.CacheLoaderManager;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.loader.modifications.Clear;
+import org.horizon.loader.modifications.Modification;
+import org.horizon.loader.modifications.Remove;
+import org.horizon.loader.modifications.Store;
import org.horizon.logging.LogFactory;
import org.horizon.transaction.GlobalTransaction;
@@ -64,14 +68,15 @@
* @since 1.0
*/
public class CacheStoreInterceptor extends JmxStatsCommandInterceptor {
- private CacheLoaderConfig loaderConfig = null;
+ private CacheLoaderManagerConfig loaderConfig = null;
private TransactionManager txMgr = null;
private HashMap<GlobalTransaction, Integer> txStores = new HashMap<GlobalTransaction, Integer>();
private Map<GlobalTransaction, Set<Object>> preparingTxs = new ConcurrentHashMap<GlobalTransaction, Set<Object>>();
private long cacheStores = 0;
- CacheLoaderOld<Object, Object> loader;
+ CacheStore store;
private CacheLoaderManager loaderManager;
private boolean statsEnabled;
+ private DataContainer dataContainer;
public CacheStoreInterceptor() {
log = LogFactory.getLog(getClass());
@@ -79,17 +84,18 @@
}
@Inject
- protected void init(CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig) {
+ protected void init(CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderManagerConfig clConfig, DataContainer dataContainer) {
// never inject a CacheLoaderOld at this stage - only a CacheLoaderManager, since the CacheLoaderManager only creates a CacheLoaderOld instance when it @Starts.
this.loaderManager = loaderManager;
this.loaderConfig = clConfig;
txMgr = txManager;
+ this.dataContainer = dataContainer;
}
@Start
protected void start() {
// this should only happen after the CacheLoaderManager has started, since the CacheLoaderManager only creates the CacheLoaderOld instance in its @Start method.
- loader = loaderManager.getCacheLoader();
+ store = loaderManager.getCacheStore();
this.setStatisticsEnabled(configuration.isExposeManagementStatistics());
}
@@ -97,6 +103,7 @@
* if this is a shared cache loader and the call is of remote origin, pass up the chain
*/
public final boolean skip(InvocationContext ctx, VisitableCommand command) {
+ if (store == null) return true;
if ((!ctx.isOriginLocal() && loaderConfig.isShared()) || ctx.hasOption(Options.SKIP_CACHE_STORE)) {
if (trace)
log.trace("Passing up method call and bypassing this interceptor since the cache loader is shared and this call originated remotely.");
@@ -116,7 +123,7 @@
// ignore modified FQNs
// List fqnsModified = getFqnsFromModificationList(txTable.get(globalTransaction).getCacheLoaderModifications());
try {
- loader.commit(gtx);
+// store.commit(gtx);
}
catch (Throwable t) {
preparingTxs.remove(gtx);
@@ -146,7 +153,7 @@
// this is a rollback method
if (preparingTxs.containsKey(gtx)) {
preparingTxs.remove(gtx);
- loader.rollback(gtx);
+// store.rollback(gtx);
}
if (getStatisticsEnabled()) txStores.remove(gtx);
} else {
@@ -168,7 +175,7 @@
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
if (!skip(ctx, command) && !inTransaction()) {
- Object returnValue = loader.remove(command.getKey());
+ Object returnValue = store.remove(command.getKey());
invokeNextInterceptor(ctx, command);
return returnValue;
}
@@ -181,7 +188,7 @@
if (skip(ctx, command) || inTransaction())
return returnValue;
- returnValue = loader.put(command.getKey(), command.getValue());
+ store.store((StoredEntry) null);//command.getKey(), command.getValue());
if (getStatisticsEnabled()) cacheStores++;
return returnValue;
@@ -196,7 +203,7 @@
// Perhaps this should be optimized
Map<Object, Object> map = command.getMap();
List<Modification> modifications = toModifications(map);
- loader.put(modifications);
+// store.put(modifications);
if (getStatisticsEnabled()) cacheStores++;
@@ -205,8 +212,9 @@
private static List<Modification> toModifications(Map<Object, Object> map) {
List<Modification> modifications = new ArrayList<Modification>(map.size());
- for (Map.Entry<Object, Object> entry : map.entrySet())
- modifications.add(new Modification(ModificationType.PUT, entry.getKey(), entry.getValue()));
+ // TODO fix me
+// for (Map.Entry<Object, Object> entry : map.entrySet())
+// modifications.add(new Modification(ModificationType.PUT, entry.getKey(), entry.getValue()));
return modifications;
}
@@ -232,7 +240,7 @@
log.trace("Converted method calls to cache loader modifications. List size: " + modsBuilder.modifications.size());
}
if (modsBuilder.modifications.size() > 0) {
- loader.prepare(gtx, modsBuilder.modifications, onePhase);
+// loader.prepare(gtx, modsBuilder.modifications, onePhase);
preparingTxs.put(gtx, modsBuilder.affectedKeys);
if (getStatisticsEnabled() && modsBuilder.putCount > 0) {
@@ -241,7 +249,7 @@
}
}
- public static class StoreModificationsBuilder extends AbstractVisitor {
+ public class StoreModificationsBuilder extends AbstractVisitor {
boolean generateStatistics;
@@ -256,32 +264,37 @@
}
@Override
+ @SuppressWarnings("unchecked")
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
if (generateStatistics) putCount++;
- modifications.add(new Modification(Modification.ModificationType.PUT, command.getKey(), command.getValue()));
+ modifications.add(new Store(dataContainer.createEntryForStorage(command.getKey())));
affectedKeys.add(command.getKey());
return null;
}
@Override
+ @SuppressWarnings("unchecked")
public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable {
Map<Object, Object> map = command.getMap();
if (generateStatistics) putCount += map.size();
affectedKeys.addAll(map.keySet());
- modifications.addAll(toModifications(map));
+ Set<StoredEntry> entries = new HashSet<StoredEntry>();
+ for (Object key : map.keySet()) modifications.add(new Store(dataContainer.createEntryForStorage(key)));
return null;
}
@Override
+ @SuppressWarnings("unchecked")
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
- modifications.add(new Modification(Modification.ModificationType.REMOVE, command.getKey(), null));
+ modifications.add(new Remove(command.getKey()));
affectedKeys.add(command.getKey());
return null;
}
@Override
+ @SuppressWarnings("unchecked")
public Object visitClearCommand(InvocationContext ctx, ClearCommand command) throws Throwable {
- modifications.add(new Modification(Modification.ModificationType.CLEAR, null, null));
+ modifications.add(new Clear());
return null;
}
}
Added: core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoader.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,10 @@
+package org.horizon.loader;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public abstract class AbstractCacheLoader<K, V> implements CacheLoader<K, V> {
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheLoaderConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,129 @@
+package org.horizon.loader;
+
+import org.horizon.config.PluggableConfigurationComponent;
+import org.horizon.loader.decorators.SingletonStoreConfig;
+import org.horizon.util.Util;
+
+public class AbstractCacheLoaderConfig extends PluggableConfigurationComponent implements CacheLoaderConfig {
+ private boolean async;
+ private boolean ignoreModifications;
+ private boolean fetchPersistentState;
+ private boolean purgeOnStartup;
+ private SingletonStoreConfig singletonStoreConfig;
+
+// protected void populateFromBaseConfig(CacheLoaderManagerConfig.IndividualCacheLoaderConfig base) {
+// if (base != null) {
+// setAsync(base.isAsync());
+// setIgnoreModifications(base.isIgnoreModifications());
+// setFetchPersistentState(base.isFetchPersistentState());
+// setSingletonStoreConfig(base.getSingletonStoreConfig());
+// setPurgeOnStartup(base.isPurgeOnStartup());
+// setProperties(base.getProperties());
+// }
+// }
+
+ public boolean isPurgeOnStartup() {
+ return purgeOnStartup;
+ }
+
+ public boolean isFetchPersistentState() {
+ return fetchPersistentState;
+ }
+
+ public void setFetchPersistentState(boolean fetchPersistentState) {
+ testImmutability("fetchPersistentState");
+ this.fetchPersistentState = fetchPersistentState;
+ }
+
+ public void setAsync(boolean async) {
+ testImmutability("async");
+ this.async = async;
+ }
+
+ public boolean isAsync() {
+ return async;
+ }
+
+ public void setIgnoreModifications(boolean ignoreModifications) {
+ testImmutability("ignoreModifications");
+ this.ignoreModifications = ignoreModifications;
+ }
+
+ public boolean isIgnoreModifications() {
+ return ignoreModifications;
+ }
+
+ public void setPurgeOnStartup(boolean purgeOnStartup) {
+ testImmutability("purgeOnStartup");
+ this.purgeOnStartup = purgeOnStartup;
+ }
+
+ public SingletonStoreConfig getSingletonStoreConfig() {
+ return singletonStoreConfig;
+ }
+
+ public void setSingletonStoreConfig(SingletonStoreConfig singletonStoreConfig) {
+ testImmutability("singletonStoreConfig");
+ this.singletonStoreConfig = singletonStoreConfig;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (super.equals(obj)) {
+ if (!(obj instanceof AbstractCacheLoaderConfig)) return false;
+ AbstractCacheLoaderConfig i = (AbstractCacheLoaderConfig) obj;
+ return equalsExcludingProperties(i);
+ }
+ return false;
+ }
+
+ protected boolean equalsExcludingProperties(Object obj) {
+ AbstractCacheLoaderConfig other = (AbstractCacheLoaderConfig) obj;
+
+ return Util.safeEquals(this.className, other.className)
+ && (this.async == other.async)
+ && (this.ignoreModifications == other.ignoreModifications)
+ && (this.fetchPersistentState == other.fetchPersistentState)
+ && Util.safeEquals(this.singletonStoreConfig, other.singletonStoreConfig);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * hashCodeExcludingProperties() + (properties == null ? 0 : properties.hashCode());
+ }
+
+ protected int hashCodeExcludingProperties() {
+ int result = 17;
+ result = 31 * result + (className == null ? 0 : className.hashCode());
+ result = 31 * result + (async ? 0 : 1);
+ result = 31 * result + (ignoreModifications ? 0 : 1);
+ result = 31 * result + (fetchPersistentState ? 0 : 1);
+ result = 31 * result + (singletonStoreConfig == null ? 0 : singletonStoreConfig.hashCode());
+ result = 31 * result + (purgeOnStartup ? 0 : 1);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder().append("IndividualCacheLoaderConfig{").append("className='").append(className).append('\'')
+ .append(", async=").append(async)
+ .append(", ignoreModifications=").append(ignoreModifications)
+ .append(", fetchPersistentState=").append(fetchPersistentState)
+ .append(", properties=").append(properties)
+ .append(", purgeOnStartup=").append(purgeOnStartup).append("},")
+ .append("SingletonStoreConfig{").append(singletonStoreConfig).append('}')
+ .toString();
+ }
+
+ @Override
+ public AbstractCacheLoaderConfig clone() {
+ AbstractCacheLoaderConfig clone = null;
+ try {
+ clone = (AbstractCacheLoaderConfig) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Should not happen!", e);
+ }
+ if (singletonStoreConfig != null) clone.setSingletonStoreConfig(singletonStoreConfig.clone());
+ return clone;
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/AbstractCacheStore.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,38 @@
+package org.horizon.loader;
+
+import org.horizon.loader.modifications.Modification;
+import org.horizon.loader.modifications.Remove;
+import org.horizon.loader.modifications.Store;
+
+import java.util.List;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public abstract class AbstractCacheStore<K, V> extends AbstractCacheLoader<K, V> implements CacheStore<K, V> {
+
+ @SuppressWarnings("unchecked")
+ protected void applyModifications(List<Modification> mods) {
+ for (Modification m : mods) {
+ switch (m.getType()) {
+ case STORE:
+ Store<K, V> s = (Store<K, V>) m;
+ store(s.getStoredEntry());
+ break;
+ case CLEAR:
+ clear();
+ break;
+ case REMOVE:
+ Remove<K> r = (Remove<K>) m;
+ remove(r.getKey());
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown modification type " + m.getType());
+ }
+ }
+ }
+
+}
Copied: core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java (from rev 7675, core/branches/flat/src/main/java/org/horizon/loaderold/CacheLoader.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoader.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,56 @@
+package org.horizon.loader;
+
+import org.horizon.Cache;
+import org.horizon.lifecycle.Lifecycle;
+import org.horizon.marshall.Marshaller;
+
+import java.util.Set;
+
+/**
+ * Responsible for loading cache data from an external source
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public interface CacheLoader<K, V> extends Lifecycle {
+
+ /**
+ * Used to initialize a cache loader. Typically invoked by the {@link org.horizon.loader.CacheLoaderManager} when
+ * setting up cache loaders.
+ *
+ * @param config the cache loader configuration bean
+ * @param cache cache associated with this cache loader. Implementations may use this to determine cache name when
+ * selecting where refer to state in storage, for example, a different database table name.
+ * @param m marshaller to use when loading state from a stream, if supported by the implementation.
+ */
+ void init(CacheLoaderConfig config, Cache cache, Marshaller m);
+
+ /**
+ * Loads an entry mapped to by a given key. Should return null if the entry does not exist. Expired entries are not
+ * returned.
+ *
+ * @param key key
+ * @return an entry
+ */
+ StoredEntry<K, V> load(K key);
+
+ /**
+ * Loads all entries in the loader. Expired entries are not returned.
+ *
+ * @return a set of entries, or an empty set if the loader is emptied.
+ */
+ Set<StoredEntry<K, V>> loadAll();
+
+ /**
+ * @param key key to test
+ * @return true if the key exists, false otherwise
+ */
+ boolean containsKey(K key);
+
+
+ /**
+ * @return the type of the {@link org.horizon.loader.CacheLoaderConfig} bean used to configure this implementation of
+ * {@link org.horizon.loader.CacheLoader}
+ */
+ Class<? extends CacheLoaderConfig> getConfigurationClass();
+}
Copied: core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java (from rev 7675, core/branches/flat/src/main/java/org/horizon/config/CacheLoaderConfig.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,37 @@
+package org.horizon.loader;
+
+import org.horizon.loader.decorators.SingletonStoreConfig;
+
+/**
+ * Configures individual cache loaders
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public interface CacheLoaderConfig extends Cloneable {
+ boolean isPurgeOnStartup();
+
+ boolean isFetchPersistentState();
+
+ void setFetchPersistentState(boolean fetchPersistentState);
+
+ void setAsync(boolean async);
+
+ boolean isAsync();
+
+ void setIgnoreModifications(boolean ignoreModifications);
+
+ boolean isIgnoreModifications();
+
+ void setPurgeOnStartup(boolean purgeOnStartup);
+
+ SingletonStoreConfig getSingletonStoreConfig();
+
+ void setSingletonStoreConfig(SingletonStoreConfig singletonStoreConfig);
+
+ CacheLoaderConfig clone();
+
+ String getClassName();
+
+ void setClassName(String s);
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManager.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManager.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManager.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,28 @@
+package org.horizon.loader;
+
+import org.horizon.lifecycle.Lifecycle;
+
+/**
+ * The cache loader manager interface
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public interface CacheLoaderManager extends Lifecycle {
+
+ CacheLoader getCacheLoader();
+
+ CacheStore getCacheStore();
+
+ void purge();
+
+ boolean isUsingPassivation();
+
+ boolean isShared();
+
+ boolean isFetchPersistentState();
+
+ void preload();
+}
+
+
Added: core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheLoaderManagerImpl.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,200 @@
+package org.horizon.loader;
+
+import org.horizon.Cache;
+import org.horizon.CacheException;
+import org.horizon.config.CacheLoaderManagerConfig;
+import org.horizon.config.Configuration;
+import org.horizon.config.ConfigurationException;
+import org.horizon.factories.annotations.Inject;
+import org.horizon.factories.annotations.Start;
+import org.horizon.factories.annotations.Stop;
+import org.horizon.invocation.Options;
+import org.horizon.loader.decorators.AsyncStore;
+import org.horizon.loader.decorators.ChainingCacheLoader;
+import org.horizon.loader.decorators.ReadOnlyStore;
+import org.horizon.loader.decorators.SingletonStore;
+import org.horizon.loader.decorators.SingletonStoreConfig;
+import org.horizon.logging.Log;
+import org.horizon.logging.LogFactory;
+import org.horizon.marshall.Marshaller;
+import org.horizon.util.ReflectionUtil;
+import org.horizon.util.Util;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class CacheLoaderManagerImpl implements CacheLoaderManager {
+
+ Configuration configuration;
+ CacheLoaderManagerConfig clmConfig;
+ Cache<Object, Object> cache;
+ Marshaller m;
+ CacheLoader loader;
+ private static final Log log = LogFactory.getLog(CacheLoaderManagerImpl.class);
+
+ @Inject
+ public void inject(Cache cache, Marshaller marshaller, Configuration configuration) {
+ this.cache = cache;
+ this.m = marshaller;
+ this.configuration = configuration;
+ }
+
+ public CacheLoader getCacheLoader() {
+ return loader;
+ }
+
+ public final CacheStore getCacheStore() {
+ if (loader != null && loader instanceof CacheStore) {
+ return (CacheStore) loader;
+ } else {
+ return null;
+ }
+ }
+
+ public void purge() {
+ CacheStore cs = getCacheStore();
+ if (cs != null) cs.clear();
+ }
+
+ private void purgeLoaders(boolean force) throws Exception {
+ CacheStore cs = getCacheStore();
+ if (cs != null) {
+ if ((cs instanceof ChainingCacheLoader) && !force) {
+ ((ChainingCacheLoader) loader).purgeIfNecessary();
+ } else {
+ CacheLoaderConfig first = clmConfig.getFirstCacheLoaderConfig();
+ if (force || (first != null && first.isPurgeOnStartup())) {
+ cs.clear();
+ }
+ }
+ }
+ }
+
+ public boolean isUsingPassivation() {
+ return clmConfig.isPassivation();
+ }
+
+ public boolean isShared() {
+ return clmConfig.isShared();
+ }
+
+ public boolean isFetchPersistentState() {
+ return clmConfig.isFetchPersistentState();
+ }
+
+ @Start
+ public void start() {
+ clmConfig = configuration.getCacheLoaderConfig();
+ if (clmConfig != null) {
+ try {
+ loader = createCacheLoader();
+ if (loader != null) loader.start();
+ purgeLoaders(false);
+ } catch (Exception e) {
+ throw new CacheException("Unable to start cache loaders", e);
+ }
+ }
+ }
+
+ /**
+ * Performs a preload on the cache based on the cache loader preload configs used when configuring the cache.
+ */
+ @Start(priority = 50)
+ public void preload() {
+ if (loader != null) {
+ if (clmConfig.isPreload()) {
+ log.debug("Preloading transient state from cache loader {0}", loader);
+ long start = 0, stop = 0, total = 0;
+ if (log.isDebugEnabled()) start = System.currentTimeMillis();
+ Set<StoredEntry> state = loader.loadAll();
+
+ for (StoredEntry se : state)
+ cache.getAdvancedCache().put(se.getKey(), se.getValue(), se.getLifespan(),
+ TimeUnit.MILLISECONDS, Options.SKIP_CACHE_STATUS_CHECK);
+
+ if (log.isDebugEnabled()) stop = System.currentTimeMillis();
+ if (log.isDebugEnabled()) total = stop - start;
+ log.debug("Preloaded {0} keys in {1} milliseconds", state.size(), total);
+ }
+ }
+ }
+
+ @Stop
+ public void stop() {
+ if (loader != null) loader.stop();
+ loader = null;
+ }
+
+ CacheLoader createCacheLoader() throws Exception {
+ CacheLoader tmpLoader;
+ // if we only have a single cache loader configured in the chaining cacheloader then
+ // don't use a chaining cache loader at all.
+ // also if we are using passivation then just directly use the first cache loader.
+ if (clmConfig.useChainingCacheLoader()) {
+ // create chaining cache loader.
+ ChainingCacheLoader ccl = new ChainingCacheLoader();
+ tmpLoader = ccl;
+
+ // only one cache loader may have fetchPersistentState to true.
+ int numLoadersWithFetchPersistentState = 0;
+ for (CacheLoaderConfig cfg : clmConfig.getIndividualCacheLoaderConfigs()) {
+ if (cfg.isFetchPersistentState()) numLoadersWithFetchPersistentState++;
+
+ if (numLoadersWithFetchPersistentState > 1)
+ throw new Exception("Invalid cache loader configuration!! Only ONE cache loader may have fetchPersistentState set to true. Cache will not start!");
+
+ assertNotSingletonAndShared(cfg);
+
+ CacheLoader l = createCacheLoader(cfg, cache);
+ ccl.addCacheLoader(l, cfg);
+ }
+ } else {
+ CacheLoaderConfig cfg = clmConfig.getFirstCacheLoaderConfig();
+ tmpLoader = createCacheLoader(cfg, cache);
+ assertNotSingletonAndShared(cfg);
+ }
+
+ // Update the config with those actually used by the loaders
+ ReflectionUtil.setValue(clmConfig, "accessible", true);
+
+ return tmpLoader;
+ }
+
+ CacheLoader createCacheLoader(CacheLoaderConfig cfg, Cache cache) throws Exception {
+ CacheLoader tmpLoader = (CacheLoader) Util.getInstance(cfg.getClassName());
+
+ if (tmpLoader != null) {
+ if (tmpLoader instanceof CacheStore) {
+ CacheStore tmpStore = (CacheStore) tmpLoader;
+ // async?
+ if (cfg.isAsync()) {
+ tmpStore = new AsyncStore(tmpStore);
+ tmpLoader = tmpStore;
+ }
+
+ // read only?
+ if (cfg.isIgnoreModifications()) {
+ tmpStore = new ReadOnlyStore(tmpStore);
+ tmpLoader = tmpStore;
+ }
+
+ // singleton?
+ SingletonStoreConfig ssc = cfg.getSingletonStoreConfig();
+ if (ssc != null && ssc.isSingletonStoreEnabled()) {
+ tmpStore = new SingletonStore(tmpStore);
+ tmpLoader = tmpStore;
+ }
+ }
+
+ // load props
+ tmpLoader.init(cfg, cache, m);
+ }
+ return tmpLoader;
+ }
+
+ void assertNotSingletonAndShared(CacheLoaderConfig cfg) {
+ SingletonStoreConfig ssc = cfg.getSingletonStoreConfig();
+ if (ssc != null && ssc.isSingletonStoreEnabled() && clmConfig.isShared())
+ throw new ConfigurationException("Invalid cache loader configuration!! If a cache loader is configured as a singleton, the cache loader cannot be shared in a cluster!");
+ }
+}
Copied: core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java (from rev 7675, core/branches/flat/src/main/java/org/horizon/loaderold/CacheStore.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/CacheStore.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,89 @@
+package org.horizon.loader;
+
+import org.horizon.loader.modifications.Modification;
+
+import javax.transaction.Transaction;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * A specialization of the {@link CacheLoader} interface that can be written to.
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public interface CacheStore<K, V> extends CacheLoader<K, V> {
+
+ /**
+ * Stores an entry
+ *
+ * @param ed entry to store
+ */
+ void store(StoredEntry<K, V> ed);
+
+ /**
+ * Writes contents of the stream to the store. Implementations should expect that the stream contains data in an
+ * implementation-specific format, typically generated using {@link #load(java.io.OutputStream)}. While not a
+ * requirement, it is recommended that implementations make use of the {@link org.horizon.marshall.Marshaller} when
+ * dealing with the stream to make use of efficient marshalling.
+ *
+ * @param inputStream stream to read from
+ */
+ void store(InputStream inputStream) throws IOException, ClassNotFoundException;
+
+ /**
+ * Loads the entire state into a stream, using whichever format is most efficient for the cache loader
+ * implementation. Typically read and parsed by {@link #store(java.io.InputStream)}.
+ * <p/>
+ * While not a requirement, it is recommended that implementations make use of the {@link
+ * org.horizon.marshall.Marshaller} when dealing with the stream to make use of efficient marshalling.
+ *
+ * @param outputStream stream to write to
+ * @throws java.io.IOException in the event of problems writing to the stream
+ */
+ void load(OutputStream outputStream) throws IOException;
+
+ /**
+ * Clears all entries in the store
+ */
+ void clear();
+
+ /**
+ * Removes an entry in the store.
+ *
+ * @param key key to remove
+ * @return true if the entry was removed; false if the entry wasn't found.
+ */
+ boolean remove(K key);
+
+ /**
+ * Purges expired entries from the store.
+ */
+ void purgeExpired();
+
+ /**
+ * Issues a prepare call with a set of modifications to be applied to the cache store
+ *
+ * @param modifications modifications to be applied
+ * @param tx transaction identifier
+ * @param isOnePhase if true, there will not be a commit or rollback phase and changes should be flushed
+ * immediately
+ */
+ void prepare(List<Modification> modifications, Transaction tx, boolean isOnePhase);
+
+ /**
+ * Commits a transaction that has been previously prepared
+ *
+ * @param tx tx to commit
+ */
+ void commit(Transaction tx);
+
+ /**
+ * Rolls back a transaction that has been previously prepared
+ *
+ * @param tx tx to roll back
+ */
+ void rollback(Transaction tx);
+}
Copied: core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java (from rev 7675, core/branches/flat/src/main/java/org/horizon/loaderold/StoredEntry.java)
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/StoredEntry.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,74 @@
+package org.horizon.loader;
+
+import org.horizon.container.ExpirableCachedValue;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * An entry that is stored in a cache loader.
+ *
+ * @author Manik Surtani
+ */
+public class StoredEntry<K, V> extends ExpirableCachedValue<V> implements Externalizable {
+ private K key;
+
+ public StoredEntry() {
+ }
+
+ public StoredEntry(K key, V value, long created, long expiry) {
+ super(value, created, expiry);
+ this.key = key;
+ }
+
+ public final K getKey() {
+ return key;
+ }
+
+ public final long getLifespan() {
+ if (createdTime < 0 || expiryTime < 0) return -1;
+ return expiryTime - createdTime;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ StoredEntry that = (StoredEntry) o;
+
+ if (key != null ? !key.equals(that.key) : that.key != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return key != null ? key.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ return "StoredEntry{" +
+ "key=" + key +
+ '}';
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeObject(key);
+ out.writeObject(value);
+ out.writeLong(createdTime);
+ out.writeLong(expiryTime);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ key = (K) in.readObject();
+ value = (V) in.readObject();
+ createdTime = in.readLong();
+ expiryTime = in.readLong();
+ modifiedTime = System.currentTimeMillis();
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/AbstractDelegatingStore.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,21 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.loader.CacheStore;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ */
+public abstract class AbstractDelegatingStore implements CacheStore {
+
+ CacheStore delegate;
+
+ public void setDelegate(CacheStore cacheStore) {
+ this.delegate = cacheStore;
+ }
+
+ public CacheStore getDelegate() {
+ return delegate;
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/AsyncStore.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,107 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.marshall.Marshaller;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An asynchronous wrapper around a cache store
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class AsyncStore implements CacheStore {
+
+ CacheStore delegate;
+
+ public AsyncStore(CacheStore delegate) {
+ this.delegate = delegate;
+ }
+
+ public void store(StoredEntry ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void storeAll(Collection ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void store(InputStream inputStream) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void clear() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public boolean remove(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public void purgeExpired() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void commit(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void rollback(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void prepare(List list, Transaction tx, boolean isOnePhase) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, TransactionManager tm, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public StoredEntry load(Object key) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll(Collection keys) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public boolean containsKey(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public Class getConfigurationClass() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public void start() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void stop() {
+ // TODO: Manik: Customise this generated block
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/ChainingCacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/ChainingCacheLoader.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/ChainingCacheLoader.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,114 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoader;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.marshall.Marshaller;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A chaining cache loader that allows us to configure > 1 cache loader.
+ * <p/>
+ * READ operations are directed to each of the cache loaders (in the order which they were configured) until a non-null
+ * (or non-empty in the case of retrieving collection objects) result is achieved.
+ * <p/>
+ * WRITE operations are propagated to ALL registered cache stores specified, that set ignoreModifications to false.
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class ChainingCacheLoader implements CacheStore {
+ public void store(StoredEntry ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void storeAll(Collection ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void store(InputStream inputStream) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void clear() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public boolean remove(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public void purgeExpired() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void commit(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void rollback(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void prepare(List list, Transaction tx, boolean isOnePhase) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, TransactionManager tm, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public StoredEntry load(Object key) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll(Collection keys) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public boolean containsKey(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public Class<? extends CacheLoaderConfig> getConfigurationClass() {
+ return null;
+ }
+
+ public void start() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void stop() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void addCacheLoader(CacheLoader loader, CacheLoaderConfig cfg) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void purgeIfNecessary() {
+ // TODO: Manik: Customise this generated block
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/ReadOnlyStore.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,106 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.marshall.Marshaller;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ */
+public class ReadOnlyStore implements CacheStore {
+
+ CacheStore delegate;
+
+ public ReadOnlyStore(CacheStore delegate) {
+ this.delegate = delegate;
+ }
+
+ public void store(StoredEntry ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void storeAll(Collection ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void store(InputStream inputStream) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void clear() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public boolean remove(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public void purgeExpired() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void commit(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void rollback(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void prepare(List list, Transaction tx, boolean isOnePhase) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, TransactionManager tm, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public StoredEntry load(Object key) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll(Collection keys) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public boolean containsKey(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public Class getConfigurationClass() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public void start() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void stop() {
+ // TODO: Manik: Customise this generated block
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStore.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,98 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.marshall.Marshaller;
+
+import javax.transaction.Transaction;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ */
+public class SingletonStore extends AbstractDelegatingStore {
+ public SingletonStore(CacheStore tmpStore) {
+ setDelegate(tmpStore);
+ }
+
+ public void store(StoredEntry ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void storeAll(Collection ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void store(InputStream inputStream) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void clear() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public boolean remove(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public void purgeExpired() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void commit(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void rollback(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void prepare(List list, Transaction tx, boolean isOnePhase) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public StoredEntry load(Object key) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll(Collection keys) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public boolean containsKey(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public Class<? extends CacheLoaderConfig> getConfigurationClass() {
+ return null;
+ }
+
+ public void start() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void stop() {
+ // TODO: Manik: Customise this generated block
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStoreConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStoreConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/decorators/SingletonStoreConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,55 @@
+package org.horizon.loader.decorators;
+
+import org.horizon.config.AbstractNamedCacheConfigurationBean;
+
+/**
+ * Configuration for a singleton store
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class SingletonStoreConfig extends AbstractNamedCacheConfigurationBean {
+
+ private static final long serialVersionUID = 824251894176131850L;
+
+ boolean singletonStoreEnabled;
+ boolean pushStateWhenCoordinator;
+ long pushStateTimeout = 10000;
+
+ public boolean isSingletonStoreEnabled() {
+ return singletonStoreEnabled;
+ }
+
+ public void setSingletonStoreEnabled(boolean singletonStoreEnabled) {
+ testImmutability("singletonStoreEnabled");
+ this.singletonStoreEnabled = singletonStoreEnabled;
+ }
+
+
+ public boolean isPushStateWhenCoordinator() {
+ return pushStateWhenCoordinator;
+ }
+
+ public void setPushStateWhenCoordinator(boolean pushStateWhenCoordinator) {
+ testImmutability("pushStateWhenCoordinator");
+ this.pushStateWhenCoordinator = pushStateWhenCoordinator;
+ }
+
+ public long getPushStateTimeout() {
+ return pushStateTimeout;
+ }
+
+ public void setPushStateTimeout(long pushStateTimeout) {
+ testImmutability("pushStateTimeout");
+ this.pushStateTimeout = pushStateTimeout;
+ }
+
+ @Override
+ public SingletonStoreConfig clone() {
+ try {
+ return (SingletonStoreConfig) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Should not happen", e);
+ }
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoader.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoader.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,94 @@
+package org.horizon.loader.jdbc;
+
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.CacheStore;
+import org.horizon.loader.StoredEntry;
+import org.horizon.marshall.Marshaller;
+
+import javax.transaction.Transaction;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ */
+public class JDBCCacheLoader implements CacheStore {
+ public void store(StoredEntry ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void storeAll(Collection ed) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void store(InputStream inputStream) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void clear() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public boolean remove(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public void purgeExpired() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void commit(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void rollback(Transaction tx) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void prepare(List list, Transaction tx, boolean isOnePhase) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public StoredEntry load(Object key) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll(Collection keys) {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public Set loadAll() {
+ return null; // TODO: Manik: Customise this generated block
+ }
+
+ public boolean containsKey(Object key) {
+ return false; // TODO: Manik: Customise this generated block
+ }
+
+ public Class<? extends CacheLoaderConfig> getConfigurationClass() {
+ return JDBCCacheLoaderConfig.class;
+ }
+
+ public void start() {
+ // TODO: Manik: Customise this generated block
+ }
+
+ public void stop() {
+ // TODO: Manik: Customise this generated block
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoaderConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoaderConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/jdbc/JDBCCacheLoaderConfig.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,51 @@
+package org.horizon.loader.jdbc;
+
+import org.horizon.loader.AbstractCacheLoaderConfig;
+
+/**
+ * // TODO: Manik: Document this!
+ *
+ * @author Manik Surtani
+ */
+public class JDBCCacheLoaderConfig extends AbstractCacheLoaderConfig {
+ String dataSource;
+ String tableNamePrefix = "horizon";
+ boolean createTable = true;
+ boolean dropTable = false;
+
+ public JDBCCacheLoaderConfig() {
+ className = JDBCCacheLoader.class.getName();
+ }
+
+ public String getDataSource() {
+ return dataSource;
+ }
+
+ public void setDataSource(String dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public String getTableNamePrefix() {
+ return tableNamePrefix;
+ }
+
+ public void setTableNamePrefix(String tableNamePrefix) {
+ this.tableNamePrefix = tableNamePrefix;
+ }
+
+ public boolean isCreateTable() {
+ return createTable;
+ }
+
+ public void setCreateTable(boolean createTable) {
+ this.createTable = createTable;
+ }
+
+ public boolean isDropTable() {
+ return dropTable;
+ }
+
+ public void setDropTable(boolean dropTable) {
+ this.dropTable = dropTable;
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Clear.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,20 @@
+package org.horizon.loader.modifications;
+
+/**
+ * Represents a {@link org.horizon.loader.CacheStore#clear()} modification
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class Clear implements Modification {
+ final Type type = Type.CLEAR;
+
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return "Clear";
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Modification.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,15 @@
+package org.horizon.loader.modifications;
+
+/**
+ * An interface that defines a {@link org.horizon.loader.CacheStore} modification
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public interface Modification {
+ public static enum Type {
+ STORE, REMOVE, CLEAR
+ }
+
+ Type getType();
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Remove.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,52 @@
+package org.horizon.loader.modifications;
+
+/**
+ * Represents a {@link org.horizon.loader.CacheStore#remove(Object)} modification
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class Remove<K> implements Modification {
+
+ final Type type = Type.REMOVE;
+ final K key;
+
+ public Remove(K key) {
+ this.key = key;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Remove remove = (Remove) o;
+
+ if (key != null ? !key.equals(remove.key) : remove.key != null) return false;
+ if (type != remove.type) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (key != null ? key.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Remove{" +
+ "key=" + key +
+ '}';
+ }
+}
Added: core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java (rev 0)
+++ core/branches/flat/src/main/java/org/horizon/loader/modifications/Store.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,54 @@
+package org.horizon.loader.modifications;
+
+import org.horizon.loader.StoredEntry;
+
+/**
+ * Modification representing {@link org.horizon.loader.CacheStore#store(org.horizon.loader.StoredEntry)}
+ *
+ * @author Manik Surtani
+ * @since 1.0
+ */
+public class Store<K, V> implements Modification {
+
+ final Type type = Type.STORE;
+ final StoredEntry<K, V> storedEntry;
+
+ public Store(StoredEntry<K, V> storedEntry) {
+ this.storedEntry = storedEntry;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public StoredEntry<K, V> getStoredEntry() {
+ return storedEntry;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Store store = (Store) o;
+
+ if (storedEntry != null ? !storedEntry.equals(store.storedEntry) : store.storedEntry != null) return false;
+ if (type != store.type) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (storedEntry != null ? storedEntry.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Store{" +
+ "storedEntry=" + storedEntry +
+ '}';
+ }
+}
Modified: core/branches/flat/src/main/java/org/horizon/statetransfer/DefaultStateTransferManager.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/statetransfer/DefaultStateTransferManager.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/java/org/horizon/statetransfer/DefaultStateTransferManager.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -24,7 +24,7 @@
import org.horizon.config.Configuration;
import org.horizon.factories.annotations.Inject;
import org.horizon.factories.annotations.Start;
-import org.horizon.loaderold.CacheLoaderManager;
+import org.horizon.loader.CacheLoaderManager;
import org.horizon.logging.Log;
import org.horizon.logging.LogFactory;
import org.horizon.marshall.Marshaller;
Modified: core/branches/flat/src/main/resources/config-samples/all.xml
===================================================================
--- core/branches/flat/src/main/resources/config-samples/all.xml 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/resources/config-samples/all.xml 2009-02-11 09:52:13 UTC (rev 7679)
@@ -154,12 +154,7 @@
horizon.jdbc.table.drop=false
</properties>
- <singletonStore enabled="true" class="org.horizon.loader.SingletonStoreCacheLoaderOld">
- <properties>
- horizon.singletonStore.pushStateWhenCoordinator=true
- horizon.singletonStore.pushStateWhenCoordinatorTimeout=20000
- </properties>
- </singletonStore>
+ <singletonStore enabled="true" pushStateWhenCoordinator="true" pushStateTimeout="20000"/>
</loader>
</loaders>
Modified: core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
===================================================================
--- core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd 2009-02-11 09:52:13 UTC (rev 7679)
@@ -171,11 +171,9 @@
<xs:element name="properties"/>
<xs:element name="singletonStore" minOccurs="0" maxOccurs="1">
<xs:complexType>
- <xs:all>
- <xs:element name="properties" type="xs:string" minOccurs="0" maxOccurs="1"/>
- </xs:all>
<xs:attribute name="enabled" type="tns:booleanType"/>
- <xs:attribute name="class" type="xs:string"/>
+ <xs:attribute name="pushStateWhenCoordinator" type="tns:booleanType"/>
+ <xs:attribute name="pushStateTimeout" type="xs:positiveInteger"/>
</xs:complexType>
</xs:element>
</xs:all>
Modified: core/branches/flat/src/test/java/org/horizon/api/tree/NodeMoveAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/api/tree/NodeMoveAPITest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/api/tree/NodeMoveAPITest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -3,7 +3,7 @@
import org.horizon.Cache;
import org.horizon.UnitTestCacheFactory;
import org.horizon.api.mvcc.LockAssert;
-import org.horizon.config.CacheLoaderConfig;
+import org.horizon.config.CacheLoaderManagerConfig;
import org.horizon.config.Configuration;
import org.horizon.config.parsing.XmlConfigHelper;
import org.horizon.config.parsing.element.LoadersElementParser;
@@ -532,7 +532,7 @@
assertNoLocks();
}
- protected CacheLoaderConfig getSingleCacheLoaderConfig(boolean passivation, String preload, String cacheloaderClass, String properties, boolean async, boolean fetchPersistentState, boolean shared, boolean purgeOnStartup) throws Exception {
+ protected CacheLoaderManagerConfig getSingleCacheLoaderConfig(boolean passivation, String preload, String cacheloaderClass, String properties, boolean async, boolean fetchPersistentState, boolean shared, boolean purgeOnStartup) throws Exception {
String xml =
" <loaders passivation=\"" + passivation + "\" shared=\"" + shared + "\">\n" +
" <preload>\n" +
Modified: core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,11 +1,14 @@
package org.horizon.config.parsing;
-import org.horizon.config.CacheLoaderConfig;
+import org.horizon.config.CacheLoaderManagerConfig;
import org.horizon.config.Configuration;
import org.horizon.config.ConfigurationException;
import org.horizon.config.EvictionConfig;
import org.horizon.eviction.DefaultEvictionAction;
import org.horizon.eviction.algorithms.fifo.FIFOAlgorithmConfig;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.decorators.SingletonStoreConfig;
+import org.horizon.loader.jdbc.JDBCCacheLoaderConfig;
import org.horizon.lock.IsolationLevel;
import org.horizon.transaction.GenericTransactionManagerLookup;
import org.testng.annotations.Test;
@@ -141,20 +144,15 @@
public void testCacheLoaders() throws Exception {
XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
String xml = "<loaders passivation=\"true\" shared=\"true\" preload=\"true\">\n" +
- " <loader class=\"org.horizon.loader.JDBCCacheLoader\" async=\"true\" fetchPersistentState=\"true\"\n" +
+ " <loader class=\"org.horizon.loader.jdbc.JDBCCacheLoader\" async=\"true\" fetchPersistentState=\"true\"\n" +
" ignoreModifications=\"false\" purgeOnStartup=\"false\">\n" +
" <properties>\n" +
- " horizon.jdbc.datasource=HorizonDS\n" +
- " horizon.jdbc.table.name=horizon\n" +
- " horizon.jdbc.table.create=true\n" +
- " horizon.jdbc.table.drop=false\n" +
+ " dataSource=HorizonDS\n" +
+ " tableNamePrefix=horizon\n" +
+ " createTable=true\n" +
+ " dropTable=false\n" +
" </properties>\n" +
- " <singletonStore enabled=\"true\" class=\"com.blah.Blah\">\n" +
- " <properties>\n" +
- " horizon.singletonStore.pushStateWhenCoordinator=true\n" +
- " horizon.singletonStore.pushStateWhenCoordinatorTimeout=20000\n" +
- " </properties>\n" +
- " </singletonStore>\n" +
+ " <singletonStore enabled=\"true\" pushStateWhenCoordinator=\"true\" pushStateTimeout=\"20000\" />\n" +
" </loader>\n" +
" </loaders>";
Element e = XmlConfigHelper.stringToElement(xml);
@@ -162,32 +160,37 @@
Configuration c = new Configuration();
parser.configureCacheLoaders(e, c);
- CacheLoaderConfig clc = c.getCacheLoaderConfig();
+ CacheLoaderManagerConfig clc = c.getCacheLoaderConfig();
assert clc != null;
assert clc.isFetchPersistentState();
assert clc.isPassivation();
assert clc.isShared();
assert clc.isPreload();
- CacheLoaderConfig.IndividualCacheLoaderConfig iclc = clc.getFirstCacheLoaderConfig();
- assert iclc.getClassName().equals("org.horizon.loader.JDBCCacheLoader");
+ CacheLoaderConfig iclc = clc.getFirstCacheLoaderConfig();
+ assert iclc.getClassName().equals("org.horizon.loader.jdbc.JDBCCacheLoader");
assert iclc.isAsync();
assert iclc.isFetchPersistentState();
assert !iclc.isIgnoreModifications();
assert !iclc.isPurgeOnStartup();
- CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig ssc = iclc.getSingletonStoreConfig();
+ JDBCCacheLoaderConfig jdbcclc = (JDBCCacheLoaderConfig) iclc;
+ assert jdbcclc.getDataSource().equals("HorizonDS");
+ assert jdbcclc.getTableNamePrefix().equals("horizon");
+ assert jdbcclc.isCreateTable();
+ assert !jdbcclc.isDropTable();
+
+ SingletonStoreConfig ssc = iclc.getSingletonStoreConfig();
assert ssc.isSingletonStoreEnabled();
- assert ssc.getClassName().equals("com.blah.Blah");
- assert ssc.getSingletonStoreProperties().size() == 2;
+ assert ssc.isPushStateWhenCoordinator();
+ assert ssc.getPushStateTimeout() == 20000;
}
public void testCacheLoadersDefaults() throws Exception {
XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
String xml = "<loaders>\n" +
- " <loader class=\"org.horizon.loader.JDBCCacheLoader\">\n" +
+ " <loader class=\"org.horizon.loader.jdbc.JDBCCacheLoader\">\n" +
" <properties />\n" +
- " <singletonStore enabled=\"true\" />\n" +
" </loader>\n" +
" </loaders>";
Element e = XmlConfigHelper.stringToElement(xml);
@@ -195,24 +198,22 @@
Configuration c = new Configuration();
parser.configureCacheLoaders(e, c);
- CacheLoaderConfig clc = c.getCacheLoaderConfig();
+ CacheLoaderManagerConfig clc = c.getCacheLoaderConfig();
assert clc != null;
assert !clc.isFetchPersistentState();
assert !clc.isPassivation();
assert !clc.isShared();
assert !clc.isPreload();
- CacheLoaderConfig.IndividualCacheLoaderConfig iclc = clc.getFirstCacheLoaderConfig();
- assert iclc.getClassName().equals("org.horizon.loader.JDBCCacheLoader");
+ CacheLoaderConfig iclc = clc.getFirstCacheLoaderConfig();
+ assert iclc.getClassName().equals("org.horizon.loader.jdbc.JDBCCacheLoader");
assert !iclc.isAsync();
assert !iclc.isFetchPersistentState();
assert !iclc.isIgnoreModifications();
assert !iclc.isPurgeOnStartup();
- CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig ssc = iclc.getSingletonStoreConfig();
- assert ssc.isSingletonStoreEnabled();
- assert ssc.getClassName().equals("org.horizon.loader.SingletonStoreCacheLoaderOld");
- assert ssc.getSingletonStoreProperties().isEmpty();
+ SingletonStoreConfig ssc = iclc.getSingletonStoreConfig();
+ assert !ssc.isSingletonStoreEnabled();
}
public void testInsufficientEviction() throws Exception {
Modified: core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/eviction/EvictionFunctionalTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -2,7 +2,6 @@
import org.horizon.Cache;
import org.horizon.config.Configuration;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.config.EvictionConfig;
import org.horizon.container.DataContainer;
import org.horizon.eviction.algorithms.fifo.FIFOAlgorithmConfig;
Modified: core/branches/flat/src/test/java/org/horizon/eviction/algorithms/BaseAlgorithmTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/eviction/algorithms/BaseAlgorithmTest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/eviction/algorithms/BaseAlgorithmTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -2,11 +2,10 @@
import org.easymock.EasyMock;
import static org.easymock.EasyMock.*;
-import org.horizon.config.EvictionAlgorithmConfig;
import org.horizon.container.DataContainer;
import org.horizon.eviction.EvictionAction;
import org.horizon.eviction.EvictionAlgorithm;
-import org.horizon.eviction.EvictionAlgorithmConfigBase;
+import org.horizon.eviction.EvictionAlgorithmConfig;
import org.horizon.eviction.events.EvictionEvent;
import static org.horizon.eviction.events.EvictionEvent.Type.*;
import org.horizon.eviction.events.InUseEvictionEvent;
@@ -20,7 +19,7 @@
@Test(groups = "unit")
public abstract class BaseAlgorithmTest {
- protected abstract EvictionAlgorithmConfigBase getNewEvictionAlgorithmConfig();
+ protected abstract BaseEvictionAlgorithmConfig getNewEvictionAlgorithmConfig();
protected BaseEvictionAlgorithm createAndInit(EvictionAlgorithmConfig cfg) throws Exception {
DataContainer dc = createNiceMock(DataContainer.class);
@@ -37,7 +36,7 @@
}
public void testMinTimeToLive() throws Exception {
- EvictionAlgorithmConfigBase cfg = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig cfg = getNewEvictionAlgorithmConfig();
cfg.setMinTimeToLive(2 * 60 * 60 * 1000); // something enormous - 2 hrs
cfg.setMaxEntries(5);
DataContainer dc = createMock(DataContainer.class);
@@ -97,7 +96,7 @@
}
public void testNumEntries1() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(4);
config.setMinEntries(2);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
@@ -131,7 +130,7 @@
}
public void testNumEntries2() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(0);
config.setMinEntries(20);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
@@ -150,7 +149,7 @@
}
public void testNumEntries3() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(3);
config.setMinEntries(20);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
@@ -179,7 +178,7 @@
}
public void testNumEntries4() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(-1);
config.setMinEntries(2);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
@@ -198,7 +197,7 @@
}
public void testNumEntries5() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(3);
config.setMinEntries(-1);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
@@ -226,7 +225,7 @@
}
public void testRemoveEvent() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMinTimeToLive(24 * 60 * 60, TimeUnit.SECONDS); // huge - so evictions wont happen
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
eventQueue.put(new EvictionEvent("one", ADD_ENTRY_EVENT));
@@ -251,7 +250,7 @@
}
public void testClearEvent() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMinTimeToLive(24 * 60 * 60, TimeUnit.SECONDS); // huge - so evictions wont happen
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
eventQueue.put(new EvictionEvent("one", ADD_ENTRY_EVENT));
@@ -276,7 +275,7 @@
}
public void testMarkInUseControl() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(1);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
eventQueue.put(new EvictionEvent("one", ADD_ENTRY_EVENT));
@@ -304,7 +303,7 @@
}
public void testMarkInUse() throws Exception {
- EvictionAlgorithmConfigBase config = getNewEvictionAlgorithmConfig();
+ BaseEvictionAlgorithmConfig config = getNewEvictionAlgorithmConfig();
config.setMaxEntries(1);
BlockingQueue<EvictionEvent> eventQueue = new LinkedBlockingQueue<EvictionEvent>();
eventQueue.put(new EvictionEvent("one", ADD_ENTRY_EVENT));
Added: core/branches/flat/src/test/java/org/horizon/loader/BaseCacheLoaderTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/BaseCacheLoaderTest.java (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/loader/BaseCacheLoaderTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,241 @@
+package org.horizon.loader;
+
+import org.easymock.EasyMock;
+import org.horizon.loader.modifications.Clear;
+import org.horizon.loader.modifications.Modification;
+import org.horizon.loader.modifications.Remove;
+import org.horizon.loader.modifications.Store;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Test(groups = "unit", sequential = true)
+@SuppressWarnings("unchecked")
+public abstract class BaseCacheLoaderTest {
+
+ protected abstract CacheStore createCacheStore();
+
+ CacheStore cs;
+
+ @BeforeTest
+ public void setUp() {
+ cs = createCacheStore();
+ }
+
+ @AfterTest
+ public void tearDown() {
+ if (cs != null) cs.clear();
+ cs = null;
+ }
+
+ @AfterMethod
+ public void cleanCL() {
+ cs.clear();
+ }
+
+ public void testLoadAndStore() throws InterruptedException {
+ assert !cs.containsKey("k");
+ StoredEntry se = new StoredEntry("k", "v", -1, -1);
+ cs.store(se);
+
+ assert cs.load("k").getValue().equals("v");
+ assert cs.load("k").getLifespan() == -1;
+ assert !cs.load("k").isExpired();
+ assert cs.containsKey("k");
+
+ long now = System.currentTimeMillis();
+ long lifespan = 120000;
+ se = new StoredEntry("k", "v", now, now + lifespan);
+ cs.store(se);
+
+ assert cs.load("k").getValue().equals("v");
+ assert cs.load("k").getLifespan() == lifespan;
+ assert !cs.load("k").isExpired();
+ assert cs.containsKey("k");
+
+ now = System.currentTimeMillis();
+ lifespan = 1;
+ se = new StoredEntry("k", "v", now, now + lifespan);
+ cs.store(se);
+ Thread.sleep(2);
+ assert se.isExpired();
+ assert cs.load("k") == null;
+ assert !cs.containsKey("k");
+ }
+
+ public void testOnePhaseCommit() {
+ List<Modification> mods = new ArrayList<Modification>();
+ mods.add(new Store(new StoredEntry("k1", "v1", -1, -1)));
+ mods.add(new Store(new StoredEntry("k2", "v2", -1, -1)));
+ mods.add(new Remove("k1"));
+ Transaction tx = EasyMock.createNiceMock(Transaction.class);
+ cs.prepare(mods, tx, true);
+
+ assert cs.load("k2").getValue().equals("v2");
+ assert !cs.containsKey("k1");
+
+ cs.clear();
+
+ mods = new ArrayList<Modification>();
+ mods.add(new Store(new StoredEntry("k1", "v1", -1, -1)));
+ mods.add(new Store(new StoredEntry("k2", "v2", -1, -1)));
+ mods.add(new Clear());
+ mods.add(new Store(new StoredEntry("k3", "v3", -1, -1)));
+
+ cs.prepare(mods, tx, true);
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert cs.containsKey("k3");
+ }
+
+ public void testTwoPhaseCommit() {
+ List<Modification> mods = new ArrayList<Modification>();
+ mods.add(new Store(new StoredEntry("k1", "v1", -1, -1)));
+ mods.add(new Store(new StoredEntry("k2", "v2", -1, -1)));
+ mods.add(new Remove("k1"));
+ Transaction tx = EasyMock.createNiceMock(Transaction.class);
+ cs.prepare(mods, tx, false);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+
+ cs.commit(tx);
+
+ assert cs.load("k2").getValue().equals("v2");
+ assert !cs.containsKey("k1");
+
+ cs.clear();
+
+ mods = new ArrayList<Modification>();
+ mods.add(new Store(new StoredEntry("k1", "v1", -1, -1)));
+ mods.add(new Store(new StoredEntry("k2", "v2", -1, -1)));
+ mods.add(new Clear());
+ mods.add(new Store(new StoredEntry("k3", "v3", -1, -1)));
+
+ cs.prepare(mods, tx, false);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert !cs.containsKey("k3");
+
+ cs.commit(tx);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert cs.containsKey("k3");
+ }
+
+ public void testRollback() {
+
+ cs.store(new StoredEntry("old", "old", -1, -1));
+
+ List<Modification> mods = new ArrayList<Modification>();
+ mods.add(new Store(new StoredEntry("k1", "v1", -1, -1)));
+ mods.add(new Store(new StoredEntry("k2", "v2", -1, -1)));
+ mods.add(new Remove("k1"));
+ mods.add(new Remove("old"));
+ Transaction tx = EasyMock.createNiceMock(Transaction.class);
+ cs.prepare(mods, tx, false);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert cs.containsKey("old");
+
+ cs.rollback(tx);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert cs.containsKey("old");
+
+ mods = new ArrayList<Modification>();
+ mods.add(new Store(new StoredEntry("k1", "v1", -1, -1)));
+ mods.add(new Store(new StoredEntry("k2", "v2", -1, -1)));
+ mods.add(new Clear());
+ mods.add(new Store(new StoredEntry("k3", "v3", -1, -1)));
+
+ cs.prepare(mods, tx, false);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert !cs.containsKey("k3");
+
+ cs.rollback(tx);
+
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert !cs.containsKey("k3");
+ assert cs.containsKey("old");
+ }
+
+ public void testCommitAndRollbackWithoutPrepare() {
+ cs.store(new StoredEntry("old", "old", -1, -1));
+ Transaction tx = EasyMock.createNiceMock(Transaction.class);
+ cs.commit(tx);
+ cs.store(new StoredEntry("old", "old", -1, -1));
+ cs.rollback(tx);
+
+ assert cs.containsKey("old");
+ }
+
+ public void testPreload() {
+ cs.store(new StoredEntry("k1", "v1", -1, -1));
+ cs.store(new StoredEntry("k2", "v2", -1, -1));
+ cs.store(new StoredEntry("k3", "v3", -1, -1));
+
+ Set<StoredEntry> set = cs.loadAll();
+
+ assert set.size() == 3;
+ Set expected = new HashSet();
+ expected.add("k1");
+ expected.add("k2");
+ expected.add("k3");
+ for (StoredEntry se : set) assert expected.remove(se.getKey());
+ assert expected.isEmpty();
+ }
+
+ public void testPurgeExpired() throws InterruptedException {
+ long now = System.currentTimeMillis();
+ long lifespan = 1000;
+ cs.store(new StoredEntry("k1", "v1", now, now + lifespan));
+ cs.store(new StoredEntry("k2", "v2", now, now + lifespan));
+ cs.store(new StoredEntry("k3", "v3", now, now + lifespan));
+ Thread.sleep(lifespan + 100);
+ cs.purgeExpired();
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ assert !cs.containsKey("k3");
+ }
+
+ public void testStreamingAPI() throws IOException, ClassNotFoundException {
+ cs.store(new StoredEntry("k1", "v1", -1, -1));
+ cs.store(new StoredEntry("k2", "v2", -1, -1));
+ cs.store(new StoredEntry("k3", "v3", -1, -1));
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ cs.load(out);
+ out.flush();
+ out.close();
+ cs.clear();
+ cs.store(new ByteArrayInputStream(out.toByteArray()));
+
+ Set<StoredEntry> set = cs.loadAll();
+
+ assert set.size() == 3;
+ Set expected = new HashSet();
+ expected.add("k1");
+ expected.add("k2");
+ expected.add("k3");
+ for (StoredEntry se : set) assert expected.remove(se.getKey());
+ assert expected.isEmpty();
+ }
+}
Added: core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoader.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,156 @@
+package org.horizon.loader.dummy;
+
+import org.horizon.Cache;
+import org.horizon.loader.AbstractCacheLoaderConfig;
+import org.horizon.loader.AbstractCacheStore;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.StoredEntry;
+import org.horizon.loader.modifications.Modification;
+import org.horizon.marshall.Marshaller;
+
+import javax.transaction.Transaction;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class DummyInMemoryCacheLoader<K, V> extends AbstractCacheStore<K, V> {
+
+ static final ConcurrentMap<String, Map> stores = new ConcurrentHashMap<String, Map>();
+ String storeName = "__DEFAULT_STORES__";
+ Map<K, StoredEntry<K, V>> store;
+ Cfg config;
+ ConcurrentMap<Transaction, List<Modification>> txs = new ConcurrentHashMap<Transaction, List<Modification>>();
+
+
+ public void store(StoredEntry<K, V> ed) {
+ store.put(ed.getKey(), ed);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void store(InputStream inputStream) throws IOException, ClassNotFoundException {
+ ObjectInputStream ois = inputStream instanceof ObjectInputStream ? (ObjectInputStream) inputStream :
+ new ObjectInputStream(inputStream);
+ int numEntries = ois.readInt();
+ store.clear();
+ for (int i = 0; i < numEntries; i++) {
+ StoredEntry<K, V> e = (StoredEntry<K, V>) ois.readObject();
+ store.put(e.getKey(), e);
+ }
+ }
+
+ public void load(OutputStream outputStream) throws IOException {
+ ObjectOutputStream oos = outputStream instanceof ObjectOutputStream ? (ObjectOutputStream) outputStream :
+ new ObjectOutputStream(outputStream);
+ oos.writeInt(store.size());
+ for (StoredEntry<K, V> se : store.values()) oos.writeObject(se);
+ }
+
+ public void clear() {
+ store.clear();
+ }
+
+ public boolean remove(K key) {
+ return store.remove(key) != null;
+ }
+
+ public void purgeExpired() {
+ for (Iterator<StoredEntry<K, V>> i = store.values().iterator(); i.hasNext();) {
+ StoredEntry<K, V> se = i.next();
+ if (se.isExpired()) i.remove();
+ }
+ }
+
+ public void commit(Transaction tx) {
+ List<Modification> mods = txs.remove(tx);
+ if (mods != null) applyModifications(mods);
+ }
+
+ public void rollback(Transaction tx) {
+ txs.remove(tx);
+ }
+
+ public void prepare(List<Modification> list, Transaction tx, boolean isOnePhase) {
+ if (isOnePhase)
+ applyModifications(list);
+ else
+ txs.put(tx, list);
+ }
+
+ public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ this.config = (Cfg) config;
+ }
+
+ public StoredEntry<K, V> load(K key) {
+ if (key == null) return null;
+ StoredEntry<K, V> se = store.get(key);
+ if (se == null) return null;
+ if (se.isExpired()) {
+ store.remove(key);
+ return null;
+ }
+
+ return se;
+ }
+
+ public Set<StoredEntry<K, V>> loadAll() {
+ Set<StoredEntry<K, V>> s = new HashSet<StoredEntry<K, V>>();
+ for (Iterator<StoredEntry<K, V>> i = store.values().iterator(); i.hasNext();) {
+ StoredEntry<K, V> se = i.next();
+ if (se.isExpired())
+ i.remove();
+ else
+ s.add(se);
+ }
+ return s;
+ }
+
+ public boolean containsKey(K key) {
+ return load(key) != null;
+ }
+
+ public Class<? extends CacheLoaderConfig> getConfigurationClass() {
+ return Cfg.class;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void start() {
+ storeName = config.getStore();
+ Map m = new ConcurrentHashMap();
+ Map existing = stores.putIfAbsent(storeName, m);
+ store = existing == null ? m : existing;
+ }
+
+ public void stop() {
+ stores.remove(storeName);
+ }
+
+ public static class Cfg extends AbstractCacheLoaderConfig {
+ boolean debug;
+ String store;
+
+ public boolean isDebug() {
+ return debug;
+ }
+
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ public String getStore() {
+ return store;
+ }
+
+ public void setStore(String store) {
+ this.store = store;
+ }
+ }
+}
Added: core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoaderTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoaderTest.java (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/loader/dummy/DummyInMemoryCacheLoaderTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -0,0 +1,18 @@
+package org.horizon.loader.dummy;
+
+import org.horizon.loader.BaseCacheLoaderTest;
+import org.horizon.loader.CacheStore;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", sequential = true)
+public class DummyInMemoryCacheLoaderTest extends BaseCacheLoaderTest {
+
+ protected CacheStore createCacheStore() {
+ DummyInMemoryCacheLoader cl = new DummyInMemoryCacheLoader();
+ DummyInMemoryCacheLoader.Cfg cfg = new DummyInMemoryCacheLoader.Cfg();
+ cfg.setStore(DummyInMemoryCacheLoaderTest.class.getName());
+ cl.init(cfg, null, null);
+ cl.start();
+ return cl;
+ }
+}
Modified: core/branches/flat/src/test/java/org/horizon/manager/CacheManagerComponentRegistryTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/manager/CacheManagerComponentRegistryTest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/manager/CacheManagerComponentRegistryTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -1,13 +1,13 @@
package org.horizon.manager;
import org.horizon.Cache;
-import org.horizon.config.CacheLoaderConfig;
import org.horizon.config.Configuration;
+import org.horizon.config.EvictionConfig;
import org.horizon.config.GlobalConfiguration;
+import org.horizon.eviction.EvictionManager;
+import org.horizon.eviction.algorithms.fifo.FIFOAlgorithmConfig;
import org.horizon.interceptors.BatchingInterceptor;
import org.horizon.interceptors.InterceptorChain;
-import org.horizon.loaderold.CacheLoaderManager;
-import org.horizon.loaderold.FileCacheLoaderConfig;
import org.horizon.remoting.RPCManager;
import org.horizon.transaction.DummyTransactionManager;
import org.horizon.transaction.DummyTransactionManagerLookup;
@@ -57,15 +57,12 @@
}
public void testForceUnsharedComponents() throws NamedCacheNotFoundException {
- CacheLoaderConfig clc = new CacheLoaderConfig();
- // TODO change this to use a dummy in memory cache loaderold instead!!
- FileCacheLoaderConfig fc = new FileCacheLoaderConfig();
- fc.setLocation("/tmp");
- clc.addIndividualCacheLoaderConfig(fc);
+ EvictionConfig ec = new EvictionConfig();
+ ec.setAlgorithmConfig(new FIFOAlgorithmConfig());
Configuration defaultCfg = new Configuration();
defaultCfg.setCacheMode(Configuration.CacheMode.REPL_SYNC);
- defaultCfg.setCacheLoaderConfig(clc);
+ defaultCfg.setEvictionConfig(ec);
// cache manager with default configuration
cm = new DefaultCacheManager(GlobalConfiguration.getClusteredDefault(), defaultCfg);
@@ -78,9 +75,9 @@
Cache transactional = cm.getCache("transactional");
// assert components.
- assert TestingUtil.extractComponent(c, CacheLoaderManager.class) != null;
- assert TestingUtil.extractComponent(transactional, CacheLoaderManager.class) != null;
- assert TestingUtil.extractComponent(c, CacheLoaderManager.class) != TestingUtil.extractComponent(transactional, CacheLoaderManager.class);
+ assert TestingUtil.extractComponent(c, EvictionManager.class) != null;
+ assert TestingUtil.extractComponent(transactional, EvictionManager.class) != null;
+ assert TestingUtil.extractComponent(c, EvictionManager.class) != TestingUtil.extractComponent(transactional, EvictionManager.class);
}
public void testOverridingComponents() throws NamedCacheNotFoundException {
Modified: core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerCacheLoaderTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerCacheLoaderTest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerCacheLoaderTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -17,7 +17,7 @@
// c.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
// c.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
//
-// CacheLoaderConfig clc = new CacheLoaderConfig();
+// CacheLoaderManagerConfig clc = new CacheLoaderManagerConfig();
// IndividualCacheLoaderConfig iclc = new IndividualCacheLoaderConfig();
// iclc.setClassName(DummyInMemoryCacheLoader.class.getName());
// clc.addIndividualCacheLoaderConfig(iclc);
Modified: core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerPassivationTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerPassivationTest.java 2009-02-11 06:00:34 UTC (rev 7678)
+++ core/branches/flat/src/test/java/org/horizon/notifications/CacheListenerPassivationTest.java 2009-02-11 09:52:13 UTC (rev 7679)
@@ -17,7 +17,7 @@
// c.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
// c.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
//
-// CacheLoaderConfig clc = new CacheLoaderConfig();
+// CacheLoaderManagerConfig clc = new CacheLoaderManagerConfig();
// IndividualCacheLoaderConfig iclc = new IndividualCacheLoaderConfig();
// iclc.setClassName(DummyInMemoryCacheLoader.class.getName());
// clc.addIndividualCacheLoaderConfig(iclc);
15 years, 11 months
JBoss Cache SVN: r7678 - in core/trunk/src: main/java/org/jboss/cache/factories and 5 other directories.
by jbosscache-commits@lists.jboss.org
Author: jason.greene(a)jboss.com
Date: 2009-02-11 01:00:34 -0500 (Wed, 11 Feb 2009)
New Revision: 7678
Added:
core/trunk/src/main/java/org/jboss/cache/marshall/ExtendedResponse.java
core/trunk/src/main/java/org/jboss/cache/marshall/RequestIgnoredResponse.java
Modified:
core/trunk/src/main/java/org/jboss/cache/RPCManager.java
core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
core/trunk/src/main/java/org/jboss/cache/marshall/CacheMarshaller200.java
core/trunk/src/main/java/org/jboss/cache/marshall/CommandAwareRpcDispatcher.java
core/trunk/src/main/java/org/jboss/cache/marshall/InactiveRegionAwareRpcDispatcher.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java
core/trunk/src/main/java/org/jboss/cache/transaction/TransactionLog.java
core/trunk/src/test/java/org/jboss/cache/statetransfer/NonBlockingStateTransferTest.java
core/trunk/src/test/java/org/jboss/cache/transaction/PrepareCommitContentionTest.java
Log:
Eliminate known race conditions in NBST
Modified: core/trunk/src/main/java/org/jboss/cache/RPCManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManager.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManager.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -21,16 +21,16 @@
*/
package org.jboss.cache;
+import java.util.List;
+import java.util.Vector;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.jboss.cache.RPCManagerImpl.FlushTracker;
import org.jboss.cache.commands.ReplicableCommand;
-import org.jboss.cache.lock.TimeoutException;
import org.jgroups.Address;
import org.jgroups.Channel;
import org.jgroups.blocks.RspFilter;
-import java.util.List;
-import java.util.Vector;
-import java.util.concurrent.TimeUnit;
-
/**
* Provides a mechanism for communicating with other caches in the cluster. For now this is based on JGroups as an underlying
* transport, and in future more transport options may become available.
@@ -153,7 +153,17 @@
*/
Channel getChannel();
- public void waitForFlush(long timeout);
+ /**
+ * Returns the last state transfer source address.
+ *
+ * @return the last state transfer source address
+ */
+ public Address getLastStateTransferSource();
- public Address getLastStateTransferSource();
+ /**
+ * Returns the flush tracker associated with this manager.
+ *
+ * @return the current flush tracker
+ */
+ public FlushTracker getFlushTracker();
}
Modified: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -21,12 +21,29 @@
*/
package org.jboss.cache;
+import java.net.URL;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+import javax.transaction.TransactionManager;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.commands.ReplicableCommand;
import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.RuntimeConfig;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
-import org.jboss.cache.config.RuntimeConfig;
import org.jboss.cache.factories.ComponentRegistry;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.Start;
@@ -65,18 +82,6 @@
import org.jgroups.util.Rsp;
import org.jgroups.util.RspList;
-import javax.transaction.TransactionManager;
-import java.net.URL;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-import java.util.concurrent.TimeUnit;
-
/**
* Manager that handles all RPC calls between JBoss Cache instances
*
@@ -97,17 +102,8 @@
* True if this Cache is the coordinator.
*/
private volatile boolean coordinator = false;
- /**
- * Thread gate used to block Dispatcher during JGroups FLUSH protocol
- */
- private final ReclosableLatch flushBlockGate = new ReclosableLatch();
/**
- * Thread gate used by NBST to wait for a flush
- */
- private final ReclosableLatch flushWaitGate = new ReclosableLatch(false);
-
- /**
* The most recent state transfer source
*/
volatile Address lastStateTransferSource;
@@ -135,7 +131,9 @@
private volatile boolean isInLocalMode;
private ComponentRegistry componentRegistry;
private LockManager lockManager;
+ private FlushTracker flushTracker = new FlushTracker();
+
@Inject
public void setupDependencies(ChannelMessageListener messageListener, Configuration configuration, Notifier notifier,
CacheSPI spi, Marshaller marshaller, TransactionTable txTable,
@@ -155,6 +153,129 @@
this.lockManager = lockManager;
}
+ public class FlushTracker
+ {
+ private final ReclosableLatch flushBlockGate = new ReclosableLatch();
+ private final AtomicInteger flushCompletionCount = new AtomicInteger();
+ private final ReentrantReadWriteLock coordinationLock = new ReentrantReadWriteLock();
+ private final ReclosableLatch flushWaitGate = new ReclosableLatch(false);
+
+ public void block()
+ {
+ flushBlockGate.close();
+ flushWaitGate.open();
+ }
+
+ public void unblock()
+ {
+ flushWaitGate.close();
+ flushCompletionCount.incrementAndGet();
+ flushBlockGate.open();
+ }
+
+ public int getFlushCompletionCount()
+ {
+ return flushCompletionCount.get();
+ }
+
+ public void lockProcessingLock()
+ {
+ if (! configuration.isNonBlockingStateTransfer())
+ return;
+
+ for (;;)
+ {
+ try
+ {
+ if (!coordinationLock.readLock().tryLock(configuration.getStateRetrievalTimeout(), TimeUnit.MILLISECONDS))
+ throw new TimeoutException("Could not obtain processing lock");
+
+ return;
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void unlockProcessingLock()
+ {
+ if (! configuration.isNonBlockingStateTransfer())
+ return;
+
+ coordinationLock.readLock().unlock();
+ }
+
+ public void lockSuspendProcessingLock()
+ {
+ if (! configuration.isNonBlockingStateTransfer())
+ return;
+
+ for (;;)
+ {
+ try
+ {
+ if (!coordinationLock.writeLock().tryLock(configuration.getStateRetrievalTimeout(), TimeUnit.MILLISECONDS))
+ throw new TimeoutException("Could not obtain processing lock");
+
+ return;
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void unlockSuspendProcessingLock()
+ {
+ if (! configuration.isNonBlockingStateTransfer())
+ return;
+
+ if (coordinationLock.isWriteLockedByCurrentThread())
+ coordinationLock.writeLock().unlock();
+ }
+
+ public void waitForFlushCompletion(long timeout)
+ {
+ for (; ;)
+ {
+ try
+ {
+ if (channel.flushSupported() && !flushBlockGate.await(timeout, TimeUnit.MILLISECONDS))
+ {
+ throw new TimeoutException("State retrieval timed out waiting for flush to block. (timeout = " + timeout + " millis) ");
+ }
+ return;
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void waitForFlushStart(long timeout)
+ {
+ for (; ;)
+ {
+ try
+ {
+ if (channel.flushSupported() && !flushWaitGate.await(timeout, TimeUnit.MILLISECONDS))
+ {
+ throw new TimeoutException("State retrieval timed out waiting for flush to block. (timeout = " + timeout + " millis) ");
+ }
+ return;
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
// ------------ START: Lifecycle methods ------------
@Start(priority = 15)
@@ -243,9 +364,9 @@
}
}
- if (log.isDebugEnabled())
+ if (log.isInfoEnabled())
{
- log.debug("state was retrieved successfully (in " + (System.currentTimeMillis() - start) + " milliseconds)");
+ log.info("state was retrieved successfully (in " + (System.currentTimeMillis() - start) + " milliseconds)");
}
}
@@ -273,9 +394,9 @@
try
{
- if (log.isTraceEnabled())
+ if (log.isInfoEnabled())
{
- log.trace("Trying to fetch state from: " + member);
+ log.info("Trying to fetch state from: " + member);
}
if (getState(null, member))
{
@@ -286,18 +407,18 @@
}
catch (Exception e)
{
- if (log.isTraceEnabled())
+ if (log.isDebugEnabled())
{
- log.trace("Error while fetching state", e);
+ log.debug("Error while fetching state", e);
}
}
}
if (!success)
{
- if (trace)
+ if (log.isWarnEnabled())
{
- log.trace("Could not find available peer for state, backing off and retrying");
+ log.warn("Could not find available peer for state, backing off and retrying");
}
try
@@ -428,12 +549,12 @@
if (configuration.isUseRegionBasedMarshalling())
{
rpcDispatcher = new InactiveRegionAwareRpcDispatcher(channel, messageListener, new MembershipListenerAdaptor(),
- spi, invocationContextContainer, interceptorChain, componentRegistry, flushBlockGate);
+ spi, invocationContextContainer, interceptorChain, componentRegistry, this);
}
else
{
rpcDispatcher = new CommandAwareRpcDispatcher(channel, messageListener, new MembershipListenerAdaptor(),
- invocationContextContainer, invocationContextContainer, interceptorChain, componentRegistry, flushBlockGate);
+ invocationContextContainer, invocationContextContainer, interceptorChain, componentRegistry, this);
}
checkAppropriateConfig();
rpcDispatcher.setRequestMarshaller(marshaller);
@@ -552,6 +673,7 @@
public List<Object> callRemoteMethods(Vector<Address> recipients, ReplicableCommand command, int mode, long timeout, RspFilter responseFilter, boolean useOutOfBandMessage) throws Exception
{
boolean success = true;
+ boolean unlock = false;
try
{
// short circuit if we don't have an RpcDispatcher!
@@ -566,10 +688,11 @@
{
log.trace("callRemoteMethods(): valid members are " + recipients + " methods: " + command + " Using OOB? " + useOutOfBandMessage + " modeToUse: " + modeToUse);
}
- if (channel.flushSupported() && !flushBlockGate.await(configuration.getStateRetrievalTimeout(), TimeUnit.MILLISECONDS))
- {
- throw new TimeoutException("State retrieval timed out waiting for flush unblock. (timeout = " + configuration.getStateRetrievalTimeout() + " millis) ");
- }
+
+ flushTracker.lockProcessingLock();
+ unlock = true;
+ flushTracker.waitForFlushCompletion(configuration.getStateRetrievalTimeout());
+
useOutOfBandMessage = false;
RspList rsps = rpcDispatcher.invokeRemoteCommands(recipients, command, modeToUse, timeout, isUsingBuddyReplication, useOutOfBandMessage, responseFilter);
if (mode == GroupRequest.GET_NONE) return Collections.emptyList();// async case
@@ -619,6 +742,8 @@
finally
{
computeStats(success);
+ if (unlock)
+ flushTracker.unlockProcessingLock();
}
}
@@ -722,24 +847,6 @@
return ((JChannel) channel).getState(target, stateId, configuration.getStateRetrievalTimeout(), !configuration.isNonBlockingStateTransfer());
}
- public void waitForFlush(long timeout)
- {
- for (; ;)
- {
- try
- {
- if (channel.flushSupported() && !flushWaitGate.await(timeout, TimeUnit.MILLISECONDS))
- {
- throw new TimeoutException("State retrieval timed out waiting for flush to block. (timeout = " + timeout + " millis) ");
- }
- return;
- }
- catch (InterruptedException e)
- {
- Thread.currentThread().interrupt();
- }
- }
- }
// ------------ END: Partial state transfer methods ------------
@@ -895,9 +1002,9 @@
{
try
{
- flushBlockGate.close();
- flushWaitGate.open();
if (log.isDebugEnabled()) log.debug("Block received at " + getLocalAddress());
+
+ flushTracker.block();
notifier.notifyCacheBlocked(true);
notifier.notifyCacheBlocked(false);
@@ -917,14 +1024,13 @@
{
try
{
- flushWaitGate.close();
if (log.isDebugEnabled()) log.debug("UnBlock received at " + getLocalAddress());
notifier.notifyCacheUnblocked(true);
notifier.notifyCacheUnblocked(false);
+ flushTracker.unblock();
if (log.isDebugEnabled()) log.debug("UnBlock processed at " + getLocalAddress());
- flushBlockGate.open();
}
catch (Throwable e)
{
@@ -1034,4 +1140,9 @@
}
}
}
+
+ public FlushTracker getFlushTracker()
+ {
+ return flushTracker;
+ }
}
Modified: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -93,7 +93,7 @@
// component and method containers
final Map<String, Component> componentLookup = new HashMap<String, Component>();
- CacheStatus state = CacheStatus.INSTANTIATED;
+ volatile CacheStatus state = CacheStatus.INSTANTIATED;
/**
* Hook to shut down the cache when the JVM exits.
@@ -899,10 +899,11 @@
Thread.currentThread().interrupt();
}
}
- else
+ else if (blockInStarting)
{
log.warn("Received a remote call but the cache is not in STARTED state - ignoring call.");
}
+
return false;
}
Modified: core/trunk/src/main/java/org/jboss/cache/marshall/CacheMarshaller200.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/CacheMarshaller200.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/CacheMarshaller200.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -38,6 +38,7 @@
import java.util.TreeMap;
import java.util.TreeSet;
+import org.apache.commons.httpclient.cookie.IgnoreCookiesSpec;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.Region;
@@ -93,6 +94,8 @@
protected static final int MAGICNUMBER_DOUBLE = 28;
protected static final int MAGICNUMBER_OBJECT = 29;
protected static final int MAGICNUMBER_TXLOG_ENTRY = 50;
+ protected static final int MAGICNUMBER_REQUEST_IGNORED_RESPONSE = 51;
+ protected static final int MAGICNUMBER_EXTENDED_RESPONSE = 52;
protected static final int MAGICNUMBER_NULL = 99;
protected static final int MAGICNUMBER_SERIALIZABLE = 100;
protected static final int MAGICNUMBER_REF = 101;
@@ -448,6 +451,15 @@
out.writeByte(MAGICNUMBER_GRAVITATERESULT);
marshallGravitateResult((GravitateResult) o, out, refMap);
}
+ else if (o instanceof RequestIgnoredResponse)
+ {
+ out.writeByte(MAGICNUMBER_REQUEST_IGNORED_RESPONSE);
+ }
+ else if (o instanceof ExtendedResponse)
+ {
+ out.writeByte(MAGICNUMBER_EXTENDED_RESPONSE);
+ marshallExtendedResponse((ExtendedResponse)o, out, refMap);
+ }
else if (o instanceof Serializable)
{
if (trace)
@@ -464,6 +476,12 @@
}
}
+ private void marshallExtendedResponse(ExtendedResponse response, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
+ {
+ out.writeBoolean(response.isReplayIgnoredRequests());
+ marshallObject(response.getResponse(), out, refMap);
+ }
+
private void marshallLogEntry(LogEntry log, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
{
marshallObject(log.getTransaction(), out, refMap);
@@ -673,6 +691,10 @@
return retVal;
case MAGICNUMBER_GRAVITATERESULT:
return unmarshallGravitateResult(in, refMap);
+ case MAGICNUMBER_REQUEST_IGNORED_RESPONSE:
+ return new RequestIgnoredResponse();
+ case MAGICNUMBER_EXTENDED_RESPONSE:
+ return unmarshallExtendedResponse(in, refMap);
default:
if (log.isErrorEnabled())
{
@@ -683,8 +705,17 @@
throw new Exception("Unknown magic number " + magicNumber);
}
+ private ExtendedResponse unmarshallExtendedResponse(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+ {
+ boolean replayIgnoredRequests = in.readBoolean();
+ ExtendedResponse response = new ExtendedResponse(unmarshallObject(in, refMap));
+ response.setReplayIgnoredRequests(replayIgnoredRequests);
+
+ return response;
+ }
+
@SuppressWarnings("unchecked")
- private Object unmarshallLogEntry(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+ private LogEntry unmarshallLogEntry(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
{
GlobalTransaction gtx = (GlobalTransaction)unmarshallObject(in, refMap);
List<WriteCommand> mods = (List<WriteCommand>)unmarshallObject(in, refMap);
Modified: core/trunk/src/main/java/org/jboss/cache/marshall/CommandAwareRpcDispatcher.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/CommandAwareRpcDispatcher.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/CommandAwareRpcDispatcher.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -22,16 +22,21 @@
package org.jboss.cache.marshall;
import java.io.NotSerializableException;
+import java.util.Map;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jboss.cache.InvocationContext;
+import org.jboss.cache.RPCManager;
+import org.jboss.cache.RPCManagerImpl.FlushTracker;
import org.jboss.cache.commands.ReplicableCommand;
import org.jboss.cache.commands.VisitableCommand;
import org.jboss.cache.commands.remote.AnnounceBuddyPoolNameCommand;
@@ -50,6 +55,7 @@
import org.jgroups.MembershipListener;
import org.jgroups.Message;
import org.jgroups.MessageListener;
+import org.jgroups.blocks.GroupRequest;
import org.jgroups.blocks.RpcDispatcher;
import org.jgroups.blocks.RspFilter;
import org.jgroups.util.Buffer;
@@ -72,20 +78,20 @@
private AtomicInteger replicationProcessorCount;
private boolean asyncSerial;
private Configuration configuration;
- private ReclosableLatch flushGate;
+ private RPCManager rpcManager;
private ReplicationObserver replicationObserver;
public CommandAwareRpcDispatcher() {}
public CommandAwareRpcDispatcher(Channel channel, MessageListener l, MembershipListener l2,
Object serverObj, InvocationContextContainer container, InterceptorChain interceptorChain,
- ComponentRegistry componentRegistry, ReclosableLatch flushGate)
+ ComponentRegistry componentRegistry, RPCManager manager)
{
super(channel, l, l2, serverObj);
this.invocationContextContainer = container;
this.componentRegistry = componentRegistry;
this.interceptorChain = interceptorChain;
- this.flushGate = flushGate;
+ this.rpcManager = manager;
trace = log.isTraceEnabled();
@@ -198,7 +204,8 @@
log.trace(new StringBuilder("dests=").append(dests).append(", command=").append(command).
append(", mode=").append(mode).append(", timeout=").append(timeout));
- ReplicationTask replicationTask = new ReplicationTask(command, oob, dests, mode, timeout, anycasting, filter);
+ boolean supportReplay = configuration.isNonBlockingStateTransfer();
+ ReplicationTask replicationTask = new ReplicationTask(command, oob, dests, mode, timeout, anycasting, supportReplay, filter);
Future<RspList> response = replicationProcessor.submit(replicationTask);
if (asyncSerial)
{
@@ -253,25 +260,41 @@
protected Object executeCommand(ReplicableCommand cmd, Message req) throws Throwable
{
+ boolean unlock = false;
+ FlushTracker flushTracker = rpcManager.getFlushTracker();
+
try
{
if (cmd == null) throw new NullPointerException("Unable to execute a null command! Message was " + req);
if (trace) log.trace("Executing command: " + cmd + " [sender=" + req.getSrc() + "]");
- if (channel.flushSupported() && !flushGate.await(configuration.getStateRetrievalTimeout(), TimeUnit.MILLISECONDS))
+ boolean replayIgnored = false;
+
+
+ if (configuration.isNonBlockingStateTransfer())
{
- throw new TimeoutException("State retrieval timed out waiting for flush unblock. (timeout = " + configuration.getStateRetrievalTimeout() + " millis) ");
+ int flushCount = flushTracker.getFlushCompletionCount();
+ flushTracker.lockProcessingLock();
+ unlock = true;
+
+ flushTracker.waitForFlushCompletion(configuration.getStateRetrievalTimeout());
+
+ // If this thread blocked during a NBST flush, then inform the sender
+ // it needs to replay ignored messages
+ replayIgnored = flushTracker.getFlushCompletionCount() != flushCount;
}
+ Object ret;
+
if (cmd instanceof VisitableCommand)
{
InvocationContext ctx = invocationContextContainer.get();
ctx.setOriginLocal(false);
if (!componentRegistry.invocationsAllowed(false))
{
- return null;
+ return new RequestIgnoredResponse();
}
- return interceptorChain.invoke(ctx, (VisitableCommand) cmd);
+ ret = interceptorChain.invoke(ctx, (VisitableCommand) cmd);
}
else
{
@@ -283,15 +306,27 @@
cmd instanceof RemoveFromBuddyGroupCommand)
&& !componentRegistry.invocationsAllowed(false))
{
- return null;
+ return new RequestIgnoredResponse();
}
- return cmd.perform(null);
+ ret = cmd.perform(null);
}
+
+ if (replayIgnored)
+ {
+ ExtendedResponse extended = new ExtendedResponse(ret);
+ extended.setReplayIgnoredRequests(true);
+ ret = extended;
+ }
+
+ return ret;
}
finally
{
if (replicationObserver != null)
replicationObserver.afterExecutingCommand(cmd);
+
+ if (unlock)
+ flushTracker.unlockProcessingLock();
}
}
@@ -309,9 +344,10 @@
private int mode;
private long timeout;
private boolean anycasting;
+ private boolean supportReplay;
private RspFilter filter;
- private ReplicationTask(ReplicableCommand command, boolean oob, Vector<Address> dests, int mode, long timeout, boolean anycasting, RspFilter filter)
+ private ReplicationTask(ReplicableCommand command, boolean oob, Vector<Address> dests, int mode, long timeout, boolean anycasting, boolean supportReplay, RspFilter filter)
{
this.command = command;
this.oob = oob;
@@ -319,6 +355,7 @@
this.mode = mode;
this.timeout = timeout;
this.anycasting = anycasting;
+ this.supportReplay = supportReplay;
this.filter = filter;
}
@@ -338,6 +375,9 @@
Message msg = new Message();
msg.setBuffer(buf);
if (oob) msg.setFlag(Message.OOB);
+
+ // Replay capability requires responses from all members!
+ int mode = supportReplay ? GroupRequest.GET_ALL : this.mode;
RspList retval = castMessage(dests, msg, mode, timeout, anycasting, filter);
if (trace) log.trace("responses: " + retval);
@@ -347,6 +387,36 @@
if (retval == null)
throw new NotSerializableException("RpcDispatcher returned a null. This is most often caused by args for " + command.getClass().getSimpleName() + " not being serializable.");
+
+ if (supportReplay)
+ {
+ boolean replay = false;
+ Vector<Address> ignorers = new Vector<Address>();
+ for (Map.Entry<Address, Rsp> entry : retval.entrySet())
+ {
+ Object value = entry.getValue().getValue();
+ if (value instanceof RequestIgnoredResponse)
+ {
+ ignorers.add(entry.getKey());
+ }
+ else if (value instanceof ExtendedResponse)
+ {
+ ExtendedResponse extended = (ExtendedResponse) value;
+ replay |= extended.isReplayIgnoredRequests();
+ entry.getValue().setValue(extended.getResponse());
+ }
+ }
+
+ if (replay && ignorers.size() > 0)
+ {
+ if (trace)
+ log.trace("Replaying message to ignoring senders: " + ignorers);
+ RspList responses = castMessage(ignorers, msg, GroupRequest.GET_ALL, timeout, anycasting, filter);
+ if (responses != null)
+ retval.putAll(responses);
+ }
+ }
+
return retval;
}
}
Added: core/trunk/src/main/java/org/jboss/cache/marshall/ExtendedResponse.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/ExtendedResponse.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/ExtendedResponse.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -0,0 +1,53 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This 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 software 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 software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.cache.marshall;
+
+/**
+ * A response with extended information
+ *
+ * @author Jason T. Greene
+ */
+public class ExtendedResponse
+{
+ private boolean replayIgnoredRequests;
+ private final Object response;
+
+ public ExtendedResponse(Object response)
+ {
+ this.response = response;
+ }
+
+ public boolean isReplayIgnoredRequests()
+ {
+ return replayIgnoredRequests;
+ }
+
+ public void setReplayIgnoredRequests(boolean replayIgnoredRequests)
+ {
+ this.replayIgnoredRequests = replayIgnoredRequests;
+ }
+
+ public Object getResponse()
+ {
+ return response;
+ }
+}
Property changes on: core/trunk/src/main/java/org/jboss/cache/marshall/ExtendedResponse.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: core/trunk/src/main/java/org/jboss/cache/marshall/InactiveRegionAwareRpcDispatcher.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/InactiveRegionAwareRpcDispatcher.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/InactiveRegionAwareRpcDispatcher.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -21,6 +21,7 @@
*/
package org.jboss.cache.marshall;
+import org.jboss.cache.RPCManager;
import org.jboss.cache.commands.ReplicableCommand;
import org.jboss.cache.factories.ComponentRegistry;
import org.jboss.cache.interceptors.InterceptorChain;
@@ -47,9 +48,9 @@
*/
public InactiveRegionAwareRpcDispatcher(Channel channel, MessageListener l, MembershipListener l2, Object serverObj,
InvocationContextContainer container, InterceptorChain interceptorChain,
- ComponentRegistry componentRegistry, ReclosableLatch flushBlockGate)
+ ComponentRegistry componentRegistry, RPCManager manager)
{
- super(channel, l, l2, serverObj, container, interceptorChain, componentRegistry, flushBlockGate);
+ super(channel, l, l2, serverObj, container, interceptorChain, componentRegistry, manager);
}
@Override
Added: core/trunk/src/main/java/org/jboss/cache/marshall/RequestIgnoredResponse.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/RequestIgnoredResponse.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/RequestIgnoredResponse.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -0,0 +1,32 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This 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 software 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 software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.cache.marshall;
+
+/**
+ * Indicates that the request was ignored,
+ *
+ * @author Jason T. Greene
+ */
+public class RequestIgnoredResponse
+{
+
+}
Property changes on: core/trunk/src/main/java/org/jboss/cache/marshall/RequestIgnoredResponse.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -26,6 +26,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -36,6 +37,7 @@
import org.jboss.cache.Node;
import org.jboss.cache.RPCManager;
import org.jboss.cache.Version;
+import org.jboss.cache.RPCManagerImpl.FlushTracker;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.Start;
@@ -136,68 +138,93 @@
CacheLoader cacheLoader = cache.getCacheLoaderManager() == null ? null : cache.getCacheLoaderManager().getCacheLoader();
if (cacheLoader != null && generatePersistent)
{
- if (log.isTraceEnabled())
- {
- log.trace("writing persistent state for " + fqn + ",using " + cache.getCacheLoaderManager().getCacheLoader().getClass());
- }
-
- if (fqn.isRoot())
- {
- cacheLoader.loadEntireState(out);
- }
- else
- {
- cacheLoader.loadState(fqn, out);
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("persistent state succesfully written");
- }
+ writePersistentData(out, fqn, cacheLoader);
}
delimitStream(out);
if (nonBlocking && generateTransient)
{
- for (int nonProgress = 0, size = txLog.size(); size > 0;)
- {
- if (log.isTraceEnabled())
- log.trace("Tx Log remaining entries = " + size);
- txLog.writeCommitLog(cache.getMarshaller(), out);
- int newSize = txLog.size();
+ writeTxLog(out);
+ }
- // If size did not decrease then we did not make progress, and could be wasting
- // our time. Limit this to the specified max.
- if (newSize >= size && ++nonProgress >= maxNonProgressingLogWrites)
- break;
+ }
+ catch (Exception e)
+ {
+ cache.getMarshaller().objectToObjectStream(new NodeDataExceptionMarker(e, cache.getLocalAddress()), out);
+ throw e;
+ }
+ finally
+ {
+ if (nonBlocking)
+ txLog.deactivate();
+ }
+ }
- size = newSize;
- }
+ private void writePersistentData(ObjectOutputStream out, Fqn fqn, CacheLoader cacheLoader) throws Exception
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("writing persistent state for " + fqn + ",using " + cache.getCacheLoaderManager().getCacheLoader().getClass());
+ }
- // Signal to sender that we need a flush to get a consistent view
- // of the remaining transactions.
- delimitStream(out);
- out.flush();
- rpcManager.waitForFlush(flushTimeout);
+ if (fqn.isRoot())
+ {
+ cacheLoader.loadEntireState(out);
+ }
+ else
+ {
+ cacheLoader.loadState(fqn, out);
+ }
- // Write remaining transactions
+ if (log.isTraceEnabled())
+ {
+ log.trace("persistent state succesfully written");
+ }
+ }
+
+ private void writeTxLog(ObjectOutputStream out) throws Exception
+ {
+ FlushTracker flushTracker = rpcManager.getFlushTracker();
+
+ try
+ {
+ for (int nonProgress = 0, size = txLog.size(); size > 0;)
+ {
+ if (log.isTraceEnabled())
+ log.trace("Tx Log remaining entries = " + size);
txLog.writeCommitLog(cache.getMarshaller(), out);
- delimitStream(out);
+ int newSize = txLog.size();
- // Write all non-completed prepares
- txLog.writePendingPrepares(cache.getMarshaller(), out);
- delimitStream(out);
+ // If size did not decrease then we did not make progress, and could be wasting
+ // our time. Limit this to the specified max.
+ if (newSize >= size && ++nonProgress >= maxNonProgressingLogWrites)
+ break;
+
+ size = newSize;
}
+ // Wait on incoming and outgoing threads to line-up in front of
+ // the flush gate.
+ flushTracker.lockSuspendProcessingLock();
+
+ // Signal to sender that we need a flush to get a consistent view
+ // of the remaining transactions.
+ delimitStream(out);
+ out.flush();
+ flushTracker.waitForFlushStart(flushTimeout);
+
+ // Write remaining transactions
+ txLog.writeCommitLog(cache.getMarshaller(), out);
+ delimitStream(out);
+
+ // Write all non-completed prepares
+ txLog.writePendingPrepares(cache.getMarshaller(), out);
+ delimitStream(out);
+ out.flush();
}
- catch (Exception e)
- {
- cache.getMarshaller().objectToObjectStream(new NodeDataExceptionMarker(e, cache.getLocalAddress()), out);
- throw e;
- }
finally
{
- txLog.deactivate();
+ flushTracker.unlockSuspendProcessingLock();
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -230,6 +230,10 @@
notifyAllNodesCreated(cache.getInvocationContext(), target);
}
+ catch (CacheException ce)
+ {
+ throw ce;
+ }
catch (Exception e)
{
throw new CacheException(e);
@@ -387,6 +391,14 @@
private List<NodeData> readNodesAsList(ObjectInputStream in) throws Exception
{
Object obj = cache.getMarshaller().objectFromObjectStream(in);
+ if (obj instanceof NodeDataExceptionMarker)
+ {
+ Throwable cause = ((NodeDataExceptionMarker)obj).getCause();
+ if (cause instanceof Exception)
+ throw (Exception) cause;
+
+ throw new CacheException(cause);
+ }
if (obj instanceof NodeDataMarker) return null;
return (List<NodeData>) obj;
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/TransactionLog.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/TransactionLog.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/TransactionLog.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -69,7 +69,7 @@
}
}
- private Log log = LogFactory.getLog(getClass().getName());
+ private static Log log = LogFactory.getLog(TransactionLog.class);
public void logPrepare(PrepareCommand command)
{
@@ -145,6 +145,8 @@
public void deactivate()
{
active.set(false);
+ if (entries.size() > 0)
+ log.error("Unprocessed Transaction Log Entries! = " + entries.size());
entries.clear();
}
Modified: core/trunk/src/test/java/org/jboss/cache/statetransfer/NonBlockingStateTransferTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/statetransfer/NonBlockingStateTransferTest.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/test/java/org/jboss/cache/statetransfer/NonBlockingStateTransferTest.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -13,11 +13,10 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.List;
-import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
@@ -27,7 +26,6 @@
import org.jboss.cache.factories.UnitTestConfigurationFactory;
import org.jboss.cache.util.TestingUtil;
import org.testng.annotations.Test;
-import org.testng.annotations.AfterMethod;
@Test(groups="functional", testName = "statetransfer.NonBlockingStateTransferTest")
public class NonBlockingStateTransferTest
@@ -46,17 +44,9 @@
public static final Integer TWENTY = 20;
public static final Integer FORTY = 40;
- private List<Cache> createdCaches = new ArrayList<Cache>();
+ private volatile int testCount = 0;
- @AfterMethod
- public void clearCaches()
- {
- for (Cache c : createdCaches)
- {
- TestingUtil.killCaches(c);
- }
- createdCaches.clear();
- }
+ private static final Log log = LogFactory.getLog(NonBlockingStateTransferTest.class);
public static class DelayTransfer implements Serializable
{
@@ -121,6 +111,8 @@
}
catch (Exception e)
{
+ e.printStackTrace();
+ log.error(e);
}
}
result = c;
@@ -134,84 +126,170 @@
private CacheSPI<Object, Object> createCache(String name)
{
+ return createCache(name, true);
+
+ }
+
+ private CacheSPI<Object, Object> createCache(String name, boolean start)
+ {
Configuration config = UnitTestConfigurationFactory.createConfiguration(CacheMode.REPL_SYNC);
+ config.setSyncCommitPhase(true);
config.setClusterName(name + "-" + Thread.currentThread().getName());
config.setNonBlockingStateTransfer(true);
+ config.setSyncReplTimeout(30000);
CacheSPI<Object, Object> cache = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(config, false, getClass());
- // Use marshaller
-
cache.create();
- cache.start();
- createdCaches.add(cache);
+ if (start)
+ cache.start();
return cache;
-
}
public void testInitialStateTransfer() throws Exception
{
- CacheSPI<Object, Object> cache1 = createCache("nbst");
+ testCount++;
+ log.info("testInitialStateTransfer start - " + testCount);
+ CacheSPI<Object, Object> cache1 = null, cache2 = null;
+ try
+ {
+ cache1 = createCache("nbst");
+ writeInitialData(cache1);
- writeInitialData(cache1);
+ cache2 = createCache("nbst");
- CacheSPI<Object, Object> cache2 = createCache("nbst");
+ // Pause to give caches time to see each other
+ TestingUtil.blockUntilViewsReceived(new CacheSPI[] { cache1, cache2 }, 60000);
- // Pause to give caches time to see each other
- TestingUtil.blockUntilViewsReceived(new CacheSPI[]{cache1, cache2}, 60000);
+ verifyInitialData(cache2);
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache1, cache2);
+ }
+ log.info("testInitialStateTransfer end - " + testCount);
+ }
- verifyInitialData(cache2);
+ public void testConcurrentStateTransfer() throws Exception
+ {
+ testCount++;
+ log.info("testConcurrentStateTransfer start - " + testCount);
+ CacheSPI<Object, Object> cache1 = null, cache2 = null, cache3 = null, cache4 = null;
+ try
+ {
+ cache1 = createCache("nbst");
+ writeInitialData(cache1);
+
+ cache2 = createCache("nbst");
+
+ cache1.put("/delay", "delay", new DelayTransfer());
+
+ // Pause to give caches time to see each other
+ TestingUtil.blockUntilViewsReceived(new CacheSPI[] { cache1, cache2 }, 60000);
+ verifyInitialData(cache2);
+
+ final CacheSPI<Object, Object >c3 = cache3 = createCache("nbst", false);
+ final CacheSPI<Object, Object >c4 = cache4 = createCache("nbst", false);
+
+ Thread t1 = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ c3.start();
+ }
+ });
+ t1.start();
+
+ Thread t2 = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ c4.start();
+ }
+ });
+ t2.start();
+
+ t1.join();
+ t2.join();
+
+ TestingUtil.blockUntilViewsReceived(new CacheSPI[] { cache1, cache2, cache3, cache4 }, 60000);
+ verifyInitialData(cache3);
+ verifyInitialData(cache4);
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache1, cache2, cache3, cache4);
+ }
+ log.info("testConcurrentStateTransfer end - " + testCount);
}
-
public void testSTWithThirdWritingNonTxCache() throws Exception
{
+ testCount++;
+ log.info("testSTWithThirdWritingNonTxCache start - " + testCount);
thirdWritingCacheTest(false, "nbst1");
+ log.info("testSTWithThirdWritingNonTxCache end - " + testCount);
}
public void testSTWithThirdWritingTxCache() throws Exception
{
+ testCount++;
+ log.info("testSTWithThirdWritingTxCache start - " + testCount);
thirdWritingCacheTest(true, "nbst2");
+ log.info("testSTWithThirdWritingTxCache end - " + testCount);
}
public void testSTWithWritingNonTxThread() throws Exception
{
+ testCount++;
+ log.info("testSTWithWritingNonTxThread start - " + testCount);
writingThreadTest(false, "nbst3");
+ log.info("testSTWithWritingNonTxThread end - " + testCount);
}
public void testSTWithWritingTxThread() throws Exception
{
+ testCount++;
+ log.info("testSTWithWritingTxThread start - " + testCount);
writingThreadTest(true, "nbst4");
+ log.info("testSTWithWritingTxThread end - " + testCount);
}
-
private void thirdWritingCacheTest(boolean tx, String name) throws InterruptedException
{
- final CacheSPI<Object, Object> cache1 = createCache(name);
- final CacheSPI<Object, Object> cache3 = createCache(name);
+ CacheSPI<Object, Object> cache1 = null, cache2 = null, cache3 = null;
+ try
+ {
+ cache1 = createCache(name);
+ cache3 = createCache(name);
- writeInitialData(cache1);
+ writeInitialData(cache1);
- // Delay the transient copy, so that we get a more thorough log test
- cache1.put("/delay", "delay", new DelayTransfer());
+ // Delay the transient copy, so that we get a more thorough log test
+ cache1.put("/delay", "delay", new DelayTransfer());
- WritingRunner writer = new WritingRunner(cache3, tx);
- Thread writerThread = new Thread(writer);
- writerThread.start();
+ WritingRunner writer = new WritingRunner(cache3, tx);
+ Thread writerThread = new Thread(writer);
+ writerThread.start();
- CacheSPI<Object, Object> cache2 = createCache(name);
+ cache2 = createCache(name);
- // Pause to give caches time to see each other
- TestingUtil.blockUntilViewsReceived(new CacheSPI[]{cache1, cache2, cache3}, 60000);
+ // Pause to give caches time to see each other
+ TestingUtil.blockUntilViewsReceived(new CacheSPI[] { cache1, cache2, cache3 }, 60000);
- writer.stop();
- writerThread.join();
+ writer.stop();
+ writerThread.join();
- verifyInitialData(cache2);
+ verifyInitialData(cache2);
- int count = writer.result();
+ int count = writer.result();
- for (int c = 0; c < count; c++)
- assertEquals(c, cache2.get("/test" + c, "test"));
+ for (int c = 0; c < count; c++)
+ assertEquals(c, cache2.get("/test" + c, "test"));
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache1, cache2, cache3);
+ }
}
private void verifyInitialData(CacheSPI<Object, Object> cache2)
@@ -232,30 +310,38 @@
private void writingThreadTest(boolean tx, String name) throws InterruptedException
{
- final CacheSPI<Object, Object> cache1 = createCache(name);
+ CacheSPI<Object, Object> cache1 = null, cache2 = null;
+ try
+ {
+ cache1 = createCache(name);
- writeInitialData(cache1);
+ writeInitialData(cache1);
- // Delay the transient copy, so that we get a more thorough log test
- cache1.put("/delay", "delay", new DelayTransfer());
+ // Delay the transient copy, so that we get a more thorough log test
+ cache1.put("/delay", "delay", new DelayTransfer());
- WritingRunner writer = new WritingRunner(cache1, tx);
- Thread writerThread = new Thread(writer);
- writerThread.start();
+ WritingRunner writer = new WritingRunner(cache1, tx);
+ Thread writerThread = new Thread(writer);
+ writerThread.start();
- CacheSPI<Object, Object> cache2 = createCache(name);
+ cache2 = createCache(name);
- // Pause to give caches time to see each other
- TestingUtil.blockUntilViewsReceived(new CacheSPI[]{cache1, cache2}, 60000);
+ // Pause to give caches time to see each other
+ TestingUtil.blockUntilViewsReceived(new CacheSPI[] { cache1, cache2 }, 60000);
- writer.stop();
- writerThread.join();
+ writer.stop();
+ writerThread.join();
- verifyInitialData(cache2);
+ verifyInitialData(cache2);
- int count = writer.result();
+ int count = writer.result();
- for (int c = 0; c < count; c++)
- assertEquals(c, cache2.get("/test" + c, "test"));
+ for (int c = 0; c < count; c++)
+ assertEquals(c, cache2.get("/test" + c, "test"));
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache1, cache2);
+ }
}
}
Modified: core/trunk/src/test/java/org/jboss/cache/transaction/PrepareCommitContentionTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/transaction/PrepareCommitContentionTest.java 2009-02-10 20:39:38 UTC (rev 7677)
+++ core/trunk/src/test/java/org/jboss/cache/transaction/PrepareCommitContentionTest.java 2009-02-11 06:00:34 UTC (rev 7678)
@@ -4,6 +4,7 @@
import org.jboss.cache.Fqn;
import org.jboss.cache.RPCManager;
import org.jboss.cache.UnitTestCacheFactory;
+import org.jboss.cache.RPCManagerImpl.FlushTracker;
import org.jboss.cache.commands.ReplicableCommand;
import org.jboss.cache.commands.remote.ReplicateCommand;
import org.jboss.cache.commands.tx.CommitCommand;
@@ -23,6 +24,7 @@
import java.util.List;
import java.util.Map;
import java.util.Vector;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* This is to test the scenario described in http://jira.jboss.org/jira/browse/JBCACHE-1270
@@ -162,9 +164,9 @@
return delegate.getLastStateTransferSource();
}
- public void waitForFlush(long timeout)
+ public FlushTracker getFlushTracker()
{
- delegate.waitForFlush(timeout);
+ return delegate.getFlushTracker();
}
}
}
15 years, 11 months
JBoss Cache SVN: r7677 - core/trunk.
by jbosscache-commits@lists.jboss.org
Author: galder.zamarreno(a)jboss.com
Date: 2009-02-10 15:39:38 -0500 (Tue, 10 Feb 2009)
New Revision: 7677
Modified:
core/trunk/
Log:
Added couple of svn ignores more.
Property changes on: core/trunk
___________________________________________________________________
Name: svn:ignore
- output
build.log
junit*
0000*
je.lck
*.iml
*.ipr
*.iws
bin
jbossdb
dist
derby.log
target
build
.classpath
.project
.settings
eclipse-output
test-output
+ output
build.log
junit*
0000*
je.lck
*.iml
*.ipr
*.iws
bin
jbossdb
dist
derby.log
target
build
.classpath
.project
.settings
eclipse-output
test-output
temp-testng-customsuite.xml
testFiles
15 years, 11 months
JBoss Cache SVN: r7676 - in core/trunk/src: main/java/org/jboss/cache/interceptors and 2 other directories.
by jbosscache-commits@lists.jboss.org
Author: galder.zamarreno(a)jboss.com
Date: 2009-02-10 15:35:01 -0500 (Tue, 10 Feb 2009)
New Revision: 7676
Modified:
core/trunk/src/main/java/org/jboss/cache/config/Option.java
core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
core/trunk/src/test/java/org/jboss/cache/notifications/CacheListenerTest.java
Log:
[JBCACHE-1470] This time is correct :). Added suppress event notification option override. Extended set of cache listener tests so that they're executed both and without suppress event notification and make sure the event notification expectations are correct in each scenario.
Modified: core/trunk/src/main/java/org/jboss/cache/config/Option.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/Option.java 2009-02-10 13:55:59 UTC (rev 7675)
+++ core/trunk/src/main/java/org/jboss/cache/config/Option.java 2009-02-10 20:35:01 UTC (rev 7676)
@@ -27,6 +27,7 @@
* Used to override characteristics of specific calls to the cache. The javadocs of each of the setters below detail functionality and behaviour.
*
* @author <a href="mailto:manik AT jboss DOT org">Manik Surtani (manik AT jboss DOT org)</a>
+ * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
* @since 1.3.0
*/
public class Option implements Cloneable
@@ -49,6 +50,7 @@
private int lockAcquisitionTimeout = -1;
private boolean suppressPersistence;
+ private boolean suppressEventNotification;
/**
* @since 1.4.0
@@ -270,6 +272,8 @@
", skipDataGravitation=" + skipDataGravitation +
", forceAsynchronous=" + forceAsynchronous +
", forceSynchronous=" + forceSynchronous +
+ ", suppressPersistence=" + suppressPersistence +
+ ", suppressEventNotification=" + suppressEventNotification +
'}';
}
@@ -320,6 +324,7 @@
if (forceSynchronous != option.forceSynchronous) return false;
if (lockAcquisitionTimeout != option.lockAcquisitionTimeout) return false;
if (suppressPersistence != option.suppressPersistence) return false;
+ if (suppressEventNotification != option.suppressEventNotification) return false;
return true;
}
@@ -338,6 +343,7 @@
result = 29 * result + (forceSynchronous ? 0 : 1);
result = 29 * result + (lockAcquisitionTimeout);
result = 29 * result + (suppressPersistence ? 0 : 1);
+ result = 29 * result + (suppressEventNotification ? 0 : 1);
return result;
}
@@ -357,6 +363,7 @@
this.forceSynchronous = false;
this.lockAcquisitionTimeout = -1;
this.suppressPersistence = false;
+ this.suppressEventNotification = false;
}
/**
@@ -475,4 +482,29 @@
{
this.suppressPersistence = suppressPersistence;
}
+
+ /**
+ * Get whether event notifications for this invocation will be suppresed. By
+ * default is false which means that corresponding events are sent depending
+ * on the type of invocation.
+ *
+ * @return true, if event notification will be suppressed for this invocation.
+ */
+ public boolean isSuppressEventNotification()
+ {
+ return suppressEventNotification;
+ }
+
+ /**
+ * Set whether event notifications should be suppressed for this particular
+ * cache or transaction invocation.
+ *
+ * @param suppressEventNotification <code>true</code> if event notification
+ * should be skipped; <code>false</code> if events
+ * should be notified if there're any listeners.
+ */
+ public void setSuppressEventNotification(boolean suppressEventNotification)
+ {
+ this.suppressEventNotification = suppressEventNotification;
+ }
}
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java 2009-02-10 13:55:59 UTC (rev 7675)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java 2009-02-10 20:35:01 UTC (rev 7676)
@@ -21,7 +21,6 @@
*/
package org.jboss.cache.interceptors;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -67,7 +66,6 @@
import org.jboss.cache.transaction.TransactionContext;
import org.jboss.cache.transaction.TransactionLog;
import org.jboss.cache.transaction.TransactionTable;
-import org.jboss.cache.util.Immutables;
import org.jboss.cache.util.concurrent.ConcurrentHashSet;
/**
@@ -78,6 +76,7 @@
*
* @author <a href="mailto:manik AT jboss DOT org">Manik Surtani (manik AT jboss DOT org)</a>
* @author <a href="mailto:stevew@jofti.com">Steve Woodcock (stevew(a)jofti.com)</a>
+ * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
*/
public class TxInterceptor extends BaseTransactionalContextInterceptor
{
@@ -956,7 +955,9 @@
{
// this should ideally be set in beforeCompletion(), after compacting the list.
if (modifications == null) modifications = transactionContext.getModifications();
+ boolean isSuppressEventNotification = ctx.getOptionOverrides().isSuppressEventNotification();
ctx.setOptionOverrides(transactionContext.getOption());
+ ctx.getOptionOverrides().setSuppressEventNotification(isSuppressEventNotification);
}
if (tx != null) transactions.remove(tx);
@@ -1086,6 +1087,7 @@
// set any transaction wide options as current for this thread, caching original options that would then be reset
originalOptions = ctx.getOptionOverrides();
transactionalOptions = transactionContext.getOption();
+ transactionalOptions.setSuppressEventNotification(originalOptions.isSuppressEventNotification());
ctx.setOptionOverrides(transactionalOptions);
try
Modified: core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java 2009-02-10 13:55:59 UTC (rev 7675)
+++ core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java 2009-02-10 20:35:01 UTC (rev 7676)
@@ -64,6 +64,7 @@
* Helper class that handles all notifications to registered listeners.
*
* @author <a href="mailto:manik AT jboss DOT org">Manik Surtani (manik AT jboss DOT org)</a>
+ * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
*/
@NonVolatile
public class NotifierImpl implements Notifier
@@ -307,7 +308,7 @@
public void notifyNodeCreated(Fqn fqn, boolean pre, InvocationContext ctx)
{
- if (!nodeCreatedListeners.isEmpty())
+ if (!nodeCreatedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean originLocal = ctx.isOriginLocal();
Transaction tx = ctx.getTransaction();
@@ -326,7 +327,7 @@
public void notifyNodeModified(Fqn fqn, boolean pre, NodeModifiedEvent.ModificationType modificationType, Map data, InvocationContext ctx)
{
- if (!nodeModifiedListeners.isEmpty())
+ if (!nodeModifiedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean originLocal = ctx.isOriginLocal();
Map dataCopy = copy(data, useMarshalledValueMaps);
@@ -353,7 +354,7 @@
public void notifyNodeRemoved(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
{
- if (!nodeRemovedListeners.isEmpty())
+ if (!nodeRemovedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean originLocal = ctx.isOriginLocal();
Map dataCopy = copy(data, useMarshalledValueMaps);
@@ -374,7 +375,7 @@
public void notifyNodeVisited(Fqn fqn, boolean pre, InvocationContext ctx)
{
- if (!nodeVisitedListeners.isEmpty())
+ if (!nodeVisitedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
Transaction tx = ctx.getTransaction();
InvocationContext backup = resetInvocationContext(ctx);
@@ -391,7 +392,7 @@
public void notifyNodeMoved(Fqn originalFqn, Fqn newFqn, boolean pre, InvocationContext ctx)
{
- if (!nodeMovedListeners.isEmpty())
+ if (!nodeMovedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean originLocal = ctx.isOriginLocal();
Transaction tx = ctx.getTransaction();
@@ -411,7 +412,7 @@
public void notifyNodeEvicted(final Fqn fqn, final boolean pre, InvocationContext ctx)
{
- if (!nodeEvictedListeners.isEmpty())
+ if (!nodeEvictedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
final boolean originLocal = ctx.isOriginLocal();
Transaction tx = ctx.getTransaction();
@@ -430,7 +431,7 @@
public void notifyNodeInvalidated(final Fqn fqn, final boolean pre, InvocationContext ctx)
{
- if (!nodeInvalidatedListeners.isEmpty())
+ if (!nodeInvalidatedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
final boolean originLocal = ctx.isOriginLocal();
Transaction tx = ctx.getTransaction();
@@ -449,7 +450,7 @@
public void notifyNodeLoaded(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
{
- if (!nodeLoadedListeners.isEmpty())
+ if (!nodeLoadedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean originLocal = ctx.isOriginLocal();
Map dataCopy = copy(data, useMarshalledValueMaps);
@@ -470,7 +471,7 @@
public void notifyNodeActivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
{
- if (!nodeActivatedListeners.isEmpty())
+ if (!nodeActivatedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean originLocal = ctx.isOriginLocal();
Map dataCopy = copy(data, useMarshalledValueMaps);
@@ -491,7 +492,7 @@
public void notifyNodePassivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
{
- if (!nodePassivatedListeners.isEmpty())
+ if (!nodePassivatedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
Map dataCopy = copy(data, useMarshalledValueMaps);
Transaction tx = ctx.getTransaction();
@@ -567,7 +568,7 @@
public void notifyTransactionCompleted(Transaction transaction, boolean successful, InvocationContext ctx)
{
- if (!transactionCompletedListeners.isEmpty())
+ if (!transactionCompletedListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean isOriginLocal = ctx.isOriginLocal();
InvocationContext backup = resetInvocationContext(ctx);
@@ -584,7 +585,7 @@
public void notifyTransactionRegistered(Transaction transaction, InvocationContext ctx)
{
- if (!transactionRegisteredListeners.isEmpty())
+ if (!transactionRegisteredListeners.isEmpty() && !ctx.getOptionOverrides().isSuppressEventNotification())
{
boolean isOriginLocal = ctx.isOriginLocal();
InvocationContext backup = resetInvocationContext(ctx);
Modified: core/trunk/src/test/java/org/jboss/cache/notifications/CacheListenerTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/notifications/CacheListenerTest.java 2009-02-10 13:55:59 UTC (rev 7675)
+++ core/trunk/src/test/java/org/jboss/cache/notifications/CacheListenerTest.java 2009-02-10 20:35:01 UTC (rev 7676)
@@ -12,6 +12,7 @@
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Option;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.notifications.event.Event;
import static org.jboss.cache.notifications.event.Event.Type.*;
@@ -38,6 +39,7 @@
* exercises the new CacheListener annotation.
*
* @since 2.0.0
+ * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
*/
@Test(groups = "functional", sequential = true, testName = "notifications.CacheListenerTest")
public class CacheListenerTest
@@ -78,32 +80,53 @@
// simple tests first
- public void testCreation() throws Exception
+ public void testCreation()
{
+ creation(false);
+ eventLog.events.clear();
+ creation(true);
+ }
+
+ protected void creation(boolean supressEventNotification)
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.put(fqn, "key", "value");
Map<Object, Object> data = new HashMap<Object, Object>();
data.put("key", "value");
//expected
List<Event> expected = new ArrayList<Event>();
- if (optLocking)
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(false, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(true, cache, PUT_DATA, Collections.emptyMap(), fqn, null, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, PUT_DATA, data, fqn, null, true, null, false, null, NODE_MODIFIED));
- if (optLocking)
+ if (!supressEventNotification)
{
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (optLocking)
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(true, cache, PUT_DATA, Collections.emptyMap(), fqn, null, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, PUT_DATA, data, fqn, null, true, null, false, null, NODE_MODIFIED));
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected, eventLog.events);
- assertEquals("value", cache.get(fqn, "key"));
+ assertEquals("value", cache.get(fqn, "key"));
}
- public void testOnlyModification() throws Exception
+ public void testOnlyModification()
{
+ onlyModification(false);
+ eventLog.events.clear();
+ onlyModification(true);
+ }
+
+ protected void onlyModification(boolean supressEventNotification)
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
cache.put(fqn, "key", "value");
Map<Object, Object> oldData = new HashMap<Object, Object>();
@@ -114,28 +137,42 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.put(fqn, "key", "value2");
Map<Object, Object> newData = new HashMap<Object, Object>();
newData.put("key", "value2");
//expected
List<Event> expected = new ArrayList<Event>();
- if (optLocking)
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, PUT_DATA, oldData, fqn, null, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, PUT_DATA, newData, fqn, null, true, null, false, null, NODE_MODIFIED));
- if (optLocking)
+ if (!supressEventNotification)
{
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (optLocking)
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, PUT_DATA, oldData, fqn, null, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, PUT_DATA, newData, fqn, null, true, null, false, null, NODE_MODIFIED));
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected.size(), eventLog.events.size());
assertEquals(expected, eventLog.events);
}
- public void testOnlyRemoval() throws Exception
+ public void testOnlyRemoval()
{
+ onlyRemoval(false);
+ eventLog.events.clear();
+ onlyRemoval(true);
+ }
+
+ protected void onlyRemoval(boolean supressEventNotification)
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
cache.put(fqn, "key", "value");
Map<Object, Object> oldData = new HashMap<Object, Object>();
@@ -148,18 +185,25 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.removeNode(fqn);
//expected
List<Event> expected = new ArrayList<Event>();
- if (optLocking)
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, oldData, fqn, null, true, null, false, null, NODE_REMOVED));
- expected.add(new EventImpl(false, cache, null, null, fqn, null, true, null, false, null, NODE_REMOVED));
- if (optLocking)
+ if (!supressEventNotification)
{
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (optLocking)
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, oldData, fqn, null, true, null, false, null, NODE_REMOVED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, null, true, null, false, null, NODE_REMOVED));
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected, eventLog.events);
@@ -168,22 +212,42 @@
assertNull("Should be null", cache.getRoot().getChild(fqn));
}
- public void testNonexistentRemove() throws Exception
+ public void testNonexistentRemove()
{
+ nonexistentRemove(false);
+ eventLog.events.clear();
+ nonexistentRemove(true);
+ }
+
+ protected void nonexistentRemove(boolean supressEventNotification)
+ {
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.removeNode("/does/not/exist");
List<Event> expected = new ArrayList<Event>();
-
- if (optLocking)
+ if (!supressEventNotification)
{
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected, eventLog.events);
}
- public void testRemoveData() throws Exception
+ public void testRemoveData()
{
+ removeData(false);
+ eventLog.events.clear();
+ removeData(true);
+ }
+
+ protected void removeData(boolean supressEventNotification)
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
cache.put(fqn, "key", "value");
cache.put(fqn, "key2", "value2");
@@ -196,6 +260,10 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.remove(fqn, "key2");
Map<Object, Object> removedData = new HashMap<Object, Object>();
removedData.put("key2", "value2");
@@ -203,14 +271,17 @@
//expected
List<Event> expected = new ArrayList<Event>();
- if (optLocking)
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, REMOVE_DATA, oldData, fqn, null, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, REMOVE_DATA, removedData, fqn, null, true, null, false, null, NODE_MODIFIED));
- if (optLocking)
+ if (!supressEventNotification)
{
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (optLocking)
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, REMOVE_DATA, oldData, fqn, null, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, REMOVE_DATA, removedData, fqn, null, true, null, false, null, NODE_MODIFIED));
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected, eventLog.events);
@@ -218,6 +289,13 @@
public void testPutMap() throws Exception
{
+ putMap(false);
+ eventLog.events.clear();
+ putMap(true);
+ }
+
+ protected void putMap(boolean supressEventNotification)
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
Map<Object, Object> oldData = new HashMap<Object, Object>();
oldData.put("key", "value");
@@ -228,20 +306,27 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.put(fqn, oldData);
//expected
List<Event> expected = new ArrayList<Event>();
- if (optLocking)
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(false, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(true, cache, PUT_MAP, Collections.emptyMap(), fqn, null, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, PUT_MAP, oldData, fqn, null, true, null, false, null, NODE_MODIFIED));
- if (optLocking)
- {
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (!supressEventNotification)
+ {
+ if (optLocking)
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, null, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(true, cache, PUT_MAP, Collections.emptyMap(), fqn, null, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, PUT_MAP, oldData, fqn, null, true, null, false, null, NODE_MODIFIED));
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected, eventLog.events);
@@ -249,6 +334,13 @@
public void testMove()
{
+ move(false);
+ eventLog.events.clear();
+ move(true);
+ }
+
+ protected void move(boolean supressEventNotification)
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
Fqn newParent = Fqn.fromString("/a");
cache.put(fqn, "key", "value");
@@ -259,19 +351,26 @@
eventLog.events.clear();// clear events
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.move(n1.getFqn(), n2.getFqn());
//expected
Fqn newFqn = Fqn.fromRelativeElements(newParent, fqn.getLastElement());
List<Event> expected = new ArrayList<Event>();
- if (optLocking)
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, null, fqn, null, true, newFqn, false, null, NODE_MOVED));
- expected.add(new EventImpl(false, cache, null, null, fqn, null, true, newFqn, false, null, NODE_MOVED));
- if (optLocking)
- {
- expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
- eventLog.scrubImplicitTransactions();
+ if (!supressEventNotification)
+ {
+ if (optLocking)
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, null, fqn, null, true, newFqn, false, null, NODE_MOVED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, null, true, newFqn, false, null, NODE_MOVED));
+ if (optLocking)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, null, true, null, true, null, TRANSACTION_COMPLETED));
+ eventLog.scrubImplicitTransactions();
+ }
}
assertEquals(expected, eventLog.events);
@@ -281,63 +380,138 @@
public void testTxNonexistentRemove() throws Exception
{
+ txNonexistentRemove(false);
+ eventLog.events.clear();
+ txNonexistentRemove(true);
+ }
+
+ protected void txNonexistentRemove(boolean supressEventNotification) throws Exception
+ {
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.begin();
Transaction tx = tm.getTransaction();
cache.removeNode("/does/not/exist");
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.commit();
List<Event> expected = new ArrayList<Event>();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ }
assertEquals(expected, eventLog.events);
}
-
+
public void testTxCreationCommit() throws Exception
{
+ txCreationCommit(false);
+ eventLog.events.clear();
+ txCreationCommit(true);
+ }
+
+ protected void txCreationCommit(boolean supressEventNotification) throws Exception
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.begin();
Transaction tx = tm.getTransaction();
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.put(fqn, "key", "value");
//expected
Map<Object, Object> data = new HashMap<Object, Object>();
data.put("key", "value");
List<Event> expected = new ArrayList<Event>();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(true, cache, PUT_DATA, Collections.emptyMap(), fqn, tx, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, PUT_DATA, data, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(true, cache, PUT_DATA, Collections.emptyMap(), fqn, tx, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, PUT_DATA, data, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ }
assertEquals(expected, eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.commit();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ }
assertEquals(expected, eventLog.events);
assertEquals("value", cache.get(fqn, "key"));
}
public void testTxCreationRollback() throws Exception
{
+ txCreationRollback(false);
+ eventLog.events.clear();
+ txCreationRollback(true);
+ }
+
+ protected void txCreationRollback(boolean supressEventNotification) throws Exception
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.begin();
Transaction tx = tm.getTransaction();
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.put(fqn, "key", "value");
//expected
Map<Object, Object> data = new HashMap<Object, Object>();
data.put("key", "value");
List<Event> expected = new ArrayList<Event>();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
- expected.add(new EventImpl(true, cache, PUT_DATA, Collections.emptyMap(), fqn, tx, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, PUT_DATA, data, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, null, false, null, NODE_CREATED));
+ expected.add(new EventImpl(true, cache, PUT_DATA, Collections.emptyMap(), fqn, tx, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, PUT_DATA, data, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ }
assertEquals(expected, eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.rollback();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_COMPLETED));
- assertEquals(expected, eventLog.events);
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_COMPLETED));
+ }
+ assertEquals(expected, eventLog.events);
}
public void testTxOnlyModification() throws Exception
{
+ txOnlyModification(false);
+ eventLog.events.clear();
+ txOnlyModification(true);
+ }
+
+ protected void txOnlyModification(boolean supressEventNotification) throws Exception
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
cache.put(fqn, "key", "value");
Map<Object, Object> oldData = new HashMap<Object, Object>();
@@ -348,26 +522,51 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.begin();
Transaction tx = tm.getTransaction();
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.put(fqn, "key", "value2");
Map<Object, Object> newData = new HashMap<Object, Object>();
newData.put("key", "value2");
//expected
List<Event> expected = new ArrayList<Event>();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, PUT_DATA, oldData, fqn, tx, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, PUT_DATA, newData, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, PUT_DATA, oldData, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, PUT_DATA, newData, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ }
assertEquals(expected, eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.commit();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ }
assertEquals(expected, eventLog.events);
- }
+ }
public void testTxOnlyRemoval() throws Exception
{
+ txOnlyRemoval(false);
+ eventLog.events.clear();
+ txOnlyRemoval(true);
+ }
+
+ protected void txOnlyRemoval(boolean supressEventNotification) throws Exception
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
cache.put(fqn, "key", "value");
Map<Object, Object> oldData = new HashMap<Object, Object>();
@@ -380,19 +579,36 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.begin();
Transaction tx = tm.getTransaction();
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.removeNode(fqn);
//expected
List<Event> expected = new ArrayList<Event>();
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, oldData, fqn, tx, true, null, false, null, NODE_REMOVED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, null, false, null, NODE_REMOVED));
+ }
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, null, oldData, fqn, tx, true, null, false, null, NODE_REMOVED));
- expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, null, false, null, NODE_REMOVED));
-
assertEquals(expected, eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.commit();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ }
assertEquals(expected, eventLog.events);
// test that the node has in fact been removed.
assertNull("Should be null", cache.getRoot().getChild(fqn));
@@ -400,6 +616,13 @@
public void testTxRemoveData() throws Exception
{
+ txRemoveData(false);
+ eventLog.events.clear();
+ txRemoveData(true);
+ }
+
+ protected void txRemoveData(boolean supressEventNotification) throws Exception
+ {
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
cache.put(fqn, "key", "value");
cache.put(fqn, "key2", "value2");
@@ -412,20 +635,38 @@
assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
// modify existing node
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.begin();
Transaction tx = tm.getTransaction();
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
cache.remove(fqn, "key2");
Map<Object, Object> removedData = new HashMap<Object, Object>();
removedData.put("key2", "value2");
//expected
List<Event> expected = new ArrayList<Event>();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
- expected.add(new EventImpl(true, cache, REMOVE_DATA, oldData, fqn, tx, true, null, false, null, NODE_MODIFIED));
- expected.add(new EventImpl(false, cache, REMOVE_DATA, removedData, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, REMOVE_DATA, oldData, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ expected.add(new EventImpl(false, cache, REMOVE_DATA, removedData, fqn, tx, true, null, false, null, NODE_MODIFIED));
+ }
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
tm.commit();
- expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ }
assertEquals(expected, eventLog.events);
assertEquals(expected, eventLog.events);
@@ -458,4 +699,57 @@
expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
assertEquals(expected, eventLog.events);
}
+
+ protected void txMove(boolean supressEventNotification) throws Exception
+ {
+ assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
+ Fqn newParent = Fqn.fromString("/a");
+ cache.put(fqn, "key", "value");
+ cache.put(newParent, "key", "value");
+
+ Node<Object, Object> n1 = cache.getRoot().getChild(fqn);
+ Node<Object, Object> n2 = cache.getRoot().getChild(newParent);
+ eventLog.events.clear();// clear events
+ assertEquals("Event log should be empty", Collections.emptyList(), eventLog.events);
+
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
+ tm.begin();
+ Transaction tx = tm.getTransaction();
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
+ cache.move(n1.getFqn(), n2.getFqn());
+ //expected
+ Fqn newFqn = Fqn.fromRelativeElements(newParent, fqn.getLastElement());
+ List<Event> expected = new ArrayList<Event>();
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, false, null, TRANSACTION_REGISTERED));
+ expected.add(new EventImpl(true, cache, null, null, fqn, tx, true, newFqn, false, null, NODE_MOVED));
+ expected.add(new EventImpl(false, cache, null, null, fqn, tx, true, newFqn, false, null, NODE_MOVED));
+ }
+
+ assertEquals(expected, eventLog.events);
+ if (supressEventNotification)
+ {
+ setSuppressEventNotification();
+ }
+ tm.commit();
+ if (!supressEventNotification)
+ {
+ expected.add(new EventImpl(false, cache, null, null, null, tx, true, null, true, null, TRANSACTION_COMPLETED));
+ }
+ assertEquals(expected, eventLog.events);
+ }
+
+ protected void setSuppressEventNotification()
+ {
+ Option option = new Option();
+ option.setSuppressEventNotification(true);
+ cache.getInvocationContext().setOptionOverrides(option);
+ }
}
15 years, 11 months