Get rid of "never" go backwards enforcement, as preinvalidate()/invalidate() sequence is 99.99% likely to go backwards
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14123 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
bd75e6db03
commit
c0f3881bae
|
@ -38,14 +38,12 @@ import org.jboss.cache.notifications.event.NodeRemovedEvent;
|
|||
|
||||
/**
|
||||
* Defines the behavior of the timestamps cache region for JBossCache 2.x.
|
||||
* <p>
|
||||
* Maintains a local (authoritative) cache of timestamps along with the
|
||||
* distributed cache held in JBoss Cache. Listens for changes in the distributed
|
||||
* cache and updates the local cache accordingly. Ensures that any changes in
|
||||
* the local cache represent an increase in the timestamp. This approach allows
|
||||
* timestamp changes to be replicated asynchronously by JBoss Cache while still
|
||||
* preventing backward changes in timestamps.
|
||||
* </p>
|
||||
*
|
||||
* TODO Need to define a way to ensure asynchronous replication events
|
||||
* do not result in timestamps moving backward, while dealing with the fact
|
||||
* that the normal sequence of UpdateTimestampsCache.preinvalidate() then
|
||||
* UpdateTimestampsCache.invalidate() will result in 2 calls to put() with
|
||||
* the latter call having an earlier timestamp.
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
|
@ -54,9 +52,9 @@ import org.jboss.cache.notifications.event.NodeRemovedEvent;
|
|||
public class TimestampsRegionImpl extends TransactionalDataRegionAdapter implements TimestampsRegion {
|
||||
|
||||
public static final String TYPE = "TS";
|
||||
|
||||
private final Map localCache = new ConcurrentHashMap();
|
||||
|
||||
private Map localCache = new ConcurrentHashMap();
|
||||
|
||||
/**
|
||||
* Create a new TimestampsRegionImpl.
|
||||
*
|
||||
|
@ -81,14 +79,12 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
|
||||
public void evict(Object key) throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
localCache.remove(key);
|
||||
Option opt = getNonLockingDataVersionOption(true);
|
||||
CacheHelper.removeNode(getCacheInstance(), getRegionFqn(), key, opt);
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
localCache.clear();
|
||||
Option opt = getNonLockingDataVersionOption(true);
|
||||
CacheHelper.removeAll(getCacheInstance(), getRegionFqn(), opt);
|
||||
// Restore the region root node
|
||||
|
@ -97,50 +93,35 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
|
||||
public Object get(Object key) throws CacheException {
|
||||
|
||||
Object timestamp = localCache.get(key);
|
||||
if (timestamp == null) {
|
||||
// Check the cluster-wide cache
|
||||
// Don't hold the cache node lock throughout the tx, as that
|
||||
// prevents updates
|
||||
timestamp = suspendAndGet(key, null, false);
|
||||
updateLocalCache(key, timestamp);
|
||||
Object value = localCache.get(key);
|
||||
if (value == null) {
|
||||
value = suspendAndGet(key, null, false);
|
||||
if (value != null)
|
||||
localCache.put(key, value);
|
||||
}
|
||||
return timestamp;
|
||||
return value;
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
|
||||
// Immediately update the local cache
|
||||
boolean incremented = updateLocalCache(key, value);
|
||||
|
||||
if (incremented) {
|
||||
// Now the cluster-wide cache
|
||||
|
||||
// TODO there's a race here where 2 threads can get through
|
||||
// updateLocalCache() in proper sequence but then the earlier
|
||||
// one updates JBC *later*. This should only affect newly
|
||||
// joined nodes who populate their initial localCache from JBC.
|
||||
|
||||
// Don't hold the JBC node lock throughout the tx, as that
|
||||
// prevents reads and other updates
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
// TODO Why not use the timestamp in a DataVersion?
|
||||
Option opt = getNonLockingDataVersionOption(false);
|
||||
// We ensure ASYNC semantics (JBCACHE-1175)
|
||||
opt.setForceAsynchronous(true);
|
||||
CacheHelper.put(getCacheInstance(), getRegionFqn(), key, value, opt);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
} finally {
|
||||
resume(tx);
|
||||
}
|
||||
// Don't hold the JBC node lock throughout the tx, as that
|
||||
// prevents reads and other updates
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
// TODO Why not use the timestamp in a DataVersion?
|
||||
Option opt = getNonLockingDataVersionOption(false);
|
||||
// We ensure ASYNC semantics (JBCACHE-1175)
|
||||
opt.setForceAsynchronous(true);
|
||||
CacheHelper.put(getCacheInstance(), getRegionFqn(), key, value, opt);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
} finally {
|
||||
resume(tx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
|
||||
localCache.clear();
|
||||
getCacheInstance().removeCacheListener(this);
|
||||
super.destroy();
|
||||
|
@ -153,14 +134,14 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
*/
|
||||
@NodeModified
|
||||
public void nodeModified(NodeModifiedEvent event) {
|
||||
if (event.isOriginLocal() || event.isPre())
|
||||
if (event.isPre())
|
||||
return;
|
||||
|
||||
Fqn fqn = event.getFqn();
|
||||
Fqn regFqn = getRegionFqn();
|
||||
if (fqn.size() == regFqn.size() + 1 && fqn.isChildOf(regFqn)) {
|
||||
Object key = fqn.get(regFqn.size());
|
||||
updateLocalCache(key, event.getData().get(ITEM));
|
||||
localCache.put(key, event.getData().get(ITEM));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +152,7 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
*/
|
||||
@NodeRemoved
|
||||
public void nodeRemoved(NodeRemovedEvent event) {
|
||||
if (event.isOriginLocal() || event.isPre())
|
||||
if (event.isPre())
|
||||
return;
|
||||
|
||||
Fqn fqn = event.getFqn();
|
||||
|
@ -194,43 +175,4 @@ public class TimestampsRegionImpl extends TransactionalDataRegionAdapter impleme
|
|||
get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the local cache, ensuring that the new value represents a higher
|
||||
* value than the old (i.e. timestamp never goes back in time).
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
private boolean updateLocalCache(Object key, Object value) {
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
boolean increase = true;
|
||||
|
||||
long newVal = 0;
|
||||
try {
|
||||
newVal = ((Long) value).longValue();
|
||||
|
||||
Long oldVal = (Long) localCache.get(key);
|
||||
increase = oldVal == null || newVal > oldVal.longValue();
|
||||
if (increase) {
|
||||
oldVal = (Long) localCache.put(key, value);
|
||||
// Double check that it was an increase
|
||||
if (oldVal != null && oldVal.longValue() > newVal) {
|
||||
// Nope; Restore the old value
|
||||
updateLocalCache(key, oldVal);
|
||||
increase = false;
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException cce) {
|
||||
// TODO -- this is stupid; look into changing TimestampsRegion API
|
||||
// not using Long; just store it
|
||||
localCache.put(key, value);
|
||||
}
|
||||
|
||||
return increase;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue