Update handling of deletion of the region root node
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14263 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
8277156f00
commit
9352a7a7d7
|
@ -40,11 +40,16 @@ import org.jboss.cache.config.Option;
|
|||
import org.jboss.cache.config.Configuration.NodeLockingScheme;
|
||||
import org.jboss.cache.notifications.annotation.CacheListener;
|
||||
import org.jboss.cache.notifications.annotation.NodeCreated;
|
||||
import org.jboss.cache.notifications.annotation.NodeRemoved;
|
||||
import org.jboss.cache.notifications.event.NodeCreatedEvent;
|
||||
import org.jboss.cache.notifications.event.NodeRemovedEvent;
|
||||
import org.jboss.cache.optimistic.DataVersion;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.jbc2.builder.JndiMultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
||||
|
||||
|
@ -56,16 +61,20 @@ import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
|||
*/
|
||||
@CacheListener
|
||||
public abstract class BasicRegionAdapter implements Region {
|
||||
|
||||
|
||||
public static final String ITEM = CacheHelper.ITEM;
|
||||
|
||||
protected final Cache jbcCache;
|
||||
protected final String regionName;
|
||||
protected final Fqn regionFqn;
|
||||
protected Node regionRoot;
|
||||
protected final boolean optimistic;
|
||||
|
||||
protected final TransactionManager transactionManager;
|
||||
protected final Logger log;
|
||||
protected final Object regionRootMutex = new Object();
|
||||
|
||||
protected SetResidentListener listener;
|
||||
protected RegionRootListener listener;
|
||||
|
||||
public BasicRegionAdapter(Cache jbcCache, String regionName, String regionPrefix) {
|
||||
this.jbcCache = jbcCache;
|
||||
|
@ -73,6 +82,7 @@ public abstract class BasicRegionAdapter implements Region {
|
|||
this.regionName = regionName;
|
||||
this.regionFqn = createRegionFqn(regionName, regionPrefix);
|
||||
optimistic = jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC;
|
||||
log = LoggerFactory.getLogger(getClass());
|
||||
activateLocalClusterNode();
|
||||
}
|
||||
|
||||
|
@ -97,14 +107,30 @@ public abstract class BasicRegionAdapter implements Region {
|
|||
// and then need to re-add it. In that case, the fact
|
||||
// that it is resident will not replicate, so use a listener
|
||||
// to set it as resident
|
||||
if (CacheHelper.isClusteredReplication(cfg.getCacheMode())) {
|
||||
listener = new SetResidentListener();
|
||||
if (CacheHelper.isClusteredReplication(cfg.getCacheMode())
|
||||
|| CacheHelper.isClusteredInvalidation(cfg.getCacheMode())) {
|
||||
listener = new RegionRootListener();
|
||||
jbcCache.addCacheListener(listener);
|
||||
}
|
||||
|
||||
establishRegionRootNode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void establishRegionRootNode()
|
||||
{
|
||||
synchronized (regionRootMutex) {
|
||||
if (regionRoot != null && regionRoot.isValid())
|
||||
return;
|
||||
// Don't hold a transactional lock for this
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
// Make sure the root node for the region exists and
|
||||
// has a DataVersion that never complains
|
||||
Node regionRoot = jbcCache.getRoot().getChild( regionFqn );
|
||||
regionRoot = jbcCache.getRoot().getChild( regionFqn );
|
||||
if (regionRoot == null) {
|
||||
// Establish the region root node with a non-locking data version
|
||||
DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
|
||||
|
@ -119,8 +145,9 @@ public abstract class BasicRegionAdapter implements Region {
|
|||
// Never evict this node
|
||||
regionRoot.setResident(true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException(e.getMessage(), e);
|
||||
finally {
|
||||
resume(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,11 +163,28 @@ public abstract class BasicRegionAdapter implements Region {
|
|||
return regionFqn;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the cache is configured for optimistic locking, checks for the
|
||||
* validity of the root cache node for this region,
|
||||
* creating a new one if it does not exist or is invalid. Suspends any
|
||||
* transaction while doing this to ensure no transactional locks are held
|
||||
* on the region root.
|
||||
*
|
||||
* This is only needed for optimistic locking, as with optimistic the
|
||||
* region root node has a special version that must be established.
|
||||
*
|
||||
* TODO remove this once JBCACHE-1250 is resolved.
|
||||
*/
|
||||
public void ensureRegionRootExists() {
|
||||
if (optimistic && (regionRoot == null || !regionRoot.isValid()))
|
||||
establishRegionRootNode();
|
||||
}
|
||||
|
||||
public void destroy() throws CacheException {
|
||||
try {
|
||||
// NOTE : this is being used from the process of shutting down a
|
||||
// SessionFactory. Specific things to consider:
|
||||
// (1) this clearing of the region should not propogate to
|
||||
// (1) this clearing of the region should not propagate to
|
||||
// other nodes on the cluster (if any); this is the
|
||||
// cache-mode-local option bit...
|
||||
// (2) really just trying a best effort to cleanup after
|
||||
|
@ -321,11 +365,12 @@ public abstract class BasicRegionAdapter implements Region {
|
|||
}
|
||||
|
||||
@CacheListener
|
||||
public class SetResidentListener {
|
||||
public class RegionRootListener {
|
||||
|
||||
@NodeCreated
|
||||
public void nodeCreated(NodeCreatedEvent event) {
|
||||
if (!event.isPre() && event.getFqn().equals(getRegionFqn())) {
|
||||
log.debug("Node created for " + getRegionFqn());
|
||||
Node regionRoot = jbcCache.getRoot().getChild(getRegionFqn());
|
||||
regionRoot.setResident(true);
|
||||
}
|
||||
|
|
|
@ -27,11 +27,11 @@ import org.hibernate.cache.CacheDataDescription;
|
|||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.TransactionalDataRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cache.jbc2.util.DataVersionAdapter;
|
||||
import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.config.Option;
|
||||
import org.jboss.cache.optimistic.DataVersion;
|
||||
|
||||
|
@ -51,9 +51,9 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
|
||||
protected final CacheDataDescription dataDescription;
|
||||
|
||||
public OptimisticTransactionalAccessDelegate(Cache cache, Fqn regionFqn, CacheDataDescription dataDescription) {
|
||||
super(cache, regionFqn);
|
||||
this.dataDescription = dataDescription;
|
||||
public OptimisticTransactionalAccessDelegate(TransactionalDataRegionAdapter region) {
|
||||
super(region);
|
||||
this.dataDescription = region.getCacheDataDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,6 +64,8 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
|
||||
region.ensureRegionRootExists();
|
||||
|
||||
Option opt = NonLockingDataVersion.getInvocationOption();
|
||||
CacheHelper.remove(cache, regionFqn, key, opt);
|
||||
}
|
||||
|
@ -78,6 +80,18 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
evictOrRemoveAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the {@link TransactionalAccessDelegate#get(Object, long) superclass}
|
||||
* by {@link BasicRegionAdapter#ensureRegionRootExists() ensuring the root
|
||||
* node for the region exists} before making the call.
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException
|
||||
{
|
||||
region.ensureRegionRootExists();
|
||||
return super.get(key, txTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the
|
||||
* {@link TransactionalAccessDelegate#insert(Object, Object, Object) superclass}
|
||||
|
@ -86,6 +100,8 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
@Override
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
|
||||
region.ensureRegionRootExists();
|
||||
|
||||
Option opt = getDataVersionOption(version, null);
|
||||
CacheHelper.put(cache, regionFqn, key, value, opt);
|
||||
return true;
|
||||
|
@ -95,6 +111,8 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
|
||||
region.ensureRegionRootExists();
|
||||
|
||||
// We ignore minimalPutOverride. JBossCache putForExternalRead is
|
||||
// already about as minimal as we can get; it will promptly return
|
||||
// if it discovers that the node we want to write to already exists
|
||||
|
@ -105,6 +123,8 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
|
||||
region.ensureRegionRootExists();
|
||||
|
||||
Option opt = getDataVersionOption(version, version);
|
||||
return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
|
||||
}
|
||||
|
@ -112,6 +132,8 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
|
||||
region.ensureRegionRootExists();
|
||||
|
||||
Option opt = NonLockingDataVersion.getInvocationOption();
|
||||
CacheHelper.remove(cache, regionFqn, key, opt);
|
||||
}
|
||||
|
@ -126,12 +148,15 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
|
||||
region.ensureRegionRootExists();
|
||||
|
||||
Option opt = getDataVersionOption(currentVersion, previousVersion);
|
||||
CacheHelper.put(cache, regionFqn, key, value, opt);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Option getDataVersionOption(Object currentVersion, Object previousVersion) {
|
||||
|
||||
DataVersion dv = (dataDescription != null && dataDescription.isVersioned()) ? new DataVersionAdapter(
|
||||
currentVersion, previousVersion, dataDescription.getVersionComparator(), dataDescription.toString())
|
||||
: NonLockingDataVersion.INSTANCE;
|
||||
|
@ -141,6 +166,7 @@ public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDe
|
|||
}
|
||||
|
||||
private void evictOrRemoveAll() {
|
||||
|
||||
Option opt = NonLockingDataVersion.getInvocationOption();
|
||||
CacheHelper.removeAll(cache, regionFqn, opt);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.hibernate.cache.CacheException;
|
|||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.access.SoftLock;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
|
@ -46,10 +47,12 @@ public class TransactionalAccessDelegate {
|
|||
|
||||
protected final Cache cache;
|
||||
protected final Fqn regionFqn;
|
||||
protected final BasicRegionAdapter region;
|
||||
|
||||
public TransactionalAccessDelegate(Cache cache, Fqn regionFqn) {
|
||||
this.cache = cache;
|
||||
this.regionFqn = regionFqn;
|
||||
public TransactionalAccessDelegate(BasicRegionAdapter adapter) {
|
||||
this.region = adapter;
|
||||
this.cache = adapter.getCacheInstance();
|
||||
this.regionFqn = adapter.getRegionFqn();
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
|
|
|
@ -42,8 +42,7 @@ public class OptimisticTransactionalAccess extends TransactionalAccess {
|
|||
public OptimisticTransactionalAccess(CollectionRegionImpl region) {
|
||||
|
||||
// We use a different delegate than the non-optimistic superclass default
|
||||
super(region, new OptimisticTransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn(),
|
||||
region.getCacheDataDescription()));
|
||||
super(region, new OptimisticTransactionalAccessDelegate(region));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public class TransactionalAccess implements CollectionRegionAccessStrategy {
|
|||
* @param region the region to which this provides access
|
||||
*/
|
||||
public TransactionalAccess(CollectionRegionImpl region) {
|
||||
this(region, new TransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn()));
|
||||
this(region, new TransactionalAccessDelegate(region));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,7 +41,6 @@ public class OptimisticTransactionalAccess extends TransactionalAccess {
|
|||
* @param region The region\ to which this is providing access
|
||||
*/
|
||||
public OptimisticTransactionalAccess(EntityRegionImpl region) {
|
||||
super(region, new OptimisticTransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn(),
|
||||
region.getCacheDataDescription()));
|
||||
super(region, new OptimisticTransactionalAccessDelegate(region));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class TransactionalAccess implements EntityRegionAccessStrategy {
|
|||
private final TransactionalAccessDelegate delegate;
|
||||
|
||||
public TransactionalAccess(EntityRegionImpl region) {
|
||||
this(region, new TransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn()));
|
||||
this(region, new TransactionalAccessDelegate(region));
|
||||
}
|
||||
|
||||
protected TransactionalAccess(EntityRegionImpl region, TransactionalAccessDelegate delegate) {
|
||||
|
|
|
@ -75,6 +75,9 @@ public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter imple
|
|||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
|
||||
ensureRegionRootExists();
|
||||
|
||||
Option opt = getNonLockingDataVersionOption(false);
|
||||
if (localOnly)
|
||||
opt.setCacheModeLocal(true);
|
||||
|
@ -92,6 +95,8 @@ public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter imple
|
|||
|
||||
public Object get(Object key) throws CacheException {
|
||||
|
||||
ensureRegionRootExists();
|
||||
|
||||
// Don't hold the JBC node lock throughout the tx, as that
|
||||
// prevents updates
|
||||
// Add a zero (or low) timeout option so we don't block
|
||||
|
@ -103,6 +108,8 @@ public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter imple
|
|||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
|
||||
ensureRegionRootExists();
|
||||
|
||||
// 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
|
||||
|
@ -110,9 +117,9 @@ public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter imple
|
|||
// 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
|
||||
// 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 for concurrent reads.
|
||||
// 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
|
||||
|
|
|
@ -85,6 +85,9 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
|
||||
ensureRegionRootExists();
|
||||
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
Option opt = getNonLockingDataVersionOption(true);
|
||||
CacheHelper.removeNode(getCacheInstance(), getRegionFqn(), key, opt);
|
||||
|
@ -102,6 +105,9 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
|
||||
Object value = localCache.get(key);
|
||||
if (value == null) {
|
||||
|
||||
ensureRegionRootExists();
|
||||
|
||||
value = suspendAndGet(key, null, false);
|
||||
if (value != null)
|
||||
localCache.put(key, value);
|
||||
|
@ -111,6 +117,8 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
|
||||
ensureRegionRootExists();
|
||||
|
||||
// Don't hold the JBC node lock throughout the tx, as that
|
||||
// prevents reads and other updates
|
||||
Transaction tx = suspend();
|
||||
|
|
Loading…
Reference in New Issue