| //$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
[email protected]
https://lists.jboss.org/mailman/listinfo/jboss-user