All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.internal.cache.AbstractRegion Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, 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. See accompanying
 * LICENSE file.
 */

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 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.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.DataSerializableFixedID;
import com.gemstone.gemfire.internal.cache.lru.LRUAlgorithm;
import com.gemstone.gemfire.internal.cache.snapshot.RegionSnapshotServiceImpl;
import com.gemstone.gemfire.internal.concurrent.AL;
import com.gemstone.gemfire.internal.concurrent.CFactory;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
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
{
  /**
   * 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;

  protected final boolean isPdxTypesRegion;

  protected boolean enableGateway;
  
  protected String gatewayHubId;

  protected Set gatewaySenderIds;
  
  protected Set asyncEventQueueIds;

  protected Set allGatewaySenderIds;

  protected Set allGatewayHubIds;

  protected boolean enableSubscriptionConflation;

  protected boolean publisher;

  protected boolean enableAsyncConflation;
  
  protected EvictorService evService;

  /**
   * True if this region uses off-heap memory; otherwise false (default)
   * 
   * If this is ever made mutable, then also need to change in GemFireXD layer
   * including in GemFireContainer and RowFormatter.
   * 
   * @since 7.5
   */
  protected boolean enableOffHeapMemory;

  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 AL lastAccessedTime;

  private final AL lastModifiedTime;

  private static final boolean trackHits = !Boolean.getBoolean("gemfire.ignoreHits");
  private static final boolean trackMisses = !Boolean.getBoolean("gemfire.ignoreMisses");

  private final AL hitCount = CFactory.createAL();

  private final AL missCount = CFactory.createAL();
  
  protected String poolName;
  
  protected String hdfsStoreName;
  
  protected boolean hdfsWriteOnly;
  
  protected Compressor compressor;
  
  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 = CFactory.createAL(cacheTimeMillis());
    this.lastModifiedTime = CFactory.createAL(lastAccessedTime.get());
    setAttributes(attrs, regionName, internalRegionArgs);
  }

  /** ******************** 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
  {
    try {
      operationStart();
    create(key, value, null);
    } finally {
      operationCompleted();
    }
  }

  public final Object destroy(Object key) throws TimeoutException,
      EntryNotFoundException, CacheWriterException
  {
    try {
      operationStart();
    return destroy(key, null);
    } finally {
      operationCompleted();
    }
  }

  public final Object get(Object name) throws CacheLoaderException,
      TimeoutException
  {
    try {
      operationStart();
    return get(name, null, true, null);
    } finally {
      operationCompleted();
    }
  }

  public final Object put(Object name, Object value) throws TimeoutException,
      CacheWriterException
  {
    try {
      operationStart();
    return put(name, value, null);
    } finally {
      operationCompleted();
    }
  }

  public Object get(Object name, Object aCallbackArgument)
      throws CacheLoaderException, TimeoutException
  {
    try {
      operationStart();
    return get(name, aCallbackArgument, true, null);
    } finally {
      operationCompleted();
    }
  }

  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 {
    try {
      operationStart();
    localDestroy(key, null);
    } finally {
      operationCompleted();
    }
  }

  public final void destroyRegion() throws CacheWriterException,
      TimeoutException
  {
    destroyRegion(null);
  }

  public final void invalidate(Object key) throws TimeoutException,
      EntryNotFoundException
  {
    try {
      operationStart();
    invalidate(key, null);
    } finally {
      operationCompleted();
    }
  }

  public final void localInvalidate(Object key) throws EntryNotFoundException
  {
    try {
      operationStart();
    localInvalidate(key, null);
    } finally {
      operationCompleted();
    }
  }

  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);
  }

  public Map getAll(Collection keys) {
    if (keys == null) {
      throw new NullPointerException("The collection of keys for getAll cannot be null");
    }
    checkReadiness();
    checkForLimitedOrNoAccess();
    return keys.isEmpty()? new HashMap(): basicGetAll(keys);
  }

  abstract Map basicGetAll(Collection keys);

  public abstract RegionEntry basicGetEntry(Object key);

  protected StringBuilder getStringBuilder() {
    final StringBuilder buf = new StringBuilder();
    buf.append(getClass().getName());
    buf.append("[path='")
       .append(getFullPath())
       .append("';scope=")
       .append(getScope())
       .append("';dataPolicy=")
       .append(this.dataPolicy);
    if (this.enableGateway){ 
       buf.append("; gatewayEnabled");
    }
    if (this.concurrencyChecksEnabled) {
      buf.append("; concurrencyChecksEnabled");
    }
    return buf;
  }

  @Override
  public final String toString() {
    return getStringBuilder().append(']').toString();
  }

  /** ********************* RegionAttributes ********************************* */

  public final CacheLoader getCacheLoader() {
    //checkReadiness();
    return this.cacheLoader;
  }

  public final 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() {
    final CacheLoader result = this.cacheLoader;
    if (result == null) {
      return null;
    }
    if (isBridgeLoader(result)) {
      return 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() {
    final CacheWriter result = this.cacheWriter;
    if (result == null) {
      return null;
    }
    if (isBridgeWriter(result)) {
      return null;
    }
    return result;
  }

  public final Class getKeyConstraint() {
    //checkReadiness();
    return this.keyConstraint;
  }

  public final 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 final ExpirationAttributes getEntryTimeToLive() {
    return this.entryTimeToLiveAtts;
  }
  
  public final 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 final CustomExpiry getCustomEntryIdleTimeout() {
    return this.customEntryIdleTimeout;
  }

  public final MirrorType getMirrorType() {
    if (this.dataPolicy == DataPolicy.NORMAL
        || this.dataPolicy == DataPolicy.PRELOADED
        || this.dataPolicy == DataPolicy.EMPTY
        || 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 final String getPoolName() {
    //checkReadiness();
    return this.poolName;
  }

  public final DataPolicy getDataPolicy() {
    //checkReadiness();
    return this.dataPolicy;
  }

  public final Scope getScope() {
    //checkReadiness();
    return this.scope;
  }

  public final 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 final Set getGatewaySenderIds() {
    return this.gatewaySenderIds;
  }

  public final Set getAsyncEventQueueIds() {
    return this.asyncEventQueueIds;
  }

  public final Set getAllGatewaySenderIds() {
    return Collections.unmodifiableSet(this.allGatewaySenderIds);
  }

  public final boolean checkNotifyGatewaySender() {
    return (this.cache.getAllGatewaySenders().size() > 0
        && this.allGatewaySenderIds.size() > 0);
  }
  
  public boolean hasDBSynchOrAsyncListener() {
    return GemFireCacheImpl.gfxdSystem()
        && getCache().hasNonWanDispatcher(getAllGatewaySenderIds());
  }

  public final Set getActiveSerialGatewaySenderIds() {
    final Set allGatewaySenders;
    HashSet activeGatewaySenderIds = null;
    final int sz = this.gatewaySenderIds.size();
    if (sz > 0
        && (allGatewaySenders = this.cache.getGatewaySenders()).size() > 0) {
      for (GatewaySender sender : allGatewaySenders) {
        if (sender.isRunning() && !sender.isParallel()
            && this.gatewaySenderIds.contains(sender.getId())) {
          if (activeGatewaySenderIds == null) {
            activeGatewaySenderIds = new HashSet();
          }
          activeGatewaySenderIds.add(sender.getId());
        }
      }
    }
    return activeGatewaySenderIds;
  }

  public final Set getActiveSerialAsyncQueueIds() {
    final Set allAsyncQueues;
    HashSet activeAsyncQueueIds = null;
    final int sz = this.asyncEventQueueIds.size();
    if (sz > 0
        && (allAsyncQueues = this.cache.getAsyncEventQueues()).size() > 0) {
      for (AsyncEventQueue asyncQueue : allAsyncQueues) {
        if (asyncQueue.isRunning() && !asyncQueue.isParallel()
            && this.asyncEventQueueIds.contains(asyncQueue.getId())) {
          if (activeAsyncQueueIds == null) {
            activeAsyncQueueIds = new HashSet();
          }
          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 getRemoteDsIds(Set allGatewaySenderIds)
      throws IllegalStateException {
    final Set allGatewaySenders;
    final int sz = allGatewaySenderIds.size();
    if ((sz > 0 || isPdxTypesRegion)
        && (allGatewaySenders = this.cache.getAllGatewaySenders()).size() > 0) {
      List allRemoteDSIds = new ArrayList(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 senderIds = new HashSet();
//    this.allGatewaySenderIds = senderIds;
//    if (getGatewaySenderIds().isEmpty() && getAsyncEventQueueIds().isEmpty()) {
//      return Collections.emptySet(); // fix for bug 45774
//    }
//    Set tmp = new CopyOnWriteArraySet();
//    tmp.addAll(this.getGatewaySenderIds());
//    for(String asyncQueueId : this.getAsyncEventQueueIds()){
//      tmp.add(AsyncEventQueueImpl.getSenderIdFromAsyncEventQueueId(asyncQueueId));
//    }
//    return tmp;
//  }

  public final boolean isGatewaySenderEnabled() {
    return this.allGatewaySenderIds.size() > 0;
  }

  private static final CacheListener[] EMPTY_LISTENERS = new CacheListener[0];

  public final 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 final int getInitialCapacity() {
    //checkReadiness();
    return this.initialCapacity;
  }

  public final 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 final boolean getMulticastEnabled() {
    //checkReadiness();
    return this.mcastEnabled;
  }

  public final boolean getStatisticsEnabled() {
    //checkReadiness();
    return this.statisticsEnabled;
  }

  public final boolean getIgnoreJTA() {
    //checkRediness();
    return this.ignoreJTA;
  }

  public final int getConcurrencyLevel() {
    //checkReadiness();
    return this.concurrencyLevel;
  }
  
  public boolean getConcurrencyChecksEnabled() {
    return this.concurrencyChecksEnabled;
  }

  public final boolean getPersistBackup() {
    //checkReadiness();
    return getDataPolicy().withPersistence();
  }

  public final boolean getEarlyAck() {
    //checkReadiness();
    return this.earlyAck;
  }

  public final boolean getEnableWAN() {
    // deprecated in 5.0
    //checkReadiness();
    return this.enableGateway;
  }

  public final boolean getEnableGateway() {
    //checkReadiness();
    return this.enableGateway;
  }

  /*
   * @deprecated as of prPersistSprint1
   */
  @Deprecated
  public final boolean getPublisher() {
    return this.publisher;
  }

  public final String getGatewayHubId() {
    //checkReadiness();
    return this.gatewayHubId;
  }
  
  public Set getAllGatewayHubIds() {
    return this.allGatewayHubIds;
  }

  public final boolean getEnableConflation() { // deprecated in 5.0
    return getEnableSubscriptionConflation();
  }

  public final boolean getEnableBridgeConflation() {// deprecated in 5.7
    return getEnableSubscriptionConflation();
  }

  public final boolean getEnableSubscriptionConflation() {
    return this.enableSubscriptionConflation;
  }

  public final boolean getEnableAsyncConflation() {
    return this.enableAsyncConflation;
  }

  /*
   * @deprecated as of prPersistSprint2
   */
  @Deprecated
  public final DiskWriteAttributes getDiskWriteAttributes() {
    //checkReadiness();
    return this.diskWriteAttributes;
  }

  public abstract File[] getDiskDirs();

  public final String getDiskStoreName() {
    return this.diskStoreName;
  }

  public final boolean isDiskSynchronous() {
    return this.isDiskSynchronous;
  }

  public final boolean getIndexMaintenanceSynchronous() {
    return this.indexMaintenanceSynchronous;
  }

  public final PartitionAttributes getPartitionAttributes() {
    return this.partitionAttributes;
  }

  public final MembershipAttributes getMembershipAttributes() {
    return this.membershipAttributes;
  }

  public final 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 final 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 final 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
  final 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 tmp = new CopyOnWriteArraySet();
    tmp.addAll(this.getGatewaySenderIds());
    for (String asyncQueueId : this.getAsyncEventQueueIds()) {
      tmp.add(AsyncEventQueueImpl
          .getSenderIdFromAsyncEventQueueId(asyncQueueId));
    }
    allGatewaySenderIds = tmp;
    gatewaySendersChanged();
  }

  protected void gatewaySendersChanged() {
  }

  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 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();
    updateRegionExpiryPossible();
    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();
    updateRegionExpiryPossible();
    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) {
        getCache().getLoggerI18n().warning(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();

  private boolean regionExpiryPossible = false;

  protected void updateRegionExpiryPossible()
  {
    this.regionExpiryPossible = this.regionTimeToLive > 0
        || this.regionIdleTimeout > 0;
  }

  /**
   * Returns true if this region could have some expiration actions.
   */
  protected boolean isRegionExpiryPossible()
  {
    return this.regionExpiryPossible;
  }

  /**
   * Returns true if this region has no storage
   *
   * @since 5.0
   */
  protected final boolean isProxy() {
    return getDataPolicy() == DataPolicy.EMPTY;
  }

  /**
   * 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
            );
  }

  protected void setAllGatewayHubIds(String gatewayHubId) {
    this.gatewayHubId = gatewayHubId;
    String[] allGatewayHubIdsArr = gatewayHubId.split(",");
    if (allGatewayHubIdsArr.length > 1) {
      this.allGatewayHubIds = new HashSet();
      for (String hubId : allGatewayHubIdsArr) {
        this.allGatewayHubIds.add(hubId);
      }
    }
  }
  
  /**
   * Returns true if this entry could have some expiration actions.
   */
  public 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.enableOffHeapMemory = attrs.getEnableOffHeapMemory();
    this.partitionAttributes = attrs.getPartitionAttributes();
    
    this.evictionAttributes = new EvictionAttributesImpl((EvictionAttributesImpl)attrs
        .getEvictionAttributes());
    if (this.partitionAttributes != null) {
      ((PartitionAttributesImpl) this.partitionAttributes).computeLocalMaxMemory();
      
      if (this.evictionAttributes != null
          && this.evictionAttributes.getAlgorithm().isLRUMemory()
          && this.partitionAttributes.getLocalMaxMemory() != 0
          && this.evictionAttributes.getMaximum() != this.partitionAttributes.getLocalMaxMemory()) {
        
        getCache().getLoggerI18n().warning(LocalizedStrings.Mem_LRU_Eviction_Attribute_Reset,
            new Object[] { regionName,this.evictionAttributes.getMaximum(),
            this.partitionAttributes.getLocalMaxMemory() });
        this.evictionAttributes.setMaximum(this.partitionAttributes.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.getEnableOffHeapMemory()));
    }
    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();
    updateRegionExpiryPossible();
    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.enableGateway = attrs.getEnableGateway();
    setAllGatewayHubIds(attrs.getGatewayHubId());
    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.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.withStorage()) {
        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() 
        // GemFireXD currently disables concurrency checks completely
        && !GemFireCacheImpl.gfxdSystem()) {
      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 EvictorService getEvictorTask() {
    if (this.evService == null && (getCustomEvictionAttributes() != null)
        && !getCustomEvictionAttributes().isEvictIncoming()) {
      LogWriterI18n logger = getSystem().getLogWriter()
          .convertToLogWriterI18n();
      if (logger.fineEnabled()) {
        logger
            .fine("LocalRegion.creating EvictorService " + this.getFullPath());
      }
      this.evService = new EvictorService(getCustomEvictionAttributes()
          .getCriteria(), getCustomEvictionAttributes().getEvictorStartTime(),
          getCustomEvictionAttributes().getEvictorInterval(),
          TimeUnit.MILLISECONDS, this);

      if (logger.fineEnabled()) {
        logger.fine("LocalRegion.created EvictorService " + this.getFullPath());
      }
    }
    return this.evService;
  }
  
  public void initilializeCustomEvictor() {
    LogWriterI18n logger = getSystem().getLogWriter().convertToLogWriterI18n();
    if (getCustomEvictionAttributes() != null
        && !getCustomEvictionAttributes().isEvictIncoming()) {
      State st = getEvictorTask().startAndWait();
      if (st != State.RUNNING) {
        if (logger.fineEnabled()) {
          logger.fine(" The Evictor Service failed to start.");
        }
      }
      if (logger.fineEnabled()) {
        logger.fine(" The Evictor Service started and its state is " + st);
      }
    }
  }

  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.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;
  }

  public final boolean getEnableOffHeapMemory() {
    return this.enableOffHeapMemory;
  }

  /**
   * 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 logHDFSCalls = DEBUG_HDFS_CALLS ? new ThreadLocal() : 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 stackTraces = new ArrayList();
    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;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy