blob: 1dcd9184580f1a6fd8e04283897727ff3aef2f4b [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2002-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
* more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.internal.cache;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.logging.log4j.Logger;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.cache.AttributesMutator;
import com.gemstone.gemfire.cache.CacheCallback;
import com.gemstone.gemfire.cache.CacheListener;
import com.gemstone.gemfire.cache.CacheLoader;
import com.gemstone.gemfire.cache.CacheLoaderException;
import com.gemstone.gemfire.cache.CacheStatistics;
import com.gemstone.gemfire.cache.CacheWriter;
import com.gemstone.gemfire.cache.CacheWriterException;
import com.gemstone.gemfire.cache.CustomEvictionAttributes;
import com.gemstone.gemfire.cache.CustomExpiry;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.DiskWriteAttributes;
import com.gemstone.gemfire.cache.EntryExistsException;
import com.gemstone.gemfire.cache.EntryNotFoundException;
import com.gemstone.gemfire.cache.EvictionAttributes;
import com.gemstone.gemfire.cache.EvictionAttributesMutator;
import com.gemstone.gemfire.cache.EvictionCriteria;
import com.gemstone.gemfire.cache.ExpirationAction;
import com.gemstone.gemfire.cache.ExpirationAttributes;
import com.gemstone.gemfire.cache.MembershipAttributes;
import com.gemstone.gemfire.cache.MirrorType;
import com.gemstone.gemfire.cache.Operation;
import com.gemstone.gemfire.cache.PartitionAttributes;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAccessException;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionDestroyedException;
import com.gemstone.gemfire.cache.RegionMembershipListener;
import com.gemstone.gemfire.cache.RegionService;
import com.gemstone.gemfire.cache.RoleException;
import com.gemstone.gemfire.cache.Scope;
import com.gemstone.gemfire.cache.StatisticsDisabledException;
import com.gemstone.gemfire.cache.SubscriptionAttributes;
import com.gemstone.gemfire.cache.TimeoutException;
import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue;
import com.gemstone.gemfire.cache.asyncqueue.internal.AsyncEventQueueImpl;
import com.gemstone.gemfire.cache.client.PoolManager;
import com.gemstone.gemfire.cache.client.internal.PoolImpl;
import com.gemstone.gemfire.cache.query.FunctionDomainException;
import com.gemstone.gemfire.cache.query.NameResolutionException;
import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
import com.gemstone.gemfire.cache.query.SelectResults;
import com.gemstone.gemfire.cache.query.TypeMismatchException;
import com.gemstone.gemfire.cache.query.internal.index.IndexManager;
import com.gemstone.gemfire.cache.snapshot.RegionSnapshotService;
import com.gemstone.gemfire.cache.util.BridgeClient;
import com.gemstone.gemfire.cache.util.BridgeLoader;
import com.gemstone.gemfire.cache.util.BridgeWriter;
import com.gemstone.gemfire.cache.wan.GatewaySender;
import com.gemstone.gemfire.compression.Compressor;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.internal.DM;
import com.gemstone.gemfire.distributed.internal.DistributionAdvisor;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.internal.DataSerializableFixedID;
import com.gemstone.gemfire.internal.cache.extension.Extensible;
import com.gemstone.gemfire.internal.cache.extension.ExtensionPoint;
import com.gemstone.gemfire.internal.cache.extension.SimpleExtensionPoint;
import com.gemstone.gemfire.internal.cache.lru.LRUAlgorithm;
import com.gemstone.gemfire.internal.cache.snapshot.RegionSnapshotServiceImpl;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.logging.LogService;
import com.gemstone.gemfire.internal.logging.log4j.LocalizedMessage;
import com.gemstone.gemfire.internal.util.ArrayUtils;
import com.gemstone.gemfire.pdx.internal.PeerTypeRegistration;
import com.google.common.util.concurrent.Service.State;
/**
* Takes care of RegionAttributes, AttributesMutator, and some no-brainer method
* implementations.
*
* @author Eric Zoerner
*/
@SuppressWarnings("deprecation")
public abstract class AbstractRegion implements Region, RegionAttributes,
AttributesMutator, CacheStatistics,
DataSerializableFixedID, RegionEntryContext,
Extensible<Region<?,?>>
{
private static final Logger logger = LogService.getLogger();
/**
* Identifies the static order in which this region was created in relation
* to other regions or other instances of this region during the life of
* this JVM.
*/
private final int serialNumber;
// RegionAttributes //
/**
* Used to synchronize WRITES to cacheListeners.
* Always do copy on write.
*/
private final Object clSync = new Object();
// Used to synchronize creation of IndexManager
private final Object imSync = new Object();
/**
* NOTE: care must be taken to never modify the array of cacheListeners in
* place. Instead allocate a new array and modify it.
* This field is volatile so that it can be read w/o getting clSync.
*/
private volatile CacheListener[] cacheListeners;
private volatile CacheLoader cacheLoader;
private volatile CacheWriter cacheWriter;
private LRUAlgorithm evictionController;
protected int entryIdleTimeout;
protected ExpirationAction entryIdleTimeoutExpirationAction;
protected CustomExpiry customEntryIdleTimeout;
protected int entryTimeToLive;
protected ExpirationAction entryTimeToLiveExpirationAction;
protected CustomExpiry customEntryTimeToLive;
protected int initialCapacity;
protected Class keyConstraint;
protected Class valueConstraint;
protected float loadFactor;
protected DataPolicy dataPolicy;
protected int regionIdleTimeout;
protected ExpirationAction regionIdleTimeoutExpirationAction;
protected int regionTimeToLive;
protected ExpirationAction regionTimeToLiveExpirationAction;
public static final Scope DEFAULT_SCOPE = Scope.DISTRIBUTED_NO_ACK;
protected Scope scope = DEFAULT_SCOPE;
protected boolean statisticsEnabled;
protected boolean isLockGrantor;
protected boolean mcastEnabled;
protected int concurrencyLevel;
protected volatile boolean concurrencyChecksEnabled;
protected boolean earlyAck;
//merge42004: revision 42004 has not defined isPdxTypesRegion. It has come to cheetah branch from merge revision 39860. This is getting used in method getRemoteDsIds.
protected final boolean isPdxTypesRegion;
protected Set<String> gatewaySenderIds;
protected boolean isGatewaySenderEnabled = false;
protected Set<String> asyncEventQueueIds;
protected Set<String> allGatewaySenderIds;
protected boolean enableSubscriptionConflation;
protected boolean publisher;
protected boolean enableAsyncConflation;
/**
* True if this region uses off-heap memory; otherwise false (default)
* @since 9.0
*/
protected boolean offHeap;
protected boolean cloningEnable = false;
protected DiskWriteAttributes diskWriteAttributes;
protected File[] diskDirs;
protected int[] diskSizes;
protected String diskStoreName;
protected boolean isDiskSynchronous;
protected boolean indexMaintenanceSynchronous = false;
protected volatile IndexManager indexManager = null;
//Asif : The ThreadLocal is used to identify if the thread is an
//index creation thread. This identification helps skip the synchronization
// block
//if the value is "REMOVED" token. This prevents the dead lock , in case the
// lock
// over the entry is held by any Index Update Thread.
// This is used to fix Bug # 33336.
private final ThreadLocal isIndexCreator = new ThreadLocal();
/** Attributes that define this Region as a PartitionedRegion */
protected PartitionAttributes partitionAttributes;
protected EvictionAttributesImpl evictionAttributes = new EvictionAttributesImpl();
protected CustomEvictionAttributes customEvictionAttributes;
/** The membership attributes defining required roles functionality */
protected MembershipAttributes membershipAttributes;
/** The subscription attributes defining required roles functionality */
protected SubscriptionAttributes subscriptionAttributes;
/** should this region ignore in-progress JTA transactions? */
protected boolean ignoreJTA;
private final AtomicLong lastAccessedTime;
private final AtomicLong lastModifiedTime;
private static final boolean trackHits = !Boolean.getBoolean("gemfire.ignoreHits");
private static final boolean trackMisses = !Boolean.getBoolean("gemfire.ignoreMisses");
private final AtomicLong hitCount = new AtomicLong();
private final AtomicLong missCount = new AtomicLong();
protected String poolName;
protected String hdfsStoreName;
protected boolean hdfsWriteOnly;
protected Compressor compressor;
/**
* @see #getExtensionPoint()
* @since 8.1
*/
protected ExtensionPoint<Region<?,?>> extensionPoint = new SimpleExtensionPoint<Region<?,?>>(this, this);
protected final GemFireCacheImpl cache;
/** Creates a new instance of AbstractRegion */
protected AbstractRegion(GemFireCacheImpl cache, RegionAttributes attrs,
String regionName, InternalRegionArguments internalRegionArgs) {
this.cache = cache;
this.serialNumber = DistributionAdvisor.createSerialNumber();
this.isPdxTypesRegion = PeerTypeRegistration.REGION_NAME.equals(regionName);
this.lastAccessedTime = new AtomicLong(cacheTimeMillis());
this.lastModifiedTime = new AtomicLong(lastAccessedTime.get());
setAttributes(attrs, regionName, internalRegionArgs);
}
/**
* Unit test constructor. DO NOT USE!
*
* @since 8.1
* @deprecated For unit testing only. Use
* {@link #AbstractRegion(GemFireCacheImpl, RegionAttributes, String, InternalRegionArguments)}
* .
*/
@Deprecated
AbstractRegion(GemFireCacheImpl cache, int serialNumber, boolean isPdxTypeRegion, long lastAccessedTime, long lastModifiedTime ) {
this.cache = cache;
this.serialNumber = serialNumber;
this.isPdxTypesRegion = isPdxTypeRegion;
this.lastAccessedTime = new AtomicLong(lastAccessedTime);
this.lastModifiedTime = new AtomicLong(lastModifiedTime);
}
/** ******************** No-Brainer methods ******************************** */
/**
* configure this region to ignore or not ignore in-progress JTA transactions.
* Setting this to true will cause cache operations to no longer notice JTA
* transactions. The default setting is false
*
* @deprecated in 5.0 and later releases, use the region attribute ignoreJTA
* to configure this
*/
@Deprecated
public void setIgnoreJTA(boolean ignore)
{
ignoreJTA = ignore;
}
public final void create(Object key, Object value) throws TimeoutException,
EntryExistsException, CacheWriterException
{
create(key, value, null);
}
public final Object destroy(Object key) throws TimeoutException,
EntryNotFoundException, CacheWriterException
{
return destroy(key, null);
}
public final Object get(Object name) throws CacheLoaderException,
TimeoutException
{
return get(name, null, true, null);
}
public final Object put(Object name, Object value) throws TimeoutException,
CacheWriterException
{
return put(name, value, null);
}
public Object get(Object name, Object aCallbackArgument)
throws CacheLoaderException, TimeoutException
{
return get(name, aCallbackArgument, true, null);
}
public final void localDestroyRegion()
{
localDestroyRegion(null);
}
/**
* @param key the key to find
* @param aCallbackArgument argument for callbacks
* @param generateCallbacks whether callbacks should be invoked
* @param clientEvent client-side event, if any (used to pass back version information)
* @return the value associated with the key
* @throws TimeoutException
* @throws CacheLoaderException
*/
abstract Object get(Object key, Object aCallbackArgument,
boolean generateCallbacks, EntryEventImpl clientEvent) throws TimeoutException, CacheLoaderException;
public final void localDestroy(Object key) throws EntryNotFoundException {
localDestroy(key, null);
}
public final void destroyRegion() throws CacheWriterException,
TimeoutException
{
destroyRegion(null);
}
public final void invalidate(Object key) throws TimeoutException,
EntryNotFoundException
{
invalidate(key, null);
}
public final void localInvalidate(Object key) throws EntryNotFoundException
{
localInvalidate(key, null);
}
public final void localInvalidateRegion()
{
localInvalidateRegion(null);
}
public final void invalidateRegion() throws TimeoutException
{
invalidateRegion(null);
}
abstract void basicClear(RegionEventImpl regionEvent);
/**
* The default Region implementation will generate EvenTID in the EntryEvent
* object. This method is overridden in special Region objects like HARegion
* or SingleWriteSingleReadRegionQueue.SingleReadWriteMetaRegion to return
* false as the event propagation from those regions do not need EventID
* objects. This method is made abstract to directly use it in clear operations.
*(clear and localclear)
* @return boolean indicating whether to generate eventID or not
*/
abstract boolean generateEventID();
protected abstract DistributedMember getMyId();
public void clear()
{
checkReadiness();
checkForLimitedOrNoAccess();
RegionEventImpl regionEvent = new RegionEventImpl(this,
Operation.REGION_CLEAR, null, false, getMyId(),generateEventID());
basicClear(regionEvent);
}
abstract void basicLocalClear(RegionEventImpl rEvent);
public void localClear()
{
checkReadiness();
checkForNoAccess();
RegionEventImpl event = new RegionEventImpl(this,
Operation.REGION_LOCAL_CLEAR, null, false, getMyId(),generateEventID()/* generate EventID */);
basicLocalClear(event);
}
@Override
public Map getAll(Collection keys) {
return getAll(keys, null);
}
@Override
public Map getAll(Collection keys, Object callback) {
if (keys == null) {
throw new NullPointerException("The collection of keys for getAll cannot be null");
}
checkReadiness();
checkForLimitedOrNoAccess();
return keys.isEmpty()? new HashMap(): basicGetAll(keys, callback);
}
abstract Map basicGetAll(Collection keys, Object callback);
public abstract RegionEntry basicGetEntry(Object key);
protected StringBuilder getStringBuilder() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getName());
buf.append("[path='")
.append(getFullPath())
.append("';scope=")
.append(getScope())
.append("';dataPolicy=")
.append(this.dataPolicy);
if (this.concurrencyChecksEnabled) {
buf.append("; concurrencyChecksEnabled");
}
return buf;
}
@Override
public String toString() {
return getStringBuilder().append(']').toString();
}
/** ********************* RegionAttributes ********************************* */
public CacheLoader getCacheLoader()
{
//checkReadiness();
return this.cacheLoader;
}
public CacheWriter getCacheWriter()
{
//checkReadiness();
return this.cacheWriter;
}
/**
* Return a cache loader if this region has one.
* Note if region's loader is used to implement bridge then null is returned.
* @since 5.7
*/
public CacheLoader basicGetLoader() {
CacheLoader result = this.cacheLoader;
if (isBridgeLoader(result)) {
result = null;
}
return result;
}
/**
* Return a cache writer if this region has one.
* Note if region's writer is used to implement bridge then null is returned.
* @since 5.7
*/
public CacheWriter basicGetWriter() {
CacheWriter result = this.cacheWriter;
if (isBridgeWriter(result)) {
result = null;
}
return result;
}
public Class getKeyConstraint()
{
//checkReadiness();
return this.keyConstraint;
}
public Class getValueConstraint()
{
return this.valueConstraint;
}
private volatile ExpirationAttributes regionTimeToLiveAtts;
private void setRegionTimeToLiveAtts() {
this.regionTimeToLiveAtts = new ExpirationAttributes(this.regionTimeToLive, this.regionTimeToLiveExpirationAction);
}
public ExpirationAttributes getRegionTimeToLive()
{
return this.regionTimeToLiveAtts;
}
private volatile ExpirationAttributes regionIdleTimeoutAtts;
private void setRegionIdleTimeoutAtts() {
this.regionIdleTimeoutAtts = new ExpirationAttributes(this.regionIdleTimeout, this.regionIdleTimeoutExpirationAction);
}
public ExpirationAttributes getRegionIdleTimeout()
{
return this.regionIdleTimeoutAtts;
}
private volatile ExpirationAttributes entryTimeToLiveAtts;
protected void setEntryTimeToLiveAtts() {
this.entryTimeToLiveAtts = new ExpirationAttributes(this.entryTimeToLive, this.entryTimeToLiveExpirationAction);
}
public ExpirationAttributes getEntryTimeToLive()
{
return this.entryTimeToLiveAtts;
}
public CustomExpiry getCustomEntryTimeToLive() {
return this.customEntryTimeToLive;
}
private volatile ExpirationAttributes entryIdleTimeoutAtts;
protected void setEntryIdleTimeoutAtts() {
this.entryIdleTimeoutAtts = new ExpirationAttributes(this.entryIdleTimeout, this.entryIdleTimeoutExpirationAction);
}
public ExpirationAttributes getEntryIdleTimeout()
{
return this.entryIdleTimeoutAtts;
}
public CustomExpiry getCustomEntryIdleTimeout() {
return this.customEntryIdleTimeout;
}
public MirrorType getMirrorType() {
if (this.dataPolicy.isNormal() || this.dataPolicy.isPreloaded()
|| this.dataPolicy.isEmpty() || this.dataPolicy.withPartitioning()) {
return MirrorType.NONE;
}
else if (this.dataPolicy.withReplication()) {
return MirrorType.KEYS_VALUES;
}
else {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_NO_MIRROR_TYPE_CORRESPONDS_TO_DATA_POLICY_0.toLocalizedString(this.dataPolicy));
}
}
public String getPoolName()
{
//checkReadiness();
return this.poolName;
}
public DataPolicy getDataPolicy()
{
//checkReadiness();
return this.dataPolicy;
}
public Scope getScope()
{
//checkReadiness();
return this.scope;
}
public CacheListener getCacheListener()
{
//checkReadiness();
CacheListener[] listeners = fetchCacheListenersField();
if (listeners == null || listeners.length == 0) {
return null;
}
if (listeners.length == 1) {
return listeners[0];
}
else {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_MORE_THAN_ONE_CACHE_LISTENER_EXISTS.toLocalizedString());
}
}
public final boolean isPdxTypesRegion() {
return this.isPdxTypesRegion;
}
public Set<String> getGatewaySenderIds() {
return this.gatewaySenderIds;
}
public Set<String> getAsyncEventQueueIds() {
return this.asyncEventQueueIds;
}
public final Set<String> getAllGatewaySenderIds() {
return Collections.unmodifiableSet(this.allGatewaySenderIds);
}
public final boolean checkNotifyGatewaySender() {
return (this.cache.getAllGatewaySenders().size() > 0
&& this.allGatewaySenderIds.size() > 0);
}
public final Set<String> getActiveGatewaySenderIds() {
final Set<GatewaySender> allGatewaySenders;
HashSet<String> activeGatewaySenderIds = null;
final int sz = this.gatewaySenderIds.size();
if (sz > 0
&& (allGatewaySenders = this.cache.getGatewaySenders()).size() > 0) {
for (GatewaySender sender : allGatewaySenders) {
if (sender.isRunning()
&& this.gatewaySenderIds.contains(sender.getId())) {
if (activeGatewaySenderIds == null) {
activeGatewaySenderIds = new HashSet<String>();
}
activeGatewaySenderIds.add(sender.getId());
}
}
}
return activeGatewaySenderIds;
}
public final Set<String> getActiveAsyncQueueIds() {
final Set<AsyncEventQueue> allAsyncQueues;
HashSet<String> activeAsyncQueueIds = null;
final int sz = this.asyncEventQueueIds.size();
if (sz > 0
&& (allAsyncQueues = this.cache.getAsyncEventQueues()).size() > 0) {
for (AsyncEventQueue asyncQueue : allAsyncQueues) {
//merge42004:In cheetah asyncEventQueue has isRunning Method. It has come from merging branches. A mail regarding the asyncEventQueue is sent to Barry to get more clarification. We need to sort this out.
if (/*asyncQueue.isRunning()
&&*/ this.asyncEventQueueIds.contains(asyncQueue.getId())) {
if (activeAsyncQueueIds == null) {
activeAsyncQueueIds = new HashSet<String>();
}
activeAsyncQueueIds.add(asyncQueue.getId());
}
}
}
return activeAsyncQueueIds;
}
/**
* Return the remote DS IDs that need to receive events for this region.
*
* @param allGatewaySenderIds the set of gateway sender IDs to consider
*/
public final List<Integer> getRemoteDsIds(Set<String> allGatewaySenderIds)
throws IllegalStateException {
final Set<GatewaySender> allGatewaySenders;
final int sz = allGatewaySenderIds.size();
if ((sz > 0 || isPdxTypesRegion)
&& (allGatewaySenders = this.cache.getAllGatewaySenders()).size() > 0) {
List<Integer> allRemoteDSIds = new ArrayList<Integer>(sz);
for (GatewaySender sender : allGatewaySenders) {
// This is for all regions except pdx Region
if (!isPdxTypesRegion) {
// Make sure we are distributing to only those senders whose id
// is avaialble on this region
if (allGatewaySenderIds.contains(sender.getId())) {
/*// ParalleGatewaySender with DR is not allowed
if (this.partitionAttributes == null && sender.isParallel()) {
throw new IllegalStateException(LocalizedStrings
.AttributesFactory_PARALLELGATEWAYSENDER_0_IS_INCOMPATIBLE_WITH_DISTRIBUTED_REPLICATION
.toLocalizedString(sender.getId()));
}*/
allRemoteDSIds.add(sender.getRemoteDSId());
}
}
else { // this else is for PDX region
allRemoteDSIds.add(sender.getRemoteDSId());
}
}
return allRemoteDSIds;
}
return null;
}
// protected final void initAllGatewaySenderIds() {
// HashSet<String> senderIds = new HashSet<String>();
// this.allGatewaySenderIds = senderIds;
// if (getGatewaySenderIds().isEmpty() && getAsyncEventQueueIds().isEmpty()) {
// return Collections.emptySet(); // fix for bug 45774
// }
// Set<String> tmp = new CopyOnWriteArraySet<String>();
// tmp.addAll(this.getGatewaySenderIds());
// for(String asyncQueueId : this.getAsyncEventQueueIds()){
// tmp.add(AsyncEventQueueImpl.getSenderIdFromAsyncEventQueueId(asyncQueueId));
// }
// return tmp;
// }
public boolean isGatewaySenderEnabled() {
return this.isGatewaySenderEnabled;
}
private static final CacheListener[] EMPTY_LISTENERS = new CacheListener[0];
public CacheListener[] getCacheListeners()
{
CacheListener[] listeners = fetchCacheListenersField();
if (listeners == null || listeners.length == 0) {
return EMPTY_LISTENERS;
}
else {
CacheListener[] result = new CacheListener[listeners.length];
System.arraycopy(listeners, 0, result, 0, listeners.length);
return result;
}
}
/**
* Sets the cacheListeners field.
*/
private final void storeCacheListenersField(CacheListener[] value)
{
synchronized (this.clSync) {
if (value != null && value.length != 0) {
CacheListener[] nv = new CacheListener[value.length];
System.arraycopy(value, 0, nv, 0, nv.length);
value = nv;
}
else {
value = EMPTY_LISTENERS;
}
this.cacheListeners = value;
}
}
/**
* Fetches the value in the cacheListeners field. NOTE: callers should not
* modify the contents of the returned array.
*/
protected final CacheListener[] fetchCacheListenersField()
{
return this.cacheListeners;
}
public int getInitialCapacity()
{
//checkReadiness();
return this.initialCapacity;
}
public float getLoadFactor()
{
//checkReadiness();
return this.loadFactor;
}
protected abstract boolean isCurrentlyLockGrantor();
public boolean isLockGrantor()
{
//checkReadiness();
return this.isLockGrantor;
}
/**
* RegionAttributes implementation. Returns true if multicast can be used by
* the cache for this region
*/
public boolean getMulticastEnabled()
{
//checkReadiness();
return this.mcastEnabled;
}
public boolean getStatisticsEnabled()
{
//checkReadiness();
return this.statisticsEnabled;
}
public boolean getIgnoreJTA()
{
//checkRediness();
return this.ignoreJTA;
}
public int getConcurrencyLevel()
{
//checkReadiness();
return this.concurrencyLevel;
}
public boolean getConcurrencyChecksEnabled() {
return this.concurrencyChecksEnabled;
}
public boolean getPersistBackup()
{
//checkReadiness();
return getDataPolicy().withPersistence();
}
public boolean getEarlyAck()
{
//checkReadiness();
return this.earlyAck;
}
/*
* @deprecated as of prPersistSprint1
*/
@Deprecated
public boolean getPublisher()
{
return this.publisher;
}
public boolean getEnableConflation() { // deprecated in 5.0
return getEnableSubscriptionConflation();
}
public boolean getEnableBridgeConflation() {// deprecated in 5.7
return getEnableSubscriptionConflation();
}
public boolean getEnableSubscriptionConflation() {
return this.enableSubscriptionConflation;
}
public boolean getEnableAsyncConflation()
{
return this.enableAsyncConflation;
}
/*
* @deprecated as of prPersistSprint2
*/
@Deprecated
public DiskWriteAttributes getDiskWriteAttributes()
{
//checkReadiness();
return this.diskWriteAttributes;
}
public abstract File[] getDiskDirs();
public final String getDiskStoreName() {
return this.diskStoreName;
}
public boolean isDiskSynchronous() {
return this.isDiskSynchronous;
}
public boolean getIndexMaintenanceSynchronous()
{
return this.indexMaintenanceSynchronous;
}
public PartitionAttributes getPartitionAttributes()
{
return this.partitionAttributes;
}
public MembershipAttributes getMembershipAttributes()
{
return this.membershipAttributes;
}
public SubscriptionAttributes getSubscriptionAttributes()
{
return this.subscriptionAttributes;
}
@Override
public final String getHDFSStoreName() {
return this.hdfsStoreName;
}
@Override
public final boolean getHDFSWriteOnly() {
return this.hdfsWriteOnly;
}
/**
* Get IndexManger for region
*/
public IndexManager getIndexManager()
{
return this.indexManager;
}
/**
* This method call is guarded by imSync lock created for each region.
* Set IndexManger for region.
*/
public IndexManager setIndexManager(IndexManager indexManager)
{
checkReadiness();
IndexManager oldIdxManager = this.indexManager;
this.indexManager = indexManager;
return oldIdxManager;
}
/**
* Use ONLY imSync for IndexManager get and set.
* @return {@link IndexManager} lock.
*/
public Object getIMSync() {
return imSync;
}
//Asif : The ThreadLocal is used to identify if the thread is an
//index creation thread. This is used to fix Bug # 33336. The value
// is set from IndexManager ,if the thread happens to be an IndexCreation
// Thread.
// Once the thread has created the Index , it will unset the value in the
// ThreadLocal Object
public void setFlagForIndexCreationThread(boolean bool)
{
this.isIndexCreator.set(bool ? Boolean.TRUE : null);
}
//Asif : The boolean is used in AbstractRegionEntry to skip the synchronized
// block
// in case the value of the entry is "REMOVED" token. This prevents dead lock
// caused by the Bug # 33336
boolean isIndexCreationThread()
{
Boolean bool = (Boolean)this.isIndexCreator.get();
return (bool != null) ? bool.booleanValue() : false;
}
/** ********************* AttributesMutator ******************************** */
public Region getRegion()
{
return this;
}
// /**
// * A CacheListener implementation that delegates to an array of listeners.
// */
// public static class ArrayCacheListener implements CacheListener {
// private final CacheListener [] listeners;
// /**
// * Creates a cache listener given the list of listeners it will delegate to.
// */
// public ArrayCacheListener(CacheListener[] listeners) {
// this.listeners = listeners;
// }
// }
public CacheListener setCacheListener(CacheListener aListener)
{
checkReadiness();
CacheListener result = null;
CacheListener[] oldListeners = null;
synchronized (this.clSync) {
oldListeners = this.cacheListeners;
if (oldListeners != null && oldListeners.length > 1) {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_MORE_THAN_ONE_CACHE_LISTENER_EXISTS.toLocalizedString());
}
this.cacheListeners = new CacheListener[] { aListener };
}
// moved the following out of the sync for bug 34512
if (oldListeners != null && oldListeners.length > 0) {
if (oldListeners.length == 1) {
result = oldListeners[0];
}
for (int i = 0; i < oldListeners.length; i++) {
if (aListener != oldListeners[i]) {
closeCacheCallback(oldListeners[i]);
}
}
if (aListener == null) {
cacheListenersChanged(false);
}
}
else { // we have no old listeners
if (aListener != null) {
// we have added a new listener
cacheListenersChanged(true);
}
}
return result;
}
public void addGatewaySenderId(String gatewaySenderId) {
getGatewaySenderIds().add(gatewaySenderId);
setAllGatewaySenderIds();
}
public void removeGatewaySenderId(String gatewaySenderId){
getGatewaySenderIds().remove(gatewaySenderId);
setAllGatewaySenderIds();
}
public void addAsyncEventQueueId(String asyncEventQueueId) {
getAsyncEventQueueIds().add(asyncEventQueueId);
setAllGatewaySenderIds();
}
public void removeAsyncEventQueueId(String asyncEventQueueId) {
getAsyncEventQueueIds().remove(asyncEventQueueId);
setAllGatewaySenderIds();
}
private void setAllGatewaySenderIds() {
if (getGatewaySenderIds().isEmpty() && getAsyncEventQueueIds().isEmpty()) {
allGatewaySenderIds = Collections.emptySet(); // fix for bug 45774
}
Set<String> tmp = new CopyOnWriteArraySet<String>();
tmp.addAll(this.getGatewaySenderIds());
for (String asyncQueueId : this.getAsyncEventQueueIds()) {
tmp.add(AsyncEventQueueImpl
.getSenderIdFromAsyncEventQueueId(asyncQueueId));
}
allGatewaySenderIds = tmp;
}
public void addCacheListener(CacheListener cl)
{
checkReadiness();
if (cl == null) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_ADDCACHELISTENER_PARAMETER_WAS_NULL.toLocalizedString());
}
CacheListener wcl = wrapRegionMembershipListener(cl);
boolean changed = false;
synchronized (this.clSync) {
CacheListener[] oldListeners = this.cacheListeners;
if (oldListeners == null || oldListeners.length == 0) {
this.cacheListeners = new CacheListener[] { wcl };
changed = true;
}
else {
List l = Arrays.asList(oldListeners);
if (!l.contains(cl)) {
this.cacheListeners = (CacheListener[])
ArrayUtils.insert(oldListeners, oldListeners.length, wcl);
}
}
}
if (changed) {
// moved the following out of the sync for bug 34512
cacheListenersChanged(true);
}
}
/**
* We wrap RegionMembershipListeners in a container when adding them at
* runtime, so that we can properly initialize their membership set prior
* to delivering events to them.
* @param cl a cache listener to be added to the region
*/
private CacheListener wrapRegionMembershipListener(CacheListener cl) {
if (cl instanceof RegionMembershipListener) {
return new WrappedRegionMembershipListener((RegionMembershipListener)cl);
}
return cl;
}
/**
* Initialize any wrapped RegionMembershipListeners in the cache listener list
*/
void initPostCreateRegionMembershipListeners(Set initialMembers) {
DistributedMember[] initMbrs = null;
CacheListener[] newcl = null;
synchronized(clSync) {
for (int i = 0; i < cacheListeners.length; i++) {
CacheListener cl = cacheListeners[i];
if (cl instanceof WrappedRegionMembershipListener) {
WrappedRegionMembershipListener wrml = (WrappedRegionMembershipListener)cl;
if (!wrml.isInitialized()) {
if (initMbrs == null) {
initMbrs = (DistributedMember[])initialMembers
.toArray(new DistributedMember[initialMembers.size()]);
}
wrml.initialMembers(this, initMbrs);
if (newcl == null) {
newcl = new CacheListener[cacheListeners.length];
System.arraycopy(cacheListeners, 0, newcl, 0, newcl.length);
}
newcl[i] = wrml.getWrappedListener();
}
}
}
if (newcl != null) {
cacheListeners = newcl;
}
}
}
public void initCacheListeners(CacheListener[] addedListeners)
{
checkReadiness();
CacheListener[] oldListeners = null;
CacheListener[] listenersToAdd = null;
if (addedListeners != null) {
listenersToAdd = new CacheListener[addedListeners.length];
for (int i=0; i<addedListeners.length; i++) {
listenersToAdd[i] = wrapRegionMembershipListener(addedListeners[i]);
}
}
synchronized (this.clSync) {
oldListeners = this.cacheListeners;
if (listenersToAdd == null || listenersToAdd.length == 0) {
this.cacheListeners = EMPTY_LISTENERS;
}
else { // we have some listeners to add
if (Arrays.asList(listenersToAdd).contains(null)) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_INITCACHELISTENERS_PARAMETER_HAD_A_NULL_ELEMENT.toLocalizedString());
}
CacheListener[] newListeners = new CacheListener[listenersToAdd.length];
System.arraycopy(listenersToAdd, 0, newListeners, 0,
newListeners.length);
this.cacheListeners = newListeners;
}
}
// moved the following out of the sync for bug 34512
if (listenersToAdd == null || listenersToAdd.length == 0) {
if (oldListeners != null && oldListeners.length > 0) {
for (int i = 0; i < oldListeners.length; i++) {
closeCacheCallback(oldListeners[i]);
}
cacheListenersChanged(false);
}
}
else { // we had some listeners to add
if (oldListeners != null && oldListeners.length > 0) {
for (int i = 0; i < oldListeners.length; i++) {
closeCacheCallback(oldListeners[i]);
}
}
else {
cacheListenersChanged(true);
}
}
}
public void removeCacheListener(CacheListener cl)
{
checkReadiness();
if (cl == null) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_REMOVECACHELISTENER_PARAMETER_WAS_NULL.toLocalizedString());
}
boolean changed = false;
synchronized (this.clSync) {
CacheListener[] oldListeners = this.cacheListeners;
if (oldListeners != null && oldListeners.length > 0) {
List l = new ArrayList(Arrays.asList(oldListeners));
if (l.remove(cl)) {
if (l.isEmpty()) {
this.cacheListeners = EMPTY_LISTENERS;
}
else {
CacheListener[] newListeners = new CacheListener[l.size()];
l.toArray(newListeners);
this.cacheListeners = newListeners;
}
closeCacheCallback(cl);
if (l.isEmpty()) {
changed = true;
}
}
}
}
if (changed) {
cacheListenersChanged(false);
}
}
// synchronized so not reentrant
public synchronized CacheLoader setCacheLoader(CacheLoader cl) {
checkReadiness();
if (cl != null && isBridgeLoader(cl)) {
if (getPoolName() != null) {
throw new IllegalStateException("A region with a connection pool can not have a BridgeLoader.");
}
}
CacheLoader oldLoader = this.cacheLoader;
assignCacheLoader(cl);
cacheLoaderChanged(oldLoader);
return oldLoader;
}
private synchronized void assignCacheLoader(CacheLoader cl) {
this.cacheLoader = cl;
if (cl instanceof BridgeLoader) {
BridgeLoader bl = (BridgeLoader) cl;
bl.attach(this);
} else if (cl instanceof BridgeClient) {
BridgeClient bc = (BridgeClient)cl;
bc.attach(this);
}
}
// synchronized so not reentrant
public synchronized CacheWriter setCacheWriter(CacheWriter cacheWriter)
{
checkReadiness();
if (cacheWriter != null && isBridgeWriter(cacheWriter)) {
if (getPoolName() != null) {
throw new IllegalStateException("A region with a connection pool can not have a BridgeWriter.");
}
}
CacheWriter oldWriter = this.cacheWriter;
assignCacheWriter(cacheWriter);
cacheWriterChanged(oldWriter);
return oldWriter;
}
private synchronized void assignCacheWriter(CacheWriter cacheWriter)
{
this.cacheWriter = cacheWriter;
if (cacheWriter instanceof BridgeWriter) {
BridgeWriter bw = (BridgeWriter)cacheWriter;
bw.attach(this);
}
}
void checkEntryTimeoutAction(String mode, ExpirationAction ea) {
if ((this.dataPolicy.withReplication()
|| this.dataPolicy.withPartitioning())
&& (ea == ExpirationAction.LOCAL_DESTROY
|| ea == ExpirationAction.LOCAL_INVALIDATE)) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_0_ACTION_IS_INCOMPATIBLE_WITH_THIS_REGIONS_DATA_POLICY.toLocalizedString(mode));
}
}
public ExpirationAttributes setEntryIdleTimeout(
ExpirationAttributes idleTimeout) {
checkReadiness();
if (idleTimeout == null) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_IDLETIMEOUT_MUST_NOT_BE_NULL.toLocalizedString());
}
checkEntryTimeoutAction("idleTimeout", idleTimeout.getAction());
if (!this.statisticsEnabled) {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_CANNOT_SET_IDLE_TIMEOUT_WHEN_STATISTICS_ARE_DISABLED.toLocalizedString());
}
ExpirationAttributes oldAttrs = getEntryIdleTimeout();
this.entryIdleTimeout = idleTimeout.getTimeout();
this.entryIdleTimeoutExpirationAction = idleTimeout.getAction();
setEntryIdleTimeoutAtts();
updateEntryExpiryPossible();
idleTimeoutChanged(oldAttrs);
return oldAttrs;
}
public CustomExpiry setCustomEntryIdleTimeout(CustomExpiry custom) {
checkReadiness();
if (custom != null && !this.statisticsEnabled) {
throw new IllegalStateException(
LocalizedStrings.AbstractRegion_CANNOT_SET_IDLE_TIMEOUT_WHEN_STATISTICS_ARE_DISABLED.toLocalizedString());
}
CustomExpiry old = getCustomEntryIdleTimeout();
this.customEntryIdleTimeout = custom;
updateEntryExpiryPossible();
idleTimeoutChanged(getEntryIdleTimeout());
return old;
}
public ExpirationAttributes setEntryTimeToLive(ExpirationAttributes timeToLive)
{
checkReadiness();
if (timeToLive == null) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_TIMETOLIVE_MUST_NOT_BE_NULL.toLocalizedString());
}
checkEntryTimeoutAction("timeToLive", timeToLive.getAction());
if (!this.statisticsEnabled) {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_CANNOT_SET_TIME_TO_LIVE_WHEN_STATISTICS_ARE_DISABLED.toLocalizedString());
}
ExpirationAttributes oldAttrs = getEntryTimeToLive();
this.entryTimeToLive = timeToLive.getTimeout();
this.entryTimeToLiveExpirationAction = timeToLive.getAction();
setEntryTimeToLiveAtts();
updateEntryExpiryPossible();
timeToLiveChanged(oldAttrs);
return oldAttrs;
}
public CustomExpiry setCustomEntryTimeToLive(CustomExpiry custom) {
checkReadiness();
if (custom != null && !this.statisticsEnabled) {
throw new IllegalStateException(
LocalizedStrings.AbstractRegion_CANNOT_SET_CUSTOM_TIME_TO_LIVE_WHEN_STATISTICS_ARE_DISABLED.toLocalizedString());
}
CustomExpiry old = getCustomEntryTimeToLive();
this.customEntryTimeToLive = custom;
updateEntryExpiryPossible();
timeToLiveChanged(getEntryTimeToLive());
return old;
}
public ExpirationAttributes setRegionIdleTimeout(
ExpirationAttributes idleTimeout)
{
checkReadiness();
if (idleTimeout == null) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_IDLETIMEOUT_MUST_NOT_BE_NULL.toLocalizedString());
}
if (idleTimeout.getAction() == ExpirationAction.LOCAL_INVALIDATE
&& this.dataPolicy.withReplication()) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_0_ACTION_IS_INCOMPATIBLE_WITH_THIS_REGIONS_DATA_POLICY.toLocalizedString("idleTimeout"));
}
if (!this.statisticsEnabled) {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_CANNOT_SET_IDLE_TIMEOUT_WHEN_STATISTICS_ARE_DISABLED.toLocalizedString());
}
ExpirationAttributes oldAttrs = getRegionIdleTimeout();
this.regionIdleTimeout = idleTimeout.getTimeout();
this.regionIdleTimeoutExpirationAction = idleTimeout.getAction();
this.setRegionIdleTimeoutAtts();
regionIdleTimeoutChanged(oldAttrs);
return oldAttrs;
}
public ExpirationAttributes setRegionTimeToLive(
ExpirationAttributes timeToLive)
{
checkReadiness();
if (timeToLive == null) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_TIMETOLIVE_MUST_NOT_BE_NULL.toLocalizedString());
}
if (timeToLive.getAction() == ExpirationAction.LOCAL_INVALIDATE
&& this.dataPolicy.withReplication()) {
throw new IllegalArgumentException(LocalizedStrings.AbstractRegion_0_ACTION_IS_INCOMPATIBLE_WITH_THIS_REGIONS_DATA_POLICY.toLocalizedString("timeToLive"));
}
if (!this.statisticsEnabled) {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_CANNOT_SET_TIME_TO_LIVE_WHEN_STATISTICS_ARE_DISABLED.toLocalizedString());
}
ExpirationAttributes oldAttrs = getRegionTimeToLive();
this.regionTimeToLive = timeToLive.getTimeout();
this.regionTimeToLiveExpirationAction = timeToLive.getAction();
this.setRegionTimeToLiveAtts();
regionTimeToLiveChanged(timeToLive);
return oldAttrs;
}
public void becomeLockGrantor()
{
checkReadiness();
checkForLimitedOrNoAccess();
if (this.scope != Scope.GLOBAL) {
throw new IllegalStateException(LocalizedStrings.AbstractRegion_CANNOT_SET_LOCK_GRANTOR_WHEN_SCOPE_IS_NOT_GLOBAL.toLocalizedString());
}
if (isCurrentlyLockGrantor())
return; // nothing to do... already lock grantor
this.isLockGrantor = true;
}
/** ********************* CacheStatistics ******************************** */
public CacheStatistics getStatistics()
{
// prefer region destroyed exception over statistics disabled exception
checkReadiness();
if (!this.statisticsEnabled) {
throw new StatisticsDisabledException(LocalizedStrings.AbstractRegion_STATISTICS_DISABLED_FOR_REGION_0.toLocalizedString(getFullPath()));
}
return this;
}
/**
* The logical lastModifiedTime of a region is the most recent
* lastModifiedTime of the region and all its subregions. This implementation
* trades performance of stat retrieval for performance of get/put, which is
* more critical.
*/
public synchronized long getLastModifiedTime()
{
checkReadiness();
long mostRecent = basicGetLastModifiedTime();
// don't need to wait on getInitialImage for this operation in subregions
int oldLevel = LocalRegion
.setThreadInitLevelRequirement(LocalRegion.ANY_INIT);
try {
Iterator subIt = subregions(false).iterator();
while (subIt.hasNext()) {
try {
LocalRegion r = (LocalRegion)subIt.next();
if (r.isInitialized()) {
mostRecent = Math.max(mostRecent, r.getLastModifiedTime());
}
}
catch (RegionDestroyedException e) {
// pass over destroyed region
}
}
}
finally {
LocalRegion.setThreadInitLevelRequirement(oldLevel);
}
return mostRecent;
}
protected long basicGetLastModifiedTime()
{
return this.lastModifiedTime.get();
}
protected long basicGetLastAccessedTime()
{
return this.lastAccessedTime.get();
}
protected void basicSetLastModifiedTime(long t)
{
this.lastModifiedTime.set(t);
}
protected void basicSetLastAccessedTime(long t)
{
this.lastAccessedTime.set(t);
}
/**
* The logical lastAccessedTime of a region is the most recent
* lastAccessedTime of the region and all its subregions. This implementation
* trades performance of stat retrieval for performance of get/put, which is
* more critical.
*/
public synchronized long getLastAccessedTime()
{
checkReadiness();
long mostRecent = basicGetLastAccessedTime();
// don't need to wait on getInitialImage for this operation in subregions
int oldLevel = LocalRegion
.setThreadInitLevelRequirement(LocalRegion.ANY_INIT);
try {
Iterator subIt = subregions(false).iterator();
while (subIt.hasNext()) {
try {
LocalRegion r = (LocalRegion)subIt.next();
if (r.isInitialized()) {
mostRecent = Math.max(mostRecent, r.getLastAccessedTime());
}
}
catch (RegionDestroyedException e) {
// pass over destroyed region
}
}
}
finally {
LocalRegion.setThreadInitLevelRequirement(oldLevel);
}
return mostRecent;
}
/**
* Update the lastAccessedTime and lastModifiedTimes to reflects those in the
* subregions
*/
protected synchronized void updateStats()
{
long mostRecentAccessed = basicGetLastAccessedTime();
long mostRecentModified = basicGetLastModifiedTime();
// don't need to wait on getInitialImage for this operation in subregions
int oldLevel = LocalRegion
.setThreadInitLevelRequirement(LocalRegion.ANY_INIT);
try {
Iterator subIt = subregions(false).iterator();
while (subIt.hasNext()) {
try {
LocalRegion r = (LocalRegion)subIt.next();
if (r.isInitialized()) {
mostRecentAccessed = Math.max(mostRecentAccessed, r
.getLastAccessedTime());
mostRecentModified = Math.max(mostRecentModified, r
.getLastModifiedTime());
}
}
catch (RegionDestroyedException e) {
// pass over destroyed region
}
}
basicSetLastAccessedTime(Math.max(mostRecentAccessed, mostRecentModified));
basicSetLastModifiedTime(mostRecentModified);
}
finally {
LocalRegion.setThreadInitLevelRequirement(oldLevel);
}
}
protected void setLastModifiedTime(long time)
{
//checkReadiness();
if (time > this.lastModifiedTime.get()) {
this.lastModifiedTime.set(time);
}
if (time > this.lastAccessedTime.get()) {
this.lastAccessedTime.set(time);
}
}
protected void setLastAccessedTime(long time, boolean hit)
{
this.lastAccessedTime.set(time);
if (hit) {
if (trackHits) {
this.hitCount.getAndIncrement();
}
} else {
if (trackMisses) {
this.missCount.getAndIncrement();
}
}
}
public final float getHitRatio()
{
//checkReadiness();
long hits = getHitCount();
long total = hits + getMissCount();
return total == 0L ? 0.0f : ((float)hits / total);
}
public long getHitCount()
{
//checkReadiness();
return this.hitCount.get();
}
public long getMissCount()
{
//checkReadiness();
return this.missCount.get();
}
public void resetCounts()
{
//checkReadiness();
if (trackMisses) {
this.missCount.set(0);
}
if (trackHits) {
this.hitCount.set(0);
}
}
/** ****************** Protected Methods *********************************** */
protected void closeCacheCallback(CacheCallback cb)
{
if (cb != null) {
if (cb instanceof BridgeWriter) {
BridgeWriter bw = (BridgeWriter)cb;
bw.detach(this);
}
else if (cb instanceof BridgeLoader) {
BridgeLoader bl = (BridgeLoader)cb;
bl.detach(this);
}
try {
cb.close();
}
catch (RuntimeException ex) {
logger.warn(LocalizedMessage.create(LocalizedStrings.AbstractRegion_CACHECALLBACK_CLOSE_EXCEPTION), ex);
}
}
}
protected void cacheLoaderChanged(CacheLoader oldLoader)
{
if (this.cacheLoader != oldLoader) {
closeCacheCallback(oldLoader);
}
}
/**
* Called if when we go from no listeners to at least one or from at least one
* to no listeners
*
* @param nowHasListener
* true if we now have at least one listener; false if we now have no
* listeners
*/
protected void cacheListenersChanged(boolean nowHasListener)
{
// nothing needed by default
}
/**
* @since 5.7
*/
public static boolean isBridgeLoader(CacheLoader cl) {
return cl instanceof BridgeLoader || cl instanceof BridgeClient;
}
/**
* @since 5.7
*/
public static boolean isBridgeWriter(CacheWriter cw) {
return cw instanceof BridgeWriter;
}
protected void cacheWriterChanged(CacheWriter oldWriter)
{
if (this.cacheWriter != oldWriter) {
closeCacheCallback(oldWriter);
}
}
protected void timeToLiveChanged(ExpirationAttributes oldTimeToLive)
{
}
protected void idleTimeoutChanged(ExpirationAttributes oldIdleTimeout)
{
}
protected void regionTimeToLiveChanged(ExpirationAttributes oldTimeToLive)
{
}
protected void regionIdleTimeoutChanged(ExpirationAttributes oldIdleTimeout)
{
};
/** Throws CacheClosedException or RegionDestroyedException */
abstract void checkReadiness();
/**
* Returns true if this region has no storage
*
* @since 5.0
*/
protected final boolean isProxy()
{
return getDataPolicy().isEmpty();
}
/**
* Returns true if this region has no storage and is only interested in what
* it contains (which is nothing)
*
* @since 5.0
*/
protected final boolean isCacheContentProxy()
{
// method added to fix bug 35195
return isProxy()
&& getSubscriptionAttributes().getInterestPolicy().isCacheContent();
}
/**
* Returns true if region subscribes to all events or is a replicate.
*
* @since 5.0
*/
final boolean isAllEvents()
{
return getDataPolicy().withReplication()
|| getSubscriptionAttributes().getInterestPolicy().isAll();
}
private boolean entryExpiryPossible = false;
protected void updateEntryExpiryPossible()
{
this.entryExpiryPossible = !isProxy()
&& (this.entryTimeToLive > 0
|| this.entryIdleTimeout > 0
|| this.customEntryIdleTimeout != null
|| this.customEntryTimeToLive != null
);
}
/**
* Returns true if this region could expire an entry
*/
protected boolean isEntryExpiryPossible()
{
return this.entryExpiryPossible;
}
public ExpirationAction getEntryExpirationAction() {
if(this.entryIdleTimeoutExpirationAction != null) {
return entryIdleTimeoutExpirationAction;
}
if(this.entryTimeToLiveExpirationAction != null) {
return entryTimeToLiveExpirationAction;
}
return null;
}
/**
* Returns true if this region can evict entries.
*/
public boolean isEntryEvictionPossible() {
return this.evictionController != null;
}
/** ****************** Private Methods ************************************* */
private void setAttributes(RegionAttributes attrs,String regionName, InternalRegionArguments internalRegionArgs)
{
this.dataPolicy = attrs.getDataPolicy(); // do this one first
this.scope = attrs.getScope();
this.offHeap = attrs.getOffHeap();
// fix bug #52033 by invoking setOffHeap now (localMaxMemory may now be the temporary placeholder for off-heap until DistributedSystem is created
// found non-null PartitionAttributes and offHeap is true so let's setOffHeap on PA now
PartitionAttributes<?, ?> pa = attrs.getPartitionAttributes();
if (this.offHeap && pa != null) {
PartitionAttributesImpl impl = (PartitionAttributesImpl)pa;
impl.setOffHeap(this.offHeap);
}
this.evictionAttributes = new EvictionAttributesImpl((EvictionAttributesImpl)attrs
.getEvictionAttributes());
if (attrs.getPartitionAttributes() != null
&& this.evictionAttributes != null
&& this.evictionAttributes.getAlgorithm().isLRUMemory()
&& attrs.getPartitionAttributes().getLocalMaxMemory() != 0
&& this.evictionAttributes.getMaximum() != attrs
.getPartitionAttributes().getLocalMaxMemory()) {
logger.warn(LocalizedMessage.create(LocalizedStrings.Mem_LRU_Eviction_Attribute_Reset,
new Object[] { regionName,this.evictionAttributes.getMaximum(),
attrs.getPartitionAttributes().getLocalMaxMemory() }));
this.evictionAttributes.setMaximum(attrs.getPartitionAttributes()
.getLocalMaxMemory());
}
//final boolean isNotPartitionedRegion = !(attrs.getPartitionAttributes() != null || attrs
// .getDataPolicy().withPartitioning());
//if (isNotPartitionedRegion && this.evictionAttributes != null
if (this.evictionAttributes != null
&& !this.evictionAttributes.getAlgorithm().isNone()) {
this.setEvictionController(this.evictionAttributes
.createEvictionController(this, attrs.getOffHeap()));
}
this.customEvictionAttributes = attrs.getCustomEvictionAttributes();
storeCacheListenersField(attrs.getCacheListeners());
assignCacheLoader(attrs.getCacheLoader());
assignCacheWriter(attrs.getCacheWriter());
this.regionTimeToLive = attrs.getRegionTimeToLive().getTimeout();
this.regionTimeToLiveExpirationAction = attrs.getRegionTimeToLive()
.getAction();
setRegionTimeToLiveAtts();
this.regionIdleTimeout = attrs.getRegionIdleTimeout().getTimeout();
this.regionIdleTimeoutExpirationAction = attrs.getRegionIdleTimeout()
.getAction();
setRegionIdleTimeoutAtts();
this.entryTimeToLive = attrs.getEntryTimeToLive().getTimeout();
this.entryTimeToLiveExpirationAction = attrs.getEntryTimeToLive()
.getAction();
setEntryTimeToLiveAtts();
this.customEntryTimeToLive = attrs.getCustomEntryTimeToLive();
this.entryIdleTimeout = attrs.getEntryIdleTimeout().getTimeout();
this.entryIdleTimeoutExpirationAction = attrs.getEntryIdleTimeout()
.getAction();
setEntryIdleTimeoutAtts();
this.customEntryIdleTimeout = attrs.getCustomEntryIdleTimeout();
updateEntryExpiryPossible();
this.statisticsEnabled = attrs.getStatisticsEnabled();
this.ignoreJTA = attrs.getIgnoreJTA();
this.isLockGrantor = attrs.isLockGrantor();
this.keyConstraint = attrs.getKeyConstraint();
this.valueConstraint = attrs.getValueConstraint();
this.initialCapacity = attrs.getInitialCapacity();
this.loadFactor = attrs.getLoadFactor();
this.concurrencyLevel = attrs.getConcurrencyLevel();
this.concurrencyChecksEnabled = attrs.getConcurrencyChecksEnabled() && supportsConcurrencyChecks();
this.earlyAck = attrs.getEarlyAck();
this.gatewaySenderIds = attrs.getGatewaySenderIds();
this.asyncEventQueueIds = attrs.getAsyncEventQueueIds();
setAllGatewaySenderIds();
this.enableSubscriptionConflation = attrs.getEnableSubscriptionConflation();
this.publisher = attrs.getPublisher();
this.enableAsyncConflation = attrs.getEnableAsyncConflation();
this.indexMaintenanceSynchronous = attrs.getIndexMaintenanceSynchronous();
this.mcastEnabled = attrs.getMulticastEnabled();
this.partitionAttributes = attrs.getPartitionAttributes();
this.membershipAttributes = attrs.getMembershipAttributes();
this.subscriptionAttributes = attrs.getSubscriptionAttributes();
this.cloningEnable = attrs.getCloningEnabled();
this.poolName = attrs.getPoolName();
if (this.poolName != null) {
PoolImpl cp = getPool();
if (cp == null) {
throw new IllegalStateException("The connection pool \""
+ this.poolName
+ "\" has not been created");
}
cp.attach();
if (cp.getMultiuserAuthentication() && !this.dataPolicy.isEmpty()) {
throw new IllegalStateException("Region must have empty data-policy "
+ "when multiuser-authentication is true.");
}
}
this.hdfsStoreName = attrs.getHDFSStoreName();
this.hdfsWriteOnly = attrs.getHDFSWriteOnly();
this.diskStoreName = attrs.getDiskStoreName();
this.isDiskSynchronous = attrs.isDiskSynchronous();
if (this.diskStoreName == null) {
this.diskWriteAttributes = attrs.getDiskWriteAttributes();
this.isDiskSynchronous = this.diskWriteAttributes.isSynchronous(); // fixes bug 41313
this.diskDirs = attrs.getDiskDirs();
this.diskSizes = attrs.getDiskDirSizes();
}
this.compressor = attrs.getCompressor();
// enable concurrency checks for persistent regions
if(!attrs.getConcurrencyChecksEnabled()
&& attrs.getDataPolicy().withPersistence()
&& supportsConcurrencyChecks()) {
throw new IllegalStateException(LocalizedStrings.AttributesFactory_CONCURRENCY_CHECKS_MUST_BE_ENABLED.toLocalizedString());
}
}
/** is this a region that supports versioning? */
public abstract boolean supportsConcurrencyChecks();
/**
* Returns the pool this region is using or null if it does not have one
* or the pool does not exist.
* @since 5.7
*/
private PoolImpl getPool() {
PoolImpl result = null;
if (getPoolName() != null) {
result = (PoolImpl)PoolManager.find(getPoolName());
}
return result;
}
public boolean existsValue(String predicate) throws FunctionDomainException,
TypeMismatchException, NameResolutionException,
QueryInvocationTargetException
{
return !query(predicate).isEmpty();
}
public Object selectValue(String predicate) throws FunctionDomainException,
TypeMismatchException, NameResolutionException,
QueryInvocationTargetException
{
SelectResults result = query(predicate);
if (result.isEmpty()) {
return null;
}
if (result.size() > 1)
throw new FunctionDomainException(LocalizedStrings.AbstractRegion_SELECTVALUE_EXPECTS_RESULTS_OF_SIZE_1_BUT_FOUND_RESULTS_OF_SIZE_0.toLocalizedString(Integer.valueOf(result.size())));
return result.iterator().next();
}
public Set entrySet(boolean recursive)
{
return entries(recursive);
}
public EvictionAttributes getEvictionAttributes()
{
return this.evictionAttributes;
}
/**
* {@inheritDoc}
*/
@Override
public CustomEvictionAttributes getCustomEvictionAttributes() {
return this.customEvictionAttributes;
}
public EvictionAttributesMutator getEvictionAttributesMutator()
{
return this.evictionAttributes;
}
/**
* {@inheritDoc}
*/
@Override
public CustomEvictionAttributes setCustomEvictionAttributes(long newStart,
long newInterval) {
checkReadiness();
if (this.customEvictionAttributes == null) {
throw new IllegalArgumentException(
LocalizedStrings.AbstractRegion_NO_CUSTOM_EVICTION_SET
.toLocalizedString(getFullPath()));
}
if (newStart == 0) {
newStart = this.customEvictionAttributes.getEvictorStartTime();
}
this.customEvictionAttributes = new CustomEvictionAttributesImpl(
this.customEvictionAttributes.getCriteria(), newStart, newInterval,
newStart == 0 && newInterval == 0);
// if (this.evService == null) {
// initilializeCustomEvictor();
// } else {// we are changing the earlier one which is already started.
// EvictorService service = getEvictorTask();
// service.changeEvictionInterval(newInterval);
// if (newStart != 0)
// service.changeStartTime(newStart);
// }
return this.customEvictionAttributes;
}
public void setEvictionController(LRUAlgorithm evictionController)
{
this.evictionController = evictionController;
}
public LRUAlgorithm getEvictionController()
{
return evictionController;
}
/**
* Throws RegionAccessException if required roles are missing and the
* LossAction is NO_ACCESS
*
* @throws RegionAccessException
* if required roles are missing and the LossAction is NO_ACCESS
*/
protected void checkForNoAccess()
{
}
/**
* Throws RegionAccessException is required roles are missing and the
* LossAction is either NO_ACCESS or LIMITED_ACCESS.
*
* @throws RegionAccessException
* if required roles are missing and the LossAction is either
* NO_ACCESS or LIMITED_ACCESS
*/
protected void checkForLimitedOrNoAccess()
{
}
/**
* Makes sure that the data was distributed to every required role. If it was
* not it either queues the data for later delivery or it throws an exception.
*
* @param data
* the data that needs to be reliably distributed
* @param successfulRecipients
* the successful recipients
* @throws RoleException
* if a required role was not sent the message and the LossAction is
* either NO_ACCESS or LIMITED_ACCESS.
* @since 5.0
*
*/
protected void handleReliableDistribution(ReliableDistributionData data,
Set successfulRecipients)
{
// do nothing by default
}
/** Returns true if region requires a reliability check. */
public boolean requiresReliabilityCheck()
{
return false;
}
/**
* Returns the serial number which identifies the static order in which this
* region was created in relation to other regions or other instances of
* this region during the life of this JVM.
*/
public int getSerialNumber() {
return this.serialNumber;
}
public final GemFireCacheImpl getCache() {
return this.cache;
}
protected final long cacheTimeMillis() {
return this.cache.getDistributedSystem().getClock().cacheTimeMillis();
}
public final RegionService getRegionService() {
return this.cache;
}
public final DM getDistributionManager() {
return getSystem().getDistributionManager();
}
public final InternalDistributedSystem getSystem() {
return getCache().getDistributedSystem();
}
// DataSerializableFixedID support
public final int getDSFID() {
return REGION;
}
// DataSerializableFixedID support
public final void toData(DataOutput out) throws IOException {
DataSerializer.writeRegion(this, out);
}
// DataSerializableFixedID support
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
// should never be called since the special DataSerializer.readRegion is used.
throw new UnsupportedOperationException();
}
public boolean forceCompaction() {
throw new UnsupportedOperationException();
}
public boolean getCloningEnabled() {
return this.cloningEnable;
}
public void setCloningEnabled(boolean cloningEnable){
this.cloningEnable = cloningEnable;
}
protected static Object handleNotAvailable(Object v) {
if (v == Token.NOT_AVAILABLE) {
v = null;
}
return v;
}
public GemFireCacheImpl getGemFireCache() {
return this.cache;
}
public RegionSnapshotService<?, ?> getSnapshotService() {
return new RegionSnapshotServiceImpl(this);
}
public Compressor getCompressor() {
return this.compressor;
}
/**
* @since 8.1
* property used to find region operations that reach out to HDFS multiple times
*/
@Override
public ExtensionPoint<Region<?, ?>> getExtensionPoint() {
return extensionPoint;
}
public boolean getOffHeap() {
return this.offHeap;
}
/**
* property used to find region operations that reach out to HDFS multiple times
*/
private static final boolean DEBUG_HDFS_CALLS = Boolean.getBoolean("DebugHDFSCalls");
/**
* throws exception if region operation goes out to HDFS multiple times
*/
private static final boolean THROW_ON_MULTIPLE_HDFS_CALLS = Boolean.getBoolean("throwOnMultipleHDFSCalls");
private ThreadLocal<CallLog> logHDFSCalls = DEBUG_HDFS_CALLS ? new ThreadLocal<CallLog>() : null;
public void hdfsCalled(Object key) {
if (!DEBUG_HDFS_CALLS) {
return;
}
logHDFSCalls.get().addStack(new Throwable());
logHDFSCalls.get().setKey(key);
}
public final void operationStart() {
if (!DEBUG_HDFS_CALLS) {
return;
}
if (logHDFSCalls.get() == null) {
logHDFSCalls.set(new CallLog());
//InternalDistributedSystem.getLoggerI18n().warning(LocalizedStrings.DEBUG, "SWAP:operationStart", new Throwable());
} else {
logHDFSCalls.get().incNestedCall();
//InternalDistributedSystem.getLoggerI18n().warning(LocalizedStrings.DEBUG, "SWAP:incNestedCall:", new Throwable());
}
}
public final void operationCompleted() {
if (!DEBUG_HDFS_CALLS) {
return;
}
//InternalDistributedSystem.getLoggerI18n().warning(LocalizedStrings.DEBUG, "SWAP:operationCompleted", new Throwable());
if (logHDFSCalls.get() != null && logHDFSCalls.get().decNestedCall() < 0) {
logHDFSCalls.get().assertCalls();
logHDFSCalls.set(null);
}
}
public static class CallLog {
private List<Throwable> stackTraces = new ArrayList<Throwable>();
private Object key;
private int nestedCall = 0;
public void incNestedCall() {
nestedCall++;
}
public int decNestedCall() {
return --nestedCall;
}
public void addStack(Throwable stack) {
this.stackTraces.add(stack);
}
public void setKey(Object key) {
this.key = key;
}
public void assertCalls() {
if (stackTraces.size() > 1) {
Throwable firstTrace = new Throwable();
Throwable lastTrace = firstTrace;
for (Throwable t : this.stackTraces) {
lastTrace.initCause(t);
lastTrace = t;
}
if (THROW_ON_MULTIPLE_HDFS_CALLS) {
throw new RuntimeException("SWAP:For key:"+key+" HDFS get called more than once: ", firstTrace);
} else {
InternalDistributedSystem.getLoggerI18n().warning(LocalizedStrings.DEBUG, "SWAP:For key:"+key+" HDFS get called more than once: ", firstTrace);
}
}
}
}
public EvictionCriteria getEvictionCriteria() {
EvictionCriteria criteria = null;
if (this.customEvictionAttributes != null
&& !this.customEvictionAttributes.isEvictIncoming()) {
criteria = this.customEvictionAttributes.getCriteria();
}
return criteria;
}
}