| //$Id: OptimisticTreeCache.java 9965 2006-05-30 13:00:28 -0500 (Tue, 30 May 2006) [EMAIL PROTECTED] $ | package org.hibernate.cache; | | import java.util.HashMap; | import java.util.Iterator; | import java.util.Map; | import java.util.Set; | import java.util.Comparator; | | | import org.apache.commons.logging.Log; | import org.apache.commons.logging.LogFactory; | import org.jboss.cache.Fqn; | import org.jboss.cache.optimistic.DataVersion; | import org.jboss.cache.config.Option; | import org.jboss.cache.lock.TimeoutException; | | /** | * Represents a particular region within the given JBossCache TreeCache | * utilizing TreeCache's optimistic locking capabilities. | * | * @see OptimisticTreeCacheProvider for more details | * | * @author Steve Ebersole | */ | public class OptimisticTreeCache implements OptimisticCache { | | // todo : eventually merge this with TreeCache and just add optional opt-lock support there. | | private static final Log log = LogFactory.getLog( OptimisticTreeCache.class); | | private static final String ITEM = "item"; | | private org.jboss.cache.TreeCache cache; | private final String regionName; | private final Fqn regionFqn; | private OptimisticCacheSource source; | | public OptimisticTreeCache(org.jboss.cache.TreeCache cache, String regionName) | throws CacheException { | this.cache = cache; | this.regionName = regionName; | this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) ); | } | | | // OptimisticCache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | public void setSource(OptimisticCacheSource source) { | this.source = source; | } | | public void writeInsert(Object key, Object value, Object currentVersion) { | writeUpdate( key, value, currentVersion, null ); | } | | public void writeUpdate(Object key, Object value, Object currentVersion, Object previousVersion) { | try { | Option option = new Option(); | DataVersion dv = ( source != null && source.isVersioned() ) | ? new DataVersionAdapter( currentVersion, previousVersion, source.getVersionComparator(), source.toString() ) | : NonLockingDataVersion.INSTANCE; | option.setDataVersion( dv ); | cache.put( new Fqn( regionFqn, key ), ITEM, value, option ); | } | catch ( Exception e ) { | throw new CacheException( e ); | } | } | | public void writeLoad(Object key, Object value, Object currentVersion) { | try { | Option option = new Option(); | option.setFailSilently( true ); | option.setDataVersion( NonLockingDataVersion.INSTANCE ); | cache.remove( new Fqn( regionFqn, key ), "ITEM", option ); | | 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 ); | cache.put( new Fqn( regionFqn, key ), ITEM, value, option ); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | | // Cache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | public Object get(Object key) throws CacheException { | try { | Option option = new Option(); | option.setFailSilently( true ); | // option.setDataVersion( NonLockingDataVersion.INSTANCE ); | return cache.get( new Fqn( regionFqn, key ), ITEM, option ); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | public Object read(Object key) throws CacheException { | try { | return cache.get( new Fqn( regionFqn, key ), ITEM ); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | public void update(Object key, Object value) throws CacheException { | try { | Option option = new Option(); | option.setDataVersion( NonLockingDataVersion.INSTANCE ); | cache.put( new Fqn( regionFqn, key ), ITEM, value, option ); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | public void put(Object key, Object value) throws CacheException { | 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 ); | cache.put( new Fqn( regionFqn, key ), ITEM, value, option ); | } | catch (TimeoutException te) { | //ignore! | log.debug("ignoring write lock acquisition failure"); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | 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 ); | cache.remove( new Fqn( regionFqn, key ), option ); | } | else { | log.trace( "skipping remove() call as the underlying node did not seem to exist" ); | } | } | catch (Exception e) { | throw new CacheException(e); | } | } | | public void clear() throws CacheException { | try { | Option option = new Option(); | option.setDataVersion( NonLockingDataVersion.INSTANCE ); | cache.remove( regionFqn, option ); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | public void destroy() throws CacheException { | try { | Option option = new Option(); | option.setCacheModeLocal( true ); | option.setFailSilently( true ); | option.setDataVersion( NonLockingDataVersion.INSTANCE ); | cache.remove( regionFqn, option ); | } | catch( Exception e ) { | throw new CacheException( 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 = cache.getChildrenNames( regionFqn ); | return children == null ? 0 : children.size(); | } | catch (Exception e) { | throw new CacheException(e); | } | } | | public long getElementCountOnDisk() { | return 0; | } | | public Map toMap() { | try { | Map result = new HashMap(); | Set childrenNames = cache.getChildrenNames( regionFqn ); | 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 new CacheException(e); | } | } | | public String toString() { | return "OptimisticTreeCache(" + regionName + ')'; | } | | public static class DataVersionAdapter implements DataVersion { | private final Object currentVersion; | private final Object previousVersion; | private final Comparator versionComparator; | private final String sourceIdentifer; | | public DataVersionAdapter(Object currentVersion, Object previousVersion, Comparator versionComparator, String sourceIdentifer) { | this.currentVersion = currentVersion; | this.previousVersion = previousVersion; | this.versionComparator = versionComparator; | this.sourceIdentifer = sourceIdentifer; | log.trace( "created " + this ); | } | | /** | * newerThan() call is dispatched against the DataVersion currently | * associated with the node; the passed dataVersion param is the | * DataVersion associated with the data we are trying to put into | * the node. | * <p/> | * we are expected to return true in the case where we (the current | * node DataVersion) are newer that then incoming value. Returning | * true here essentially means that a optimistic lock failure has | * occured (because conversely, the value we are trying to put into | * the node is "older than" the value already there...) | */ | public boolean newerThan(DataVersion dataVersion) { | log.trace( "checking [" + this + "] against [" + dataVersion + "]" ); | if ( dataVersion instanceof CircumventChecksDataVersion ) { | log.trace( "skipping lock checks..." ); | return false; | } | else if ( dataVersion instanceof NonLockingDataVersion ) { | // can happen because of the multiple ways Cache.remove() | // can be invoked :( | log.trace( "skipping lock checks..." ); | return false; | } | DataVersionAdapter other = ( DataVersionAdapter ) dataVersion; | if ( other.previousVersion == null ) { | log.warn( "Unexpected optimistic lock check on inserting data" ); | // work around the "feature" where tree cache is validating the | // inserted node during the next transaction. no idea... | if ( this == dataVersion ) { | log.trace( "skipping lock checks due to same DV instance" ); | return false; | } | } | return versionComparator.compare( currentVersion, other.previousVersion ) >= 1; | } | | public String toString() { | return super.toString() + " [current=" + currentVersion + ", previous=" + previousVersion + ", src=" + sourceIdentifer + "]"; | } | } | | /** | * Used in regions where no locking should ever occur. This includes query-caches, | * update-timestamps caches, collection caches, and entity caches where the entity | * is not versioned. | */ | public static class NonLockingDataVersion implements DataVersion { | public static final DataVersion INSTANCE = new NonLockingDataVersion(); | public boolean newerThan(DataVersion dataVersion) { | log.trace( "non locking lock check..."); | return false; | } | } | | /** | * Used to signal to a DataVersionAdapter to simply not perform any checks. This | * is currently needed for proper handling of remove() calls for entity cache regions | * (we do not know the version info...). | */ | public static class CircumventChecksDataVersion implements DataVersion { | public static final DataVersion INSTANCE = new CircumventChecksDataVersion(); | public boolean newerThan(DataVersion dataVersion) { | throw new CacheException( "optimistic locking checks should never happen on CircumventChecksDataVersion" ); | } | } | } | |
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3957608#3957608 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3957608 _______________________________________________ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user