blob: 55abb6ab87bc53355b1d807d635c754d01ee5fcc [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.modules.hibernate.internal;
import com.gemstone.gemfire.cache.CacheWriterException;
import com.gemstone.gemfire.cache.EntryExistsException;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.client.ServerOperationException;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.EntityRegion;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
import org.hibernate.cache.access.SoftLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public abstract class Access implements EntityRegionAccessStrategy {
private final GemFireEntityRegion region;
/**Thread local to remember the status of insert, which can be returned in afterInsert*/
private ThreadLocal<Map<Object, Boolean>> createStatus = new ThreadLocal<Map<Object, Boolean>>() {
@Override
protected Map<Object, Boolean> initialValue() {
return new HashMap<Object, Boolean>();
}
};
private Logger log = LoggerFactory.getLogger(getClass());
public Access(GemFireEntityRegion region) {
this.region = region;
}
@Override
public EntityRegion getRegion() {
return this.region;
}
@Override
public Object get(Object key, long txTimestamp) throws CacheException {
KeyWrapper wKey = getWrappedKey(key);
if (this.region.isRegisterInterestRequired()) {
this.region.registerInterest(wKey);
}
// first check to see if we have pre-fetched this entity
EntityWrapper wrapper = this.region.get(wKey);
if (wrapper == null) {
wrapper = this.region.getGemFireRegion().get(wKey);
}
if (wrapper == null) {
this.region.getStats().incCacheMiss();
log.debug("Cache miss for {} count: {}",wKey, this.region.getStats().getCacheMiss());
return null;
} else {
this.region.getStats().incCacheHit();
log.debug("cache hit {} count: {} ", wKey, this.region.getStats().getCacheHits());
}
return wrapper.getEntity();
}
@Override
public boolean putFromLoad(Object key, Object value, long txTimestamp,
Object version) throws CacheException {
return putFromLoad(key, value, txTimestamp, version, true);
}
@Override
public boolean putFromLoad(Object key, Object value, long txTimestamp,
Object version, boolean minimalPutOverride) throws CacheException {
return create(key, value);
}
private boolean create(Object key, Object value) {
KeyWrapper wKey = getWrappedKey(key);
EntityWrapper wrapper = new EntityWrapper(value, 1L);
log.debug("putting a new entry from load {} value: {}",wKey, wrapper);
boolean remove = false;
try {
this.region.getGemFireRegion().create(wKey, wrapper);
} catch (EntryExistsException ee) {
log.debug("key {} exists in the cache already, destroying", wKey);
remove = true;
} catch (CacheWriterException writerEx) {
this.region.getStats().incHibernateDestroyJobsScheduled();
log.debug("caught a CacheWriterException {} ",writerEx.getMessage());
remove = true;
} catch (ServerOperationException serverEx) {
if (serverEx.getCause() instanceof CacheWriterException) {
this.region.getStats().incHibernateDestroyJobsScheduled();
log.debug("caught a ServerOperationException caused by CacheWriterException {} ",serverEx.getMessage());
} else {
throw serverEx;
}
remove = true;
}
if (remove) {
this.region.getGemFireRegion().remove(wKey);
return false;
}
return true;
}
@Override
public SoftLock lockItem(Object key, Object version) throws CacheException {
KeyWrapper wKey = getWrappedKey(key);
EntityWrapper wrapper = this.region.getGemFireRegion().get(wKey);
Long ver = wrapper == null ? 0L : wrapper.getVersion();
log.debug("lockItem:key: {} entityVersion: {}", new Object[] { wKey, ver });
return new EntityVersionImpl(ver);
}
@Override
public SoftLock lockRegion() throws CacheException {
return null;
}
@Override
public void unlockItem(Object key, SoftLock lock) throws CacheException {
log.debug("unlockItem:key:" + key + " lock:" + lock);
}
@Override
public void unlockRegion(SoftLock lock) throws CacheException {
}
@Override
public boolean insert(Object key, Object value, Object version)
throws CacheException {
log.debug("insert:key:{} value:{} version:{}",
new Object[]{key, value, version});
boolean retVal = create(key, value);
createStatus.get().put(key, retVal);
return retVal;
}
@Override
public boolean afterInsert(Object key, Object value, Object version)
throws CacheException {
log.info("afterInsert:key:{} value:{} version:{}",
new Object[]{key, value, version});
return createStatus.get().remove(key);
}
@Override
public boolean update(Object key, Object value, Object currentVersion,
Object previousVersion) throws CacheException {
KeyWrapper wKey = getWrappedKey(key);
EntityWrapper oldWrapper = this.region.getGemFireRegion().get(wKey);
Long version = oldWrapper == null ? 1L : oldWrapper.getVersion() + 1;
EntityWrapper wrapper = new EntityWrapper(value, version);
log.debug("put:key:{} value:{} version:{}", new Object[] { wKey, value,
version });
boolean remove = false;
try {
if (oldWrapper == null) {
remove = this.region.getGemFireRegion().putIfAbsent(wKey, wrapper) != null;
} else {
remove = !this.region.getGemFireRegion().replace(wKey, oldWrapper, wrapper);
}
} catch (CacheWriterException writerEx) {
this.region.getStats().incHibernateDestroyJobsScheduled();
log.debug("caught a CacheWriterException {} ",writerEx.getMessage());
remove = true;
} catch (ServerOperationException serverEx) {
if (serverEx.getCause() instanceof CacheWriterException) {
this.region.getStats().incHibernateDestroyJobsScheduled();
log.debug("caught a ServerOperationException caused by CacheWriterException {} ",serverEx.getMessage());
remove = true;
} else {
throw serverEx;
}
}
if (remove) {
this.region.getGemFireRegion().remove(wKey);
return false;
}
log.debug("put for key {} succeded", wKey);
return true;
}
@Override
public boolean afterUpdate(Object key, Object value, Object currentVersion,
Object previousVersion, SoftLock lock) throws CacheException {
log.debug("afterUpdate:key:{} value:{} currVersion:{} previousVersion:{}",
new Object[] {key, value, currentVersion, previousVersion});
KeyWrapper wKey = getWrappedKey(key);
EntityWrapper wrapper = this.region.getGemFireRegion().get(wKey);
if (wrapper == null) {
// this entry was destroyed during update
return false;
}
Long version = wrapper.getVersion();
Long expectedVersion = ((EntityVersion)lock).getVersion() + 1;
log.debug("afterPut:key:{} value:{} version:{} expected: {}",
new Object[] { wKey, value, version, expectedVersion });
if (wrapper.getVersion() != expectedVersion) {
log.debug(
"for key {} expected version to be {} but was {}, so destroying the key",
new Object[] { wKey, expectedVersion, version });
this.region.getGemFireRegion().remove(wKey);
return false;
}
return true;
}
@Override
public void remove(Object key) throws CacheException {
log.debug("removing key {} ",key);
this.region.getGemFireRegion().remove(getWrappedKey(key));
}
@Override
public void removeAll() throws CacheException {
log.debug("removing all keys");
this.region.getGemFireRegion().clear();
}
@Override
public void evict(Object key) throws CacheException {
// TODO we should implement a method on Region to evict
// a particular entry, destroying is inefficient
log.debug("removing key {} ",key);
this.region.getGemFireRegion().remove(getWrappedKey(key));
}
@Override
public void evictAll() throws CacheException {
log.debug("removing all keys");
this.region.getGemFireRegion().clear();
}
protected Region<Object, EntityWrapper> getGemFireRegion() {
return this.region.getGemFireRegion();
}
protected KeyWrapper getWrappedKey(Object key) {
return new KeyWrapper(key);
}
}