Steve Ebersole wrote:
Re: #4 : what exactly are these differences? Now is the time to merge it back...
Forgot to attach the diff to my last message. Here it is. - Brian
--- C:\dev\hibernate\Branch_3_2\Hibernate3\src\org\hibernate\cache\TreeCache.java Mon Feb 19 17:05:11 2007 +++ C:\dev\jboss\jboss-4.2\ejb3\src\main\org\jboss\ejb3\entity\JBCCache.java Mon Feb 19 17:12:35 2007 @@ -1,5 +1,25 @@ -//$Id: TreeCache.java 9965 2006-05-30 18:00:28Z [EMAIL PROTECTED] $ -package org.hibernate.cache; +/* + * JBoss, Home of Professional Open Source. + * Copyright 2006, 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; @@ -12,17 +32,24 @@ 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.hibernate.cache.UpdateTimestampsCache; import org.jboss.cache.Fqn; +import org.jboss.cache.config.Option; import org.jboss.cache.lock.TimeoutException; /** - * Represents a particular region within the given JBossCache TreeCache. + * Subclass of the standard <code>org.hibernate.cache.TreeCache</code> used as + * a workaround until issues related to JBCLUSTER-150 are resolved in Hibernate. * * @author Gavin King + * @author Brian Stansberry */ -public class TreeCache implements Cache { +public class JBCCache implements Cache { - private static final Log log = LogFactory.getLog(TreeCache.class); + private static final Log log = LogFactory.getLog(JBCCache.class); private static final String ITEM = "item"; @@ -30,13 +57,40 @@ private final String regionName; private final Fqn regionFqn; private final TransactionManager transactionManager; + private boolean localWritesOnly; - public TreeCache(org.jboss.cache.TreeCache cache, String regionName, TransactionManager transactionManager) + public JBCCache(org.jboss.cache.TreeCache cache, String regionName, TransactionManager transactionManager) throws CacheException { this.cache = cache; this.regionName = regionName; this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) ); this.transactionManager = transactionManager; + if (cache.getUseRegionBasedMarshalling()) + { + localWritesOnly = StandardQueryCache.class.getName().equals(regionName); + + boolean fetchState = cache.getFetchInMemoryState(); + try + { + // We don't want a state transfer for the StandardQueryCache, + // as it can include classes from multiple scoped classloaders + if (localWritesOnly) + cache.setFetchInMemoryState(false); + + // We always activate + activateCacheRegion(regionFqn.toString()); + } + finally + { + // Restore the normal state transfer setting + if (localWritesOnly) + cache.setFetchInMemoryState(fetchState); + } + } + else + { + log.debug("TreeCache is not configured for region based marshalling"); + } } public Object get(Object key) throws CacheException { @@ -60,7 +114,14 @@ public void update(Object key, Object value) throws CacheException { try { - cache.put( new Fqn( regionFqn, key ), ITEM, value ); + if (localWritesOnly) { + Option option = new Option(); + option.setCacheModeLocal(true); + cache.put( new Fqn( regionFqn, key ), ITEM, value, option ); + } + else { + cache.put( new Fqn( regionFqn, key ), ITEM, value ); + } } catch (Exception e) { throw new CacheException(e); @@ -70,8 +131,23 @@ public void put(Object key, Object value) throws CacheException { Transaction tx = suspend(); try { - //do the failfast put outside the scope of the JTA txn - cache.putFailFast( new Fqn( regionFqn, key ), ITEM, value, 0 ); + if (localWritesOnly) { + Option option = new Option(); + option.setCacheModeLocal(true); + // Overloaded method isn't available, so have to use InvocationContext + cache.getInvocationContext().setOptionOverrides(option); + try { + // do the failfast put outside the scope of the JTA txn + cache.putFailFast( new Fqn( regionFqn, key ), ITEM, value, 0 ); + } + finally { + cache.getInvocationContext().setOptionOverrides(null); + } + } + else { + //do the failfast put outside the scope of the JTA txn + cache.putFailFast( new Fqn( regionFqn, key ), ITEM, value, 0 ); + } } catch (TimeoutException te) { //ignore! @@ -109,7 +185,14 @@ public void remove(Object key) throws CacheException { try { - cache.remove( new Fqn( regionFqn, key ) ); + if (localWritesOnly) { + Option option = new Option(); + option.setCacheModeLocal(true); + cache.remove( new Fqn( regionFqn, key ), option ); + } + else { + cache.remove( new Fqn( regionFqn, key ) ); + } } catch (Exception e) { throw new CacheException(e); @@ -127,13 +210,21 @@ 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 - cache.evict( regionFqn ); - } + // NOTE : Hibernate's class uses evict() but that isn't recursive! + //cache.evict( regionFqn ); + Option opt = new Option(); + opt.setCacheModeLocal(true); + cache.remove(regionFqn, opt); + + if (cache.getUseRegionBasedMarshalling() && !isSharedClassLoaderRegion(regionName)) + { + inactivateCacheRegion(); + } + } + catch (CacheException e) + { + throw e; + } catch( Exception e ) { throw new CacheException( e ); } @@ -201,5 +292,59 @@ public String toString() { return "TreeCache(" + regionName + ')'; } - + + private boolean isSharedClassLoaderRegion(String regionName) + { + return (StandardQueryCache.class.getName().equals(regionName) + || UpdateTimestampsCache.class.getName().equals(regionName)); + } + + private void activateCacheRegion(String regionName) throws CacheException + { + String fqnString = regionFqn.toString(); + // FIXME -- find a way that doesn't involve this API + if (cache.getMarshaller().isInactive(fqnString)) + { + try + { + // Only register the classloader if it's not a shared region. + // If it's shared, no single classloader is valid + if (!isSharedClassLoaderRegion(regionName)) + { + cache.registerClassLoader(fqnString, Thread.currentThread().getContextClassLoader()); + } + cache.activateRegion(fqnString); + } + catch (Exception e) + { + throw new CacheException("Problem activating region " + regionName, e); + } + } + else + { + log.debug("activateCacheRegion(): Region " + fqnString + " is already active"); + } + } + + private void inactivateCacheRegion() throws CacheException + { + String fqnString = regionFqn.toString(); + // FIXME -- find a way that doesn't involve this API + if (!cache.getMarshaller().isInactive(fqnString)) + { + try + { + cache.inactivateRegion(fqnString); + cache.unregisterClassLoader(fqnString); + } + catch (Exception e) + { + throw new CacheException("Problem activating region " + fqnString, e); + } + } + else + { + log.debug("inactivateCacheRegion(): Region " + fqnString + " is already inactive"); + } + } }
_______________________________________________ hibernate-dev mailing list hibernate-dev@lists.jboss.org https://lists.jboss.org/mailman/listinfo/hibernate-dev