HHH-8159 - Apply fixups indicated by analysis tools
This commit is contained in:
parent
1b637030bd
commit
bfbc0b88a8
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
package org.hibernate.cache.ehcache;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -47,13 +46,11 @@ import org.hibernate.cfg.Settings;
|
|||
* @author Alex Snaps
|
||||
*/
|
||||
public class EhCacheRegionFactory extends AbstractEhcacheRegionFactory {
|
||||
|
||||
private static final EhCacheMessageLogger LOG = Logger.getMessageLogger(
|
||||
EhCacheMessageLogger.class,
|
||||
EhCacheRegionFactory.class.getName()
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a non-singleton EhCacheRegionFactory
|
||||
*/
|
||||
|
@ -89,7 +86,7 @@ public class EhCacheRegionFactory extends AbstractEhcacheRegionFactory {
|
|||
manager = new CacheManager( configuration );
|
||||
}
|
||||
else {
|
||||
URL url = loadResource( configurationResourceName );
|
||||
final URL url = loadResource( configurationResourceName );
|
||||
final Configuration configuration = HibernateEhcacheUtils.loadAndCorrectConfiguration( url );
|
||||
manager = new CacheManager( configuration );
|
||||
}
|
||||
|
|
|
@ -49,23 +49,17 @@ public class ReadOnlyEhcacheEntityRegionAccessStrategy extends AbstractEhcacheAc
|
|||
super( region, settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return region();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region().get( key );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if ( minimalPutOverride && region().contains( key ) ) {
|
||||
|
@ -77,47 +71,58 @@ public class ReadOnlyEhcacheEntityRegionAccessStrategy extends AbstractEhcacheAc
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws UnsupportedOperationException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* A no-op since this cache is read-only
|
||||
*/
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
evict( key );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* This cache is asynchronous hence a no-op
|
||||
*/
|
||||
@Override
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
region().put( key, value );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* Throws UnsupportedOperationException since this cache is read-only
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException( "Can't write to a readonly object" );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* Throws UnsupportedOperationException since this cache is read-only
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException( "Can't write to a readonly object" );
|
||||
|
|
|
@ -115,7 +115,7 @@ public class ReadWriteEhcacheEntityRegionAccessStrategy
|
|||
final Lockable item = (Lockable) region().get( key );
|
||||
|
||||
if ( item != null && item.isUnlockable( lock ) ) {
|
||||
Lock lockItem = (Lock) item;
|
||||
final Lock lockItem = (Lock) item;
|
||||
if ( lockItem.wasLockedConcurrently() ) {
|
||||
decrementLock( key, lockItem );
|
||||
return false;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,74 +21,88 @@
|
|||
*/
|
||||
package org.hibernate.cache.infinispan;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.internal.util.jndi.JndiHelper;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
import org.infinispan.util.logging.Log;
|
||||
import org.infinispan.util.logging.LogFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.internal.util.jndi.JndiHelper;
|
||||
|
||||
/**
|
||||
* A {@link org.hibernate.cache.spi.RegionFactory} for <a href="http://www.jboss.org/infinispan">Infinispan</a>-backed cache
|
||||
* regions that finds its cache manager in JNDI rather than creating one itself.
|
||||
*
|
||||
*
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public class JndiInfinispanRegionFactory extends InfinispanRegionFactory {
|
||||
|
||||
private static final Log log = LogFactory.getLog(JndiInfinispanRegionFactory.class);
|
||||
private static final Log log = LogFactory.getLog( JndiInfinispanRegionFactory.class );
|
||||
|
||||
/**
|
||||
* Specifies the JNDI name under which the {@link EmbeddedCacheManager} to use is bound.
|
||||
* There is no default value -- the user must specify the property.
|
||||
*/
|
||||
public static final String CACHE_MANAGER_RESOURCE_PROP = "hibernate.cache.infinispan.cachemanager";
|
||||
/**
|
||||
* Specifies the JNDI name under which the {@link EmbeddedCacheManager} to use is bound.
|
||||
* There is no default value -- the user must specify the property.
|
||||
*/
|
||||
public static final String CACHE_MANAGER_RESOURCE_PROP = "hibernate.cache.infinispan.cachemanager";
|
||||
|
||||
public JndiInfinispanRegionFactory() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Constructs a JndiInfinispanRegionFactory
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public JndiInfinispanRegionFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JndiInfinispanRegionFactory(Properties props) {
|
||||
super(props);
|
||||
}
|
||||
/**
|
||||
* Constructs a JndiInfinispanRegionFactory
|
||||
*
|
||||
* @param props Any properties to apply (not used).
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public JndiInfinispanRegionFactory(Properties props) {
|
||||
super( props );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EmbeddedCacheManager createCacheManager(Properties properties) throws CacheException {
|
||||
String name = ConfigurationHelper.getString(CACHE_MANAGER_RESOURCE_PROP, properties, null);
|
||||
if (name == null)
|
||||
throw new CacheException("Configuration property " + CACHE_MANAGER_RESOURCE_PROP + " not set");
|
||||
return locateCacheManager(name, JndiHelper.extractJndiProperties(properties));
|
||||
}
|
||||
@Override
|
||||
protected EmbeddedCacheManager createCacheManager(Properties properties) throws CacheException {
|
||||
final String name = ConfigurationHelper.getString( CACHE_MANAGER_RESOURCE_PROP, properties, null );
|
||||
if ( name == null ) {
|
||||
throw new CacheException( "Configuration property " + CACHE_MANAGER_RESOURCE_PROP + " not set" );
|
||||
}
|
||||
return locateCacheManager( name, JndiHelper.extractJndiProperties( properties ) );
|
||||
}
|
||||
|
||||
private EmbeddedCacheManager locateCacheManager(String jndiNamespace, Properties jndiProperties) {
|
||||
Context ctx = null;
|
||||
try {
|
||||
ctx = new InitialContext(jndiProperties);
|
||||
return (EmbeddedCacheManager) ctx.lookup(jndiNamespace);
|
||||
} catch (NamingException ne) {
|
||||
String msg = "Unable to retrieve CacheManager from JNDI [" + jndiNamespace + "]";
|
||||
log.info(msg, ne);
|
||||
throw new CacheException( msg );
|
||||
} finally {
|
||||
if (ctx != null) {
|
||||
try {
|
||||
ctx.close();
|
||||
} catch( NamingException ne ) {
|
||||
log.info("Unable to release initial context", ne);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private EmbeddedCacheManager locateCacheManager(String jndiNamespace, Properties jndiProperties) {
|
||||
Context ctx = null;
|
||||
try {
|
||||
ctx = new InitialContext( jndiProperties );
|
||||
return (EmbeddedCacheManager) ctx.lookup( jndiNamespace );
|
||||
}
|
||||
catch (NamingException ne) {
|
||||
final String msg = "Unable to retrieve CacheManager from JNDI [" + jndiNamespace + "]";
|
||||
log.info( msg, ne );
|
||||
throw new CacheException( msg );
|
||||
}
|
||||
finally {
|
||||
if ( ctx != null ) {
|
||||
try {
|
||||
ctx.close();
|
||||
}
|
||||
catch (NamingException ne) {
|
||||
log.info( "Unable to release initial context", ne );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
// Do not attempt to stop a cache manager because it wasn't created by this region factory.
|
||||
}
|
||||
@Override
|
||||
public void stop() {
|
||||
// Do not attempt to stop a cache manager because it wasn't created by this region factory.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ package org.hibernate.cache.infinispan;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,7 @@ public class StrategyRegistrationProviderImpl implements StrategyRegistrationPro
|
|||
final List<StrategyRegistration> strategyRegistrations = new ArrayList<StrategyRegistration>();
|
||||
|
||||
strategyRegistrations.add(
|
||||
new SimpleStrategyRegistrationImpl(
|
||||
new SimpleStrategyRegistrationImpl<RegionFactory>(
|
||||
RegionFactory.class,
|
||||
InfinispanRegionFactory.class,
|
||||
"infinispan",
|
||||
|
@ -53,7 +53,7 @@ public class StrategyRegistrationProviderImpl implements StrategyRegistrationPro
|
|||
);
|
||||
|
||||
strategyRegistrations.add(
|
||||
new SimpleStrategyRegistrationImpl(
|
||||
new SimpleStrategyRegistrationImpl<RegionFactory>(
|
||||
RegionFactory.class,
|
||||
JndiInfinispanRegionFactory.class,
|
||||
"infinispan-jndi",
|
||||
|
|
|
@ -32,129 +32,135 @@ import org.infinispan.eviction.EvictionStrategy;
|
|||
import org.hibernate.cache.CacheException;
|
||||
|
||||
/**
|
||||
* This class represents Infinispan cache parameters that can be configured via hibernate configuration properties
|
||||
* for either general entity/collection/query/timestamp data type caches and overrides for individual entity or
|
||||
* This class represents Infinispan cache parameters that can be configured via hibernate configuration properties
|
||||
* for either general entity/collection/query/timestamp data type caches and overrides for individual entity or
|
||||
* collection caches. Configuration these properties override previously defined properties in XML file.
|
||||
*
|
||||
*
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public class TypeOverrides {
|
||||
|
||||
private final Set<String> overridden = new HashSet<String>();
|
||||
private final Set<String> overridden = new HashSet<String>();
|
||||
|
||||
private String cacheName;
|
||||
private String cacheName;
|
||||
|
||||
private EvictionStrategy evictionStrategy;
|
||||
private EvictionStrategy evictionStrategy;
|
||||
|
||||
private long evictionWakeUpInterval;
|
||||
private long evictionWakeUpInterval;
|
||||
|
||||
private int evictionMaxEntries;
|
||||
private int evictionMaxEntries;
|
||||
|
||||
private long expirationLifespan;
|
||||
private long expirationLifespan;
|
||||
|
||||
private long expirationMaxIdle;
|
||||
private long expirationMaxIdle;
|
||||
|
||||
private boolean isExposeStatistics;
|
||||
private boolean isExposeStatistics;
|
||||
|
||||
public String getCacheName() {
|
||||
return cacheName;
|
||||
}
|
||||
public String getCacheName() {
|
||||
return cacheName;
|
||||
}
|
||||
|
||||
public void setCacheName(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
public void setCacheName(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
|
||||
public EvictionStrategy getEvictionStrategy() {
|
||||
return evictionStrategy;
|
||||
}
|
||||
public EvictionStrategy getEvictionStrategy() {
|
||||
return evictionStrategy;
|
||||
}
|
||||
|
||||
public void setEvictionStrategy(String evictionStrategy) {
|
||||
markAsOverriden("evictionStrategy");
|
||||
this.evictionStrategy = EvictionStrategy.valueOf(uc(evictionStrategy));
|
||||
}
|
||||
public void setEvictionStrategy(String evictionStrategy) {
|
||||
markAsOverriden( "evictionStrategy" );
|
||||
this.evictionStrategy = EvictionStrategy.valueOf( uc( evictionStrategy ) );
|
||||
}
|
||||
|
||||
public long getEvictionWakeUpInterval() {
|
||||
return evictionWakeUpInterval;
|
||||
}
|
||||
public long getEvictionWakeUpInterval() {
|
||||
return evictionWakeUpInterval;
|
||||
}
|
||||
|
||||
public void setEvictionWakeUpInterval(long evictionWakeUpInterval) {
|
||||
markAsOverriden("evictionWakeUpInterval");
|
||||
this.evictionWakeUpInterval = evictionWakeUpInterval;
|
||||
}
|
||||
public void setEvictionWakeUpInterval(long evictionWakeUpInterval) {
|
||||
markAsOverriden( "evictionWakeUpInterval" );
|
||||
this.evictionWakeUpInterval = evictionWakeUpInterval;
|
||||
}
|
||||
|
||||
public int getEvictionMaxEntries() {
|
||||
return evictionMaxEntries;
|
||||
}
|
||||
public int getEvictionMaxEntries() {
|
||||
return evictionMaxEntries;
|
||||
}
|
||||
|
||||
public void setEvictionMaxEntries(int evictionMaxEntries) {
|
||||
markAsOverriden("evictionMaxEntries");
|
||||
this.evictionMaxEntries = evictionMaxEntries;
|
||||
}
|
||||
public void setEvictionMaxEntries(int evictionMaxEntries) {
|
||||
markAsOverriden( "evictionMaxEntries" );
|
||||
this.evictionMaxEntries = evictionMaxEntries;
|
||||
}
|
||||
|
||||
public long getExpirationLifespan() {
|
||||
return expirationLifespan;
|
||||
}
|
||||
public long getExpirationLifespan() {
|
||||
return expirationLifespan;
|
||||
}
|
||||
|
||||
public void setExpirationLifespan(long expirationLifespan) {
|
||||
markAsOverriden("expirationLifespan");
|
||||
this.expirationLifespan = expirationLifespan;
|
||||
}
|
||||
public void setExpirationLifespan(long expirationLifespan) {
|
||||
markAsOverriden( "expirationLifespan" );
|
||||
this.expirationLifespan = expirationLifespan;
|
||||
}
|
||||
|
||||
public long getExpirationMaxIdle() {
|
||||
return expirationMaxIdle;
|
||||
}
|
||||
public long getExpirationMaxIdle() {
|
||||
return expirationMaxIdle;
|
||||
}
|
||||
|
||||
public void setExpirationMaxIdle(long expirationMaxIdle) {
|
||||
markAsOverriden("expirationMaxIdle");
|
||||
this.expirationMaxIdle = expirationMaxIdle;
|
||||
}
|
||||
public void setExpirationMaxIdle(long expirationMaxIdle) {
|
||||
markAsOverriden( "expirationMaxIdle" );
|
||||
this.expirationMaxIdle = expirationMaxIdle;
|
||||
}
|
||||
|
||||
public boolean isExposeStatistics() {
|
||||
return isExposeStatistics;
|
||||
}
|
||||
public boolean isExposeStatistics() {
|
||||
return isExposeStatistics;
|
||||
}
|
||||
|
||||
public void setExposeStatistics(boolean isExposeStatistics) {
|
||||
markAsOverriden("isExposeStatistics");
|
||||
this.isExposeStatistics = isExposeStatistics;
|
||||
}
|
||||
public void setExposeStatistics(boolean isExposeStatistics) {
|
||||
markAsOverriden( "isExposeStatistics" );
|
||||
this.isExposeStatistics = isExposeStatistics;
|
||||
}
|
||||
|
||||
public void applyTo(ConfigurationBuilder builder) {
|
||||
if (overridden.contains("evictionStrategy"))
|
||||
builder.eviction().strategy(evictionStrategy);
|
||||
if (overridden.contains("evictionWakeUpInterval"))
|
||||
builder.expiration().wakeUpInterval(evictionWakeUpInterval);
|
||||
if (overridden.contains("evictionMaxEntries"))
|
||||
builder.eviction().maxEntries(evictionMaxEntries);
|
||||
if (overridden.contains("expirationLifespan"))
|
||||
builder.expiration().lifespan(expirationLifespan);
|
||||
if (overridden.contains("expirationMaxIdle"))
|
||||
builder.expiration().maxIdle(expirationMaxIdle);
|
||||
if (overridden.contains("isExposeStatistics") && isExposeStatistics)
|
||||
builder.jmxStatistics().enable();
|
||||
}
|
||||
public void applyTo(ConfigurationBuilder builder) {
|
||||
if ( overridden.contains( "evictionStrategy" ) ) {
|
||||
builder.eviction().strategy( evictionStrategy );
|
||||
}
|
||||
if ( overridden.contains( "evictionWakeUpInterval" ) ) {
|
||||
builder.expiration().wakeUpInterval( evictionWakeUpInterval );
|
||||
}
|
||||
if ( overridden.contains( "evictionMaxEntries" ) ) {
|
||||
builder.eviction().maxEntries( evictionMaxEntries );
|
||||
}
|
||||
if ( overridden.contains( "expirationLifespan" ) ) {
|
||||
builder.expiration().lifespan( expirationLifespan );
|
||||
}
|
||||
if ( overridden.contains( "expirationMaxIdle" ) ) {
|
||||
builder.expiration().maxIdle( expirationMaxIdle );
|
||||
}
|
||||
if ( overridden.contains( "isExposeStatistics" ) && isExposeStatistics ) {
|
||||
builder.jmxStatistics().enable();
|
||||
}
|
||||
}
|
||||
|
||||
public void validateInfinispanConfiguration(Configuration cfg) throws CacheException {
|
||||
// no-op, method overriden
|
||||
}
|
||||
public void validateInfinispanConfiguration(Configuration cfg) throws CacheException {
|
||||
// no-op, method overriden
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append(getClass().getSimpleName()).append('{')
|
||||
.append("cache=").append(cacheName)
|
||||
.append(", strategy=").append(evictionStrategy)
|
||||
.append(", wakeUpInterval=").append(evictionWakeUpInterval)
|
||||
.append(", maxEntries=").append(evictionMaxEntries)
|
||||
.append(", lifespan=").append(expirationLifespan)
|
||||
.append(", maxIdle=").append(expirationMaxIdle)
|
||||
.append('}').toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()
|
||||
+ '{' + "cache=" + cacheName
|
||||
+ ", strategy=" + evictionStrategy
|
||||
+ ", wakeUpInterval=" + evictionWakeUpInterval
|
||||
+ ", maxEntries=" + evictionMaxEntries
|
||||
+ ", lifespan=" + expirationLifespan
|
||||
+ ", maxIdle=" + expirationMaxIdle
|
||||
+ '}';
|
||||
}
|
||||
|
||||
private String uc(String s) {
|
||||
return s == null ? null : s.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
private String uc(String s) {
|
||||
return s == null ? null : s.toUpperCase( Locale.ENGLISH );
|
||||
}
|
||||
|
||||
private void markAsOverriden(String fieldName) {
|
||||
overridden.add(fieldName);
|
||||
}
|
||||
private void markAsOverriden(String fieldName) {
|
||||
overridden.add( fieldName );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
*/
|
||||
package org.hibernate.cache.infinispan.access;
|
||||
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -32,47 +35,45 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
|
||||
/**
|
||||
* Encapsulates logic to allow a {@link TransactionalAccessDelegate} to determine
|
||||
* whether a {@link TransactionalAccessDelegate#putFromLoad(Object, Object, long, Object, boolean)}
|
||||
* call should be allowed to update the cache. A <code>putFromLoad</code> has
|
||||
* the potential to store stale data, since the data may have been removed from the
|
||||
* database and the cache between the time when the data was read from the database
|
||||
* database and the cache between the time when the data was read from the database
|
||||
* and the actual call to <code>putFromLoad</code>.
|
||||
* <p>
|
||||
* The expected usage of this class by a thread that read the cache and did
|
||||
* not find data is:
|
||||
*
|
||||
* <p/>
|
||||
* <ol>
|
||||
* <li> Call {@link #registerPendingPut(Object)}</li>
|
||||
* <li> Read the database</li>
|
||||
* <li> Call {@link #acquirePutFromLoadLock(Object)}
|
||||
* <li> if above returns <code>false</code>, the thread should not cache the data;
|
||||
* only if above returns <code>true</code>, put data in the cache and...</li>
|
||||
* only if above returns <code>true</code>, put data in the cache and...</li>
|
||||
* <li> then call {@link #releasePutFromLoadLock(Object)}</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* <p/>
|
||||
* <p>
|
||||
* The expected usage by a thread that is taking an action such that any pending
|
||||
* <code>putFromLoad</code> may have stale data and should not cache it is to either
|
||||
* call
|
||||
*
|
||||
* <p/>
|
||||
* <ul>
|
||||
* <li> {@link #invalidateKey(Object)} (for a single key invalidation)</li>
|
||||
* <li>or {@link #invalidateRegion()} (for a general invalidation all pending puts)</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* <p/>
|
||||
* <p>
|
||||
* This class also supports the concept of "naked puts", which are calls to
|
||||
* {@link #acquirePutFromLoadLock(Object)} without a preceding {@link #registerPendingPut(Object)}
|
||||
|
@ -80,454 +81,477 @@ import org.infinispan.manager.EmbeddedCacheManager;
|
|||
* </p>
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
*
|
||||
* @version $Revision: $
|
||||
*/
|
||||
public class PutFromLoadValidator {
|
||||
/**
|
||||
* Period (in ms) after a removal during which a call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} that hasn't been
|
||||
* {@link #registerPendingPut(Object) pre-registered} (aka a "naked put")
|
||||
* will return false.
|
||||
* will return false.
|
||||
*/
|
||||
public static final long NAKED_PUT_INVALIDATION_PERIOD = TimeUnit.SECONDS.toMillis(20);
|
||||
/**
|
||||
* Period (in ms) after a removal during which a call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} that hasn't been
|
||||
* {@link #registerPendingPut(Object) pre-registered} (aka a "naked put")
|
||||
* will return false.
|
||||
* will return false.
|
||||
*/
|
||||
public static final long NAKED_PUT_INVALIDATION_PERIOD = TimeUnit.SECONDS.toMillis( 20 );
|
||||
|
||||
/**
|
||||
* Used to determine whether the owner of a pending put is a thread or a transaction
|
||||
*/
|
||||
private final TransactionManager transactionManager;
|
||||
/**
|
||||
* Used to determine whether the owner of a pending put is a thread or a transaction
|
||||
*/
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final long nakedPutInvalidationPeriod;
|
||||
private final long nakedPutInvalidationPeriod;
|
||||
|
||||
/**
|
||||
* Registry of expected, future, isPutValid calls. If a key+owner is registered in this map, it
|
||||
* is not a "naked put" and is allowed to proceed.
|
||||
*/
|
||||
private final ConcurrentMap<Object, PendingPutMap> pendingPuts;
|
||||
/**
|
||||
* Registry of expected, future, isPutValid calls. If a key+owner is registered in this map, it
|
||||
* is not a "naked put" and is allowed to proceed.
|
||||
*/
|
||||
private final ConcurrentMap<Object, PendingPutMap> pendingPuts;
|
||||
|
||||
private final ConcurrentMap<Object, Long> recentRemovals = new ConcurrentHashMap<Object, Long>();
|
||||
/**
|
||||
* List of recent removals. Used to ensure we don't leak memory via the recentRemovals map
|
||||
*/
|
||||
private final List<RecentRemoval> removalsQueue = new LinkedList<RecentRemoval>();
|
||||
/**
|
||||
* The time when the first element in removalsQueue will expire. No reason to do housekeeping on
|
||||
* the queue before this time.
|
||||
*/
|
||||
private volatile long earliestRemovalTimestamp;
|
||||
/** Lock controlling access to removalsQueue */
|
||||
private final Lock removalsLock = new ReentrantLock();
|
||||
private final ConcurrentMap<Object, Long> recentRemovals = new ConcurrentHashMap<Object, Long>();
|
||||
/**
|
||||
* List of recent removals. Used to ensure we don't leak memory via the recentRemovals map
|
||||
*/
|
||||
private final List<RecentRemoval> removalsQueue = new LinkedList<RecentRemoval>();
|
||||
/**
|
||||
* The time when the first element in removalsQueue will expire. No reason to do housekeeping on
|
||||
* the queue before this time.
|
||||
*/
|
||||
private volatile long earliestRemovalTimestamp;
|
||||
/**
|
||||
* Lock controlling access to removalsQueue
|
||||
*/
|
||||
private final Lock removalsLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The time of the last call to regionRemoved(), plus NAKED_PUT_INVALIDATION_PERIOD. All naked
|
||||
* puts will be rejected until the current time is greater than this value.
|
||||
*/
|
||||
private volatile long invalidationTimestamp;
|
||||
/**
|
||||
* The time of the last call to regionRemoved(), plus NAKED_PUT_INVALIDATION_PERIOD. All naked
|
||||
* puts will be rejected until the current time is greater than this value.
|
||||
*/
|
||||
private volatile long invalidationTimestamp;
|
||||
|
||||
/**
|
||||
* Creates a new PutFromLoadValidator.
|
||||
*/
|
||||
public PutFromLoadValidator(AdvancedCache cache) {
|
||||
this(cache, NAKED_PUT_INVALIDATION_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor variant for use by unit tests; allows control of various timeouts by the test.
|
||||
*/
|
||||
public PutFromLoadValidator(AdvancedCache cache,
|
||||
long nakedPutInvalidationPeriod) {
|
||||
this(cache.getCacheManager(), cache.getTransactionManager(),
|
||||
nakedPutInvalidationPeriod);
|
||||
}
|
||||
|
||||
public PutFromLoadValidator(EmbeddedCacheManager cacheManager,
|
||||
TransactionManager tm, long nakedPutInvalidationPeriod) {
|
||||
this.pendingPuts = cacheManager
|
||||
.getCache(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME);
|
||||
this.transactionManager = tm;
|
||||
this.nakedPutInvalidationPeriod = nakedPutInvalidationPeriod;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- Public
|
||||
|
||||
/**
|
||||
* Acquire a lock giving the calling thread the right to put data in the
|
||||
* cache for the given key.
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> A call to this method that returns <code>true</code>
|
||||
* should always be matched with a call to {@link #releasePutFromLoadLock(Object)}.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key
|
||||
*
|
||||
* @return <code>true</code> if the lock is acquired and the cache put
|
||||
* can proceed; <code>false</code> if the data should not be cached
|
||||
*/
|
||||
public boolean acquirePutFromLoadLock(Object key) {
|
||||
boolean valid = false;
|
||||
boolean locked = false;
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
PendingPutMap pending = pendingPuts.get(key);
|
||||
if (pending != null) {
|
||||
locked = pending.acquireLock(100, TimeUnit.MILLISECONDS);
|
||||
if (locked) {
|
||||
try {
|
||||
PendingPut toCancel = pending.remove(getOwnerForPut());
|
||||
if (toCancel != null) {
|
||||
valid = !toCancel.completed;
|
||||
toCancel.completed = true;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (!valid) {
|
||||
pending.releaseLock();
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Key wasn't in pendingPuts, so either this is a "naked put"
|
||||
// or regionRemoved has been called. Check if we can proceed
|
||||
if (now > invalidationTimestamp) {
|
||||
Long removedTime = recentRemovals.get(key);
|
||||
if (removedTime == null || now > removedTime ) {
|
||||
// It's legal to proceed. But we have to record this key
|
||||
// in pendingPuts so releasePutFromLoadLock can find it.
|
||||
// To do this we basically simulate a normal "register
|
||||
// then acquire lock" pattern
|
||||
registerPendingPut(key);
|
||||
locked = acquirePutFromLoadLock(key);
|
||||
valid = locked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (locked) {
|
||||
PendingPutMap toRelease = pendingPuts.get(key);
|
||||
if (toRelease != null) {
|
||||
toRelease.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
if (t instanceof RuntimeException) {
|
||||
throw (RuntimeException) t;
|
||||
} else if (t instanceof Error) {
|
||||
throw (Error) t;
|
||||
} else {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the lock previously obtained by a call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} that returned <code>true</code>.
|
||||
*
|
||||
* @param key the key
|
||||
*/
|
||||
public void releasePutFromLoadLock(Object key) {
|
||||
PendingPutMap pending = pendingPuts.get(key);
|
||||
if (pending != null) {
|
||||
if (pending.size() == 0) {
|
||||
pendingPuts.remove(key, pending);
|
||||
}
|
||||
pending.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates any {@link #registerPendingPut(Object) previously registered pending puts} ensuring a subsequent call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} will return <code>false</code>. <p> This method will block until any
|
||||
* concurrent thread that has {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for the given key
|
||||
* has released the lock. This allows the caller to be certain the putFromLoad will not execute after this method
|
||||
* returns, possibly caching stale data. </p>
|
||||
*
|
||||
* @param key key identifying data whose pending puts should be invalidated
|
||||
* @return <code>true</code> if the invalidation was successful; <code>false</code> if a problem occured (which the
|
||||
* caller should treat as an exception condition)
|
||||
*/
|
||||
public boolean invalidateKey(Object key) {
|
||||
boolean success = true;
|
||||
|
||||
// Invalidate any pending puts
|
||||
PendingPutMap pending = pendingPuts.get(key);
|
||||
if (pending != null) {
|
||||
// This lock should be available very quickly, but we'll be
|
||||
// very patient waiting for it as callers should treat not
|
||||
// acquiring it as an exception condition
|
||||
if (pending.acquireLock(60, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
pending.invalidate();
|
||||
}
|
||||
finally {
|
||||
pending.releaseLock();
|
||||
}
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Record when this occurred to invalidate later naked puts
|
||||
RecentRemoval removal = new RecentRemoval(key, this.nakedPutInvalidationPeriod);
|
||||
recentRemovals.put(key, removal.timestamp);
|
||||
|
||||
// Don't let recentRemovals map become a memory leak
|
||||
RecentRemoval toClean = null;
|
||||
boolean attemptClean = removal.timestamp > earliestRemovalTimestamp;
|
||||
removalsLock.lock();
|
||||
try {
|
||||
removalsQueue.add(removal);
|
||||
|
||||
if (attemptClean) {
|
||||
if (removalsQueue.size() > 1) { // we have at least one as we
|
||||
// just added it
|
||||
toClean = removalsQueue.remove(0);
|
||||
}
|
||||
earliestRemovalTimestamp = removalsQueue.get( 0 ).timestamp;
|
||||
}
|
||||
} finally {
|
||||
removalsLock.unlock();
|
||||
}
|
||||
|
||||
if (toClean != null) {
|
||||
Long cleaned = recentRemovals.get(toClean.key);
|
||||
if (cleaned != null && cleaned.equals(toClean.timestamp)) {
|
||||
cleaned = recentRemovals.remove(toClean.key);
|
||||
if (cleaned != null && !cleaned.equals(toClean.timestamp)) {
|
||||
// Oops; removed the wrong timestamp; restore it
|
||||
recentRemovals.putIfAbsent(toClean.key, cleaned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all {@link #registerPendingPut(Object) previously registered pending puts} ensuring a subsequent call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} will return <code>false</code>. <p> This method will block until any
|
||||
* concurrent thread that has {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for the any key has
|
||||
* released the lock. This allows the caller to be certain the putFromLoad will not execute after this method returns,
|
||||
* possibly caching stale data. </p>
|
||||
*
|
||||
* @return <code>true</code> if the invalidation was successful; <code>false</code> if a problem occured (which the
|
||||
* caller should treat as an exception condition)
|
||||
*/
|
||||
public boolean invalidateRegion() {
|
||||
|
||||
boolean ok = false;
|
||||
invalidationTimestamp = System.currentTimeMillis() + this.nakedPutInvalidationPeriod;
|
||||
|
||||
try {
|
||||
|
||||
// Acquire the lock for each entry to ensure any ongoing
|
||||
// work associated with it is completed before we return
|
||||
for (PendingPutMap entry : pendingPuts.values()) {
|
||||
if (entry.acquireLock(60, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
entry.invalidate();
|
||||
}
|
||||
finally {
|
||||
entry.releaseLock();
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
removalsLock.lock();
|
||||
try {
|
||||
recentRemovals.clear();
|
||||
removalsQueue.clear();
|
||||
|
||||
ok = true;
|
||||
|
||||
} finally {
|
||||
removalsLock.unlock();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
ok = false;
|
||||
}
|
||||
finally {
|
||||
earliestRemovalTimestamp = invalidationTimestamp;
|
||||
}
|
||||
|
||||
return ok;
|
||||
/**
|
||||
* Creates a new PutFromLoadValidator.
|
||||
*/
|
||||
public PutFromLoadValidator(AdvancedCache cache) {
|
||||
this( cache, NAKED_PUT_INVALIDATION_PERIOD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this validator that it is expected that a database read followed by a subsequent {@link
|
||||
* #acquirePutFromLoadLock(Object)} call will occur. The intent is this method would be called following a cache miss
|
||||
* wherein it is expected that a database read plus cache put will occur. Calling this method allows the validator to
|
||||
* treat the subsequent <code>acquirePutFromLoadLock</code> as if the database read occurred when this method was
|
||||
* invoked. This allows the validator to compare the timestamp of this call against the timestamp of subsequent removal
|
||||
* notifications. A put that occurs without this call preceding it is "naked"; i.e the validator must assume the put is
|
||||
* not valid if any relevant removal has occurred within {@link #NAKED_PUT_INVALIDATION_PERIOD} milliseconds.
|
||||
*
|
||||
* @param key key that will be used for subsequent cache put
|
||||
*/
|
||||
public void registerPendingPut(Object key) {
|
||||
PendingPut pendingPut = new PendingPut(getOwnerForPut());
|
||||
PendingPutMap pendingForKey = new PendingPutMap(pendingPut);
|
||||
/**
|
||||
* Constructor variant for use by unit tests; allows control of various timeouts by the test.
|
||||
*/
|
||||
public PutFromLoadValidator(
|
||||
AdvancedCache cache,
|
||||
long nakedPutInvalidationPeriod) {
|
||||
this(
|
||||
cache.getCacheManager(), cache.getTransactionManager(),
|
||||
nakedPutInvalidationPeriod
|
||||
);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
PendingPutMap existing = pendingPuts.putIfAbsent(key, pendingForKey);
|
||||
if (existing != null) {
|
||||
if (existing.acquireLock(10, TimeUnit.SECONDS)) {
|
||||
public PutFromLoadValidator(
|
||||
EmbeddedCacheManager cacheManager,
|
||||
TransactionManager tm, long nakedPutInvalidationPeriod) {
|
||||
this.pendingPuts = cacheManager
|
||||
.getCache( InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME );
|
||||
this.transactionManager = tm;
|
||||
this.nakedPutInvalidationPeriod = nakedPutInvalidationPeriod;
|
||||
}
|
||||
|
||||
try {
|
||||
existing.put(pendingPut);
|
||||
PendingPutMap doublecheck = pendingPuts.putIfAbsent(key, existing);
|
||||
if (doublecheck == null || doublecheck == existing) {
|
||||
break;
|
||||
}
|
||||
// else we hit a race and need to loop to try again
|
||||
}
|
||||
finally {
|
||||
existing.releaseLock();
|
||||
}
|
||||
} else {
|
||||
// Can't get the lock; when we come back we'll be a "naked put"
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// normal case
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------- Public
|
||||
|
||||
// -------------------------------------------------------------- Protected
|
||||
/**
|
||||
* Acquire a lock giving the calling thread the right to put data in the
|
||||
* cache for the given key.
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> A call to this method that returns <code>true</code>
|
||||
* should always be matched with a call to {@link #releasePutFromLoadLock(Object)}.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key
|
||||
*
|
||||
* @return <code>true</code> if the lock is acquired and the cache put
|
||||
* can proceed; <code>false</code> if the data should not be cached
|
||||
*/
|
||||
public boolean acquirePutFromLoadLock(Object key) {
|
||||
boolean valid = false;
|
||||
boolean locked = false;
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
/** Only for use by unit tests; may be removed at any time */
|
||||
protected int getRemovalQueueLength() {
|
||||
removalsLock.lock();
|
||||
try {
|
||||
return removalsQueue.size();
|
||||
} finally {
|
||||
removalsLock.unlock();
|
||||
}
|
||||
}
|
||||
try {
|
||||
final PendingPutMap pending = pendingPuts.get( key );
|
||||
if ( pending != null ) {
|
||||
locked = pending.acquireLock( 100, TimeUnit.MILLISECONDS );
|
||||
if ( locked ) {
|
||||
try {
|
||||
final PendingPut toCancel = pending.remove( getOwnerForPut() );
|
||||
if ( toCancel != null ) {
|
||||
valid = !toCancel.completed;
|
||||
toCancel.completed = true;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ( !valid ) {
|
||||
pending.releaseLock();
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Key wasn't in pendingPuts, so either this is a "naked put"
|
||||
// or regionRemoved has been called. Check if we can proceed
|
||||
if ( now > invalidationTimestamp ) {
|
||||
final Long removedTime = recentRemovals.get( key );
|
||||
if ( removedTime == null || now > removedTime ) {
|
||||
// It's legal to proceed. But we have to record this key
|
||||
// in pendingPuts so releasePutFromLoadLock can find it.
|
||||
// To do this we basically simulate a normal "register
|
||||
// then acquire lock" pattern
|
||||
registerPendingPut( key );
|
||||
locked = acquirePutFromLoadLock( key );
|
||||
valid = locked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if ( locked ) {
|
||||
final PendingPutMap toRelease = pendingPuts.get( key );
|
||||
if ( toRelease != null ) {
|
||||
toRelease.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Private
|
||||
if ( t instanceof RuntimeException ) {
|
||||
throw (RuntimeException) t;
|
||||
}
|
||||
else if ( t instanceof Error ) {
|
||||
throw (Error) t;
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException( t );
|
||||
}
|
||||
}
|
||||
|
||||
private Object getOwnerForPut() {
|
||||
Transaction tx = null;
|
||||
try {
|
||||
if (transactionManager != null) {
|
||||
tx = transactionManager.getTransaction();
|
||||
}
|
||||
} catch (SystemException se) {
|
||||
throw new CacheException("Could not obtain transaction", se);
|
||||
}
|
||||
return tx == null ? Thread.currentThread() : tx;
|
||||
return valid;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Releases the lock previously obtained by a call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} that returned <code>true</code>.
|
||||
*
|
||||
* @param key the key
|
||||
*/
|
||||
public void releasePutFromLoadLock(Object key) {
|
||||
final PendingPutMap pending = pendingPuts.get( key );
|
||||
if ( pending != null ) {
|
||||
if ( pending.size() == 0 ) {
|
||||
pendingPuts.remove( key, pending );
|
||||
}
|
||||
pending.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy-initialization map for PendingPut. Optimized for the expected usual case where only a
|
||||
* single put is pending for a given key.
|
||||
*
|
||||
* This class is NOT THREAD SAFE. All operations on it must be performed with the lock held.
|
||||
*/
|
||||
private static class PendingPutMap {
|
||||
private PendingPut singlePendingPut;
|
||||
private Map<Object, PendingPut> fullMap;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
/**
|
||||
* Invalidates any {@link #registerPendingPut(Object) previously registered pending puts} ensuring a subsequent call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} will return <code>false</code>. <p> This method will block until any
|
||||
* concurrent thread that has {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for the given key
|
||||
* has released the lock. This allows the caller to be certain the putFromLoad will not execute after this method
|
||||
* returns, possibly caching stale data. </p>
|
||||
*
|
||||
* @param key key identifying data whose pending puts should be invalidated
|
||||
*
|
||||
* @return <code>true</code> if the invalidation was successful; <code>false</code> if a problem occured (which the
|
||||
* caller should treat as an exception condition)
|
||||
*/
|
||||
public boolean invalidateKey(Object key) {
|
||||
boolean success = true;
|
||||
|
||||
PendingPutMap(PendingPut singleItem) {
|
||||
this.singlePendingPut = singleItem;
|
||||
}
|
||||
// Invalidate any pending puts
|
||||
final PendingPutMap pending = pendingPuts.get( key );
|
||||
if ( pending != null ) {
|
||||
// This lock should be available very quickly, but we'll be
|
||||
// very patient waiting for it as callers should treat not
|
||||
// acquiring it as an exception condition
|
||||
if ( pending.acquireLock( 60, TimeUnit.SECONDS ) ) {
|
||||
try {
|
||||
pending.invalidate();
|
||||
}
|
||||
finally {
|
||||
pending.releaseLock();
|
||||
}
|
||||
}
|
||||
else {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void put(PendingPut pendingPut) {
|
||||
if (singlePendingPut == null) {
|
||||
if (fullMap == null) {
|
||||
// initial put
|
||||
singlePendingPut = pendingPut;
|
||||
} else {
|
||||
fullMap.put(pendingPut.owner, pendingPut);
|
||||
}
|
||||
} else {
|
||||
// 2nd put; need a map
|
||||
fullMap = new HashMap<Object, PendingPut>(4);
|
||||
fullMap.put(singlePendingPut.owner, singlePendingPut);
|
||||
singlePendingPut = null;
|
||||
fullMap.put(pendingPut.owner, pendingPut);
|
||||
}
|
||||
}
|
||||
// Record when this occurred to invalidate later naked puts
|
||||
final RecentRemoval removal = new RecentRemoval( key, this.nakedPutInvalidationPeriod );
|
||||
recentRemovals.put( key, removal.timestamp );
|
||||
|
||||
public PendingPut remove(Object ownerForPut) {
|
||||
PendingPut removed = null;
|
||||
if (fullMap == null) {
|
||||
if (singlePendingPut != null
|
||||
&& singlePendingPut.owner.equals(ownerForPut)) {
|
||||
removed = singlePendingPut;
|
||||
singlePendingPut = null;
|
||||
}
|
||||
} else {
|
||||
removed = fullMap.remove(ownerForPut);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
// Don't let recentRemovals map become a memory leak
|
||||
RecentRemoval toClean = null;
|
||||
final boolean attemptClean = removal.timestamp > earliestRemovalTimestamp;
|
||||
removalsLock.lock();
|
||||
try {
|
||||
removalsQueue.add( removal );
|
||||
|
||||
public int size() {
|
||||
return fullMap == null ? (singlePendingPut == null ? 0 : 1)
|
||||
: fullMap.size();
|
||||
}
|
||||
if ( attemptClean ) {
|
||||
if ( removalsQueue.size() > 1 ) {
|
||||
// we have at least one as we just added it
|
||||
toClean = removalsQueue.remove( 0 );
|
||||
}
|
||||
earliestRemovalTimestamp = removalsQueue.get( 0 ).timestamp;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
removalsLock.unlock();
|
||||
}
|
||||
|
||||
public boolean acquireLock(long time, TimeUnit unit) {
|
||||
try {
|
||||
return lock.tryLock(time, unit);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( toClean != null ) {
|
||||
Long cleaned = recentRemovals.get( toClean.key );
|
||||
if ( cleaned != null && cleaned.equals( toClean.timestamp ) ) {
|
||||
cleaned = recentRemovals.remove( toClean.key );
|
||||
if ( cleaned != null && !cleaned.equals( toClean.timestamp ) ) {
|
||||
// Oops; removed the wrong timestamp; restore it
|
||||
recentRemovals.putIfAbsent( toClean.key, cleaned );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseLock() {
|
||||
lock.unlock();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
if (singlePendingPut != null) {
|
||||
singlePendingPut.completed = true;
|
||||
// Nullify to avoid leaking completed pending puts
|
||||
singlePendingPut = null;
|
||||
} else if (fullMap != null) {
|
||||
for (PendingPut pp : fullMap.values()) {
|
||||
pp.completed = true;
|
||||
}
|
||||
// Nullify to avoid leaking completed pending puts
|
||||
fullMap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Invalidates all {@link #registerPendingPut(Object) previously registered pending puts} ensuring a subsequent call to
|
||||
* {@link #acquirePutFromLoadLock(Object)} will return <code>false</code>. <p> This method will block until any
|
||||
* concurrent thread that has {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for the any key has
|
||||
* released the lock. This allows the caller to be certain the putFromLoad will not execute after this method returns,
|
||||
* possibly caching stale data. </p>
|
||||
*
|
||||
* @return <code>true</code> if the invalidation was successful; <code>false</code> if a problem occured (which the
|
||||
* caller should treat as an exception condition)
|
||||
*/
|
||||
public boolean invalidateRegion() {
|
||||
|
||||
private static class PendingPut {
|
||||
private final Object owner;
|
||||
private volatile boolean completed;
|
||||
boolean ok = false;
|
||||
invalidationTimestamp = System.currentTimeMillis() + this.nakedPutInvalidationPeriod;
|
||||
|
||||
private PendingPut(Object owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
||||
private static class RecentRemoval {
|
||||
private final Object key;
|
||||
private final Long timestamp;
|
||||
// Acquire the lock for each entry to ensure any ongoing
|
||||
// work associated with it is completed before we return
|
||||
for ( PendingPutMap entry : pendingPuts.values() ) {
|
||||
if ( entry.acquireLock( 60, TimeUnit.SECONDS ) ) {
|
||||
try {
|
||||
entry.invalidate();
|
||||
}
|
||||
finally {
|
||||
entry.releaseLock();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
private RecentRemoval(Object key, long nakedPutInvalidationPeriod) {
|
||||
this.key = key;
|
||||
timestamp = System.currentTimeMillis() + nakedPutInvalidationPeriod;
|
||||
}
|
||||
}
|
||||
removalsLock.lock();
|
||||
try {
|
||||
recentRemovals.clear();
|
||||
removalsQueue.clear();
|
||||
|
||||
ok = true;
|
||||
|
||||
}
|
||||
finally {
|
||||
removalsLock.unlock();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
ok = false;
|
||||
}
|
||||
finally {
|
||||
earliestRemovalTimestamp = invalidationTimestamp;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this validator that it is expected that a database read followed by a subsequent {@link
|
||||
* #acquirePutFromLoadLock(Object)} call will occur. The intent is this method would be called following a cache miss
|
||||
* wherein it is expected that a database read plus cache put will occur. Calling this method allows the validator to
|
||||
* treat the subsequent <code>acquirePutFromLoadLock</code> as if the database read occurred when this method was
|
||||
* invoked. This allows the validator to compare the timestamp of this call against the timestamp of subsequent removal
|
||||
* notifications. A put that occurs without this call preceding it is "naked"; i.e the validator must assume the put is
|
||||
* not valid if any relevant removal has occurred within {@link #NAKED_PUT_INVALIDATION_PERIOD} milliseconds.
|
||||
*
|
||||
* @param key key that will be used for subsequent cache put
|
||||
*/
|
||||
public void registerPendingPut(Object key) {
|
||||
final PendingPut pendingPut = new PendingPut( getOwnerForPut() );
|
||||
final PendingPutMap pendingForKey = new PendingPutMap( pendingPut );
|
||||
|
||||
for (; ; ) {
|
||||
final PendingPutMap existing = pendingPuts.putIfAbsent( key, pendingForKey );
|
||||
if ( existing != null ) {
|
||||
if ( existing.acquireLock( 10, TimeUnit.SECONDS ) ) {
|
||||
|
||||
try {
|
||||
existing.put( pendingPut );
|
||||
final PendingPutMap doublecheck = pendingPuts.putIfAbsent( key, existing );
|
||||
if ( doublecheck == null || doublecheck == existing ) {
|
||||
break;
|
||||
}
|
||||
// else we hit a race and need to loop to try again
|
||||
}
|
||||
finally {
|
||||
existing.releaseLock();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Can't get the lock; when we come back we'll be a "naked put"
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// normal case
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- Protected
|
||||
|
||||
/**
|
||||
* Only for use by unit tests; may be removed at any time
|
||||
*/
|
||||
protected int getRemovalQueueLength() {
|
||||
removalsLock.lock();
|
||||
try {
|
||||
return removalsQueue.size();
|
||||
}
|
||||
finally {
|
||||
removalsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Private
|
||||
|
||||
private Object getOwnerForPut() {
|
||||
Transaction tx = null;
|
||||
try {
|
||||
if ( transactionManager != null ) {
|
||||
tx = transactionManager.getTransaction();
|
||||
}
|
||||
}
|
||||
catch (SystemException se) {
|
||||
throw new CacheException( "Could not obtain transaction", se );
|
||||
}
|
||||
return tx == null ? Thread.currentThread() : tx;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy-initialization map for PendingPut. Optimized for the expected usual case where only a
|
||||
* single put is pending for a given key.
|
||||
* <p/>
|
||||
* This class is NOT THREAD SAFE. All operations on it must be performed with the lock held.
|
||||
*/
|
||||
private static class PendingPutMap {
|
||||
private PendingPut singlePendingPut;
|
||||
private Map<Object, PendingPut> fullMap;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
PendingPutMap(PendingPut singleItem) {
|
||||
this.singlePendingPut = singleItem;
|
||||
}
|
||||
|
||||
public void put(PendingPut pendingPut) {
|
||||
if ( singlePendingPut == null ) {
|
||||
if ( fullMap == null ) {
|
||||
// initial put
|
||||
singlePendingPut = pendingPut;
|
||||
}
|
||||
else {
|
||||
fullMap.put( pendingPut.owner, pendingPut );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 2nd put; need a map
|
||||
fullMap = new HashMap<Object, PendingPut>( 4 );
|
||||
fullMap.put( singlePendingPut.owner, singlePendingPut );
|
||||
singlePendingPut = null;
|
||||
fullMap.put( pendingPut.owner, pendingPut );
|
||||
}
|
||||
}
|
||||
|
||||
public PendingPut remove(Object ownerForPut) {
|
||||
PendingPut removed = null;
|
||||
if ( fullMap == null ) {
|
||||
if ( singlePendingPut != null
|
||||
&& singlePendingPut.owner.equals( ownerForPut ) ) {
|
||||
removed = singlePendingPut;
|
||||
singlePendingPut = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
removed = fullMap.remove( ownerForPut );
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return fullMap == null ? (singlePendingPut == null ? 0 : 1)
|
||||
: fullMap.size();
|
||||
}
|
||||
|
||||
public boolean acquireLock(long time, TimeUnit unit) {
|
||||
try {
|
||||
return lock.tryLock( time, unit );
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseLock() {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
if ( singlePendingPut != null ) {
|
||||
singlePendingPut.completed = true;
|
||||
// Nullify to avoid leaking completed pending puts
|
||||
singlePendingPut = null;
|
||||
}
|
||||
else if ( fullMap != null ) {
|
||||
for ( PendingPut pp : fullMap.values() ) {
|
||||
pp.completed = true;
|
||||
}
|
||||
// Nullify to avoid leaking completed pending puts
|
||||
fullMap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PendingPut {
|
||||
private final Object owner;
|
||||
private volatile boolean completed;
|
||||
|
||||
private PendingPut(Object owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RecentRemoval {
|
||||
private final Object key;
|
||||
private final Long timestamp;
|
||||
|
||||
private RecentRemoval(Object key, long nakedPutInvalidationPeriod) {
|
||||
this.key = key;
|
||||
timestamp = System.currentTimeMillis() + nakedPutInvalidationPeriod;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,158 +25,172 @@ package org.hibernate.cache.infinispan.access;
|
|||
|
||||
import javax.transaction.Transaction;
|
||||
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.util.logging.Log;
|
||||
import org.infinispan.util.logging.LogFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.impl.BaseRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
|
||||
/**
|
||||
* Defines the strategy for transactional access to entity or collection data in a Infinispan instance.
|
||||
* <p>
|
||||
* <p/>
|
||||
* The intent of this class is to encapsulate common code and serve as a delegate for
|
||||
* {@link EntityRegionAccessStrategy} and {@link CollectionRegionAccessStrategy} implementations.
|
||||
*
|
||||
* {@link org.hibernate.cache.spi.access.EntityRegionAccessStrategy}
|
||||
* and {@link org.hibernate.cache.spi.access.CollectionRegionAccessStrategy} implementations.
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public class TransactionalAccessDelegate {
|
||||
private static final Log log = LogFactory.getLog(TransactionalAccessDelegate.class);
|
||||
private static final boolean isTrace = log.isTraceEnabled();
|
||||
private final AdvancedCache cache;
|
||||
private final BaseRegion region;
|
||||
private final PutFromLoadValidator putValidator;
|
||||
private final AdvancedCache<Object, Object> writeCache;
|
||||
private static final Log log = LogFactory.getLog( TransactionalAccessDelegate.class );
|
||||
private static final boolean TRACE_ENABLED = log.isTraceEnabled();
|
||||
private final AdvancedCache cache;
|
||||
private final BaseRegion region;
|
||||
private final PutFromLoadValidator putValidator;
|
||||
private final AdvancedCache<Object, Object> writeCache;
|
||||
|
||||
public TransactionalAccessDelegate(BaseRegion region, PutFromLoadValidator validator) {
|
||||
this.region = region;
|
||||
this.cache = region.getCache();
|
||||
this.putValidator = validator;
|
||||
this.writeCache = Caches.ignoreReturnValuesCache(cache);
|
||||
}
|
||||
public TransactionalAccessDelegate(BaseRegion region, PutFromLoadValidator validator) {
|
||||
this.region = region;
|
||||
this.cache = region.getCache();
|
||||
this.putValidator = validator;
|
||||
this.writeCache = Caches.ignoreReturnValuesCache( cache );
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
if (!region.checkValid())
|
||||
return null;
|
||||
Object val = cache.get(key);
|
||||
if (val == null)
|
||||
putValidator.registerPendingPut(key);
|
||||
return val;
|
||||
}
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
if ( !region.checkValid() ) {
|
||||
return null;
|
||||
}
|
||||
Object val = cache.get( key );
|
||||
if ( val == null ) {
|
||||
putValidator.registerPendingPut( key );
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) {
|
||||
return putFromLoad(key, value, txTimestamp, version, false);
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) {
|
||||
return putFromLoad( key, value, txTimestamp, version, false );
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (!region.checkValid()) {
|
||||
if (isTrace) log.tracef("Region %s not valid", region.getName());
|
||||
return false;
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if ( !region.checkValid() ) {
|
||||
if ( TRACE_ENABLED ) {
|
||||
log.tracef( "Region %s not valid", region.getName() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// In theory, since putForExternalRead is already as minimal as it can
|
||||
// get, we shouldn't be need this check. However, without the check and
|
||||
// without https://issues.jboss.org/browse/ISPN-1986, it's impossible to
|
||||
// know whether the put actually occurred. Knowing this is crucial so
|
||||
// that Hibernate can expose accurate statistics.
|
||||
if (minimalPutOverride && cache.containsKey(key))
|
||||
return false;
|
||||
// In theory, since putForExternalRead is already as minimal as it can
|
||||
// get, we shouldn't be need this check. However, without the check and
|
||||
// without https://issues.jboss.org/browse/ISPN-1986, it's impossible to
|
||||
// know whether the put actually occurred. Knowing this is crucial so
|
||||
// that Hibernate can expose accurate statistics.
|
||||
if ( minimalPutOverride && cache.containsKey( key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!putValidator.acquirePutFromLoadLock(key)) {
|
||||
if (isTrace) log.tracef("Put from load lock not acquired for key %s", key);
|
||||
return false;
|
||||
}
|
||||
if ( !putValidator.acquirePutFromLoadLock( key ) ) {
|
||||
if ( TRACE_ENABLED ) {
|
||||
log.tracef( "Put from load lock not acquired for key %s", key );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
writeCache.putForExternalRead(key, value);
|
||||
} finally {
|
||||
putValidator.releasePutFromLoadLock(key);
|
||||
}
|
||||
try {
|
||||
writeCache.putForExternalRead( key, value );
|
||||
}
|
||||
finally {
|
||||
putValidator.releasePutFromLoadLock( key );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
if (!region.checkValid())
|
||||
return false;
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
if ( !region.checkValid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
writeCache.put(key, value);
|
||||
return true;
|
||||
}
|
||||
writeCache.put( key, value );
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
|
||||
// We update whether or not the region is valid. Other nodes
|
||||
// may have already restored the region so they need to
|
||||
// be informed of the change.
|
||||
writeCache.put(key, value);
|
||||
return true;
|
||||
}
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
// We update whether or not the region is valid. Other nodes
|
||||
// may have already restored the region so they need to
|
||||
// be informed of the change.
|
||||
writeCache.put( key, value );
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void remove(Object key) throws CacheException {
|
||||
if (!putValidator.invalidateKey(key)) {
|
||||
throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
|
||||
}
|
||||
// We update whether or not the region is valid. Other nodes
|
||||
// may have already restored the region so they need to
|
||||
// be informed of the change.
|
||||
writeCache.remove(key);
|
||||
}
|
||||
public void remove(Object key) throws CacheException {
|
||||
if ( !putValidator.invalidateKey( key ) ) {
|
||||
throw new CacheException(
|
||||
"Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName()
|
||||
);
|
||||
}
|
||||
// We update whether or not the region is valid. Other nodes
|
||||
// may have already restored the region so they need to
|
||||
// be informed of the change.
|
||||
writeCache.remove( key );
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
if (!putValidator.invalidateRegion()) {
|
||||
throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
|
||||
}
|
||||
cache.clear();
|
||||
}
|
||||
public void removeAll() throws CacheException {
|
||||
if ( !putValidator.invalidateRegion() ) {
|
||||
throw new CacheException( "Failed to invalidate pending putFromLoad calls for region " + region.getName() );
|
||||
}
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
if (!putValidator.invalidateKey(key)) {
|
||||
throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
|
||||
}
|
||||
writeCache.remove(key);
|
||||
}
|
||||
public void evict(Object key) throws CacheException {
|
||||
if ( !putValidator.invalidateKey( key ) ) {
|
||||
throw new CacheException(
|
||||
"Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName()
|
||||
);
|
||||
}
|
||||
writeCache.remove( key );
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
if (!putValidator.invalidateRegion()) {
|
||||
throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
|
||||
}
|
||||
Transaction tx = region.suspend();
|
||||
try {
|
||||
region.invalidateRegion(); // Invalidate the local region and then go remote
|
||||
Caches.broadcastEvictAll(cache);
|
||||
} finally {
|
||||
region.resume(tx);
|
||||
}
|
||||
}
|
||||
public void evictAll() throws CacheException {
|
||||
if ( !putValidator.invalidateRegion() ) {
|
||||
throw new CacheException( "Failed to invalidate pending putFromLoad calls for region " + region.getName() );
|
||||
}
|
||||
final Transaction tx = region.suspend();
|
||||
try {
|
||||
region.invalidateRegion(); // Invalidate the local region and then go remote
|
||||
Caches.broadcastEvictAll( cache );
|
||||
}
|
||||
finally {
|
||||
region.resume( tx );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-based implementation of the cache region access strategies
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.access;
|
|
@ -1,5 +1,30 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.collection;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
|
||||
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||
|
@ -8,7 +33,6 @@ import org.hibernate.cache.spi.CollectionRegion;
|
|||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
/**
|
||||
* @author Chris Bredesen
|
||||
|
@ -17,21 +41,23 @@ import org.infinispan.AdvancedCache;
|
|||
*/
|
||||
public class CollectionRegionImpl extends BaseTransactionalDataRegion implements CollectionRegion {
|
||||
|
||||
public CollectionRegionImpl(AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super(cache, name, metadata, factory);
|
||||
}
|
||||
public CollectionRegionImpl(
|
||||
AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super( cache, name, metadata, factory );
|
||||
}
|
||||
|
||||
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (AccessType.READ_ONLY.equals(accessType)
|
||||
|| AccessType.TRANSACTIONAL.equals(accessType))
|
||||
return new TransactionalAccess(this);
|
||||
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if ( AccessType.READ_ONLY.equals( accessType )
|
||||
|| AccessType.TRANSACTIONAL.equals( accessType ) ) {
|
||||
return new TransactionalAccess( this );
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access type [" + accessType.getExternalName() + "]");
|
||||
}
|
||||
throw new CacheException( "Unsupported access type [" + accessType.getExternalName() + "]" );
|
||||
}
|
||||
|
||||
public PutFromLoadValidator getPutFromLoadValidator() {
|
||||
return new PutFromLoadValidator(cache);
|
||||
}
|
||||
public PutFromLoadValidator getPutFromLoadValidator() {
|
||||
return new PutFromLoadValidator( cache );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.collection;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
|
@ -8,66 +31,67 @@ import org.hibernate.cache.spi.access.SoftLock;
|
|||
|
||||
/**
|
||||
* Transactional collection region access for Infinispan.
|
||||
*
|
||||
*
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
class TransactionalAccess implements CollectionRegionAccessStrategy {
|
||||
|
||||
private final CollectionRegionImpl region;
|
||||
|
||||
private final TransactionalAccessDelegate delegate;
|
||||
private final CollectionRegionImpl region;
|
||||
|
||||
TransactionalAccess(CollectionRegionImpl region) {
|
||||
this.region = region;
|
||||
this.delegate = new TransactionalAccessDelegate(region, region.getPutFromLoadValidator());
|
||||
}
|
||||
private final TransactionalAccessDelegate delegate;
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
delegate.evict(key);
|
||||
}
|
||||
TransactionalAccess(CollectionRegionImpl region) {
|
||||
this.region = region;
|
||||
this.delegate = new TransactionalAccessDelegate( region, region.getPutFromLoadValidator() );
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
delegate.evictAll();
|
||||
}
|
||||
public void evict(Object key) throws CacheException {
|
||||
delegate.evict( key );
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return delegate.get(key, txTimestamp);
|
||||
}
|
||||
public void evictAll() throws CacheException {
|
||||
delegate.evictAll();
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version);
|
||||
}
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return delegate.get( key, txTimestamp );
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return delegate.putFromLoad( key, value, txTimestamp, version );
|
||||
}
|
||||
|
||||
public void remove(Object key) throws CacheException {
|
||||
delegate.remove(key);
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
return delegate.putFromLoad( key, value, txTimestamp, version, minimalPutOverride );
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
delegate.removeAll();
|
||||
}
|
||||
public void remove(Object key) throws CacheException {
|
||||
delegate.remove( key );
|
||||
}
|
||||
|
||||
public CollectionRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
public void removeAll() throws CacheException {
|
||||
delegate.removeAll();
|
||||
}
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public CollectionRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-based implementation of the collection cache region
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.collection;
|
|
@ -1,5 +1,30 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.entity;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
|
||||
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||
|
@ -9,8 +34,6 @@ import org.hibernate.cache.spi.RegionFactory;
|
|||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
/**
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
|
@ -18,8 +41,9 @@ import org.infinispan.AdvancedCache;
|
|||
*/
|
||||
public class EntityRegionImpl extends BaseTransactionalDataRegion implements EntityRegion {
|
||||
|
||||
public EntityRegionImpl(AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
public EntityRegionImpl(
|
||||
AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super( cache, name, metadata, factory );
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.entity;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
|
@ -14,19 +37,21 @@ import org.hibernate.cache.spi.access.SoftLock;
|
|||
class ReadOnlyAccess extends TransactionalAccess {
|
||||
|
||||
ReadOnlyAccess(EntityRegionImpl region) {
|
||||
super(region);
|
||||
super( region );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion,
|
||||
Object previousVersion) throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only item");
|
||||
public boolean update(
|
||||
Object key, Object value, Object currentVersion,
|
||||
Object previousVersion) throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion,
|
||||
Object previousVersion, SoftLock lock) throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only item");
|
||||
public boolean afterUpdate(
|
||||
Object key, Object value, Object currentVersion,
|
||||
Object previousVersion, SoftLock lock) throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.entity;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
|
@ -8,81 +31,84 @@ import org.hibernate.cache.spi.access.SoftLock;
|
|||
|
||||
/**
|
||||
* Transactional entity region access for Infinispan.
|
||||
*
|
||||
*
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
class TransactionalAccess implements EntityRegionAccessStrategy {
|
||||
|
||||
private final EntityRegionImpl region;
|
||||
|
||||
private final TransactionalAccessDelegate delegate;
|
||||
|
||||
TransactionalAccess(EntityRegionImpl region) {
|
||||
this.region = region;
|
||||
this.delegate = new TransactionalAccessDelegate(region, region.getPutFromLoadValidator());
|
||||
}
|
||||
private final EntityRegionImpl region;
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
delegate.evict(key);
|
||||
}
|
||||
private final TransactionalAccessDelegate delegate;
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
delegate.evictAll();
|
||||
}
|
||||
TransactionalAccess(EntityRegionImpl region) {
|
||||
this.region = region;
|
||||
this.delegate = new TransactionalAccessDelegate( region, region.getPutFromLoadValidator() );
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return delegate.get(key, txTimestamp);
|
||||
}
|
||||
public void evict(Object key) throws CacheException {
|
||||
delegate.evict( key );
|
||||
}
|
||||
|
||||
public EntityRegion getRegion() {
|
||||
return this.region;
|
||||
}
|
||||
public void evictAll() throws CacheException {
|
||||
delegate.evictAll();
|
||||
}
|
||||
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
return delegate.insert(key, value, version);
|
||||
}
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return delegate.get( key, txTimestamp );
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version);
|
||||
}
|
||||
public EntityRegion getRegion() {
|
||||
return this.region;
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
|
||||
}
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
return delegate.insert( key, value, version );
|
||||
}
|
||||
|
||||
public void remove(Object key) throws CacheException {
|
||||
delegate.remove(key);
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return delegate.putFromLoad( key, value, txTimestamp, version );
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
delegate.removeAll();
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
return delegate.putFromLoad( key, value, txTimestamp, version, minimalPutOverride );
|
||||
}
|
||||
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
|
||||
return delegate.update(key, value, currentVersion, previousVersion);
|
||||
}
|
||||
public void remove(Object key) throws CacheException {
|
||||
delegate.remove( key );
|
||||
}
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public void removeAll() throws CacheException {
|
||||
delegate.removeAll();
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return delegate.update( key, value, currentVersion, previousVersion );
|
||||
}
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
}
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-based implementation of the entity cache region
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.entity;
|
|
@ -1,44 +1,49 @@
|
|||
package org.hibernate.cache.infinispan.impl;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
/**
|
||||
* Support for Infinispan {@link GeneralDataRegion} implementors.
|
||||
*
|
||||
*
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public abstract class BaseGeneralDataRegion extends BaseRegion implements GeneralDataRegion {
|
||||
private final AdvancedCache putCache;
|
||||
|
||||
private final AdvancedCache putCache;
|
||||
public BaseGeneralDataRegion(
|
||||
AdvancedCache cache, String name,
|
||||
RegionFactory factory) {
|
||||
super( cache, name, factory );
|
||||
this.putCache = Caches.ignoreReturnValuesCache( cache );
|
||||
}
|
||||
|
||||
public BaseGeneralDataRegion(AdvancedCache cache, String name,
|
||||
RegionFactory factory) {
|
||||
super(cache, name, factory);
|
||||
this.putCache = Caches.ignoreReturnValuesCache(cache);
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void evict(Object key) throws CacheException {
|
||||
cache.evict( key );
|
||||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
cache.evict(key);
|
||||
}
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
cache.clear();
|
||||
}
|
||||
@Override
|
||||
public Object get(Object key) throws CacheException {
|
||||
return cache.get( key );
|
||||
}
|
||||
|
||||
public Object get(Object key) throws CacheException {
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
putCache.put(key, value);
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
putCache.put( key, value );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.impl;
|
||||
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
import org.infinispan.util.logging.Log;
|
||||
import org.infinispan.util.logging.LogFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.Region;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
|
@ -22,184 +45,208 @@ import org.hibernate.cache.spi.RegionFactory;
|
|||
* Support for Infinispan {@link Region}s. Handles common "utility" methods for an underlying named
|
||||
* Cache. In other words, this implementation doesn't actually read or write data. Subclasses are
|
||||
* expected to provide core cache interaction appropriate to the semantics needed.
|
||||
*
|
||||
*
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public abstract class BaseRegion implements Region {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BaseRegion.class);
|
||||
private static final Log log = LogFactory.getLog( BaseRegion.class );
|
||||
|
||||
private enum InvalidateState {
|
||||
INVALID, CLEARING, VALID
|
||||
}
|
||||
private enum InvalidateState {
|
||||
INVALID, CLEARING, VALID
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final AdvancedCache regionClearCache;
|
||||
private final TransactionManager tm;
|
||||
private final Object invalidationMutex = new Object();
|
||||
private final AtomicReference<InvalidateState> invalidateState =
|
||||
new AtomicReference<InvalidateState>(InvalidateState.VALID);
|
||||
private final RegionFactory factory;
|
||||
private final String name;
|
||||
private final AdvancedCache regionClearCache;
|
||||
private final TransactionManager tm;
|
||||
private final Object invalidationMutex = new Object();
|
||||
private final AtomicReference<InvalidateState> invalidateState =
|
||||
new AtomicReference<InvalidateState>( InvalidateState.VALID );
|
||||
private final RegionFactory factory;
|
||||
|
||||
protected final AdvancedCache cache;
|
||||
protected final AdvancedCache cache;
|
||||
|
||||
public BaseRegion(AdvancedCache cache, String name, RegionFactory factory) {
|
||||
this.cache = cache;
|
||||
this.name = name;
|
||||
this.tm = cache.getTransactionManager();
|
||||
this.factory = factory;
|
||||
this.regionClearCache = cache.withFlags(
|
||||
Flag.CACHE_MODE_LOCAL, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT);
|
||||
}
|
||||
public BaseRegion(AdvancedCache cache, String name, RegionFactory factory) {
|
||||
this.cache = cache;
|
||||
this.name = name;
|
||||
this.tm = cache.getTransactionManager();
|
||||
this.factory = factory;
|
||||
this.regionClearCache = cache.withFlags(
|
||||
Flag.CACHE_MODE_LOCAL, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT
|
||||
);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getElementCountInMemory() {
|
||||
if (checkValid())
|
||||
return cache.size();
|
||||
@Override
|
||||
public long getElementCountInMemory() {
|
||||
if ( checkValid() ) {
|
||||
return cache.size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @return -1
|
||||
*/
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* Not supported; returns -1
|
||||
*/
|
||||
@Override
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @return -1
|
||||
*/
|
||||
public long getSizeInMemory() {
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* Not supported; returns -1
|
||||
*/
|
||||
@Override
|
||||
public long getSizeInMemory() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return 600; // 60 seconds
|
||||
}
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
// 60 seconds
|
||||
return 600;
|
||||
}
|
||||
|
||||
public long nextTimestamp() {
|
||||
return factory.nextTimestamp();
|
||||
}
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
return factory.nextTimestamp();
|
||||
}
|
||||
|
||||
public Map toMap() {
|
||||
if (checkValid())
|
||||
return cache;
|
||||
@Override
|
||||
public Map toMap() {
|
||||
if ( checkValid() ) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
public void destroy() throws CacheException {
|
||||
try {
|
||||
cache.stop();
|
||||
} finally {
|
||||
cache.removeListener(this);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
try {
|
||||
cache.stop();
|
||||
}
|
||||
finally {
|
||||
cache.removeListener( this );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Object key) {
|
||||
return checkValid() && cache.containsKey(key);
|
||||
}
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
return checkValid() && cache.containsKey( key );
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
boolean valid = isValid();
|
||||
if (!valid) {
|
||||
synchronized (invalidationMutex) {
|
||||
if (invalidateState.compareAndSet(
|
||||
InvalidateState.INVALID, InvalidateState.CLEARING)) {
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
// Clear region in a separate transaction
|
||||
Caches.withinTx(cache, new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
regionClearCache.clear();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
invalidateState.compareAndSet(
|
||||
InvalidateState.CLEARING, InvalidateState.VALID);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Could not invalidate region: "
|
||||
+ e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resume(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
valid = isValid();
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
public boolean checkValid() {
|
||||
boolean valid = isValid();
|
||||
if ( !valid ) {
|
||||
synchronized (invalidationMutex) {
|
||||
if ( invalidateState.compareAndSet(
|
||||
InvalidateState.INVALID, InvalidateState.CLEARING
|
||||
) ) {
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
// Clear region in a separate transaction
|
||||
Caches.withinTx(
|
||||
cache, new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
regionClearCache.clear();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
invalidateState.compareAndSet(
|
||||
InvalidateState.CLEARING, InvalidateState.VALID
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if ( log.isTraceEnabled() ) {
|
||||
log.trace(
|
||||
"Could not invalidate region: "
|
||||
+ e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resume( tx );
|
||||
}
|
||||
}
|
||||
}
|
||||
valid = isValid();
|
||||
}
|
||||
|
||||
protected boolean isValid() {
|
||||
return invalidateState.get() == InvalidateState.VALID;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the TransactionManager to suspend any ongoing transaction.
|
||||
*
|
||||
* @return the transaction that was suspended, or <code>null</code> if
|
||||
* there wasn't one
|
||||
*/
|
||||
public Transaction suspend() {
|
||||
Transaction tx = null;
|
||||
try {
|
||||
if (tm != null) {
|
||||
tx = tm.suspend();
|
||||
}
|
||||
} catch (SystemException se) {
|
||||
throw new CacheException("Could not suspend transaction", se);
|
||||
}
|
||||
return tx;
|
||||
}
|
||||
protected boolean isValid() {
|
||||
return invalidateState.get() == InvalidateState.VALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the TransactionManager to resume the given transaction
|
||||
*
|
||||
* @param tx
|
||||
* the transaction to suspend. May be <code>null</code>.
|
||||
*/
|
||||
public void resume(Transaction tx) {
|
||||
try {
|
||||
if (tx != null)
|
||||
tm.resume(tx);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException("Could not resume transaction", e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Tell the TransactionManager to suspend any ongoing transaction.
|
||||
*
|
||||
* @return the transaction that was suspended, or <code>null</code> if
|
||||
* there wasn't one
|
||||
*/
|
||||
public Transaction suspend() {
|
||||
Transaction tx = null;
|
||||
try {
|
||||
if ( tm != null ) {
|
||||
tx = tm.suspend();
|
||||
}
|
||||
}
|
||||
catch (SystemException se) {
|
||||
throw new CacheException( "Could not suspend transaction", se );
|
||||
}
|
||||
return tx;
|
||||
}
|
||||
|
||||
public void invalidateRegion() {
|
||||
if (log.isTraceEnabled()) log.trace("Invalidate region: " + name);
|
||||
invalidateState.set(InvalidateState.INVALID);
|
||||
}
|
||||
/**
|
||||
* Tell the TransactionManager to resume the given transaction
|
||||
*
|
||||
* @param tx the transaction to suspend. May be <code>null</code>.
|
||||
*/
|
||||
public void resume(Transaction tx) {
|
||||
try {
|
||||
if ( tx != null ) {
|
||||
tm.resume( tx );
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException( "Could not resume transaction", e );
|
||||
}
|
||||
}
|
||||
|
||||
public TransactionManager getTransactionManager() {
|
||||
return tm;
|
||||
}
|
||||
public void invalidateRegion() {
|
||||
if ( log.isTraceEnabled() ) {
|
||||
log.trace( "Invalidate region: " + name );
|
||||
}
|
||||
invalidateState.set( InvalidateState.INVALID );
|
||||
}
|
||||
|
||||
// Used to satisfy TransactionalDataRegion.isTransactionAware in subclasses
|
||||
@SuppressWarnings("unused")
|
||||
public boolean isTransactionAware() {
|
||||
return tm != null;
|
||||
}
|
||||
public TransactionManager getTransactionManager() {
|
||||
return tm;
|
||||
}
|
||||
|
||||
public AdvancedCache getCache() {
|
||||
return cache;
|
||||
}
|
||||
// Used to satisfy TransactionalDataRegion.isTransactionAware in subclasses
|
||||
@SuppressWarnings("unused")
|
||||
public boolean isTransactionAware() {
|
||||
return tm != null;
|
||||
}
|
||||
|
||||
public AdvancedCache getCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,31 +1,56 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.impl;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
/**
|
||||
* Support for Inifinispan {@link org.hibernate.cache.spi.TransactionalDataRegion} implementors.
|
||||
*
|
||||
*
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public abstract class BaseTransactionalDataRegion
|
||||
extends BaseRegion implements TransactionalDataRegion {
|
||||
extends BaseRegion implements TransactionalDataRegion {
|
||||
|
||||
private final CacheDataDescription metadata;
|
||||
private final CacheDataDescription metadata;
|
||||
|
||||
public BaseTransactionalDataRegion(AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super(cache, name, factory);
|
||||
this.metadata = metadata;
|
||||
}
|
||||
public BaseTransactionalDataRegion(
|
||||
AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super( cache, name, factory );
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
}
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-specific base cache region implementations
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.impl;
|
|
@ -1,5 +1,30 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.naturalid;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
|
||||
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||
|
@ -8,7 +33,6 @@ import org.hibernate.cache.spi.NaturalIdRegion;
|
|||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.infinispan.AdvancedCache;
|
||||
|
||||
/**
|
||||
* Natural ID cache region
|
||||
|
@ -17,16 +41,17 @@ import org.infinispan.AdvancedCache;
|
|||
* @author Galder Zamarreño
|
||||
*/
|
||||
public class NaturalIdRegionImpl extends BaseTransactionalDataRegion
|
||||
implements NaturalIdRegion {
|
||||
implements NaturalIdRegion {
|
||||
|
||||
public NaturalIdRegionImpl(AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super(cache, name, metadata, factory);
|
||||
public NaturalIdRegionImpl(
|
||||
AdvancedCache cache, String name,
|
||||
CacheDataDescription metadata, RegionFactory factory) {
|
||||
super( cache, name, metadata, factory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
switch ( accessType ){
|
||||
switch ( accessType ) {
|
||||
case READ_ONLY:
|
||||
return new ReadOnlyAccess( this );
|
||||
case TRANSACTIONAL:
|
||||
|
@ -37,7 +62,7 @@ public class NaturalIdRegionImpl extends BaseTransactionalDataRegion
|
|||
}
|
||||
|
||||
public PutFromLoadValidator getPutFromLoadValidator() {
|
||||
return new PutFromLoadValidator(cache);
|
||||
return new PutFromLoadValidator( cache );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,28 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.naturalid;
|
||||
|
||||
import org.infinispan.util.logging.Log;
|
||||
import org.infinispan.util.logging.LogFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
|
||||
|
|
|
@ -1,8 +1,30 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.naturalid;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
|
@ -21,12 +43,12 @@ class TransactionalAccess implements NaturalIdRegionAccessStrategy {
|
|||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value) throws CacheException {
|
||||
return delegate.insert(key, value, null);
|
||||
return delegate.insert( key, value, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value) throws CacheException {
|
||||
return delegate.update(key, value, null, null);
|
||||
return delegate.update( key, value, null, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,14 +110,14 @@ class TransactionalAccess implements NaturalIdRegionAccessStrategy {
|
|||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-based implementation of the natural-id cache region
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.naturalid;
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Defines the integration with Infinispan as a second-level cache service.
|
||||
*/
|
||||
package org.hibernate.cache.infinispan;
|
|
@ -1,14 +1,38 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.query;
|
||||
|
||||
import javax.transaction.Transaction;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
|
||||
/**
|
||||
* @author Chris Bredesen
|
||||
|
@ -17,80 +41,91 @@ import org.infinispan.context.Flag;
|
|||
*/
|
||||
public class QueryResultsRegionImpl extends BaseTransactionalDataRegion implements QueryResultsRegion {
|
||||
|
||||
private final AdvancedCache evictCache;
|
||||
private final AdvancedCache putCache;
|
||||
private final AdvancedCache getCache;
|
||||
private final AdvancedCache evictCache;
|
||||
private final AdvancedCache putCache;
|
||||
private final AdvancedCache getCache;
|
||||
|
||||
public QueryResultsRegionImpl(AdvancedCache cache, String name, RegionFactory factory) {
|
||||
super(cache, name, null, factory);
|
||||
// If Infinispan is using INVALIDATION for query cache, we don't want to propagate changes.
|
||||
// We use the Timestamps cache to manage invalidation
|
||||
boolean localOnly = Caches.isInvalidationCache(cache);
|
||||
public QueryResultsRegionImpl(AdvancedCache cache, String name, RegionFactory factory) {
|
||||
super( cache, name, null, factory );
|
||||
// If Infinispan is using INVALIDATION for query cache, we don't want to propagate changes.
|
||||
// We use the Timestamps cache to manage invalidation
|
||||
final boolean localOnly = Caches.isInvalidationCache( cache );
|
||||
|
||||
this.evictCache = localOnly ? Caches.localCache(cache) : cache;
|
||||
this.evictCache = localOnly ? Caches.localCache( cache ) : cache;
|
||||
|
||||
this.putCache = localOnly ?
|
||||
Caches.failSilentWriteCache(cache, Flag.CACHE_MODE_LOCAL) :
|
||||
Caches.failSilentWriteCache(cache);
|
||||
this.putCache = localOnly ?
|
||||
Caches.failSilentWriteCache( cache, Flag.CACHE_MODE_LOCAL ) :
|
||||
Caches.failSilentWriteCache( cache );
|
||||
|
||||
this.getCache = Caches.failSilentReadCache(cache);
|
||||
}
|
||||
this.getCache = Caches.failSilentReadCache( cache );
|
||||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
evictCache.remove(key);
|
||||
}
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
evictCache.remove( key );
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
invalidateRegion(); // Invalidate the local region and then go remote
|
||||
Caches.broadcastEvictAll(cache);
|
||||
} finally {
|
||||
resume(tx);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
final Transaction tx = suspend();
|
||||
try {
|
||||
// Invalidate the local region and then go remote
|
||||
invalidateRegion();
|
||||
Caches.broadcastEvictAll( cache );
|
||||
}
|
||||
finally {
|
||||
resume( tx );
|
||||
}
|
||||
}
|
||||
|
||||
public Object get(Object key) throws CacheException {
|
||||
// If the region is not valid, skip cache store to avoid going remote to retrieve the query.
|
||||
// The aim of this is to maintain same logic/semantics as when state transfer was configured.
|
||||
// TODO: Once https://issues.jboss.org/browse/ISPN-835 has been resolved, revert to state transfer and remove workaround
|
||||
boolean skipCacheStore = false;
|
||||
if (!isValid())
|
||||
skipCacheStore = true;
|
||||
@Override
|
||||
public Object get(Object key) throws CacheException {
|
||||
// If the region is not valid, skip cache store to avoid going remote to retrieve the query.
|
||||
// The aim of this is to maintain same logic/semantics as when state transfer was configured.
|
||||
// TODO: Once https://issues.jboss.org/browse/ISPN-835 has been resolved, revert to state transfer and remove workaround
|
||||
boolean skipCacheStore = false;
|
||||
if ( !isValid() ) {
|
||||
skipCacheStore = true;
|
||||
}
|
||||
|
||||
if (!checkValid())
|
||||
return null;
|
||||
if ( !checkValid() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// In Infinispan get doesn't acquire any locks, so no need to suspend the tx.
|
||||
// In the past, when get operations acquired locks, suspending the tx was a way
|
||||
// to avoid holding locks that would prevent updates.
|
||||
// Add a zero (or low) timeout option so we don't block
|
||||
// waiting for tx's that did a put to commit
|
||||
if (skipCacheStore)
|
||||
return getCache.withFlags(Flag.SKIP_CACHE_STORE).get(key);
|
||||
else
|
||||
return getCache.get(key);
|
||||
}
|
||||
// In Infinispan get doesn't acquire any locks, so no need to suspend the tx.
|
||||
// In the past, when get operations acquired locks, suspending the tx was a way
|
||||
// to avoid holding locks that would prevent updates.
|
||||
// Add a zero (or low) timeout option so we don't block
|
||||
// waiting for tx's that did a put to commit
|
||||
if ( skipCacheStore ) {
|
||||
return getCache.withFlags( Flag.SKIP_CACHE_STORE ).get( key );
|
||||
}
|
||||
else {
|
||||
return getCache.get( key );
|
||||
}
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
if (checkValid()) {
|
||||
// Here we don't want to suspend the tx. If we do:
|
||||
// 1) We might be caching query results that reflect uncommitted
|
||||
// changes. No tx == no WL on cache node, so other threads
|
||||
// can prematurely see those query results
|
||||
// 2) No tx == immediate replication. More overhead, plus we
|
||||
// spread issue #1 above around the cluster
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
if ( checkValid() ) {
|
||||
// Here we don't want to suspend the tx. If we do:
|
||||
// 1) We might be caching query results that reflect uncommitted
|
||||
// changes. No tx == no WL on cache node, so other threads
|
||||
// can prematurely see those query results
|
||||
// 2) No tx == immediate replication. More overhead, plus we
|
||||
// spread issue #1 above around the cluster
|
||||
|
||||
// Add a zero (or quite low) timeout option so we don't block.
|
||||
// Ignore any TimeoutException. Basically we forego caching the
|
||||
// query result in order to avoid blocking.
|
||||
// Reads are done with suspended tx, so they should not hold the
|
||||
// lock for long. Not caching the query result is OK, since
|
||||
// any subsequent read will just see the old result with its
|
||||
// out-of-date timestamp; that result will be discarded and the
|
||||
// db query performed again.
|
||||
putCache.put(key, value);
|
||||
}
|
||||
}
|
||||
// Add a zero (or quite low) timeout option so we don't block.
|
||||
// Ignore any TimeoutException. Basically we forego caching the
|
||||
// query result in order to avoid blocking.
|
||||
// Reads are done with suspended tx, so they should not hold the
|
||||
// lock for long. Not caching the query result is OK, since
|
||||
// any subsequent read will just see the old result with its
|
||||
// out-of-date timestamp; that result will be discarded and the
|
||||
// db query performed again.
|
||||
putCache.put( key, value );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/query/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/query/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-based implementation of the "query results" cache region
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.query;
|
|
@ -20,12 +20,13 @@
|
|||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
|
||||
package org.hibernate.cache.infinispan.timestamp;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import javax.transaction.Transaction;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
import org.infinispan.notifications.Listener;
|
||||
|
@ -34,10 +35,9 @@ import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
|
|||
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
|
||||
|
||||
import javax.transaction.Transaction;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
* Timestamp cache region for clustered environments.
|
||||
|
@ -48,105 +48,118 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
@Listener
|
||||
public class ClusteredTimestampsRegionImpl extends TimestampsRegionImpl {
|
||||
|
||||
/**
|
||||
* Maintains a local (authoritative) cache of timestamps along with the
|
||||
* replicated cache held in Infinispan. It listens for changes in the
|
||||
* cache and updates the local cache accordingly. This approach allows
|
||||
* timestamp changes to be replicated asynchronously.
|
||||
*/
|
||||
private final Map localCache = new ConcurrentHashMap();
|
||||
/**
|
||||
* Maintains a local (authoritative) cache of timestamps along with the
|
||||
* replicated cache held in Infinispan. It listens for changes in the
|
||||
* cache and updates the local cache accordingly. This approach allows
|
||||
* timestamp changes to be replicated asynchronously.
|
||||
*/
|
||||
private final Map localCache = new ConcurrentHashMap();
|
||||
|
||||
public ClusteredTimestampsRegionImpl(AdvancedCache cache,
|
||||
String name, RegionFactory factory) {
|
||||
super(cache, name, factory);
|
||||
cache.addListener(this);
|
||||
populateLocalCache();
|
||||
}
|
||||
public ClusteredTimestampsRegionImpl(
|
||||
AdvancedCache cache,
|
||||
String name, RegionFactory factory) {
|
||||
super( cache, name, factory );
|
||||
cache.addListener( this );
|
||||
populateLocalCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AdvancedCache getTimestampsPutCache(AdvancedCache cache) {
|
||||
return Caches.asyncWriteCache(cache, Flag.SKIP_LOCKING);
|
||||
}
|
||||
@Override
|
||||
protected AdvancedCache getTimestampsPutCache(AdvancedCache cache) {
|
||||
return Caches.asyncWriteCache( cache, Flag.SKIP_LOCKING );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) throws CacheException {
|
||||
Object value = localCache.get(key);
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object get(Object key) throws CacheException {
|
||||
Object value = localCache.get( key );
|
||||
|
||||
// If the region is not valid, skip cache store to avoid going remote to retrieve the query.
|
||||
// The aim of this is to maintain same logic/semantics as when state transfer was configured.
|
||||
// TODO: Once https://issues.jboss.org/browse/ISPN-835 has been resolved, revert to state transfer and remove workaround
|
||||
boolean skipCacheStore = false;
|
||||
if (!isValid())
|
||||
skipCacheStore = true;
|
||||
// If the region is not valid, skip cache store to avoid going remote to retrieve the query.
|
||||
// The aim of this is to maintain same logic/semantics as when state transfer was configured.
|
||||
// TODO: Once https://issues.jboss.org/browse/ISPN-835 has been resolved, revert to state transfer and remove workaround
|
||||
boolean skipCacheStore = false;
|
||||
if ( !isValid() ) {
|
||||
skipCacheStore = true;
|
||||
}
|
||||
|
||||
if (value == null && checkValid()) {
|
||||
if (skipCacheStore)
|
||||
value = cache.withFlags(Flag.SKIP_CACHE_STORE).get(key);
|
||||
else
|
||||
value = cache.get(key);
|
||||
if ( value == null && checkValid() ) {
|
||||
if ( skipCacheStore ) {
|
||||
value = cache.withFlags( Flag.SKIP_CACHE_STORE ).get( key );
|
||||
}
|
||||
else {
|
||||
value = cache.get( key );
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
localCache.put(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if ( value != null ) {
|
||||
localCache.put( key, value );
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
invalidateRegion(); // Invalidate the local region and then go remote
|
||||
Caches.broadcastEvictAll(cache);
|
||||
} finally {
|
||||
resume(tx);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
final Transaction tx = suspend();
|
||||
try {
|
||||
// Invalidate the local region and then go remote
|
||||
invalidateRegion();
|
||||
Caches.broadcastEvictAll( cache );
|
||||
}
|
||||
finally {
|
||||
resume( tx );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateRegion() {
|
||||
super.invalidateRegion(); // Invalidate first
|
||||
localCache.clear();
|
||||
}
|
||||
@Override
|
||||
public void invalidateRegion() {
|
||||
// Invalidate first
|
||||
super.invalidateRegion();
|
||||
localCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
localCache.clear();
|
||||
cache.removeListener(this);
|
||||
super.destroy();
|
||||
}
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
localCache.clear();
|
||||
cache.removeListener( this );
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Brings all data from the distributed cache into our local cache.
|
||||
*/
|
||||
private void populateLocalCache() {
|
||||
Set children = cache.keySet();
|
||||
for (Object key : children)
|
||||
get(key);
|
||||
}
|
||||
/**
|
||||
* Brings all data from the distributed cache into our local cache.
|
||||
*/
|
||||
private void populateLocalCache() {
|
||||
final Set children = cache.keySet();
|
||||
for ( Object key : children ) {
|
||||
get( key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors cache events and updates the local cache
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@CacheEntryModified
|
||||
@SuppressWarnings("unused")
|
||||
public void nodeModified(CacheEntryModifiedEvent event) {
|
||||
if (!event.isPre())
|
||||
localCache.put(event.getKey(), event.getValue());
|
||||
}
|
||||
/**
|
||||
* Monitors cache events and updates the local cache
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
@CacheEntryModified
|
||||
@SuppressWarnings({"unused", "unchecked"})
|
||||
public void nodeModified(CacheEntryModifiedEvent event) {
|
||||
if ( !event.isPre() ) {
|
||||
localCache.put( event.getKey(), event.getValue() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors cache events and updates the local cache
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@CacheEntryRemoved
|
||||
@SuppressWarnings("unused")
|
||||
public void nodeRemoved(CacheEntryRemovedEvent event) {
|
||||
if (event.isPre()) return;
|
||||
localCache.remove(event.getKey());
|
||||
}
|
||||
/**
|
||||
* Monitors cache events and updates the local cache
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
@CacheEntryRemoved
|
||||
@SuppressWarnings("unused")
|
||||
public void nodeRemoved(CacheEntryRemovedEvent event) {
|
||||
if ( event.isPre() ) {
|
||||
return;
|
||||
}
|
||||
localCache.remove( event.getKey() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,21 +29,21 @@ import org.hibernate.cache.infinispan.TypeOverrides;
|
|||
|
||||
/**
|
||||
* TimestampTypeOverrides.
|
||||
*
|
||||
*
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public class TimestampTypeOverrides extends TypeOverrides {
|
||||
|
||||
@Override
|
||||
public void validateInfinispanConfiguration(Configuration cfg) throws CacheException {
|
||||
if (cfg.clustering().cacheMode().isInvalidation()) {
|
||||
throw new CacheException("Timestamp cache cannot be configured with invalidation");
|
||||
}
|
||||
EvictionStrategy strategy = cfg.eviction().strategy();
|
||||
if (!strategy.equals(EvictionStrategy.NONE)) {
|
||||
throw new CacheException("Timestamp cache cannot be configured with eviction");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void validateInfinispanConfiguration(Configuration cfg) throws CacheException {
|
||||
if ( cfg.clustering().cacheMode().isInvalidation() ) {
|
||||
throw new CacheException( "Timestamp cache cannot be configured with invalidation" );
|
||||
}
|
||||
final EvictionStrategy strategy = cfg.eviction().strategy();
|
||||
if ( !strategy.equals( EvictionStrategy.NONE ) ) {
|
||||
throw new CacheException( "Timestamp cache cannot be configured with eviction" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,89 +1,114 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.timestamp;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.transaction.Transaction;
|
||||
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
import org.infinispan.notifications.Listener;
|
||||
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
|
||||
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.infinispan.impl.BaseGeneralDataRegion;
|
||||
import org.hibernate.cache.infinispan.util.Caches;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
|
||||
/**
|
||||
* Defines the behavior of the timestamps cache region for Infinispan.
|
||||
*
|
||||
*
|
||||
* @author Chris Bredesen
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
public class TimestampsRegionImpl extends BaseGeneralDataRegion implements TimestampsRegion {
|
||||
|
||||
private final AdvancedCache removeCache;
|
||||
private final AdvancedCache timestampsPutCache;
|
||||
private final AdvancedCache removeCache;
|
||||
private final AdvancedCache timestampsPutCache;
|
||||
|
||||
public TimestampsRegionImpl(AdvancedCache cache, String name,
|
||||
RegionFactory factory) {
|
||||
super(cache, name, factory);
|
||||
this.removeCache = Caches.ignoreReturnValuesCache(cache);
|
||||
public TimestampsRegionImpl(
|
||||
AdvancedCache cache, String name,
|
||||
RegionFactory factory) {
|
||||
super( cache, name, factory );
|
||||
this.removeCache = Caches.ignoreReturnValuesCache( cache );
|
||||
|
||||
// Skip locking when updating timestamps to provide better performance
|
||||
// under highly concurrent insert scenarios, where update timestamps
|
||||
// for an entity/collection type are constantly updated, creating
|
||||
// contention.
|
||||
//
|
||||
// The worst it can happen is that an earlier an earlier timestamp
|
||||
// (i.e. ts=1) will override a later on (i.e. ts=2), so it means that
|
||||
// in highly concurrent environments, queries might be considered stale
|
||||
// earlier in time. The upside is that inserts/updates are way faster
|
||||
// in local set ups.
|
||||
this.timestampsPutCache = getTimestampsPutCache(cache);
|
||||
}
|
||||
// Skip locking when updating timestamps to provide better performance
|
||||
// under highly concurrent insert scenarios, where update timestamps
|
||||
// for an entity/collection type are constantly updated, creating
|
||||
// contention.
|
||||
//
|
||||
// The worst it can happen is that an earlier an earlier timestamp
|
||||
// (i.e. ts=1) will override a later on (i.e. ts=2), so it means that
|
||||
// in highly concurrent environments, queries might be considered stale
|
||||
// earlier in time. The upside is that inserts/updates are way faster
|
||||
// in local set ups.
|
||||
this.timestampsPutCache = getTimestampsPutCache( cache );
|
||||
}
|
||||
|
||||
protected AdvancedCache getTimestampsPutCache(AdvancedCache cache) {
|
||||
return Caches.ignoreReturnValuesCache(cache, Flag.SKIP_LOCKING);
|
||||
}
|
||||
protected AdvancedCache getTimestampsPutCache(AdvancedCache cache) {
|
||||
return Caches.ignoreReturnValuesCache( cache, Flag.SKIP_LOCKING );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
removeCache.remove(key);
|
||||
}
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
removeCache.remove( key );
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
invalidateRegion(); // Invalidate the local region
|
||||
} finally {
|
||||
resume(tx);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
final Transaction tx = suspend();
|
||||
try {
|
||||
// Invalidate the local region
|
||||
invalidateRegion();
|
||||
}
|
||||
finally {
|
||||
resume( tx );
|
||||
}
|
||||
}
|
||||
|
||||
public Object get(Object key) throws CacheException {
|
||||
if (checkValid())
|
||||
return cache.get(key);
|
||||
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object get(Object key) throws CacheException {
|
||||
if ( checkValid() ) {
|
||||
return cache.get( key );
|
||||
}
|
||||
|
||||
public void put(final Object key, final Object value) throws CacheException {
|
||||
try {
|
||||
// We ensure ASYNC semantics (JBCACHE-1175) and make sure previous
|
||||
// value is not loaded from cache store cos it's not needed.
|
||||
timestampsPutCache.put(key, value);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(final Object key, final Object value) throws CacheException {
|
||||
try {
|
||||
// We ensure ASYNC semantics (JBCACHE-1175) and make sure previous
|
||||
// value is not loaded from cache store cos it's not needed.
|
||||
timestampsPutCache.put( key, value );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException( e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal Infinispan-based implementation of the "update timestamps" cache region
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.timestamp;
|
|
@ -21,15 +21,15 @@
|
|||
*/
|
||||
package org.hibernate.cache.infinispan.tm;
|
||||
|
||||
import java.util.Properties;
|
||||
import javax.transaction.TransactionManager;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||
|
||||
/**
|
||||
* HibernateTransactionManagerLookup.
|
||||
*
|
||||
*
|
||||
* @author Galder Zamarreño
|
||||
* @since 3.5
|
||||
*/
|
||||
|
@ -39,9 +39,10 @@ public class HibernateTransactionManagerLookup implements org.infinispan.transac
|
|||
public HibernateTransactionManagerLookup(Settings settings, Properties properties) {
|
||||
this.jtaPlatform = settings != null ? settings.getJtaPlatform() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionManager getTransactionManager() throws Exception {
|
||||
return jtaPlatform == null ? null : jtaPlatform.retrieveTransactionManager();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal bridging between Infinispan and Hibernate notions of talking to JTA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.tm;
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.util;
|
||||
|
||||
import org.infinispan.commands.module.ExtendedModuleCommandFactory;
|
||||
|
@ -11,18 +34,17 @@ import org.infinispan.commands.module.ModuleCommandInitializer;
|
|||
* @since 4.0
|
||||
*/
|
||||
public class CacheCommandExtensions implements ModuleCommandExtensions {
|
||||
final CacheCommandFactory cacheCommandFactory = new CacheCommandFactory();
|
||||
final CacheCommandInitializer cacheCommandInitializer = new CacheCommandInitializer();
|
||||
|
||||
final CacheCommandFactory cacheCommandFactory = new CacheCommandFactory();
|
||||
final CacheCommandInitializer cacheCommandInitializer = new CacheCommandInitializer();
|
||||
@Override
|
||||
public ExtendedModuleCommandFactory getModuleCommandFactory() {
|
||||
return cacheCommandFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedModuleCommandFactory getModuleCommandFactory() {
|
||||
return cacheCommandFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleCommandInitializer getModuleCommandInitializer() {
|
||||
return cacheCommandInitializer;
|
||||
}
|
||||
@Override
|
||||
public ModuleCommandInitializer getModuleCommandInitializer() {
|
||||
return cacheCommandInitializer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -19,45 +42,45 @@ import org.hibernate.cache.infinispan.impl.BaseRegion;
|
|||
* @since 4.0
|
||||
*/
|
||||
public class CacheCommandFactory implements ExtendedModuleCommandFactory {
|
||||
private ConcurrentMap<String, BaseRegion> allRegions =
|
||||
new ConcurrentHashMap<String, BaseRegion>();
|
||||
|
||||
private ConcurrentMap<String, BaseRegion> allRegions =
|
||||
new ConcurrentHashMap<String, BaseRegion>();
|
||||
public void addRegion(String regionName, BaseRegion region) {
|
||||
allRegions.put( regionName, region );
|
||||
}
|
||||
|
||||
public void addRegion(String regionName, BaseRegion region) {
|
||||
allRegions.put(regionName, region);
|
||||
}
|
||||
public void clearRegions(List<String> regionNames) {
|
||||
for ( String regionName : regionNames ) {
|
||||
allRegions.remove( regionName );
|
||||
}
|
||||
}
|
||||
|
||||
public void clearRegions(List<String> regionNames) {
|
||||
for (String regionName : regionNames)
|
||||
allRegions.remove(regionName);
|
||||
}
|
||||
@Override
|
||||
public Map<Byte, Class<? extends ReplicableCommand>> getModuleCommands() {
|
||||
final Map<Byte, Class<? extends ReplicableCommand>> map = new HashMap<Byte, Class<? extends ReplicableCommand>>( 3 );
|
||||
map.put( CacheCommandIds.EVICT_ALL, EvictAllCommand.class );
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Byte, Class<? extends ReplicableCommand>> getModuleCommands() {
|
||||
Map<Byte, Class<? extends ReplicableCommand>> map = new HashMap<Byte, Class<? extends ReplicableCommand>>(3);
|
||||
map.put(CacheCommandIds.EVICT_ALL, EvictAllCommand.class);
|
||||
return map;
|
||||
}
|
||||
@Override
|
||||
public CacheRpcCommand fromStream(byte commandId, Object[] args, String cacheName) {
|
||||
CacheRpcCommand c;
|
||||
switch ( commandId ) {
|
||||
case CacheCommandIds.EVICT_ALL:
|
||||
c = new EvictAllCommand( cacheName, allRegions.get( cacheName ) );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException( "Not registered to handle command id " + commandId );
|
||||
}
|
||||
c.setParameters( commandId, args );
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheRpcCommand fromStream(byte commandId, Object[] args, String cacheName) {
|
||||
CacheRpcCommand c;
|
||||
switch (commandId) {
|
||||
case CacheCommandIds.EVICT_ALL:
|
||||
c = new EvictAllCommand(cacheName, allRegions.get(cacheName));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Not registered to handle command id " + commandId);
|
||||
}
|
||||
c.setParameters(commandId, args);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplicableCommand fromStream(byte commandId, Object[] args) {
|
||||
// Should not be called while this factory only
|
||||
// provides cache specific replicable commands.
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public ReplicableCommand fromStream(byte commandId, Object[] args) {
|
||||
// Should not be called while this factory only
|
||||
// provides cache specific replicable commands.
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.util;
|
||||
|
||||
/**
|
||||
|
@ -7,7 +30,8 @@ package org.hibernate.cache.infinispan.util;
|
|||
* @since 4.0
|
||||
*/
|
||||
public interface CacheCommandIds {
|
||||
|
||||
byte EVICT_ALL = 120;
|
||||
|
||||
/**
|
||||
* The "evict all" command id
|
||||
*/
|
||||
public static final byte EVICT_ALL = 120;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.util;
|
||||
|
||||
import org.infinispan.commands.ReplicableCommand;
|
||||
|
@ -11,17 +34,17 @@ import org.infinispan.commands.module.ModuleCommandInitializer;
|
|||
*/
|
||||
public class CacheCommandInitializer implements ModuleCommandInitializer {
|
||||
|
||||
public EvictAllCommand buildEvictAllCommand(String regionName) {
|
||||
// No need to pass region factory because no information on that object
|
||||
// is sent around the cluster. However, when the command factory builds
|
||||
// and evict all command remotely, it does need to initialize it with
|
||||
// the right region factory so that it can call it back.
|
||||
return new EvictAllCommand(regionName);
|
||||
}
|
||||
public EvictAllCommand buildEvictAllCommand(String regionName) {
|
||||
// No need to pass region factory because no information on that object
|
||||
// is sent around the cluster. However, when the command factory builds
|
||||
// and evict all command remotely, it does need to initialize it with
|
||||
// the right region factory so that it can call it back.
|
||||
return new EvictAllCommand( regionName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeReplicableCommand(ReplicableCommand c, boolean isRemote) {
|
||||
// No need to initialize...
|
||||
}
|
||||
@Override
|
||||
public void initializeReplicableCommand(ReplicableCommand c, boolean isRemote) {
|
||||
// No need to initialize...
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,17 +20,16 @@
|
|||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
|
||||
package org.hibernate.cache.infinispan.util;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
import org.infinispan.remoting.rpc.RpcManager;
|
||||
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.TransactionManager;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.context.Flag;
|
||||
import org.infinispan.remoting.rpc.RpcManager;
|
||||
|
||||
/**
|
||||
* Helper for dealing with Infinispan cache instances.
|
||||
*
|
||||
|
@ -39,103 +38,118 @@ import java.util.concurrent.Callable;
|
|||
*/
|
||||
public class Caches {
|
||||
|
||||
private Caches() {
|
||||
// Suppresses default constructor, ensuring non-instantiability.
|
||||
}
|
||||
private Caches() {
|
||||
// Suppresses default constructor, ensuring non-instantiability.
|
||||
}
|
||||
|
||||
public static <T> T withinTx(AdvancedCache cache,
|
||||
Callable<T> c) throws Exception {
|
||||
// Retrieve transaction manager
|
||||
return withinTx(cache.getTransactionManager(), c);
|
||||
}
|
||||
public static <T> T withinTx(
|
||||
AdvancedCache cache,
|
||||
Callable<T> c) throws Exception {
|
||||
// Retrieve transaction manager
|
||||
return withinTx( cache.getTransactionManager(), c );
|
||||
}
|
||||
|
||||
public static <T> T withinTx(TransactionManager tm,
|
||||
Callable<T> c) throws Exception {
|
||||
tm.begin();
|
||||
try {
|
||||
return c.call();
|
||||
} catch (Exception e) {
|
||||
tm.setRollbackOnly();
|
||||
throw e;
|
||||
} finally {
|
||||
if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
|
||||
else tm.rollback();
|
||||
}
|
||||
}
|
||||
public static <T> T withinTx(
|
||||
TransactionManager tm,
|
||||
Callable<T> c) throws Exception {
|
||||
tm.begin();
|
||||
try {
|
||||
return c.call();
|
||||
}
|
||||
catch (Exception e) {
|
||||
tm.setRollbackOnly();
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
if ( tm.getStatus() == Status.STATUS_ACTIVE ) {
|
||||
tm.commit();
|
||||
}
|
||||
else {
|
||||
tm.rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AdvancedCache localCache(AdvancedCache cache) {
|
||||
return cache.withFlags(Flag.CACHE_MODE_LOCAL);
|
||||
}
|
||||
public static AdvancedCache localCache(AdvancedCache cache) {
|
||||
return cache.withFlags( Flag.CACHE_MODE_LOCAL );
|
||||
}
|
||||
|
||||
public static AdvancedCache ignoreReturnValuesCache(AdvancedCache cache) {
|
||||
return cache.withFlags(Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP);
|
||||
}
|
||||
public static AdvancedCache ignoreReturnValuesCache(AdvancedCache cache) {
|
||||
return cache.withFlags( Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP );
|
||||
}
|
||||
|
||||
public static AdvancedCache ignoreReturnValuesCache(
|
||||
AdvancedCache cache, Flag extraFlag) {
|
||||
return cache.withFlags(
|
||||
Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP, extraFlag);
|
||||
}
|
||||
public static AdvancedCache ignoreReturnValuesCache(
|
||||
AdvancedCache cache, Flag extraFlag) {
|
||||
return cache.withFlags(
|
||||
Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP, extraFlag
|
||||
);
|
||||
}
|
||||
|
||||
public static AdvancedCache asyncWriteCache(AdvancedCache cache,
|
||||
Flag extraFlag) {
|
||||
return cache.withFlags(
|
||||
Flag.SKIP_CACHE_LOAD,
|
||||
Flag.SKIP_REMOTE_LOOKUP,
|
||||
Flag.FORCE_ASYNCHRONOUS,
|
||||
extraFlag);
|
||||
}
|
||||
public static AdvancedCache asyncWriteCache(
|
||||
AdvancedCache cache,
|
||||
Flag extraFlag) {
|
||||
return cache.withFlags(
|
||||
Flag.SKIP_CACHE_LOAD,
|
||||
Flag.SKIP_REMOTE_LOOKUP,
|
||||
Flag.FORCE_ASYNCHRONOUS,
|
||||
extraFlag
|
||||
);
|
||||
}
|
||||
|
||||
public static AdvancedCache failSilentWriteCache(AdvancedCache cache) {
|
||||
return cache.withFlags(
|
||||
Flag.FAIL_SILENTLY,
|
||||
Flag.ZERO_LOCK_ACQUISITION_TIMEOUT,
|
||||
Flag.SKIP_CACHE_LOAD,
|
||||
Flag.SKIP_REMOTE_LOOKUP);
|
||||
}
|
||||
public static AdvancedCache failSilentWriteCache(AdvancedCache cache) {
|
||||
return cache.withFlags(
|
||||
Flag.FAIL_SILENTLY,
|
||||
Flag.ZERO_LOCK_ACQUISITION_TIMEOUT,
|
||||
Flag.SKIP_CACHE_LOAD,
|
||||
Flag.SKIP_REMOTE_LOOKUP
|
||||
);
|
||||
}
|
||||
|
||||
public static AdvancedCache failSilentWriteCache(AdvancedCache cache,
|
||||
Flag extraFlag) {
|
||||
return cache.withFlags(
|
||||
Flag.FAIL_SILENTLY,
|
||||
Flag.ZERO_LOCK_ACQUISITION_TIMEOUT,
|
||||
Flag.SKIP_CACHE_LOAD,
|
||||
Flag.SKIP_REMOTE_LOOKUP,
|
||||
extraFlag);
|
||||
}
|
||||
public static AdvancedCache failSilentWriteCache(
|
||||
AdvancedCache cache,
|
||||
Flag extraFlag) {
|
||||
return cache.withFlags(
|
||||
Flag.FAIL_SILENTLY,
|
||||
Flag.ZERO_LOCK_ACQUISITION_TIMEOUT,
|
||||
Flag.SKIP_CACHE_LOAD,
|
||||
Flag.SKIP_REMOTE_LOOKUP,
|
||||
extraFlag
|
||||
);
|
||||
}
|
||||
|
||||
public static AdvancedCache failSilentReadCache(AdvancedCache cache) {
|
||||
return cache.withFlags(
|
||||
Flag.FAIL_SILENTLY,
|
||||
Flag.ZERO_LOCK_ACQUISITION_TIMEOUT);
|
||||
}
|
||||
public static AdvancedCache failSilentReadCache(AdvancedCache cache) {
|
||||
return cache.withFlags(
|
||||
Flag.FAIL_SILENTLY,
|
||||
Flag.ZERO_LOCK_ACQUISITION_TIMEOUT
|
||||
);
|
||||
}
|
||||
|
||||
public static void broadcastEvictAll(AdvancedCache cache) {
|
||||
RpcManager rpcManager = cache.getRpcManager();
|
||||
if (rpcManager != null) {
|
||||
// Only broadcast evict all if it's clustered
|
||||
CacheCommandInitializer factory = cache.getComponentRegistry()
|
||||
.getComponent(CacheCommandInitializer.class);
|
||||
boolean isSync = isSynchronousCache(cache);
|
||||
public static void broadcastEvictAll(AdvancedCache cache) {
|
||||
final RpcManager rpcManager = cache.getRpcManager();
|
||||
if ( rpcManager != null ) {
|
||||
// Only broadcast evict all if it's clustered
|
||||
final CacheCommandInitializer factory = cache.getComponentRegistry()
|
||||
.getComponent( CacheCommandInitializer.class );
|
||||
final boolean isSync = isSynchronousCache( cache );
|
||||
|
||||
EvictAllCommand cmd = factory.buildEvictAllCommand(cache.getName());
|
||||
rpcManager.broadcastRpcCommand(cmd, isSync);
|
||||
}
|
||||
}
|
||||
final EvictAllCommand cmd = factory.buildEvictAllCommand( cache.getName() );
|
||||
rpcManager.broadcastRpcCommand( cmd, isSync );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isInvalidationCache(AdvancedCache cache) {
|
||||
return cache.getCacheConfiguration()
|
||||
.clustering().cacheMode().isInvalidation();
|
||||
}
|
||||
public static boolean isInvalidationCache(AdvancedCache cache) {
|
||||
return cache.getCacheConfiguration()
|
||||
.clustering().cacheMode().isInvalidation();
|
||||
}
|
||||
|
||||
public static boolean isSynchronousCache(AdvancedCache cache) {
|
||||
return cache.getCacheConfiguration()
|
||||
.clustering().cacheMode().isSynchronous();
|
||||
}
|
||||
public static boolean isSynchronousCache(AdvancedCache cache) {
|
||||
return cache.getCacheConfiguration()
|
||||
.clustering().cacheMode().isSynchronous();
|
||||
}
|
||||
|
||||
public static boolean isClustered(AdvancedCache cache) {
|
||||
return cache.getCacheConfiguration()
|
||||
.clustering().cacheMode().isClustered();
|
||||
}
|
||||
public static boolean isClustered(AdvancedCache cache) {
|
||||
return cache.getCacheConfiguration()
|
||||
.clustering().cacheMode().isClustered();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.util;
|
||||
|
||||
import org.infinispan.commands.remote.BaseRpcCommand;
|
||||
|
@ -13,41 +36,42 @@ import org.hibernate.cache.infinispan.impl.BaseRegion;
|
|||
*/
|
||||
public class EvictAllCommand extends BaseRpcCommand {
|
||||
|
||||
private final BaseRegion region;
|
||||
private final BaseRegion region;
|
||||
|
||||
public EvictAllCommand(String regionName, BaseRegion region) {
|
||||
super(regionName); // region name and cache names are the same...
|
||||
this.region = region;
|
||||
}
|
||||
public EvictAllCommand(String regionName, BaseRegion region) {
|
||||
// region name and cache names are the same...
|
||||
super( regionName );
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public EvictAllCommand(String regionName) {
|
||||
this(regionName, null);
|
||||
}
|
||||
public EvictAllCommand(String regionName) {
|
||||
this( regionName, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object perform(InvocationContext ctx) throws Throwable {
|
||||
region.invalidateRegion();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object perform(InvocationContext ctx) throws Throwable {
|
||||
region.invalidateRegion();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getCommandId() {
|
||||
return CacheCommandIds.EVICT_ALL;
|
||||
}
|
||||
@Override
|
||||
public byte getCommandId() {
|
||||
return CacheCommandIds.EVICT_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getParameters() {
|
||||
return new Object[0];
|
||||
}
|
||||
@Override
|
||||
public Object[] getParameters() {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(int commandId, Object[] parameters) {
|
||||
// No-op
|
||||
}
|
||||
@Override
|
||||
public void setParameters(int commandId, Object[] parameters) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReturnValueExpected() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isReturnValueExpected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/package-info.java
vendored
Normal file
4
hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/package-info.java
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal utilities for the Infinispan integration
|
||||
*/
|
||||
package org.hibernate.cache.infinispan.util;
|
Loading…
Reference in New Issue