alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (AbstractReadWriteAccessStrategy.java)

This example Hibernate source code file (AbstractReadWriteAccessStrategy.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

atomiclong, cacheexception, comparator, io, item, lock, lock, lockable, lockable, object, object, override, softlock, util, uuid, uuid

The Hibernate AbstractReadWriteAccessStrategy.java source code

package org.hibernate.testing.cache;

import java.io.Serializable;
import java.util.Comparator;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.jboss.logging.Logger;

import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.internal.CoreMessageLogger;

/**
 * @author Strong Liu
 */
abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy {
	private static final CoreMessageLogger LOG = Logger.getMessageLogger(
			CoreMessageLogger.class, AbstractReadWriteAccessStrategy.class.getName()
	);
	private final UUID uuid = UUID.randomUUID();
	private final AtomicLong nextLockId = new AtomicLong();
	private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
	protected java.util.concurrent.locks.Lock readLock = reentrantReadWriteLock.readLock();
	protected java.util.concurrent.locks.Lock writeLock = reentrantReadWriteLock.writeLock();

	/**
	 * Returns <code>null if the item is not readable.  Locked items are not readable, nor are items created
	 * after the start of this transaction.
	 */
	@Override
	public final Object get(Object key, long txTimestamp) throws CacheException {
		try {
			readLock.lock();
			Lockable item = (Lockable) getInternalRegion().get( key );

			boolean readable = item != null && item.isReadable( txTimestamp );
			if ( readable ) {
				return item.getValue();
			}
			else {
				return null;
			}
		}
		finally {
			readLock.unlock();
		}
	}

	abstract Comparator getVersionComparator();

	/**
	 * Returns <code>false and fails to put the value if there is an existing un-writeable item mapped to this
	 * key.
	 */
	@Override
	public final boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
			throws CacheException {
		try {
			writeLock.lock();
			Lockable item = (Lockable) getInternalRegion().get( key );
			boolean writeable = item == null || item.isWriteable( txTimestamp, version, getVersionComparator() );
			if ( writeable ) {
				getInternalRegion().put( key, new Item( value, version, getInternalRegion().nextTimestamp() ) );
				return true;
			}
			else {
				return false;
			}
		}
		finally {
			writeLock.unlock();
		}
	}

	/**
	 * Soft-lock a cache item.
	 */
	public final SoftLock lockItem(Object key, Object version) throws CacheException {

		try {
			writeLock.lock();
			Lockable item = (Lockable) getInternalRegion().get( key );
			long timeout = getInternalRegion().nextTimestamp() + getInternalRegion().getTimeout();
			final Lock lock = ( item == null ) ? new Lock( timeout, uuid, nextLockId(), version ) : item.lock(
					timeout,
					uuid,
					nextLockId()
			);
			getInternalRegion().put( key, lock );
			return lock;
		}
		finally {
			writeLock.unlock();
		}
	}

	/**
	 * Soft-unlock a cache item.
	 */
	public final void unlockItem(Object key, SoftLock lock) throws CacheException {

		try {
			writeLock.lock();
			Lockable item = (Lockable) getInternalRegion().get( key );

			if ( ( item != null ) && item.isUnlockable( lock ) ) {
				decrementLock( key, (Lock) item );
			}
			else {
				handleLockExpiry( key, item );
			}
		}
		finally {
			writeLock.unlock();
		}
	}

	private long nextLockId() {
		return nextLockId.getAndIncrement();
	}

	/**
	 * Unlock and re-put the given key, lock combination.
	 */
	protected void decrementLock(Object key, Lock lock) {
		lock.unlock( getInternalRegion().nextTimestamp() );
		getInternalRegion().put( key, lock );
	}

	/**
	 * Handle the timeout of a previous lock mapped to this key
	 */
	protected void handleLockExpiry(Object key, Lockable lock) {
		LOG.expired(key);
		long ts = getInternalRegion().nextTimestamp() + getInternalRegion().getTimeout();
		// create new lock that times out immediately
		Lock newLock = new Lock( ts, uuid, nextLockId.getAndIncrement(), null );
		newLock.unlock( ts );
		getInternalRegion().put( key, newLock );
	}

	/**
	 * Interface type implemented by all wrapper objects in the cache.
	 */
	protected static interface Lockable {

		/**
		 * Returns <code>true if the enclosed value can be read by a transaction started at the given time.
		 */
		public boolean isReadable(long txTimestamp);

		/**
		 * Returns <code>true if the enclosed value can be replaced with one of the given version by a
		 * transaction started at the given time.
		 */
		public boolean isWriteable(long txTimestamp, Object version, Comparator versionComparator);

		/**
		 * Returns the enclosed value.
		 */
		public Object getValue();

		/**
		 * Returns <code>true if the given lock can be unlocked using the given SoftLock instance as a handle.
		 */
		public boolean isUnlockable(SoftLock lock);

		/**
		 * Locks this entry, stamping it with the UUID and lockId given, with the lock timeout occuring at the specified
		 * time.  The returned Lock object can be used to unlock the entry in the future.
		 */
		public Lock lock(long timeout, UUID uuid, long lockId);
	}

	/**
	 * Wrapper type representing unlocked items.
	 */
	protected final static class Item implements Serializable, Lockable {

		private static final long serialVersionUID = 1L;
		private final Object value;
		private final Object version;
		private final long timestamp;

		/**
		 * Creates an unlocked item wrapping the given value with a version and creation timestamp.
		 */
		Item(Object value, Object version, long timestamp) {
			this.value = value;
			this.version = version;
			this.timestamp = timestamp;
		}

		/**
		 * {@inheritDoc}
		 */
		public boolean isReadable(long txTimestamp) {
			return txTimestamp > timestamp;
		}

		/**
		 * {@inheritDoc}
		 */
		public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) {
			return version != null && versionComparator.compare( version, newVersion ) < 0;
		}

		/**
		 * {@inheritDoc}
		 */
		public Object getValue() {
			return value;
		}

		/**
		 * {@inheritDoc}
		 */
		public boolean isUnlockable(SoftLock lock) {
			return false;
		}

		/**
		 * {@inheritDoc}
		 */
		public Lock lock(long timeout, UUID uuid, long lockId) {
			return new Lock( timeout, uuid, lockId, version );
		}
	}

	/**
	 * Wrapper type representing locked items.
	 */
	protected final static class Lock implements Serializable, Lockable, SoftLock {

		private static final long serialVersionUID = 2L;

		private final UUID sourceUuid;
		private final long lockId;
		private final Object version;

		private long timeout;
		private boolean concurrent;
		private int multiplicity = 1;
		private long unlockTimestamp;

		/**
		 * Creates a locked item with the given identifiers and object version.
		 */
		Lock(long timeout, UUID sourceUuid, long lockId, Object version) {
			this.timeout = timeout;
			this.lockId = lockId;
			this.version = version;
			this.sourceUuid = sourceUuid;
		}

		/**
		 * {@inheritDoc}
		 */
		public boolean isReadable(long txTimestamp) {
			return false;
		}

		/**
		 * {@inheritDoc}
		 */
		public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) {
			if ( txTimestamp > timeout ) {
				// if timedout then allow write
				return true;
			}
			if ( multiplicity > 0 ) {
				// if still locked then disallow write
				return false;
			}
			return version == null ? txTimestamp > unlockTimestamp : versionComparator.compare(
					version,
					newVersion
			) < 0;
		}

		/**
		 * {@inheritDoc}
		 */
		public Object getValue() {
			return null;
		}

		/**
		 * {@inheritDoc}
		 */
		public boolean isUnlockable(SoftLock lock) {
			return equals( lock );
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean equals(Object o) {
			if ( o == this ) {
				return true;
			}
			else if ( o instanceof Lock ) {
				return ( lockId == ( (Lock) o ).lockId ) && sourceUuid.equals( ( (Lock) o ).sourceUuid );
			}
			else {
				return false;
			}
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public int hashCode() {
			int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 );
			int temp = (int) lockId;
			for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) {
				temp ^= ( lockId >>> ( i * Integer.SIZE ) );
			}
			return hash + temp;
		}

		/**
		 * Returns true if this Lock has been concurrently locked by more than one transaction.
		 */
		public boolean wasLockedConcurrently() {
			return concurrent;
		}

		/**
		 * {@inheritDoc}
		 */
		public Lock lock(long timeout, UUID uuid, long lockId) {
			concurrent = true;
			multiplicity++;
			this.timeout = timeout;
			return this;
		}

		/**
		 * Unlocks this Lock, and timestamps the unlock event.
		 */
		public void unlock(long timestamp) {
			if ( --multiplicity == 0 ) {
				unlockTimestamp = timestamp;
			}
		}

		/**
		 * {@inheritDoc}
		 */
		public String toString() {
			StringBuilder sb = new StringBuilder( "Lock Source-UUID:" + sourceUuid + " Lock-ID:" + lockId );
			return sb.toString();
		}
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate AbstractReadWriteAccessStrategy.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.