org.infinispan.hibernate.cache.v53.impl.ClusteredTimestampsRegionImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of infinispan-hibernate-cache-v53 Show documentation
Show all versions of infinispan-hibernate-cache-v53 Show documentation
Infinispan Hibernate 5.3 Cache module
package org.infinispan.hibernate.cache.v53.impl;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.cache.CacheException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.infinispan.AdvancedCache;
import org.infinispan.commons.util.CloseableIterator;
import org.infinispan.context.Flag;
import org.infinispan.hibernate.cache.commons.util.Caches;
import org.infinispan.hibernate.cache.v53.InfinispanRegionFactory;
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;
@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();
/**
* Clustered timestamps region constructor.
*
* @param cache instance to store update timestamps
* @param name of the update timestamps region
* @param factory for the update timestamps region
*/
public ClusteredTimestampsRegionImpl(
AdvancedCache cache,
String name, InfinispanRegionFactory factory) {
super( cache, name, factory );
cache.addListener( this );
populateLocalCache();
}
@Override
protected AdvancedCache getTimestampsPutCache(AdvancedCache cache) {
return Caches.asyncWriteCache( cache, Flag.SKIP_LOCKING );
}
@Override
@SuppressWarnings("unchecked")
public Object getFromCache(Object key, SharedSessionContractImplementor session) {
Object value = localCache.get( key );
if ( value == null && checkValid() ) {
value = cache.get( key );
if ( value != null ) {
localCache.put( key, value );
}
}
return value;
}
@Override
public void putIntoCache(Object key, Object value, SharedSessionContractImplementor session) {
updateLocalCache(key, value);
super.putIntoCache(key, value, session);
}
@Override
public void invalidateRegion() {
// Invalidate first
super.invalidateRegion();
localCache.clear();
}
@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() {
try (CloseableIterator iterator = cache.keySet().iterator()) {
while (iterator.hasNext()) {
getFromCache(iterator.next(), null);
}
}
}
/**
* Monitors cache events and updates the local cache
*
* @param event The event
*/
@CacheEntryModified
@SuppressWarnings({"unused", "unchecked"})
public void nodeModified(CacheEntryModifiedEvent event) {
if ( !event.isPre() ) {
updateLocalCache( event.getKey(), event.getValue() );
}
}
/**
* 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() );
}
// TODO: with recent Infinispan we should access the cache directly
private void updateLocalCache(Object key, Object value) {
localCache.compute(key, (k, v) -> {
if (v instanceof Number && value instanceof Number) {
return Math.max(((Number) v).longValue(), ((Number) value).longValue());
} else {
return value;
}
});
}
}