optimistictreecache.java

来自「好东西,hibernate-3.2.0,他是一开元的树杖hibernate-3.」· Java 代码 · 共 330 行

JAVA
330
字号
//$Id: OptimisticTreeCache.java 10118 2006-07-13 21:38:41Z steve.ebersole@jboss.com $
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" );
		}
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?