
com.hazelcast.cache.impl.AbstractCacheRecordStore Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.cache.impl;
import com.hazelcast.cache.CacheNotExistsException;
import com.hazelcast.cache.impl.maxsize.MaxSizeChecker;
import com.hazelcast.cache.impl.maxsize.impl.EntryCountCacheMaxSizeChecker;
import com.hazelcast.cache.impl.record.CacheRecord;
import com.hazelcast.cache.impl.record.SampleableCacheRecordMap;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.config.EvictionConfig;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.internal.eviction.EvictionChecker;
import com.hazelcast.internal.eviction.EvictionListener;
import com.hazelcast.internal.eviction.EvictionPolicyEvaluator;
import com.hazelcast.internal.eviction.EvictionPolicyEvaluatorProvider;
import com.hazelcast.internal.eviction.EvictionStrategy;
import com.hazelcast.internal.eviction.EvictionStrategyProvider;
import com.hazelcast.map.impl.MapEntries;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.partition.InternalPartition;
import com.hazelcast.partition.InternalPartitionService;
import com.hazelcast.spi.EventRegistration;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.impl.eventservice.InternalEventService;
import com.hazelcast.util.Clock;
import com.hazelcast.util.EmptyStatement;
import com.hazelcast.util.ExceptionUtil;
import javax.cache.configuration.Factory;
import javax.cache.expiry.Duration;
import javax.cache.expiry.ExpiryPolicy;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CacheLoaderException;
import javax.cache.integration.CacheWriter;
import javax.cache.integration.CacheWriterException;
import javax.cache.processor.EntryProcessor;
import java.io.Closeable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.hazelcast.cache.impl.CacheEventContextUtil.createBaseEventContext;
import static com.hazelcast.cache.impl.CacheEventContextUtil.createCacheCompleteEvent;
import static com.hazelcast.cache.impl.CacheEventContextUtil.createCacheCreatedEvent;
import static com.hazelcast.cache.impl.CacheEventContextUtil.createCacheExpiredEvent;
import static com.hazelcast.cache.impl.CacheEventContextUtil.createCacheRemovedEvent;
import static com.hazelcast.cache.impl.CacheEventContextUtil.createCacheUpdatedEvent;
import static com.hazelcast.cache.impl.operation.MutableOperation.IGNORE_COMPLETION;
import static com.hazelcast.cache.impl.record.CacheRecordFactory.isExpiredAt;
/**
* @author sozal 14/10/14
*/
public abstract class AbstractCacheRecordStore>
implements ICacheRecordStore, EvictionListener {
protected static final int DEFAULT_INITIAL_CAPACITY = 256;
protected static final String SOURCE_NOT_AVAILABLE = "";
protected final String name;
protected final int partitionId;
protected final int partitionCount;
protected final NodeEngine nodeEngine;
protected final AbstractCacheService cacheService;
protected final CacheConfig cacheConfig;
protected CRM records;
protected CacheContext cacheContext;
protected CacheStatisticsImpl statistics;
protected CacheLoader cacheLoader;
protected CacheWriter cacheWriter;
protected boolean eventsEnabled = true;
protected boolean eventsBatchingEnabled;
protected ExpiryPolicy defaultExpiryPolicy;
protected final EvictionConfig evictionConfig;
protected final Map> batchEvent = new HashMap>();
protected final MaxSizeChecker maxSizeChecker;
protected final EvictionPolicyEvaluator evictionPolicyEvaluator;
protected final EvictionChecker evictionChecker;
protected final EvictionStrategy evictionStrategy;
protected final boolean wanReplicationEnabled;
protected boolean primary;
//CHECKSTYLE:OFF
public AbstractCacheRecordStore(final String name, final int partitionId, final NodeEngine nodeEngine,
final AbstractCacheService cacheService) {
this.name = name;
this.partitionId = partitionId;
this.nodeEngine = nodeEngine;
this.partitionCount = nodeEngine.getPartitionService().getPartitionCount();
this.cacheService = cacheService;
this.cacheConfig = cacheService.getCacheConfig(name);
this.cacheContext = cacheService.getOrCreateCacheContext(name);
if (cacheConfig == null) {
throw new CacheNotExistsException("Cache " + name + " is already destroyed or not created yet, on "
+ nodeEngine.getLocalMember());
}
this.wanReplicationEnabled = cacheService.isWanReplicationEnabled(name);
this.evictionConfig = cacheConfig.getEvictionConfig();
if (evictionConfig == null) {
throw new IllegalStateException("Eviction config cannot be null");
}
if (cacheConfig.getCacheLoaderFactory() != null) {
final Factory cacheLoaderFactory = cacheConfig.getCacheLoaderFactory();
if (cacheLoaderFactory instanceof HazelcastInstanceAware) {
((HazelcastInstanceAware) cacheLoaderFactory).setHazelcastInstance(nodeEngine.getHazelcastInstance());
}
cacheLoader = cacheLoaderFactory.create();
}
if (cacheConfig.getCacheWriterFactory() != null) {
final Factory cacheWriterFactory = cacheConfig.getCacheWriterFactory();
if (cacheWriterFactory instanceof HazelcastInstanceAware) {
((HazelcastInstanceAware) cacheWriterFactory).setHazelcastInstance(nodeEngine.getHazelcastInstance());
}
cacheWriter = cacheWriterFactory.create();
}
if (cacheConfig.isStatisticsEnabled()) {
this.statistics = cacheService.createCacheStatIfAbsent(name);
}
final Factory expiryPolicyFactory = cacheConfig.getExpiryPolicyFactory();
this.defaultExpiryPolicy = expiryPolicyFactory.create();
this.records = createRecordCacheMap();
this.maxSizeChecker = createCacheMaxSizeChecker(evictionConfig.getSize(), evictionConfig.getMaximumSizePolicy());
this.evictionPolicyEvaluator = createEvictionPolicyEvaluator(evictionConfig);
this.evictionChecker = createEvictionChecker(evictionConfig);
this.evictionStrategy = createEvictionStrategy(evictionConfig);
// Register "cacheWriter" if it is "Closable" to be closed while cache is being destroyed
if (cacheWriter instanceof Closeable) {
cacheService.addCacheResource(name, (Closeable) cacheWriter);
}
// Register "cacheLoader" if it is "Closable" to be closed while cache is being destroyed
if (cacheLoader instanceof Closeable) {
cacheService.addCacheResource(name, (Closeable) cacheLoader);
}
// Register "defaultExpiryPolicy" if it is "Closable" to be closed while cache is being destroyed
if (defaultExpiryPolicy instanceof Closeable) {
cacheService.addCacheResource(name, (Closeable) defaultExpiryPolicy);
}
init();
}
//CHECKSTYLE:ON
private boolean isPrimary() {
InternalPartitionService partitionService = nodeEngine.getPartitionService();
InternalPartition partition = partitionService.getPartition(partitionId, false);
Address owner = partition.getOwnerOrNull();
Address thisAddress = nodeEngine.getThisAddress();
return owner != null && owner.equals(thisAddress);
}
@Override
public void init() {
primary = isPrimary();
records.setEntryCounting(primary);
}
protected boolean isReadThrough() {
return cacheConfig.isReadThrough();
}
protected boolean isWriteThrough() {
return cacheConfig.isWriteThrough();
}
protected boolean isStatisticsEnabled() {
return statistics != null;
}
protected abstract CRM createRecordCacheMap();
protected abstract CacheEntryProcessorEntry createCacheEntryProcessorEntry(Data key, R record,
long now, int completionId);
protected abstract R createRecord(Object value, long creationTime, long expiryTime);
protected abstract Data valueToData(Object value);
protected abstract Object dataToValue(Data data);
protected abstract Object recordToValue(R record);
protected abstract Data recordToData(R record);
protected abstract Data toHeapData(Object obj);
protected MaxSizeChecker createCacheMaxSizeChecker(int size, EvictionConfig.MaxSizePolicy maxSizePolicy) {
if (maxSizePolicy == null) {
throw new IllegalArgumentException("Max-Size policy cannot be null");
}
if (maxSizePolicy == EvictionConfig.MaxSizePolicy.ENTRY_COUNT) {
return new EntryCountCacheMaxSizeChecker(size, records, partitionCount);
}
return null;
}
protected EvictionPolicyEvaluator createEvictionPolicyEvaluator(EvictionConfig cacheEvictionConfig) {
final EvictionPolicy evictionPolicy = cacheEvictionConfig.getEvictionPolicy();
if (evictionPolicy == null || evictionPolicy == EvictionPolicy.NONE || evictionPolicy == EvictionPolicy.RANDOM) {
throw new IllegalArgumentException("Eviction policy cannot be `null`, `NONE` or `RANDOM`");
}
return EvictionPolicyEvaluatorProvider.getEvictionPolicyEvaluator(cacheEvictionConfig);
}
protected EvictionChecker createEvictionChecker(EvictionConfig cacheEvictionConfig) {
return new MaxSizeEvictionChecker();
}
protected EvictionStrategy createEvictionStrategy(EvictionConfig cacheEvictionConfig) {
return EvictionStrategyProvider.getEvictionStrategy(cacheEvictionConfig);
}
protected boolean isEvictionEnabled() {
return evictionStrategy != null && evictionPolicyEvaluator != null;
}
protected boolean isEventsEnabled() {
return eventsEnabled && (cacheContext.getCacheEntryListenerCount() > 0 || wanReplicationEnabled);
}
protected boolean isInvalidationEnabled() {
return primary && cacheContext.getInvalidationListenerCount() > 0;
}
@Override
public int evictIfRequired() {
int evictedCount = 0;
if (isEvictionEnabled()) {
evictedCount = evictionStrategy.evict(records, evictionPolicyEvaluator, evictionChecker, this);
if (isStatisticsEnabled() && evictedCount > 0) {
statistics.increaseCacheEvictions(evictedCount);
}
}
return evictedCount;
}
protected Data toData(Object obj) {
if (obj instanceof Data) {
return (Data) obj;
} else if (obj instanceof CacheRecord) {
return recordToData((R) obj);
} else {
return valueToData(obj);
}
}
protected Object toValue(Object obj) {
if (obj instanceof Data) {
return dataToValue((Data) obj);
} else if (obj instanceof CacheRecord) {
return recordToValue((R) obj);
} else {
return obj;
}
}
protected Object toStorageValue(Object obj) {
if (obj instanceof Data) {
if (cacheConfig.getInMemoryFormat() == InMemoryFormat.OBJECT) {
return dataToValue((Data) obj);
} else {
return obj;
}
} else if (obj instanceof CacheRecord) {
return recordToValue((R) obj);
} else {
return obj;
}
}
public Data toEventData(Object obj) {
return isEventsEnabled() ? toHeapData(obj) : null;
}
private long getAdjustedExpireTime(Duration duration, long now) {
return duration.getAdjustedTime(now);
}
protected ExpiryPolicy getExpiryPolicy(ExpiryPolicy expiryPolicy) {
return expiryPolicy != null ? expiryPolicy : defaultExpiryPolicy;
}
protected boolean processExpiredEntry(Data key, R record, long now) {
return processExpiredEntry(key, record, now, SOURCE_NOT_AVAILABLE);
}
protected boolean processExpiredEntry(Data key, R record, long now, String source) {
return processExpiredEntry(key, record, now, source, null);
}
protected boolean processExpiredEntry(Data key, R record, long now, String source, String origin) {
final boolean isExpired = record != null && record.isExpiredAt(now);
if (!isExpired) {
return false;
}
if (isStatisticsEnabled()) {
statistics.increaseCacheExpiries(1);
}
R removedRecord = doRemoveRecord(key, source);
Data keyEventData = toEventData(key);
Data recordEventData = toEventData(removedRecord);
onProcessExpiredEntry(key, removedRecord, removedRecord.getExpirationTime(), now, source, origin);
if (isEventsEnabled()) {
publishEvent(createCacheExpiredEvent(keyEventData, recordEventData,
CacheRecord.TIME_NOT_AVAILABLE, origin, IGNORE_COMPLETION));
}
return true;
}
protected R processExpiredEntry(Data key, R record, long expiryTime, long now, String source) {
return processExpiredEntry(key, record, expiryTime, now, source, null);
}
protected R processExpiredEntry(Data key, R record, long expiryTime, long now, String source, String origin) {
final boolean isExpired = isExpiredAt(expiryTime, now);
if (!isExpired) {
return record;
}
if (isStatisticsEnabled()) {
statistics.increaseCacheExpiries(1);
}
R removedRecord = doRemoveRecord(key, source);
Data keyEventData = toEventData(key);
Data recordEventData = toEventData(removedRecord);
onProcessExpiredEntry(key, removedRecord, expiryTime, now, source, origin);
if (isEventsEnabled()) {
publishEvent(createCacheExpiredEvent(keyEventData, recordEventData, CacheRecord.TIME_NOT_AVAILABLE,
origin, IGNORE_COMPLETION));
}
return null;
}
protected void onProcessExpiredEntry(Data key, R record, long expiryTime, long now, String source, String origin) {
}
public R accessRecord(Data key, R record, ExpiryPolicy expiryPolicy, long now) {
onRecordAccess(key, record, getExpiryPolicy(expiryPolicy), now);
return record;
}
@Override
public void onEvict(Data key, R record) {
invalidateEntry(key);
}
protected void invalidateEntry(Data key, String source) {
if (isInvalidationEnabled()) {
cacheService.sendInvalidationEvent(name, toHeapData(key), source);
}
}
protected void invalidateEntry(Data key) {
invalidateEntry(key, SOURCE_NOT_AVAILABLE);
}
protected void invalidateAllEntries() {
invalidateAllEntries(SOURCE_NOT_AVAILABLE);
}
protected void invalidateAllEntries(String source) {
invalidateEntry(null, source);
}
protected void updateGetAndPutStat(boolean isPutSucceed, boolean getValue, boolean oldValueNull, long start) {
if (isStatisticsEnabled()) {
if (isPutSucceed) {
statistics.increaseCachePuts(1);
statistics.addPutTimeNanos(System.nanoTime() - start);
}
if (getValue) {
if (oldValueNull) {
statistics.increaseCacheMisses(1);
} else {
statistics.increaseCacheHits(1);
}
statistics.addGetTimeNanos(System.nanoTime() - start);
}
}
}
protected long updateAccessDuration(Data key, R record, ExpiryPolicy expiryPolicy, long now) {
long expiryTime = CacheRecord.TIME_NOT_AVAILABLE;
try {
Duration expiryDuration = expiryPolicy.getExpiryForAccess();
if (expiryDuration != null) {
expiryTime = getAdjustedExpireTime(expiryDuration, now);
record.setExpirationTime(expiryTime);
if (isEventsEnabled()) {
CacheEventContext cacheEventContext =
createBaseEventContext(CacheEventType.EXPIRATION_TIME_UPDATED, toEventData(key),
toEventData(record.getValue()), expiryTime, null, IGNORE_COMPLETION);
cacheEventContext.setAccessHit(record.getAccessHit());
publishEvent(cacheEventContext);
}
}
} catch (Exception e) {
EmptyStatement.ignore(e);
}
return expiryTime;
}
protected long onRecordAccess(Data key, R record, ExpiryPolicy expiryPolicy, long now) {
record.setAccessTime(now);
record.incrementAccessHit();
return updateAccessDuration(key, record, expiryPolicy, now);
}
protected void updateReplaceStat(boolean result, boolean isHit, long start) {
if (isStatisticsEnabled()) {
if (result) {
statistics.increaseCachePuts(1);
statistics.addPutTimeNanos(System.nanoTime() - start);
}
if (isHit) {
statistics.increaseCacheHits(1);
} else {
statistics.increaseCacheMisses(1);
}
}
}
protected void publishEvent(CacheEventContext cacheEventContext) {
if (isEventsEnabled()) {
cacheEventContext.setCacheName(name);
if (eventsBatchingEnabled) {
final CacheEventDataImpl cacheEventData =
new CacheEventDataImpl(name, cacheEventContext.getEventType(), cacheEventContext.getDataKey(),
cacheEventContext.getDataValue(), cacheEventContext.getDataOldValue(),
cacheEventContext.isOldValueAvailable());
Set cacheEventDataSet = batchEvent.remove(cacheEventContext.getEventType());
if (cacheEventDataSet == null) {
cacheEventDataSet = new HashSet();
batchEvent.put(cacheEventContext.getEventType(), cacheEventDataSet);
}
cacheEventDataSet.add(cacheEventData);
} else {
cacheService.publishEvent(cacheEventContext);
}
}
}
protected void publishBatchedEvents(String cacheName, CacheEventType cacheEventType, int orderKey) {
if (isEventsEnabled()) {
final Set cacheEventDatas = batchEvent.remove(cacheEventType);
if (cacheEventDatas != null) {
CacheEventSet ces = new CacheEventSet(cacheEventType, cacheEventDatas);
cacheService.publishEvent(cacheName, ces, orderKey);
}
}
}
protected boolean compare(Object v1, Object v2) {
if (v1 == null && v2 == null) {
return true;
}
if (v1 == null) {
return false;
}
if (v2 == null) {
return false;
}
return v1.equals(v2);
}
protected R createRecord(long expiryTime) {
return createRecord(null, Clock.currentTimeMillis(), expiryTime);
}
protected R createRecord(Object value, long expiryTime) {
return createRecord(value, Clock.currentTimeMillis(), expiryTime);
}
protected R createRecord(Data keyData, Object value, long expirationTime, int completionId) {
final R record = createRecord(value, expirationTime);
if (isEventsEnabled()) {
publishEvent(createCacheCreatedEvent(toEventData(keyData), toEventData(value),
expirationTime, null, completionId));
}
return record;
}
protected void onCreateRecordError(Data key, Object value, long expiryTime, long now, boolean disableWriteThrough,
int completionId, String origin, R record, Throwable error) {
}
protected R createRecord(Data key, Object value, long expiryTime,
long now, boolean disableWriteThrough, int completionId, String origin) {
R record = createRecord(value, now, expiryTime);
try {
doPutRecord(key, record);
} catch (Throwable error) {
onCreateRecordError(key, value, expiryTime, now, disableWriteThrough,
completionId, origin, record, error);
throw ExceptionUtil.rethrow(error);
}
try {
if (!disableWriteThrough) {
writeThroughCache(key, value);
}
} catch (Throwable error) {
// Writing to `CacheWriter` failed, so we should revert entry (remove added record).
records.remove(key);
// Disposing key/value/record should be handled inside `onCreateRecordWithExpiryError`.
onCreateRecordError(key, value, expiryTime, now, disableWriteThrough,
completionId, origin, record, error);
throw ExceptionUtil.rethrow(error);
}
if (isEventsEnabled()) {
publishEvent(createCacheCreatedEvent(toEventData(key), toEventData(value),
expiryTime, origin, completionId));
}
return record;
}
protected R createRecordWithExpiry(Data key, Object value, long expiryTime,
long now, boolean disableWriteThrough, int completionId, String origin) {
if (!isExpiredAt(expiryTime, now)) {
return createRecord(key, value, expiryTime, now, disableWriteThrough, completionId, origin);
}
if (isEventsEnabled()) {
publishEvent(createCacheCompleteEvent(toEventData(key), CacheRecord.TIME_NOT_AVAILABLE,
origin, completionId));
}
return null;
}
protected R createRecordWithExpiry(Data key, Object value, long expiryTime,
long now, boolean disableWriteThrough, int completionId) {
return createRecordWithExpiry(key, value, expiryTime, now, disableWriteThrough, completionId, null);
}
protected R createRecordWithExpiry(Data key, Object value, ExpiryPolicy expiryPolicy,
long now, boolean disableWriteThrough, int completionId) {
return createRecordWithExpiry(key, value, expiryPolicy, now, disableWriteThrough, completionId, null);
}
protected R createRecordWithExpiry(Data key, Object value, ExpiryPolicy expiryPolicy,
long now, boolean disableWriteThrough, int completionId, String origin) {
expiryPolicy = getExpiryPolicy(expiryPolicy);
Duration expiryDuration;
try {
expiryDuration = expiryPolicy.getExpiryForCreation();
} catch (Exception e) {
expiryDuration = Duration.ETERNAL;
}
long expiryTime = getAdjustedExpireTime(expiryDuration, now);
return createRecordWithExpiry(key, value, expiryTime, now, disableWriteThrough, completionId, origin);
}
protected void onUpdateRecord(Data key, R record, Object value, Data oldDataValue) {
}
protected void onUpdateRecordError(Data key, R record, Object value, Data newDataValue,
Data oldDataValue, Throwable error) {
}
protected void updateRecord(Data key, R record, Object value, long expiryTime, long now,
boolean disableWriteThrough, int completionId, String source, String origin) {
Data dataOldValue = null;
Data dataValue = null;
Object recordValue = value;
try {
if (expiryTime != CacheRecord.TIME_NOT_AVAILABLE) {
record.setExpirationTime(expiryTime);
}
if (isExpiredAt(expiryTime, now)) {
// No need to update record value if it is expired
if (!disableWriteThrough) {
writeThroughCache(key, value);
}
} else {
switch (cacheConfig.getInMemoryFormat()) {
case BINARY:
recordValue = toData(value);
dataValue = (Data) recordValue;
dataOldValue = toData(record);
break;
case OBJECT:
if (value instanceof Data) {
recordValue = dataToValue((Data) value);
dataValue = (Data) value;
} else {
dataValue = valueToData(value);
}
dataOldValue = toData(record);
break;
case NATIVE:
recordValue = toData(value);
dataValue = (Data) recordValue;
dataOldValue = toData(record);
break;
default:
throw new IllegalArgumentException("Invalid storage format: " + cacheConfig.getInMemoryFormat());
}
if (!disableWriteThrough) {
writeThroughCache(key, value);
// If writing to `CacheWriter` fails no need to revert.
// Because we have not update record value yet with its new value
// but just converted new value to required storage type.
}
Data eventDataKey = toEventData(key);
Data eventDataValue = toEventData(dataValue);
Data eventDataOldValue = toEventData(dataOldValue);
updateRecordValue(record, recordValue);
onUpdateRecord(key, record, value, dataOldValue);
invalidateEntry(key, source);
if (isEventsEnabled()) {
publishEvent(createCacheUpdatedEvent(eventDataKey, eventDataValue, eventDataOldValue,
record.getExpirationTime(), record.getAccessTime(),
record.getAccessHit(), origin, completionId));
}
}
} catch (Throwable error) {
onUpdateRecordError(key, record, value, dataValue, dataOldValue, error);
throw ExceptionUtil.rethrow(error);
}
}
protected void updateRecordValue(R record, Object recordValue) {
record.setValue(recordValue);
}
protected boolean updateRecordWithExpiry(Data key, Object value, R record, long expiryTime, long now,
boolean disableWriteThrough, int completionId,
String source, String origin) {
updateRecord(key, record, value, expiryTime, now, disableWriteThrough, completionId, source, origin);
return processExpiredEntry(key, record, expiryTime, now, source) != null;
}
protected boolean updateRecordWithExpiry(Data key, Object value, R record, long expiryTime,
long now, boolean disableWriteThrough, int completionId) {
return updateRecordWithExpiry(key, value, record, expiryTime, now, disableWriteThrough,
completionId, SOURCE_NOT_AVAILABLE);
}
protected boolean updateRecordWithExpiry(Data key, Object value, R record, long expiryTime,
long now, boolean disableWriteThrough, int completionId, String source) {
return updateRecordWithExpiry(key, value, record, expiryTime, now,
disableWriteThrough, completionId, source, null);
}
protected boolean updateRecordWithExpiry(Data key, Object value, R record, ExpiryPolicy expiryPolicy,
long now, boolean disableWriteThrough, int completionId) {
return updateRecordWithExpiry(key, value, record, expiryPolicy, now,
disableWriteThrough, completionId, SOURCE_NOT_AVAILABLE);
}
protected boolean updateRecordWithExpiry(Data key, Object value, R record, ExpiryPolicy expiryPolicy,
long now, boolean disableWriteThrough, int completionId, String source) {
return updateRecordWithExpiry(key, value, record, expiryPolicy, now,
disableWriteThrough, completionId, source, null);
}
protected boolean updateRecordWithExpiry(Data key, Object value, R record, ExpiryPolicy expiryPolicy, long now,
boolean disableWriteThrough, int completionId, String source, String origin) {
expiryPolicy = getExpiryPolicy(expiryPolicy);
long expiryTime = CacheRecord.TIME_NOT_AVAILABLE;
try {
Duration expiryDuration = expiryPolicy.getExpiryForUpdate();
if (expiryDuration != null) {
expiryTime = getAdjustedExpireTime(expiryDuration, now);
}
} catch (Exception e) {
EmptyStatement.ignore(e);
}
return updateRecordWithExpiry(key, value, record, expiryTime, now,
disableWriteThrough, completionId, source, origin);
}
protected void onDeleteRecord(Data key, R record, Data dataValue, boolean deleted) {
}
protected void onDeleteRecordError(Data key, R record, Data dataValue, boolean deleted, Throwable error) {
}
protected boolean deleteRecord(Data key, int completionId) {
return deleteRecord(key, completionId, SOURCE_NOT_AVAILABLE);
}
protected boolean deleteRecord(Data key, int completionId, String source) {
return deleteRecord(key, completionId, source, null);
}
protected boolean deleteRecord(Data key, int completionId, String source, String origin) {
final R record = doRemoveRecord(key, source);
Data dataValue = null;
try {
switch (cacheConfig.getInMemoryFormat()) {
case BINARY:
case OBJECT:
case NATIVE:
dataValue = toData(record);
break;
default:
throw new IllegalArgumentException("Invalid storage format: " + cacheConfig.getInMemoryFormat());
}
Data eventDataKey = toEventData(key);
Data eventDataValue = toEventData(dataValue);
onDeleteRecord(key, record, dataValue, record != null);
if (isEventsEnabled()) {
publishEvent(createCacheRemovedEvent(eventDataKey, eventDataValue,
CacheRecord.TIME_NOT_AVAILABLE, origin, completionId));
}
return record != null;
} catch (Throwable error) {
onDeleteRecordError(key, record, dataValue, record != null, error);
throw ExceptionUtil.rethrow(error);
}
}
public R readThroughRecord(Data key, long now) {
Object value = readThroughCache(key);
if (value == null) {
return null;
}
Duration expiryDuration;
try {
expiryDuration = defaultExpiryPolicy.getExpiryForCreation();
} catch (Exception e) {
expiryDuration = Duration.ETERNAL;
}
long expiryTime = getAdjustedExpireTime(expiryDuration, now);
if (isExpiredAt(expiryTime, now)) {
return null;
}
return createRecord(key, value, expiryTime, IGNORE_COMPLETION);
}
public Object readThroughCache(Data key) throws CacheLoaderException {
if (this.isReadThrough() && cacheLoader != null) {
try {
Object o = dataToValue(key);
return cacheLoader.load(o);
} catch (Exception e) {
if (!(e instanceof CacheLoaderException)) {
throw new CacheLoaderException("Exception in CacheLoader during load", e);
} else {
throw (CacheLoaderException) e;
}
}
}
return null;
}
public void writeThroughCache(Data key, Object value) throws CacheWriterException {
if (isWriteThrough() && cacheWriter != null) {
try {
final Object objKey = dataToValue(key);
final Object objValue = toValue(value);
CacheEntry, ?> entry = new CacheEntry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy