[jboss-cvs] JBossAS SVN: r73532 - in projects/ejb3/trunk/core/src: test/java/org/jboss/ejb3/test/clusteredentity and 2 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue May 20 10:48:58 EDT 2008
Author: bstansberry at jboss.com
Date: 2008-05-20 10:48:58 -0400 (Tue, 20 May 2008)
New Revision: 73532
Added:
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheBase.java
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/PessimisticJBCCache.java
Removed:
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCache.java
Modified:
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheFactory.java
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/OptimisticJBCCache.java
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TransactionalCacheFactory.java
projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TreeCacheProviderHook.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/EntityTestBean.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTest.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTestBean.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityClassloaderTestBase.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryRedeployUnitTestCase.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryUnitTestCase.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityUnitTestCase.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryRedeployUnitTestCase.java
projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryUnitTestCase.java
Log:
[EJBTHREE-1373] Fix JBC 2 integration via TreeCacheProviderHook
Deleted: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCache.java
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCache.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCache.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -1,346 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2007, 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.jboss.ejb3.entity;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hibernate.cache.Cache;
-import org.hibernate.cache.CacheException;
-import org.hibernate.cache.StandardQueryCache;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.Node;
-import org.jboss.cache.Region;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.lock.TimeoutException;
-
-/**
- * {@link Cache} implementation that uses a 2.x or later release of JBoss Cache.
- *
- * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
- * @version $Revision: 1.1 $
- */
-public class JBCCache implements Cache
-{
-
- private static final Log log = LogFactory.getLog(JBCCache.class);
-
- private static final String ITEM = "item";
-
- private org.jboss.cache.Cache cache;
- private final String regionName;
- private final Fqn regionFqn;
- private final TransactionManager transactionManager;
- private boolean localWritesOnly;
-
- public JBCCache(org.jboss.cache.Cache cache, String regionName,
- String regionPrefix, TransactionManager transactionManager)
- throws CacheException {
- this.cache = cache;
- this.regionName = regionName;
- this.regionFqn = Fqn.fromString(SecondLevelCacheUtil.createRegionFqn(regionName, regionPrefix));
- this.transactionManager = transactionManager;
- if (cache.getConfiguration().isUseRegionBasedMarshalling())
- {
- localWritesOnly = StandardQueryCache.class.getName().equals(regionName);
-
- boolean fetchState = cache.getConfiguration().isFetchInMemoryState();
- try
- {
- // We don't want a state transfer for the StandardQueryCache,
- // as it can include classes from multiple scoped classloaders
- if (localWritesOnly)
- cache.getConfiguration().setFetchInMemoryState(false);
-
- // We always activate
- activateCacheRegion(regionFqn.toString());
- }
- finally
- {
- // Restore the normal state transfer setting
- if (localWritesOnly)
- cache.getConfiguration().setFetchInMemoryState(fetchState);
- }
- }
- else
- {
- log.debug("TreeCache is not configured for region based marshalling");
- }
- }
-
- public Object get(Object key) throws CacheException {
- Transaction tx = suspend();
- try {
- return read(key);
- }
- finally {
- resume( tx );
- }
- }
-
- public Object read(Object key) throws CacheException {
- try {
- return cache.get( new Fqn( regionFqn, key ), ITEM );
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public void update(Object key, Object value) throws CacheException {
- try {
- if (localWritesOnly) {
- Option option = new Option();
- option.setCacheModeLocal(true);
- cache.getInvocationContext().setOptionOverrides(option);
- cache.put( new Fqn( regionFqn, key ), ITEM, value );
- }
- else {
- cache.put( new Fqn( regionFqn, key ), ITEM, value );
- }
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public void put(Object key, Object value) throws CacheException {
- Transaction tx = suspend();
- try {
- if (localWritesOnly) {
- Option option = new Option();
- option.setCacheModeLocal(true);
- cache.getInvocationContext().setOptionOverrides(option);
- //do the failfast put outside the scope of the JTA txn
- cache.putForExternalRead(new Fqn( regionFqn, key ), ITEM, value);
- }
- else {
- cache.putForExternalRead(new Fqn( regionFqn, key ), ITEM, value);
- }
- }
- catch (TimeoutException te) {
- //ignore!
- log.debug("ignoring write lock acquisition failure");
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- finally {
- resume( tx );
- }
- }
-
- private void resume(Transaction tx) {
- try {
- if (tx!=null) transactionManager.resume(tx);
- }
- catch (Exception e) {
- throw new CacheException("Could not resume transaction", e);
- }
- }
-
- private Transaction suspend() {
- Transaction tx = null;
- try {
- if ( transactionManager!=null ) {
- tx = transactionManager.suspend();
- }
- }
- catch (SystemException se) {
- throw new CacheException("Could not suspend transaction", se);
- }
- return tx;
- }
-
- public void remove(Object key) throws CacheException {
- try {
- if (localWritesOnly) {
- Option option = new Option();
- option.setCacheModeLocal(true);
- cache.getInvocationContext().setOptionOverrides(option);
- cache.removeNode( new Fqn( regionFqn, key ) );
- }
- else {
- cache.removeNode( new Fqn( regionFqn, key ) );
- }
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public void clear() throws CacheException {
- try {
- cache.removeNode( regionFqn );
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public void destroy() throws CacheException {
- try {
- // NOTE : evict() operates locally only (i.e., does not propogate
- // to any other nodes in the potential cluster). This is
- // exactly what is needed when we destroy() here; destroy() is used
- // as part of the process of shutting down a SessionFactory; thus
- // these removals should not be propogated
- // FIXME NPE bug in 2.0.0.ALPHA1, so we don't use evict 'til fixed
-// cache.evict( regionFqn, true );
- InvocationContext ctx = cache.getInvocationContext();
- Option opt = new Option();
- opt.setCacheModeLocal(true);
- ctx.setOptionOverrides(opt);
- cache.removeNode( regionFqn );
-
- if (cache.getConfiguration().isUseRegionBasedMarshalling() && !SecondLevelCacheUtil.isSharedClassLoaderRegion(regionName))
- {
- inactivateCacheRegion();
- }
- }
- catch( Exception e ) {
- throw SecondLevelCacheUtil.convertToHibernateException( e );
- }
- }
-
- public void lock(Object key) throws CacheException {
- throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
- }
-
- public void unlock(Object key) throws CacheException {
- throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
- }
-
- public long nextTimestamp() {
- return System.currentTimeMillis() / 100;
- }
-
- public int getTimeout() {
- return 600; //60 seconds
- }
-
- public String getRegionName() {
- return regionName;
- }
-
- public long getSizeInMemory() {
- return -1;
- }
-
- public long getElementCountInMemory() {
- try {
- Set children = getChildrenNames();
- return children == null ? 0 : children.size();
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public long getElementCountOnDisk() {
- return 0;
- }
-
- public Map toMap() {
- try {
- Map result = new HashMap();
- Set childrenNames = getChildrenNames();
- if (childrenNames != null) {
- Iterator iter = childrenNames.iterator();
- while ( iter.hasNext() ) {
- Object key = iter.next();
- result.put(
- key,
- cache.get( new Fqn( regionFqn, key ), ITEM )
- );
- }
- }
- return result;
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- private Set getChildrenNames()
- {
- try {
- Node base = cache.getRoot().getChild( regionFqn );
- return base == null ? null : base.getChildrenNames();
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public String toString() {
- return "JBCCache(" + regionName + ')';
- }
-
- private void activateCacheRegion(String regionName) throws CacheException
- {
- Region region = cache.getRegion(regionFqn, true);
- if (region.isActive() == false)
- {
- try
- {
- // Only register the classloader if it's not a shared region.
- // If it's shared, no single classloader is valid
- if (!SecondLevelCacheUtil.isSharedClassLoaderRegion(regionName))
- {
- region.registerContextClassLoader(Thread.currentThread().getContextClassLoader());
- }
- region.activate();
- }
- catch (Exception e)
- {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
- }
-
- private void inactivateCacheRegion() throws CacheException
- {
- Region region = cache.getRegion(regionFqn, false);
- if (region != null && region.isActive())
- {
- try
- {
- region.deactivate();
- region.unregisterContextClassLoader();
- }
- catch (Exception e)
- {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
- }
-}
Added: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheBase.java
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheBase.java (rev 0)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheBase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -0,0 +1,304 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 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.jboss.ejb3.entity;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.StandardQueryCache;
+import org.hibernate.cache.UpdateTimestampsCache;
+import org.hibernate.util.PropertiesHelper;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.Region;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.CacheMode;
+
+/**
+ * Base superclass for a {@link Cache} implementation that uses a 2.x or later
+ * release of JBoss Cache.
+ *
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class JBCCacheBase
+{
+ public static final String QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.region.jbc2.query.localonly";
+
+ protected static final String ITEM = "item";
+
+ protected org.jboss.cache.Cache<Object, Object> cache;
+ protected final String regionName;
+ protected final Fqn<String> regionFqn;
+ protected final TransactionManager transactionManager;
+ protected boolean localOnlyQueries;
+ protected boolean forTimestamps;
+ protected boolean forceAsync;
+ protected Node<Object, Object> regionRoot;
+ protected final Object regionRootMutex = new Object();
+
+
+ public JBCCacheBase(org.jboss.cache.Cache<Object, Object> cache, String regionName,
+ String regionPrefix, TransactionManager transactionManager,
+ Properties properties)
+ throws CacheException
+ {
+ this.cache = cache;
+ this.regionName = regionName;
+ this.regionFqn = Fqn.fromString(SecondLevelCacheUtil.createRegionFqn(regionName, regionPrefix));
+ this.transactionManager = transactionManager;
+ this.forTimestamps = regionName.contains(UpdateTimestampsCache.class.getName());
+ CacheMode mode = cache.getConfiguration().getCacheMode();
+ if (forTimestamps)
+ {
+ if (mode == CacheMode.INVALIDATION_ASYNC || mode == CacheMode.INVALIDATION_SYNC)
+ {
+ throw new IllegalStateException("Cache is configured for " + mode +
+ "; not supported for a timestamps cache");
+ }
+
+ forceAsync = (mode == CacheMode.REPL_SYNC);
+ }
+
+ // We don't want to waste effort setting an option if JBC is
+ // already in LOCAL mode. If JBC is REPL_(A)SYNC then check
+ // if they passed a config option to disable query replication
+ if (mode != CacheMode.LOCAL)
+ {
+ localOnlyQueries = PropertiesHelper.getBoolean(QUERY_CACHE_LOCAL_ONLY_PROP, properties, false);
+ // If its the standard query region with no prefix, its possibly shared
+ // between classloaders, so we make it local only
+ localOnlyQueries = localOnlyQueries ||
+ StandardQueryCache.class.getName().equals(regionName);
+ }
+
+ activateLocalClusterNode();
+ }
+
+ private void activateLocalClusterNode()
+ {
+ // Regions can get instantiated in the course of normal work (e.g.
+ // a named query region will be created the first time the query is
+ // executed), so suspend any ongoing tx
+ Transaction tx = suspend();
+ try {
+ Configuration cfg = cache.getConfiguration();
+ if (cfg.isUseRegionBasedMarshalling()) {
+
+ Region jbcRegion = cache.getRegion(regionFqn, true);
+
+ // Only register the classloader if it's not a shared region.
+ // If it's shared, no single classloader is valid
+ boolean shared = SecondLevelCacheUtil.isSharedClassLoaderRegion(regionName);
+ if (!shared)
+ {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ classLoader = getClass().getClassLoader();
+ }
+ jbcRegion.registerContextClassLoader(classLoader);
+ }
+
+ if ( !jbcRegion.isActive() )
+ {
+ boolean fetchState = cfg.isFetchInMemoryState();
+ try
+ {
+ // We don't want a state transfer for a shared region,
+ // as it can include classes from multiple scoped classloaders
+ if (shared)
+ cfg.setFetchInMemoryState(false);
+
+ jbcRegion.activate();
+ }
+ finally
+ {
+ // Restore the normal state transfer setting
+ if (shared)
+ cfg.setFetchInMemoryState(fetchState);
+ }
+
+ }
+ }
+
+ regionRoot = createRegionRootNode();
+ }
+ catch (Exception e)
+ {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ finally {
+ resume(tx);
+ }
+ }
+
+ protected abstract void establishRegionRootNode();
+
+ protected abstract Node<Object, Object> createRegionRootNode();
+
+ /**
+ * Checks for the validity of the root cache node for this region,
+ * creating a new one if it does not exist or is invalid, and also
+ * ensuring that the root node is marked as resident. Suspends any
+ * transaction while doing this to ensure no transactional locks are held
+ * on the region root.
+ *
+ * TODO remove this once JBCACHE-1250 is resolved.
+ */
+ protected void ensureRegionRootExists()
+ {
+ if (regionRoot == null || !regionRoot.isValid())
+ {
+ synchronized (regionRootMutex)
+ {
+ // If we've been blocking for the mutex, perhaps another
+ // thread has already reestablished the root.
+ // In case the node was reestablised via replication, confirm it's
+ // marked "resident" (a status which doesn't replicate)
+ if (regionRoot != null && regionRoot.isValid()) {
+ return;
+ }
+
+ establishRegionRootNode();
+ }
+ }
+
+ // Fix up the resident flag
+ if (regionRoot != null && regionRoot.isValid() && !regionRoot.isResident())
+ regionRoot.setResident(true);
+ }
+
+ protected void resume(Transaction tx)
+ {
+ if (tx != null)
+ {
+ try {
+ transactionManager.resume(tx);
+ }
+ catch (Exception e) {
+ throw new CacheException("Could not resume transaction", e);
+ }
+ }
+ }
+
+ protected Transaction suspend()
+ {
+ Transaction tx = null;
+ if (transactionManager != null)
+ {
+ try {
+ tx = transactionManager.suspend();
+ }
+ catch (SystemException se) {
+ throw new CacheException("Could not suspend transaction", se);
+ }
+ }
+ return tx;
+ }
+
+ protected void inactivateCacheRegion() throws CacheException
+ {
+ Region region = cache.getRegion(regionFqn, false);
+ if (region != null && region.isActive())
+ {
+ try
+ {
+ region.deactivate();
+ region.unregisterContextClassLoader();
+ }
+ catch (Exception e)
+ {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+ }
+
+ public void lock(Object key) throws CacheException {
+ throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
+ }
+
+ public void unlock(Object key) throws CacheException {
+ throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
+ }
+
+ public long nextTimestamp() {
+ return System.currentTimeMillis() / 100;
+ }
+
+ public int getTimeout() {
+ return 600; //60 seconds
+ }
+
+ public String getRegionName() {
+ return regionName;
+ }
+
+ public long getSizeInMemory() {
+ return -1;
+ }
+
+ public long getElementCountInMemory() {
+ try {
+ return getChildrenNames().size();
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+ public long getElementCountOnDisk() {
+ return 0;
+ }
+
+ public Map<Object, Object> toMap() {
+ try {
+ Map<Object, Object> result = new HashMap<Object, Object>();
+ for (Object key : getChildrenNames() ) {
+ result.put(key, cache.get( new Fqn( regionFqn, key ), ITEM ));
+ }
+ return result;
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+ private Set<Object> getChildrenNames()
+ {
+ try {
+ return regionRoot == null ? new HashSet<Object>() : regionRoot.getChildrenNames();
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+}
\ No newline at end of file
Modified: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheFactory.java
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheFactory.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCacheFactory.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -1,3 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 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.jboss.ejb3.entity;
import java.util.Properties;
@@ -8,12 +29,21 @@
import org.jboss.cache.CacheStatus;
import org.jboss.ejb3.tx.TxUtil;
import org.jboss.ha.framework.server.CacheManagerLocator;
+import org.jboss.logging.Logger;
+/**
+ * Concrete implementation of TransactionalCacheFactory meant for use with
+ * JBoss Cache 2.x
+ *
+ * @author Brian Stansberry
+ */
class JBCCacheFactory extends TransactionalCacheFactory
{
+ private static final Logger log = Logger.getLogger(JBCCacheFactory.class);
+
private CacheManager cacheManager;
private String cacheName;
- private org.jboss.cache.Cache cache;
+ private org.jboss.cache.Cache<Object, Object> cache;
private boolean optimistic;
JBCCacheFactory()
@@ -76,19 +106,25 @@
if (optimistic)
{
- return new OptimisticJBCCache(cache, regionName, regionPrefix);
+ return new OptimisticJBCCache(cache, regionName, regionPrefix,
+ TxUtil.getTransactionManager(),
+ properties);
}
else
{
- return new JBCCache(cache, regionName, regionPrefix,
- TxUtil.getTransactionManager());
+ return new PessimisticJBCCache(cache, regionName, regionPrefix,
+ TxUtil.getTransactionManager(),
+ properties);
}
}
public void stop()
{
if (cache != null)
+ {
cacheManager.releaseCache(cacheName);
+ log.debug("Cache " + cacheName + " released");
+ }
}
public boolean isOptimistic()
Modified: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/OptimisticJBCCache.java
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/OptimisticJBCCache.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/OptimisticJBCCache.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -21,27 +21,24 @@
*/
package org.jboss.ejb3.entity;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
import java.util.Comparator;
+import java.util.Properties;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+
import org.hibernate.cache.CacheException;
import org.hibernate.cache.OptimisticCache;
import org.hibernate.cache.OptimisticCacheSource;
-import org.hibernate.cache.StandardQueryCache;
-import org.hibernate.cache.UpdateTimestampsCache;
+import org.hibernate.cache.QueryKey;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
-import org.jboss.cache.Region;
+import org.jboss.cache.NodeSPI;
import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.Option;
import org.jboss.cache.lock.TimeoutException;
+import org.jboss.logging.Logger;
/**
* Represents a particular region within the given JBossCache TreeCache
@@ -52,56 +49,61 @@
* @author Steve Ebersole
* @author Brian Stansberry
*/
-public class OptimisticJBCCache implements OptimisticCache {
+public class OptimisticJBCCache extends JBCCacheBase implements OptimisticCache
+{
- // todo : eventually merge this with TreeCache and just add optional opt-lock support there.
+ private static final Logger log = Logger.getLogger(OptimisticJBCCache.class);
+
+ private OptimisticCacheSource source;
- private static final Log log = LogFactory.getLog( OptimisticJBCCache.class);
+ public OptimisticJBCCache(org.jboss.cache.Cache<Object, Object> cache,
+ String regionName, String regionPrefix,
+ TransactionManager transactionManager,
+ Properties properties)
+ throws CacheException {
+ super(cache, regionName, regionPrefix, transactionManager, properties);
+ }
- private static final String ITEM = "item";
+ @Override
+ protected void establishRegionRootNode()
+ {
+ // Don't hold a transactional lock for this
+ Transaction tx = suspend();
+ Node<Object, Object> newRoot = null;
+ try {
+ // Make sure the root node for the region exists and
+ // has a DataVersion that never complains
+ newRoot = createRegionRootNode();
+ }
+ finally {
+ resume(tx);
+ regionRoot = newRoot;
+ }
+ }
- private org.jboss.cache.Cache cache;
- private final String regionName;
- private final Fqn regionFqn;
- private OptimisticCacheSource source;
- private boolean localWritesOnly;
+ @Override
+ protected Node<Object, Object> createRegionRootNode()
+ {
+ Node<Object, Object> root = cache.getRoot();
+ Node<Object, Object> targetNode = root.getChild( regionFqn );
+ if (targetNode == null || !targetNode.isValid()) {
+ cache.getInvocationContext().getOptionOverrides().setDataVersion(NonLockingDataVersion.INSTANCE);
+ targetNode = root.addChild( regionFqn );
+ }
+ else if (targetNode instanceof NodeSPI) {
+ // FIXME Hacky workaround to JBCACHE-1202
+ if ( !( ( ( NodeSPI ) targetNode ).getVersion() instanceof NonLockingDataVersion ) ) {
+ ((NodeSPI) targetNode).setVersion(NonLockingDataVersion.INSTANCE);
+ }
+ }
- public OptimisticJBCCache(org.jboss.cache.Cache cache,
- String regionName, String regionPrefix)
- throws CacheException {
- this.cache = cache;
- this.regionName = regionName;
- this.regionFqn = Fqn.fromString(SecondLevelCacheUtil.createRegionFqn(regionName, regionPrefix));
- Configuration config = cache.getConfiguration();
- if (config.isUseRegionBasedMarshalling())
- {
- localWritesOnly = StandardQueryCache.class.getName().equals(regionName);
-
- boolean fetchState = config.isFetchInMemoryState();
- try
- {
- // We don't want a state transfer for the StandardQueryCache,
- // as it can include classes from multiple scoped classloaders
- if (localWritesOnly)
- config.setFetchInMemoryState(false);
-
- // We always activate
- activateCacheRegion(regionFqn.toString());
- }
- finally
- {
- // Restore the normal state transfer setting
- if (localWritesOnly)
- config.setFetchInMemoryState(fetchState);
- }
- }
- else
- {
- log.debug("TreeCache is not configured for region based marshalling");
- }
- }
+ // Never evict this node
+ targetNode.setResident(true);
+ return targetNode;
+ }
+
// OptimisticCache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void setSource(OptimisticCacheSource source) {
@@ -112,14 +114,18 @@
writeUpdate( key, value, currentVersion, null );
}
+ @SuppressWarnings("unchecked")
public void writeUpdate(Object key, Object value, Object currentVersion, Object previousVersion) {
try {
+ ensureRegionRootExists();
+
Option option = new Option();
DataVersion dv = ( source != null && source.isVersioned() )
? new DataVersionAdapter( currentVersion, previousVersion, source.getVersionComparator(), source.toString() )
: NonLockingDataVersion.INSTANCE;
option.setDataVersion( dv );
- option.setCacheModeLocal(localWritesOnly);
+ if (localOnlyQueries && key instanceof QueryKey)
+ option.setCacheModeLocal(true);
cache.getInvocationContext().setOptionOverrides(option);
cache.put( new Fqn( regionFqn, key ), ITEM, value );
}
@@ -128,48 +134,86 @@
}
}
- public void writeLoad(Object key, Object value, Object currentVersion) {
- try {
- Option option = new Option();
- option.setFailSilently( true );
- option.setDataVersion( NonLockingDataVersion.INSTANCE );
- option.setCacheModeLocal(localWritesOnly);
- cache.getInvocationContext().setOptionOverrides(option);
- cache.remove( new Fqn( regionFqn, key ), "ITEM" );
+ @SuppressWarnings("unchecked")
+ public void writeLoad(Object key, Object value, Object currentVersion) {
+ Transaction tx = null;
+ try {
+ Option option = new Option();
+ DataVersion dv = ( source != null && source.isVersioned() )
+ ? new DataVersionAdapter( currentVersion, currentVersion, source.getVersionComparator(), source.toString() )
+ : NonLockingDataVersion.INSTANCE;
+ option.setDataVersion( dv );
- option = new Option();
- option.setFailSilently( true );
- DataVersion dv = ( source != null && source.isVersioned() )
- ? new DataVersionAdapter( currentVersion, currentVersion, source.getVersionComparator(), source.toString() )
- : NonLockingDataVersion.INSTANCE;
- option.setDataVersion( dv );
- option.setCacheModeLocal(localWritesOnly);
- cache.getInvocationContext().setOptionOverrides(option);
- cache.put( new Fqn( regionFqn, key ), ITEM, value );
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
+ if (forTimestamps)
+ {
+ tx = suspend();
+
+ ensureRegionRootExists();
+
+ // Timestamps don't use putForExternalRead, but are async
+ if (forceAsync)
+ option.setForceAsynchronous(true);
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.put(new Fqn( regionFqn, key ), ITEM, value);
+ }
+ else if (key instanceof QueryKey)
+ {
+ ensureRegionRootExists();
+
+ option.setCacheModeLocal(localOnlyQueries);
+ option.setLockAcquisitionTimeout(2);
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.put( new Fqn( regionFqn, key ), ITEM, value );
+ }
+ else
+ {
+ ensureRegionRootExists();
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.putForExternalRead( new Fqn( regionFqn, key ), ITEM, value );
+ }
+ }
+ catch (TimeoutException te) {
+ if (!(key instanceof QueryKey))
+ throw SecondLevelCacheUtil.convertToHibernateException(te);
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ finally {
+ resume(tx);
+ }
}
// Cache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public Object get(Object key) throws CacheException {
- try {
- Option option = new Option();
- option.setFailSilently( true );
-// option.setDataVersion( NonLockingDataVersion.INSTANCE );
- cache.getInvocationContext().setOptionOverrides(option);
+ Transaction tx = suspend();
+ try {
+ ensureRegionRootExists();
+ if (key instanceof QueryKey)
+ {
+ cache.getInvocationContext().getOptionOverrides().setLockAcquisitionTimeout(0);
+ }
+
return cache.get( new Fqn( regionFqn, key ), ITEM );
}
+ catch (TimeoutException e) {
+ if (key instanceof QueryKey)
+ return null;
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
catch (Exception e) {
throw SecondLevelCacheUtil.convertToHibernateException(e);
}
+ finally {
+ resume(tx);
+ }
}
public Object read(Object key) throws CacheException {
try {
+ ensureRegionRootExists();
return cache.get( new Fqn( regionFqn, key ), ITEM );
}
catch (Exception e) {
@@ -179,9 +223,11 @@
public void update(Object key, Object value) throws CacheException {
try {
+ ensureRegionRootExists();
Option option = new Option();
option.setDataVersion( NonLockingDataVersion.INSTANCE );
- option.setCacheModeLocal(localWritesOnly);
+ if (localOnlyQueries && key instanceof QueryKey)
+ option.setCacheModeLocal(true);
cache.getInvocationContext().setOptionOverrides(option);
cache.put( new Fqn( regionFqn, key ), ITEM, value );
}
@@ -191,51 +237,67 @@
}
public void put(Object key, Object value) throws CacheException {
+ Transaction tx = null;
try {
- log.trace( "performing put() into region [" + regionName + "]" );
- // do the put outside the scope of the JTA txn
- Option option = new Option();
- option.setFailSilently( true );
- option.setDataVersion( NonLockingDataVersion.INSTANCE );
- option.setCacheModeLocal(localWritesOnly);
- cache.getInvocationContext().setOptionOverrides(option);
- cache.put( new Fqn( regionFqn, key ), ITEM, value );
+ Option option = new Option();
+ option.setDataVersion( NonLockingDataVersion.INSTANCE );
+ if (forTimestamps) {
+ tx = suspend();
+
+ ensureRegionRootExists();
+
+ // Timestamps don't use putForExternalRead, but are async
+ if (forceAsync)
+ option.setForceAsynchronous(true);
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.put(new Fqn( regionFqn, key ), ITEM, value);
+ }
+ else if (key instanceof QueryKey) {
+
+ ensureRegionRootExists();
+
+ option.setCacheModeLocal(localOnlyQueries);
+ option.setLockAcquisitionTimeout(2);
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.put(new Fqn( regionFqn, key ), ITEM, value);
+ }
+ else {
+ ensureRegionRootExists();
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.putForExternalRead( new Fqn( regionFqn, key ), ITEM, value );
+ }
}
catch (TimeoutException te) {
- //ignore!
- log.debug("ignoring write lock acquisition failure");
+ if (!(key instanceof QueryKey))
+ throw SecondLevelCacheUtil.convertToHibernateException(te);
}
catch (Exception e) {
throw SecondLevelCacheUtil.convertToHibernateException(e);
}
+ finally {
+ resume(tx);
+ }
}
public void remove(Object key) throws CacheException {
- try {
- // tree cache in optimistic mode seems to have as very difficult
- // time with remove calls on non-existent nodes (NPEs)...
- if ( cache.get( new Fqn( regionFqn, key ), ITEM ) != null ) {
- Option option = new Option();
- option.setDataVersion( NonLockingDataVersion.INSTANCE );
- option.setCacheModeLocal(localWritesOnly);
- cache.getInvocationContext().setOptionOverrides(option);
- cache.removeNode( new Fqn( regionFqn, key ) );
- }
- else {
- log.trace( "skipping remove() call as the underlying node did not seem to exist" );
- }
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
+ try {
+ ensureRegionRootExists();
+
+ Option option = new Option();
+ option.setDataVersion( NonLockingDataVersion.INSTANCE );
+ if (localOnlyQueries && key instanceof QueryKey)
+ option.setCacheModeLocal(true);
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.removeNode( new Fqn( regionFqn, key ) );
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
}
public void clear() throws CacheException {
try {
- Option option = new Option();
- option.setDataVersion( NonLockingDataVersion.INSTANCE );
- option.setCacheModeLocal(localWritesOnly);
- cache.getInvocationContext().setOptionOverrides(option);
+ cache.getInvocationContext().getOptionOverrides().setDataVersion( NonLockingDataVersion.INSTANCE );
cache.removeNode( regionFqn );
}
catch (Exception e) {
@@ -247,13 +309,12 @@
try {
Option option = new Option();
option.setCacheModeLocal( true );
- option.setFailSilently( true );
option.setDataVersion( NonLockingDataVersion.INSTANCE );
cache.getInvocationContext().setOptionOverrides(option);
cache.removeNode( regionFqn );
if (cache.getConfiguration().isUseRegionBasedMarshalling()
- && !isSharedClassLoaderRegion(regionName))
+ && !SecondLevelCacheUtil.isSharedClassLoaderRegion(regionName))
{
inactivateCacheRegion();
}
@@ -263,134 +324,19 @@
}
}
- public void lock(Object key) throws CacheException {
- throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
- }
-
- public void unlock(Object key) throws CacheException {
- throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
- }
-
- public long nextTimestamp() {
- return System.currentTimeMillis() / 100;
- }
-
- public int getTimeout() {
- return 600; //60 seconds
- }
-
- public String getRegionName() {
- return regionName;
- }
-
- public long getSizeInMemory() {
- return -1;
- }
-
- public long getElementCountInMemory() {
- try {
- Set children = getChildrenNames();
- return children == null ? 0 : children.size();
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- public long getElementCountOnDisk() {
- return 0;
- }
-
- public Map toMap() {
- try {
- Map result = new HashMap();
- Set childrenNames = getChildrenNames();
- if (childrenNames != null) {
- Iterator iter = childrenNames.iterator();
- while ( iter.hasNext() ) {
- Object key = iter.next();
- result.put(
- key,
- cache.get( new Fqn( regionFqn, key ), ITEM )
- );
- }
- }
- return result;
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
- private Set getChildrenNames()
- {
- try {
- Node base = cache.getRoot().getChild( regionFqn );
- return base == null ? null : base.getChildrenNames();
- }
- catch (Exception e) {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
-
public String toString() {
- return "OptimisticTreeCache(" + regionName + ')';
+ return "OptimisticJBCCache(" + regionName + ')';
}
-
- private boolean isSharedClassLoaderRegion(String regionName)
- {
- return (StandardQueryCache.class.getName().equals(regionName)
- || UpdateTimestampsCache.class.getName().equals(regionName));
- }
-
- private void activateCacheRegion(String regionName) throws CacheException
- {
- Region region = cache.getRegion(regionFqn, true);
- if (region.isActive() == false)
- {
- try
- {
- // Only register the classloader if it's not a shared region.
- // If it's shared, no single classloader is valid
- if (!isSharedClassLoaderRegion(regionName))
- {
- region.registerContextClassLoader(Thread.currentThread().getContextClassLoader());
- }
- region.activate();
- }
- catch (Exception e)
- {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
- }
-
- private void inactivateCacheRegion() throws CacheException
- {
- Region region = cache.getRegion(regionFqn, false);
- if (region != null && region.isActive())
- {
- try
- {
- region.deactivate();
- region.unregisterContextClassLoader();
- }
- catch (Exception e)
- {
- throw SecondLevelCacheUtil.convertToHibernateException(e);
- }
- }
- }
public static class DataVersionAdapter implements DataVersion
{
private static final long serialVersionUID = 5564692336076405571L;
private final Object currentVersion;
private final Object previousVersion;
- private final Comparator versionComparator;
+ private final Comparator<Object> versionComparator;
private final String sourceIdentifer;
- public DataVersionAdapter(Object currentVersion, Object previousVersion, Comparator versionComparator, String sourceIdentifer) {
+ public DataVersionAdapter(Object currentVersion, Object previousVersion, Comparator<Object> versionComparator, String sourceIdentifer) {
this.currentVersion = currentVersion;
this.previousVersion = previousVersion;
this.versionComparator = versionComparator;
Copied: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/PessimisticJBCCache.java (from rev 73422, projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/JBCCache.java)
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/PessimisticJBCCache.java (rev 0)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/PessimisticJBCCache.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -0,0 +1,208 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 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.jboss.ejb3.entity;
+
+import java.util.Properties;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.QueryKey;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.ejb3.entity.OptimisticJBCCache.NonLockingDataVersion;
+
+/**
+ * {@link Cache} implementation that uses a 2.x or later release of
+ * JBoss Cache configured for pessimistic locking.
+ *
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1.1 $
+ */
+public class PessimisticJBCCache extends JBCCacheBase implements Cache
+{
+ public PessimisticJBCCache(org.jboss.cache.Cache<Object, Object> cache, String regionName,
+ String regionPrefix, TransactionManager transactionManager,
+ Properties properties)
+ throws CacheException {
+ super(cache, regionName, regionPrefix, transactionManager, properties);
+ }
+
+ @Override
+ protected void establishRegionRootNode()
+ {
+ // For pessimistic locking, we just want to toss out our ref
+ // to any old invalid root node and get the latest (may be null)
+ regionRoot = cache.getRoot().getChild( regionFqn );
+ }
+
+ @Override
+ protected Node<Object, Object> createRegionRootNode()
+ {
+ Node<Object, Object> root = cache.getRoot();
+ Node<Object, Object> targetNode = root.getChild( regionFqn );
+ if (targetNode == null || !targetNode.isValid()) {
+ cache.getInvocationContext().getOptionOverrides().setDataVersion(NonLockingDataVersion.INSTANCE);
+ targetNode = root.addChild( regionFqn );
+ }
+
+ // Never evict this node
+ targetNode.setResident(true);
+
+ return targetNode;
+ }
+
+ public Object get(Object key) throws CacheException {
+ Transaction tx = suspend();
+ try {
+ ensureRegionRootExists();
+ if (key instanceof QueryKey) {
+ cache.getInvocationContext().getOptionOverrides().setLockAcquisitionTimeout(0);
+ }
+ return cache.get( new Fqn( regionFqn, key ), ITEM );
+ }
+ catch (TimeoutException e) {
+ if (key instanceof QueryKey)
+ return null;
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ finally {
+ resume( tx );
+ }
+ }
+
+ public Object read(Object key) throws CacheException {
+ try {
+ ensureRegionRootExists();
+ return cache.get( new Fqn( regionFqn, key ), ITEM );
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+ public void update(Object key, Object value) throws CacheException {
+ try {
+ ensureRegionRootExists();
+ if (localOnlyQueries && key instanceof QueryKey) {
+ cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+ }
+ cache.put( new Fqn( regionFqn, key ), ITEM, value );
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+ public void put(Object key, Object value) throws CacheException {
+ Transaction tx = null;
+ try {
+ if (forTimestamps) {
+ // For timestamps, we suspend and send async
+ tx = suspend();
+ ensureRegionRootExists();
+ // Timestamps don't use putForExternalRead, but are async
+ if (forceAsync) // else the cache already is async or local
+ {
+ cache.getInvocationContext().getOptionOverrides().setForceAsynchronous(true);
+ }
+ cache.put(new Fqn( regionFqn, key ), ITEM, value);
+ }
+ else if (key instanceof QueryKey) {
+ // For queries we use a short timeout and ignore failures
+ ensureRegionRootExists();
+ Option option = new Option();
+ option.setCacheModeLocal(localOnlyQueries);
+ option.setLockAcquisitionTimeout(2);
+ cache.getInvocationContext().setOptionOverrides(option);
+ cache.put(new Fqn( regionFqn, key ), ITEM, value);
+ }
+ else {
+ ensureRegionRootExists();
+ cache.putForExternalRead(new Fqn( regionFqn, key ), ITEM, value);
+ }
+ }
+ catch (TimeoutException te) {
+ if (!(key instanceof QueryKey))
+ throw SecondLevelCacheUtil.convertToHibernateException(te);
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ finally {
+ resume( tx );
+ }
+ }
+
+ public void remove(Object key) throws CacheException {
+ try {
+ ensureRegionRootExists();
+ if (localOnlyQueries && key instanceof QueryKey) {
+ cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+ }
+ cache.removeNode( new Fqn( regionFqn, key ) );
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+ public void clear() throws CacheException {
+ try {
+ cache.removeNode( regionFqn );
+ }
+ catch (Exception e) {
+ throw SecondLevelCacheUtil.convertToHibernateException(e);
+ }
+ }
+
+ public void destroy() throws CacheException {
+ try {
+ // NOTE : evict() operates locally only (i.e., does not propogate
+ // to any other nodes in the potential cluster). This is
+ // exactly what is needed when we destroy() here; destroy() is used
+ // as part of the process of shutting down a SessionFactory; thus
+ // these removals should not be propogated
+ // FIXME NPE bug in 2.0.0.ALPHA1, so we don't use evict 'til fixed
+// cache.evict( regionFqn, true );
+ cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+ cache.removeNode( regionFqn );
+
+ if (cache.getConfiguration().isUseRegionBasedMarshalling()
+ && !SecondLevelCacheUtil.isSharedClassLoaderRegion(regionName))
+ {
+ inactivateCacheRegion();
+ }
+ }
+ catch( Exception e ) {
+ throw SecondLevelCacheUtil.convertToHibernateException( e );
+ }
+ }
+
+ public String toString() {
+ return "PessimisticJBCCache(" + regionName + ')';
+ }
+}
Modified: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TransactionalCacheFactory.java
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TransactionalCacheFactory.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TransactionalCacheFactory.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -1,3 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 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.jboss.ejb3.entity;
import java.util.Properties;
@@ -6,6 +27,12 @@
import org.hibernate.cache.CacheException;
import org.jboss.cache.Version;
+/**
+ * Factory for <cdoe>org.hibernate.cache.Cache</code> implementations that
+ * work with JBoss Cache.
+ *
+ * @author Brian Stansberry
+ */
public abstract class TransactionalCacheFactory
{
Modified: projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TreeCacheProviderHook.java
===================================================================
--- projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TreeCacheProviderHook.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/main/java/org/jboss/ejb3/entity/TreeCacheProviderHook.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -103,7 +103,7 @@
* @throws org.hibernate.cache.CacheException
* Indicates a problem preparing cache for use.
*/
- public void start(Properties properties)
+ public void start(Properties properties) throws CacheException
{
cacheFactory = TransactionalCacheFactory.getFactory(properties);
cacheFactory.start();
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/EntityTestBean.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/EntityTestBean.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/EntityTestBean.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -60,7 +60,7 @@
private String cacheConfigName;
- private transient Cache cache;
+ private transient Cache<Object, Object> cache;
private transient MyListener listener;
@@ -78,7 +78,7 @@
try
{
//Just to initialise the cache with a listener
- Cache cache = getCache();
+ Cache<Object, Object> cache = getCache();
if (listener == null)
{
listener = new MyListener();
@@ -193,7 +193,6 @@
Cache c = getCache();
if (c != null)
c.removeCacheListener(listener);
- listener = null;
}
}
catch (Exception e)
@@ -232,7 +231,7 @@
}
}
- private Cache getCache() throws Exception
+ private Cache<Object, Object> getCache() throws Exception
{
if (cache == null && cacheConfigName != null)
{
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTest.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTest.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTest.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -52,6 +52,6 @@
public abstract void cleanup();
- public abstract void remove();
+ public abstract void remove(boolean removeEntities);
}
\ No newline at end of file
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTestBean.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTestBean.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/classloader/EntityQueryTestBean.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -66,7 +66,7 @@
private String cacheConfigName;
- private transient Cache cache;
+ private transient Cache<Object, Object> cache;
private MyListener listener;
@@ -84,7 +84,7 @@
try
{
//Just to initialise the cache with a listener
- Cache cache = getCache();
+ Cache<Object, Object> cache = getCache();
listener = new MyListener();
cache.addCacheListener(listener);
}
@@ -243,7 +243,7 @@
saw = true;
}
}
- return saw;
+ return saw;
}
@@ -276,21 +276,24 @@
@PreDestroy
@Remove
- public void remove()
+ public void remove(boolean removeEntities)
{
- try
+ if (removeEntities)
{
- internalCleanup();
+ try
+ {
+ internalCleanup();
+ }
+ catch (Exception e)
+ {
+ log.error("Caught exception in remove", e);
+ }
}
- catch (Exception e)
- {
- log.error("Caught exception in remove", e);
- }
try
{
listener.clear();
- getCache().removeCacheListener(listener);
+ getCache().removeCacheListener(listener);
}
catch (Exception e)
{
@@ -308,7 +311,7 @@
}
}
- private Cache getCache() throws Exception
+ private Cache<Object, Object> getCache() throws Exception
{
if (cache == null && cacheConfigName != null)
{
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityClassloaderTestBase.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityClassloaderTestBase.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityClassloaderTestBase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -99,7 +99,7 @@
{
try
{
- sfsb0.remove();
+ sfsb0.remove(true);
}
catch (Exception e) {}
}
@@ -107,7 +107,7 @@
{
try
{
- sfsb1.remove();
+ sfsb1.remove(true);
}
catch (Exception e) {}
}
@@ -191,8 +191,9 @@
* <code>false</code> if it should be assumed
* the region is activated and able to
* receive replication events.
+ * @param localOnly TODO
*/
- protected void queryTest(boolean setupEntities, boolean useNamedQuery, boolean useNamedRegion, boolean expectInactivatedRegion)
+ protected void queryTest(boolean setupEntities, boolean useNamedQuery, boolean useNamedRegion, boolean expectInactivatedRegion, boolean localOnly)
{
if (setupEntities)
standardEntitySetup();
@@ -219,33 +220,33 @@
// Sleep a bit to allow async repl to happen
sleep(SLEEP_TIME);
- // If region isn't activated yet, should not have been modified
- if (expectInactivatedRegion)
+ // If region is activated and cache isn't localOnly, replication should have been modified
+ boolean modifiedRemotely = sfsb1.getSawRegionModification(regionName);
+ assertEquals("Query cache remotely modified " + regionName,
+ !expectInactivatedRegion && !localOnly,
+ modifiedRemotely);
+ // Clear the access state
+ sfsb1.getSawRegionAccess(regionName);
+
+ assertEquals("63088 has correct # of accounts", 6, sfsb1.getCountForBranch("63088", useNamedQuery, useNamedRegion));
+
+ if (!modifiedRemotely)
{
- assertFalse("Query cache remotely modified " + regionName,
+ // If not replicated before, local query should have cached it
+ assertTrue("Query cache modified " + regionName,
sfsb1.getSawRegionModification(regionName));
// Clear the access state
sfsb1.getSawRegionAccess(regionName);
}
- else //if (useNamedRegion)
+ else
{
- assertTrue("Query cache remotely modified " + regionName,
- sfsb1.getSawRegionModification(regionName));
- // Clear the access state
- sfsb1.getSawRegionAccess(regionName);
+ // Hibernate may change the query SQL slightly, so we could either
+ // have a modification or an access; either are OK
+ boolean modified = sfsb1.getSawRegionModification(regionName);
+ boolean accessed = sfsb1.getSawRegionAccess(regionName);
+ assertTrue("Query cache used " + regionName, modified || accessed);
}
- assertEquals("63088 has correct # of accounts", 6, sfsb1.getCountForBranch("63088", useNamedQuery, useNamedRegion));
-
- if (expectInactivatedRegion)
- {
- // Query should have activated the region and then been inserted
- assertTrue("Query cache modified " + regionName,
- sfsb1.getSawRegionModification(regionName));
- // Clear the access state
- sfsb1.getSawRegionAccess(regionName);
- }
-
log.info("First query on node 1 done");
// We now have the query cache region activated on both nodes.
@@ -272,9 +273,9 @@
// Do it again from node 1
// First check if the previous queries replicated (if the region is replicable)
-
- assertTrue("Query cache remotely modified " + regionName,
- sfsb1.getSawRegionModification(regionName));
+ modifiedRemotely = sfsb1.getSawRegionModification(regionName);
+ assertEquals("Query cache remotely modified " + regionName,
+ !localOnly, modifiedRemotely);
// Clear the access state
sfsb1.getSawRegionAccess(regionName);
@@ -282,11 +283,22 @@
assertEquals("Correct high balances for Jones", 40, sfsb1.getTotalBalance(JONES, useNamedQuery, useNamedRegion));
- // Should be no change; query was already there
- assertFalse("Query cache modified " + regionName,
- sfsb1.getSawRegionModification(regionName));
- assertTrue("Query cache accessed " + regionName,
- sfsb1.getSawRegionAccess(regionName));
+ if (!modifiedRemotely)
+ {
+ // If not replicated before, local query should have cached it
+ assertTrue("Query cache modified " + regionName,
+ sfsb1.getSawRegionModification(regionName));
+ // Clear the access state
+ sfsb1.getSawRegionAccess(regionName);
+ }
+ else
+ {
+ // Hibernate may change the query SQL slightly, so we could either
+ // have a modification or an access; either are OK
+ boolean modified = sfsb1.getSawRegionModification(regionName);
+ boolean accessed = sfsb1.getSawRegionAccess(regionName);
+ assertTrue("Query cache used " + regionName, modified || accessed);
+ }
log.info("Second set of queries on node1 done");
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryRedeployUnitTestCase.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryRedeployUnitTestCase.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryRedeployUnitTestCase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -46,19 +46,22 @@
public void testRedeploy() throws Exception
{
// Set things up with the default region
- queryTest(true, true, false, false);
+ queryTest(true, true, false, false, false);
// Now get the named query regions active
- queryTest(false, true, true, true);
+ queryTest(false, true, true, true, false);
redeploy();
// Redo the test, but no entity creation
- queryTest(false, true, false, false);
- queryTest(false, true, true, true);
+ queryTest(false, true, false, false, false);
+ queryTest(false, true, true, true, false);
}
private void redeploy() throws Exception
{
+ // Get rid of our old sfsb and make sure its listener is removed from cache
+ sfsb1.remove(false);
+
MBeanServerConnection[] adaptors = getAdaptors();
undeploy(adaptors[1], getEarName() + ".ear");
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryUnitTestCase.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryUnitTestCase.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityQueryUnitTestCase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -45,7 +45,7 @@
public void testManualQueryDefaultRegion() throws Exception
{
log.info("+++ start testManualQueryDefaultRegion");
- queryTest(true, false, false, false);
+ queryTest(true, false, false, false, false);
log.info("+++ end testManualQueryDefaultRegion");
}
@@ -54,7 +54,7 @@
log.info("+++ start testManualQueryNamedRegion");
try
{
- queryTest(true, false, true, firstNamedRegionTest);
+ queryTest(true, false, true, firstNamedRegionTest, false);
}
finally
{
@@ -66,7 +66,7 @@
public void testNamedQueryDefaultRegion() throws Exception
{
log.info("+++ start testNamedQueryDefaultRegion");
- queryTest(true, true, false, false);
+ queryTest(true, true, false, false, false);
log.info("+++ end testNamedQueryDefaultRegion");
}
@@ -75,7 +75,7 @@
log.info("+++ start testNamedQueryNamedRegion");
try
{
- queryTest(true, true, true, firstNamedRegionTest);
+ queryTest(true, true, true, firstNamedRegionTest, false);
}
finally
{
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityUnitTestCase.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityUnitTestCase.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/EntityUnitTestCase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -45,13 +45,46 @@
static boolean deployed = false;
static int test = 0;
+ private EntityTest tester0;
+ private EntityTest tester1;
+
public EntityUnitTestCase(String name)
{
-
super(name);
-
}
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (tester0 != null)
+ {
+ try
+ {
+ tester0.cleanup();
+ }
+ catch (Exception e)
+ {
+ log.error("Problem cleaning up tester0", e);
+ }
+ }
+
+ if (tester1 != null)
+ {
+ try
+ {
+ tester1.cleanup();
+ }
+ catch (Exception e)
+ {
+ log.error("Problem cleaning up tester1", e);
+ }
+ }
+ }
+
+
public void testAll() throws Exception
{
System.out.println("*** testServerFound()");
@@ -78,63 +111,56 @@
InitialContext ctx0 = new InitialContext(prop0);
System.out.println("Create node 0");
- EntityTest tester0 = (EntityTest)ctx0.lookup("EntityTestBean/remote");
+ tester0 = (EntityTest)ctx0.lookup("EntityTestBean/remote");
+ System.out.println("Lookup node 1");
+ InitialContext ctx1 = new InitialContext(prop1);
+ tester1 = (EntityTest)ctx1.lookup("EntityTestBean/remote");
+
+ tester0.getCache(isOptimistic());
+
+ Customer customer = tester0.createCustomer();
+
+ //Call finder twice since Hibernate seems to not actually save collections
+ //into cache on persist(), so make sure it is put into cache on find.
+ System.out.println("Find node 0");
+ customer = tester0.findByCustomerId(customer.getId());
+ System.out.println("Find(2) node 0");
+ customer = tester0.findByCustomerId(customer.getId());
+
+ //Check everything was in cache
+ System.out.println("Check cache 0");
+ try
+ {
+ tester0.loadedFromCache();
+ }
+ catch (Exception e)
+ {
+ log.info("Call to tester0 failed", e);
+ fail(e.getMessage());
+ }
+ // The above placement of the collection in the cache is replicated async
+ // so pause a bit before checking node 1
+ sleep(SLEEP_TIME);
+
+ //Now connect to cache on node2 and make sure it is all there
+
+
+ tester1.getCache(isOptimistic());
+
+ System.out.println("Find node 1");
+ customer = tester1.findByCustomerId(customer.getId());
+
+ //Check everything was in cache
+ System.out.println("Check cache 1");
try
{
- tester0.getCache(isOptimistic());
-
- Customer customer = tester0.createCustomer();
-
- //Call finder twice since Hibernate seems to not actually save collections
- //into cache on persist(), so make sure it is put into cache on find.
- System.out.println("Find node 0");
- customer = tester0.findByCustomerId(customer.getId());
- System.out.println("Find(2) node 0");
- customer = tester0.findByCustomerId(customer.getId());
-
- //Check everything was in cache
- System.out.println("Check cache 0");
- try
- {
- tester0.loadedFromCache();
- }
- catch (Exception e)
- {
- log.info("Call to tester0 failed", e);
- fail(e.getMessage());
- }
-
- // The above placement of the collection in the cache is replicated async
- // so pause a bit before checking node 1
- sleep(SLEEP_TIME);
-
- //Now connect to cache on node2 and make sure it is all there
- System.out.println("Lookup node 1");
- InitialContext ctx1 = new InitialContext(prop1);
-
- EntityTest tester1 = (EntityTest)ctx1.lookup("EntityTestBean/remote");
- tester1.getCache(isOptimistic());
-
- System.out.println("Find node 1");
- customer = tester1.findByCustomerId(customer.getId());
-
- //Check everything was in cache
- System.out.println("Check cache 1");
- try
- {
- tester1.loadedFromCache();
- }
- catch (Exception e)
- {
- log.info("Call to tester1 failed", e);
- fail(e.getMessage());
- }
+ tester1.loadedFromCache();
}
- finally
+ catch (Exception e)
{
- // cleanup the db so we can run this test multiple times w/o restarting the cluster
- tester0.cleanup();
+ log.info("Call to tester1 failed", e);
+ fail(e.getMessage());
}
}
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryRedeployUnitTestCase.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryRedeployUnitTestCase.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryRedeployUnitTestCase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -65,6 +65,11 @@
{
return EAR_NAME;
}
+
+ protected String getJarName()
+ {
+ return EAR_NAME;
+ }
@Override
protected boolean isOptimistic()
Modified: projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryUnitTestCase.java
===================================================================
--- projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryUnitTestCase.java 2008-05-20 14:48:50 UTC (rev 73531)
+++ projects/ejb3/trunk/core/src/test/java/org/jboss/ejb3/test/clusteredentity/unit/OptimisticEntityQueryUnitTestCase.java 2008-05-20 14:48:58 UTC (rev 73532)
@@ -62,6 +62,11 @@
{
return EAR_NAME;
}
+
+ protected String getJarName()
+ {
+ return EAR_NAME;
+ }
@Override
protected boolean isOptimistic()
More information about the jboss-cvs-commits
mailing list