org.apache.geode.internal.cache.GemFireCacheImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.geode.internal.cache.GemFireCacheImpl.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package org.apache.geode.internal.cache;

import com.sun.jna.Native;
import com.sun.jna.Platform;
import org.apache.commons.lang.StringUtils;
import org.apache.geode.CancelCriterion;
import org.apache.geode.CancelException;
import org.apache.geode.ForcedDisconnectException;
import org.apache.geode.GemFireCacheException;
import org.apache.geode.GemFireConfigException;
import org.apache.geode.InternalGemFireError;
import org.apache.geode.LogWriter;
import org.apache.geode.SystemFailure;
import org.apache.geode.admin.internal.SystemMemberCacheEventProcessor;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheExistsException;
import org.apache.geode.cache.CacheTransactionManager;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.CacheXmlException;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.DiskStore;
import org.apache.geode.cache.DiskStoreFactory;
import org.apache.geode.cache.DynamicRegionFactory;
import org.apache.geode.cache.EvictionAction;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.GatewayException;
import org.apache.geode.cache.Operation;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionDestroyedException;
import org.apache.geode.cache.RegionExistsException;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionService;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
import org.apache.geode.cache.asyncqueue.AsyncEventQueueFactory;
import org.apache.geode.cache.asyncqueue.internal.AsyncEventQueueFactoryImpl;
import org.apache.geode.cache.asyncqueue.internal.AsyncEventQueueImpl;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionFactory;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolFactory;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.client.internal.ClientMetadataService;
import org.apache.geode.cache.client.internal.ClientRegionFactoryImpl;
import org.apache.geode.cache.client.internal.PoolImpl;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.internal.DefaultQuery;
import org.apache.geode.cache.query.internal.DefaultQueryService;
import org.apache.geode.cache.query.internal.QueryMonitor;
import org.apache.geode.cache.query.internal.cq.CqService;
import org.apache.geode.cache.query.internal.cq.CqServiceProvider;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache.snapshot.CacheSnapshotService;
import org.apache.geode.cache.util.GatewayConflictResolver;
import org.apache.geode.cache.wan.GatewayReceiver;
import org.apache.geode.cache.wan.GatewayReceiverFactory;
import org.apache.geode.cache.wan.GatewaySender;
import org.apache.geode.cache.wan.GatewaySenderFactory;
import org.apache.geode.distributed.ConfigurationProperties;
import org.apache.geode.distributed.DistributedLockService;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.DistributedSystemDisconnectedException;
import org.apache.geode.distributed.Locator;
import org.apache.geode.distributed.internal.CacheTime;
import org.apache.geode.distributed.internal.DM;
import org.apache.geode.distributed.internal.DistributionAdvisee;
import org.apache.geode.distributed.internal.DistributionAdvisor;
import org.apache.geode.distributed.internal.DistributionAdvisor.Profile;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.InternalLocator;
import org.apache.geode.distributed.internal.PooledExecutorWithDMStats;
import org.apache.geode.distributed.internal.ReplyException;
import org.apache.geode.distributed.internal.ReplyProcessor21;
import org.apache.geode.distributed.internal.ResourceEvent;
import org.apache.geode.distributed.internal.ResourceEventsListener;
import org.apache.geode.distributed.internal.ServerLocation;
import org.apache.geode.distributed.internal.ClusterConfigurationService;
import org.apache.geode.distributed.internal.locks.DLockService;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.i18n.LogWriterI18n;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.SystemTimer;
import org.apache.geode.internal.cache.control.InternalResourceManager;
import org.apache.geode.internal.cache.control.InternalResourceManager.ResourceType;
import org.apache.geode.internal.cache.control.ResourceAdvisor;
import org.apache.geode.internal.cache.execute.util.FindRestEnabledServersFunction;
import org.apache.geode.internal.cache.extension.Extensible;
import org.apache.geode.internal.cache.extension.ExtensionPoint;
import org.apache.geode.internal.cache.extension.SimpleExtensionPoint;
import org.apache.geode.internal.cache.ha.HARegionQueue;
import org.apache.geode.internal.cache.locks.TXLockService;
import org.apache.geode.internal.cache.lru.HeapEvictor;
import org.apache.geode.internal.cache.lru.OffHeapEvictor;
import org.apache.geode.internal.cache.partitioned.RedundancyAlreadyMetException;
import org.apache.geode.internal.cache.persistence.BackupManager;
import org.apache.geode.internal.cache.persistence.PersistentMemberID;
import org.apache.geode.internal.cache.persistence.PersistentMemberManager;
import org.apache.geode.internal.cache.persistence.query.TemporaryResultSetFactory;
import org.apache.geode.internal.cache.snapshot.CacheSnapshotServiceImpl;
import org.apache.geode.internal.cache.tier.sockets.AcceptorImpl;
import org.apache.geode.internal.cache.tier.sockets.CacheClientNotifier;
import org.apache.geode.internal.cache.tier.sockets.CacheClientProxy;
import org.apache.geode.internal.cache.tier.sockets.ClientHealthMonitor;
import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
import org.apache.geode.internal.cache.tier.sockets.ServerConnection;
import org.apache.geode.internal.cache.wan.AbstractGatewaySender;
import org.apache.geode.internal.cache.wan.GatewaySenderAdvisor;
import org.apache.geode.internal.cache.wan.WANServiceProvider;
import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderQueue;
import org.apache.geode.internal.cache.xmlcache.CacheXmlParser;
import org.apache.geode.internal.cache.xmlcache.CacheXmlPropertyResolver;
import org.apache.geode.internal.cache.xmlcache.PropertyResolver;
import org.apache.geode.internal.concurrent.ConcurrentHashSet;
import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.jndi.JNDIInvoker;
import org.apache.geode.internal.jta.TransactionManagerImpl;
import org.apache.geode.internal.logging.InternalLogWriter;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.logging.LoggingThreadGroup;
import org.apache.geode.internal.logging.log4j.LocalizedMessage;
import org.apache.geode.internal.net.SocketCreator;
import org.apache.geode.internal.offheap.MemoryAllocator;
import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.internal.sequencelog.SequenceLoggerImpl;
import org.apache.geode.internal.tcp.ConnectionTable;
import org.apache.geode.internal.util.concurrent.FutureResult;
import org.apache.geode.lang.Identifiable;
import org.apache.geode.management.internal.JmxManagerAdvisee;
import org.apache.geode.management.internal.JmxManagerAdvisor;
import org.apache.geode.management.internal.RestAgent;
import org.apache.geode.management.internal.beans.ManagementListener;
import org.apache.geode.management.internal.configuration.domain.Configuration;
import org.apache.geode.management.internal.configuration.messages.ConfigurationResponse;
import org.apache.geode.memcached.GemFireMemcachedServer;
import org.apache.geode.memcached.GemFireMemcachedServer.Protocol;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.PdxInstanceFactory;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.ReflectionBasedAutoSerializer;
import org.apache.geode.pdx.internal.AutoSerializableManager;
import org.apache.geode.pdx.internal.PdxInstanceFactoryImpl;
import org.apache.geode.pdx.internal.PdxInstanceImpl;
import org.apache.geode.pdx.internal.TypeRegistry;
import org.apache.geode.redis.GeodeRedisServer;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringBufferInputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.naming.Context;

// @todo somebody Come up with more reasonable values for {@link #DEFAULT_LOCK_TIMEOUT}, etc.
/**
 * GemFire's implementation of a distributed {@link org.apache.geode.cache.Cache}.
 *
 */
@SuppressWarnings("deprecation")
public class GemFireCacheImpl
        implements InternalCache, ClientCache, HasCachePerfStats, DistributionAdvisee, CacheTime {
    private static final Logger logger = LogService.getLogger();

    // moved *SERIAL_NUMBER stuff to DistributionAdvisor

    /** The default number of seconds to wait for a distributed lock */
    public static final int DEFAULT_LOCK_TIMEOUT = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "Cache.defaultLockTimeout", 60).intValue();

    /**
     * The default duration (in seconds) of a lease on a distributed lock
     */
    public static final int DEFAULT_LOCK_LEASE = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "Cache.defaultLockLease", 120).intValue();

    /** The default "copy on read" attribute value */
    public static final boolean DEFAULT_COPY_ON_READ = false;

    /** the last instance of GemFireCache created */
    private static volatile GemFireCacheImpl instance = null;
    /**
     * Just like instance but is valid for a bit longer so that pdx can still find the cache during a
     * close.
     */
    private static volatile GemFireCacheImpl pdxInstance = null;

    /**
     * The default amount of time to wait for a <code>netSearch</code> to complete
     */
    public static final int DEFAULT_SEARCH_TIMEOUT = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "Cache.defaultSearchTimeout", 300).intValue();

    /**
     * The <code>CacheLifecycleListener</code> s that have been registered in this VM
     */
    private static final Set<CacheLifecycleListener> cacheLifecycleListeners = new HashSet<CacheLifecycleListener>();

    /**
     * Define gemfire.Cache.ASYNC_EVENT_LISTENERS=true to invoke event listeners in the background
     */
    private static final boolean ASYNC_EVENT_LISTENERS = Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "Cache.ASYNC_EVENT_LISTENERS");

    /**
     * If true then when a delta is applied the size of the entry value will be recalculated. If false
     * (the default) then the size of the entry value is unchanged by a delta application. Not a final
     * so that tests can change this value.
     *
     * @since GemFire hitachi 6.1.2.9
     */
    public static boolean DELTAS_RECALCULATE_SIZE = Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "DELTAS_RECALCULATE_SIZE");

    public static final int EVENT_QUEUE_LIMIT = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "Cache.EVENT_QUEUE_LIMIT", 4096).intValue();
    public static final int EVENT_THREAD_LIMIT = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "Cache.EVENT_THREAD_LIMIT", 16).intValue();

    /**
     * System property to limit the max query-execution time. By default its turned off (-1), the time
     * is set in MiliSecs.
     */
    public static final int MAX_QUERY_EXECUTION_TIME = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "Cache.MAX_QUERY_EXECUTION_TIME", -1).intValue();

    /**
     * System property to disable query monitor even if resource manager is in use
     */
    public final boolean QUERY_MONITOR_DISABLED_FOR_LOW_MEM = Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "Cache.DISABLE_QUERY_MONITOR_FOR_LOW_MEMORY");

    /**
     * Property set to true if resource manager heap percentage is set and query monitor is required
     */
    public static Boolean QUERY_MONITOR_REQUIRED_FOR_RESOURCE_MANAGER = Boolean.FALSE;

    /**
     * This property defines internal function that will get executed on each node to fetch active
     * REST service endpoints (servers).
     */
    public static final String FIND_REST_ENABLED_SERVERS_FUNCTION_ID = FindRestEnabledServersFunction.class
            .getName();

    /**
     * True if the user is allowed lock when memory resources appear to be overcommitted.
     */
    public static final boolean ALLOW_MEMORY_LOCK_WHEN_OVERCOMMITTED = Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "Cache.ALLOW_MEMORY_OVERCOMMIT");

    // time in ms
    private static final int FIVE_HOURS = 5 * 60 * 60 * 1000;
    /** To test MAX_QUERY_EXECUTION_TIME option. */
    public int TEST_MAX_QUERY_EXECUTION_TIME = -1;
    public boolean TEST_MAX_QUERY_EXECUTION_TIME_OVERRIDE_EXCEPTION = false;

    // ///////////////////// Instance Fields ///////////////////////

    private final InternalDistributedSystem system;

    private final DM dm;

    // This is a HashMap because I know that clear() on it does
    // not allocate objects.
    private final HashMap rootRegions;

    /**
     * True if this cache is being created by a ClientCacheFactory.
     */
    private final boolean isClient;
    private PoolFactory clientpf;
    /**
     * It is not final to allow cache.xml parsing to set it.
     */
    private Pool defaultPool;

    private final ConcurrentMap pathToRegion = new ConcurrentHashMap();

    protected volatile boolean isInitialized = false;
    protected volatile boolean isClosing = false;
    protected volatile boolean closingGatewaySendersByShutdownAll = false;
    protected volatile boolean closingGatewayReceiversByShutdownAll = false;

    /** Amount of time (in seconds) to wait for a distributed lock */
    private int lockTimeout = DEFAULT_LOCK_TIMEOUT;

    /** Amount of time a lease of a distributed lock lasts */
    private int lockLease = DEFAULT_LOCK_LEASE;

    /** Amount of time to wait for a <code>netSearch</code> to complete */
    private int searchTimeout = DEFAULT_SEARCH_TIMEOUT;

    private final CachePerfStats cachePerfStats;

    /** Date on which this instances was created */
    private final Date creationDate;

    /** thread pool for event dispatching */
    private final ThreadPoolExecutor eventThreadPool;

    /**
     * the list of all cache servers. CopyOnWriteArrayList is used to allow concurrent add, remove and
     * retrieval operations. It is assumed that the traversal operations on cache servers list vastly
     * outnumber the mutative operations such as add, remove.
     */
    private volatile List allCacheServers = new CopyOnWriteArrayList();

    /**
     * Controls updates to the list of all gateway senders
     *
     * @see #allGatewaySenders
     */
    public final Object allGatewaySendersLock = new Object();

    /**
     * the set of all gateway senders. It may be fetched safely (for enumeration), but updates must by
     * synchronized via {@link #allGatewaySendersLock}
     */
    private volatile Set<GatewaySender> allGatewaySenders = Collections.emptySet();

    /**
     * The list of all async event queues added to the cache. CopyOnWriteArrayList is used to allow
     * concurrent add, remove and retrieval operations.
     */
    private volatile Set<AsyncEventQueue> allVisibleAsyncEventQueues = new CopyOnWriteArraySet<AsyncEventQueue>();

    /**
     * The list of all async event queues added to the cache. CopyOnWriteArrayList is used to allow
     * concurrent add, remove and retrieval operations.
     */
    private volatile Set<AsyncEventQueue> allAsyncEventQueues = new CopyOnWriteArraySet<AsyncEventQueue>();

    /**
     * Controls updates to the list of all gateway receivers
     *
     * @see #allGatewayReceivers
     */
    public final Object allGatewayReceiversLock = new Object();

    /**
     * the list of all gateway Receivers. It may be fetched safely (for enumeration), but updates must
     * by synchronized via {@link #allGatewayReceiversLock}
     */
    private volatile Set<GatewayReceiver> allGatewayReceivers = Collections.emptySet();

    /** PartitionedRegion instances (for required-events notification */
    // This is a HashSet because I know that clear() on it does not
    // allocate any objects.
    private final HashSet<PartitionedRegion> partitionedRegions = new HashSet<PartitionedRegion>();

    /**
     * Fix for 42051 This is a map of regions that are in the process of being destroyed. We could
     * potentially leave the regions in the pathToRegion map, but that would entail too many changes
     * at this point in the release. We need to know which regions are being destroyed so that a
     * profile exchange can get the persistent id of the destroying region and know not to persist
     * that ID if it receives it as part of the persistent view.
     */
    private final ConcurrentMap<String, DistributedRegion> regionsInDestroy = new ConcurrentHashMap<String, DistributedRegion>();

    public final Object allGatewayHubsLock = new Object();

    /**
     * conflict resolver for WAN, if any
     * 
     * @guarded.By {@link #allGatewayHubsLock}
     */
    private GatewayConflictResolver gatewayConflictResolver;

    /** Is this is "server" cache? */
    private boolean isServer = false;

    /** transaction manager for this cache */
    private final TXManagerImpl txMgr;

    private RestAgent restAgent;

    private boolean isRESTServiceRunning = false;

    /** Copy on Read feature for all read operations e.g. get */
    private volatile boolean copyOnRead = DEFAULT_COPY_ON_READ;

    /** The named region attributes registered with this cache. */
    private final Map namedRegionAttributes = Collections.synchronizedMap(new HashMap());

    /**
     * if this cache was forced to close due to a forced-disconnect, we retain a
     * ForcedDisconnectException that can be used as the cause
     */
    private boolean forcedDisconnect;

    /**
     * if this cache was forced to close due to a forced-disconnect or system failure, this keeps
     * track of the reason
     */
    protected volatile Throwable disconnectCause = null;

    /** context where this cache was created -- for debugging, really... */
    public Exception creationStack = null;

    /**
     * a system timer task for cleaning up old bridge thread event entries
     */
    private EventTracker.ExpiryTask recordedEventSweeper;

    private TombstoneService tombstoneService;

    /**
     * DistributedLockService for PartitionedRegions. Remains null until the first PartitionedRegion
     * is created. Destroyed by GemFireCache when closing the cache. Protected by synchronization on
     * this GemFireCache.
     *
     * @guarded.By prLockServiceLock
     */
    private DistributedLockService prLockService;

    /**
     * lock used to access prLockService
     */
    private final Object prLockServiceLock = new Object();

    /**
     * DistributedLockService for GatewaySenders. Remains null until the first GatewaySender is
     * created. Destroyed by GemFireCache when closing the cache.
     * 
     * @guarded.By gatewayLockServiceLock
     */
    private volatile DistributedLockService gatewayLockService;

    /**
     * Lock used to access gatewayLockService
     */
    private final Object gatewayLockServiceLock = new Object();

    private final InternalResourceManager resourceManager;

    private final AtomicReference<BackupManager> backupManager = new AtomicReference<BackupManager>();

    private HeapEvictor heapEvictor = null;

    private OffHeapEvictor offHeapEvictor = null;

    private final Object heapEvictorLock = new Object();

    private final Object offHeapEvictorLock = new Object();

    private ResourceEventsListener listener;

    /**
     * Enabled when CacheExistsException issues arise in debugging
     *
     * @see #creationStack
     */
    private static final boolean DEBUG_CREATION_STACK = false;

    private volatile QueryMonitor queryMonitor;

    private final Object queryMonitorLock = new Object();

    private final PersistentMemberManager persistentMemberManager;

    private ClientMetadataService clientMetadatService = null;

    private final Object clientMetaDatServiceLock = new Object();

    private final AtomicBoolean isShutDownAll = new AtomicBoolean();
    private final CountDownLatch shutDownAllFinished = new CountDownLatch(1);

    private final ResourceAdvisor resourceAdvisor;
    private final JmxManagerAdvisor jmxAdvisor;

    private final int serialNumber;

    private final TXEntryStateFactory txEntryStateFactory;

    private final CacheConfig cacheConfig;

    private final DiskStoreMonitor diskMonitor;

    // Stores the properties used to initialize declarables.
    private final Map<Declarable, Properties> declarablePropertiesMap = new ConcurrentHashMap<Declarable, Properties>();

    /** {@link PropertyResolver} to resolve ${} type property strings */
    protected static PropertyResolver resolver;

    protected static boolean xmlParameterizationEnabled = !Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "xml.parameterization.disabled");

    public static Runnable internalBeforeApplyChanges;

    public static Runnable internalBeforeNonTXBasicPut;

    /**
     * the memcachedServer instance that is started when {@link DistributionConfig#getMemcachedPort()}
     * is specified
     */
    private GemFireMemcachedServer memcachedServer;

    /**
     * Redis server is started when {@link DistributionConfig#getRedisPort()} is set
     */
    private GeodeRedisServer redisServer;

    /**
     * {@link ExtensionPoint} support.
     * 
     * @since GemFire 8.1
     */
    private SimpleExtensionPoint<Cache> extensionPoint = new SimpleExtensionPoint<Cache>(this, this);

    private final CqService cqService;

    private final Set<RegionListener> regionListeners = new ConcurrentHashSet<RegionListener>();

    private final Map<Class<? extends CacheService>, CacheService> services = new HashMap<Class<? extends CacheService>, CacheService>();

    public static final int DEFAULT_CLIENT_FUNCTION_TIMEOUT = 0;

    private static int clientFunctionTimeout;

    private final static Boolean DISABLE_AUTO_EVICTION = Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "disableAutoEviction");

    private static SecurityService securityService = SecurityService.getSecurityService();

    static {
        // this works around jdk bug 6427854, reported in ticket #44434
        String propertyName = "sun.nio.ch.bugLevel";
        String value = System.getProperty(propertyName);
        if (value == null) {
            System.setProperty(propertyName, "");
        }
    }

    /**
     * Invokes mlockall(). Locks all pages mapped into the address space of the calling process. This
     * includes the pages of the code, data and stack segment, as well as shared libraries, user space
     * kernel data, shared memory, and memory-mapped files. All mapped pages are guaranteed to be
     * resident in RAM when the call returns successfully; the pages are guaranteed to stay in RAM
     * until later unlocked.
     * 
     * @param flags MCL_CURRENT 1 - Lock all pages which are currently mapped into the address space
     *        of the process.
     * 
     *        MCL_FUTURE 2 - Lock all pages which will become mapped into the address space of the
     *        process in the future. These could be for instance new pages required by a growing heap
     *        and stack as well as new memory mapped files or shared memory regions.
     * 
     * @return 0 if success, non-zero if error and errno set
     * 
     */
    private static native int mlockall(int flags);

    public static void lockMemory() {
        int result = 0;
        try {
            Native.register(Platform.C_LIBRARY_NAME);
            result = mlockall(1);
            if (result == 0) {
                return;
            }
        } catch (Throwable t) {
            throw new IllegalStateException("Error trying to lock memory", t);
        }

        int errno = Native.getLastError();
        String msg = "mlockall failed: " + errno;
        if (errno == 1 || errno == 12) { // EPERM || ENOMEM
            msg = "Unable to lock memory due to insufficient free space or privileges.  "
                    + "Please check the RLIMIT_MEMLOCK soft resource limit (ulimit -l) and "
                    + "increase the available memory if needed";
        }
        throw new IllegalStateException(msg);
    }

    /**
     * This is for debugging cache-open issues (esp.
     * {@link org.apache.geode.cache.CacheExistsException})
     */
    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer();
        sb.append("GemFireCache[");
        sb.append("id = " + System.identityHashCode(this));
        sb.append("; isClosing = " + this.isClosing);
        sb.append("; isShutDownAll = " + isCacheAtShutdownAll());
        sb.append("; created = " + this.creationDate);
        sb.append("; server = " + this.isServer);
        sb.append("; copyOnRead = " + this.copyOnRead);
        sb.append("; lockLease = " + this.lockLease);
        sb.append("; lockTimeout = " + this.lockTimeout);
        // sb.append("; rootRegions = (" + this.rootRegions + ")");
        // sb.append("; cacheServers = (" + this.cacheServers + ")");
        // sb.append("; regionAttributes = (" + this.listRegionAttributes());
        // sb.append("; gatewayHub = " + gatewayHub);
        if (this.creationStack != null) {
            sb.append("\nCreation context:\n");
            OutputStream os = new OutputStream() {
                @Override
                public void write(int i) {
                    sb.append((char) i);
                }
            };
            PrintStream ps = new PrintStream(os);
            this.creationStack.printStackTrace(ps);
        }
        sb.append("]");
        return sb.toString();
    }

    // ////////////////////// Constructors /////////////////////////

    /** Map of Futures used to track Regions that are being reinitialized */
    private final ConcurrentMap reinitializingRegions = new ConcurrentHashMap();

    /** Returns the last created instance of GemFireCache */
    public static GemFireCacheImpl getInstance() {
        return instance;
    }

    /*
     * Used for testing, retain the old instance in the test and re-set the value when test completes
     */
    public static GemFireCacheImpl setInstanceForTests(GemFireCacheImpl cache) {
        GemFireCacheImpl oldInstance = instance;
        instance = cache;
        return oldInstance;
    }

    /**
     * Returns an existing instance. If a cache does not exist throws a cache closed exception.
     * 
     * @return the existing cache
     * @throws CacheClosedException if an existing cache can not be found.
     */
    public static final GemFireCacheImpl getExisting() {
        final GemFireCacheImpl result = instance;
        if (result != null && !result.isClosing) {
            return result;
        }
        if (result != null) {
            throw result.getCacheClosedException(
                    LocalizedStrings.CacheFactory_THE_CACHE_HAS_BEEN_CLOSED.toLocalizedString(), null);
        }
        throw new CacheClosedException(
                LocalizedStrings.CacheFactory_A_CACHE_HAS_NOT_YET_BEEN_CREATED.toLocalizedString());
    }

    /**
     * Returns an existing instance. If a cache does not exist throws an exception.
     *
     * @param reason the reason an existing cache is being requested.
     * @return the existing cache
     * @throws CacheClosedException if an existing cache can not be found.
     */
    public static GemFireCacheImpl getExisting(String reason) {
        GemFireCacheImpl result = getInstance();
        if (result == null) {
            throw new CacheClosedException(reason);
        }
        return result;
    }

    /**
     * Pdx is allowed to obtain the cache even while it is being closed
     */
    public static GemFireCacheImpl getForPdx(String reason) {
        GemFireCacheImpl result = pdxInstance;
        if (result == null) {
            throw new CacheClosedException(reason);
        }
        return result;
    }

    // /**
    // * @deprecated remove when Lise allows a Hydra VM to
    // * be re-created
    // */
    // public static void clearInstance() {
    // System.err.println("DEBUG: do not commit GemFireCache#clearInstance");
    // instance = null;
    // }

    public static GemFireCacheImpl createClient(DistributedSystem system, PoolFactory pf, CacheConfig cacheConfig) {
        return basicCreate(system, true, cacheConfig, pf, true, ASYNC_EVENT_LISTENERS, null);
    }

    public static GemFireCacheImpl create(DistributedSystem system, CacheConfig cacheConfig) {
        return basicCreate(system, true, cacheConfig, null, false, ASYNC_EVENT_LISTENERS, null);
    }

    public static GemFireCacheImpl createWithAsyncEventListeners(DistributedSystem system, CacheConfig cacheConfig,
            TypeRegistry typeRegistry) {
        return basicCreate(system, true, cacheConfig, null, false, true, typeRegistry);
    }

    public static Cache create(DistributedSystem system, boolean existingOk, CacheConfig cacheConfig) {
        return basicCreate(system, existingOk, cacheConfig, null, false, ASYNC_EVENT_LISTENERS, null);
    }

    private static GemFireCacheImpl basicCreate(DistributedSystem system, boolean existingOk,
            CacheConfig cacheConfig, PoolFactory pf, boolean isClient, boolean asyncEventListeners,
            TypeRegistry typeRegistry) throws CacheExistsException, TimeoutException, CacheWriterException,
            GatewayException, RegionExistsException {
        try {
            synchronized (GemFireCacheImpl.class) {
                GemFireCacheImpl instance = checkExistingCache(existingOk, cacheConfig);
                if (instance == null) {
                    instance = new GemFireCacheImpl(isClient, pf, system, cacheConfig, asyncEventListeners,
                            typeRegistry);
                    instance.initialize();
                }
                return instance;
            }
        } catch (CacheXmlException | IllegalArgumentException e) {
            logger.error(e.getLocalizedMessage());
            throw e;
        } catch (Error | RuntimeException e) {
            logger.error(e);
            throw e;
        }
    }

    private static GemFireCacheImpl checkExistingCache(boolean existingOk, CacheConfig cacheConfig) {
        GemFireCacheImpl instance = getInstance();

        if (instance != null && !instance.isClosed()) {
            if (existingOk) {
                // Check if cache configuration matches.
                cacheConfig.validateCacheConfig(instance);
                return instance;
            } else {
                // instance.creationStack argument is for debugging...
                throw new CacheExistsException(instance,
                        LocalizedStrings.CacheFactory_0_AN_OPEN_CACHE_ALREADY_EXISTS.toLocalizedString(instance),
                        instance.creationStack);
            }
        }
        return null;
    }

    /**
     * Creates a new instance of GemFireCache and populates it according to the
     * <code>cache.xml</code>, if appropriate.
     * 
     * @param typeRegistry: currently only unit tests set this parameter to a non-null value
     */
    private GemFireCacheImpl(boolean isClient, PoolFactory pf, DistributedSystem system, CacheConfig cacheConfig,
            boolean asyncEventListeners, TypeRegistry typeRegistry) {
        this.isClient = isClient;
        this.clientpf = pf;
        this.cacheConfig = cacheConfig; // do early for bug 43213
        this.pdxRegistry = typeRegistry;

        // Synchronized to prevent a new cache from being created
        // before an old one has finished closing
        synchronized (GemFireCacheImpl.class) {

            // start JTA transaction manager within this synchronized block
            // to prevent race with cache close. fixes bug 43987
            JNDIInvoker.mapTransactions(system);
            this.system = (InternalDistributedSystem) system;
            this.dm = this.system.getDistributionManager();
            if (!this.isClient && PoolManager.getAll().isEmpty()) {
                // We only support management on members of a distributed system
                // Should do this: if (!getSystem().isLoner()) {
                // but it causes quickstart.CqClientTest to hang
                this.listener = new ManagementListener();
                this.system.addResourceListener(listener);
                if (this.system.isLoner()) {
                    this.system.getInternalLogWriter()
                            .info(LocalizedStrings.GemFireCacheImpl_RUNNING_IN_LOCAL_MODE);
                }
            } else {
                getLogger().info("Running in client mode");
                this.listener = null;
            }

            // Don't let admin-only VMs create Cache's just yet.
            DM dm = this.system.getDistributionManager();
            if (dm instanceof DistributionManager) {
                if (((DistributionManager) dm).getDMType() == DistributionManager.ADMIN_ONLY_DM_TYPE) {
                    throw new IllegalStateException(
                            LocalizedStrings.GemFireCache_CANNOT_CREATE_A_CACHE_IN_AN_ADMINONLY_VM
                                    .toLocalizedString());
                }
            }

            this.rootRegions = new HashMap();

            this.cqService = CqServiceProvider.create(this);

            this.rmqFactory = new ReliableMessageQueueFactoryImpl();

            // Create the CacheStatistics
            this.cachePerfStats = new CachePerfStats(system);
            CachePerfStats.enableClockStats = this.system.getConfig().getEnableTimeStatistics();

            this.txMgr = new TXManagerImpl(this.cachePerfStats, this);
            dm.addMembershipListener(this.txMgr);

            this.creationDate = new Date();

            this.persistentMemberManager = new PersistentMemberManager();

            if (asyncEventListeners) {
                final ThreadGroup group = LoggingThreadGroup.createThreadGroup("Message Event Threads", logger);
                ThreadFactory tf = new ThreadFactory() {
                    public Thread newThread(final Runnable command) {
                        final Runnable r = new Runnable() {
                            public void run() {
                                ConnectionTable.threadWantsSharedResources();
                                command.run();
                            }
                        };
                        Thread thread = new Thread(group, r, "Message Event Thread");
                        thread.setDaemon(true);
                        return thread;
                    }
                };
                ArrayBlockingQueue q = new ArrayBlockingQueue(EVENT_QUEUE_LIMIT);
                this.eventThreadPool = new PooledExecutorWithDMStats(q, EVENT_THREAD_LIMIT,
                        this.cachePerfStats.getEventPoolHelper(), tf, 1000);
            } else {
                this.eventThreadPool = null;
            }

            // Initialize the advisor here, but wait to exchange profiles until cache is fully built
            this.resourceAdvisor = ResourceAdvisor.createResourceAdvisor(this);
            // Initialize the advisor here, but wait to exchange profiles until cache is fully built
            this.jmxAdvisor = JmxManagerAdvisor.createJmxManagerAdvisor(new JmxManagerAdvisee(this));

            resourceManager = InternalResourceManager.createResourceManager(this);
            this.serialNumber = DistributionAdvisor.createSerialNumber();

            getResourceManager().addResourceListener(ResourceType.HEAP_MEMORY, getHeapEvictor());

            /*
             * Only bother creating an off-heap evictor if we have off-heap memory enabled.
             */
            if (null != getOffHeapStore()) {
                getResourceManager().addResourceListener(ResourceType.OFFHEAP_MEMORY, getOffHeapEvictor());
            }

            recordedEventSweeper = EventTracker.startTrackerServices(this);
            tombstoneService = TombstoneService.initialize(this);

            TypeRegistry.init();
            basicSetPdxSerializer(this.cacheConfig.getPdxSerializer());
            TypeRegistry.open();

            if (!isClient()) {
                // Initialize the QRM thread freqeuncy to default (1 second )to prevent spill
                // over from previous Cache , as the interval is stored in a static
                // volatile field.
                HARegionQueue.setMessageSyncInterval(HARegionQueue.DEFAULT_MESSAGE_SYNC_INTERVAL);
            }
            FunctionService.registerFunction(new PRContainsValueFunction());
            this.expirationScheduler = new ExpirationScheduler(this.system);

            // uncomment following line when debugging CacheExistsException
            if (DEBUG_CREATION_STACK) {
                this.creationStack = new Exception(
                        LocalizedStrings.GemFireCache_CREATED_GEMFIRECACHE_0.toLocalizedString(toString()));
            }

            this.txEntryStateFactory = TXEntryState.getFactory();
            if (xmlParameterizationEnabled) {
                /** If product properties file is available replace properties from there */
                Properties userProps = this.system.getConfig().getUserDefinedProps();
                if (userProps != null && !userProps.isEmpty()) {
                    resolver = new CacheXmlPropertyResolver(false, PropertyResolver.NO_SYSTEM_PROPERTIES_OVERRIDE,
                            userProps);
                } else {
                    resolver = new CacheXmlPropertyResolver(false, PropertyResolver.NO_SYSTEM_PROPERTIES_OVERRIDE,
                            null);
                }
            }

            SystemFailure.signalCacheCreate();

            diskMonitor = new DiskStoreMonitor();
        } // synchronized
    }

    public boolean isRESTServiceRunning() {
        return isRESTServiceRunning;
    }

    public void setRESTServiceRunning(boolean isRESTServiceRunning) {
        this.isRESTServiceRunning = isRESTServiceRunning;
    }

    /**
     * Used by Hydra tests to get handle of Rest Agent
     * 
     * @return RestAgent
     */
    public RestAgent getRestAgent() {
        return restAgent;
    }

    /*****
     * Request the shared configuration from the locator(s) which have the Cluster config service
     * running
     */
    public ConfigurationResponse requestSharedConfiguration() {
        final DistributionConfig config = this.system.getConfig();

        if (!(dm instanceof DistributionManager))
            return null;

        // do nothing if this vm is/has locator or this is a client
        if (((DistributionManager) dm).getDMType() == DistributionManager.LOCATOR_DM_TYPE || isClient
                || Locator.getLocator() != null)
            return null;

        // can't simply return null if server is not using shared configuration, since we need to find
        // out
        // if the locator is running in secure mode or not, if yes, then we need to throw an exception
        // if server is not using cluster config

        Map<InternalDistributedMember, Collection<String>> scl = this.getDistributionManager()
                .getAllHostedLocatorsWithSharedConfiguration();

        // If there are no locators with Shared configuration, that means the system has been started
        // without shared configuration
        // then do not make requests to the locators
        if (scl.isEmpty()) {
            logger.info(LocalizedMessage
                    .create(LocalizedStrings.GemFireCache_NO_LOCATORS_FOUND_WITH_SHARED_CONFIGURATION));
            return null;
        }

        ConfigurationResponse response = null;
        List<String> locatorConnectionStrings = getSharedConfigLocatorConnectionStringList();

        try {
            response = ClusterConfigurationLoader.requestConfigurationFromLocators(system.getConfig(),
                    locatorConnectionStrings);

            // log the configuration received from the locator
            logger.info(LocalizedMessage
                    .create(LocalizedStrings.GemFireCache_RECEIVED_SHARED_CONFIGURATION_FROM_LOCATORS));
            logger.info(response.describeConfig());

            Configuration clusterConfig = response.getRequestedConfiguration()
                    .get(ClusterConfigurationService.CLUSTER_CONFIG);
            Properties clusterSecProperties = (clusterConfig == null) ? new Properties()
                    : clusterConfig.getGemfireProperties();

            // If not using shared configuration, return null or throw an exception is locator is secured
            if (!config.getUseSharedConfiguration()) {
                if (clusterSecProperties.containsKey(ConfigurationProperties.SECURITY_MANAGER)) {
                    throw new GemFireConfigException(
                            LocalizedStrings.GEMFIRE_CACHE_SECURITY_MISCONFIGURATION_2.toLocalizedString());
                } else {
                    logger.info(
                            LocalizedMessage.create(LocalizedStrings.GemFireCache_NOT_USING_SHARED_CONFIGURATION));
                    return null;
                }
            }

            Properties serverSecProperties = config.getSecurityProps();
            // check for possible mis-configuration
            if (isMisConfigured(clusterSecProperties, serverSecProperties, ConfigurationProperties.SECURITY_MANAGER)
                    || isMisConfigured(clusterSecProperties, serverSecProperties,
                            ConfigurationProperties.SECURITY_POST_PROCESSOR)) {
                throw new GemFireConfigException(
                        LocalizedStrings.GEMFIRE_CACHE_SECURITY_MISCONFIGURATION.toLocalizedString());
            }
            return response;

        } catch (ClusterConfigurationNotAvailableException e) {
            throw new GemFireConfigException(
                    LocalizedStrings.GemFireCache_SHARED_CONFIGURATION_NOT_AVAILABLE.toLocalizedString(), e);
        } catch (UnknownHostException e) {
            throw new GemFireConfigException(e.getLocalizedMessage(), e);
        }
    }

    public void deployJarsRecevedFromClusterConfiguration(ConfigurationResponse response) {
        try {
            ClusterConfigurationLoader.deployJarsReceivedFromClusterConfiguration(this, response);
        } catch (IOException e) {
            throw new GemFireConfigException(
                    LocalizedStrings.GemFireCache_EXCEPTION_OCCURED_WHILE_DEPLOYING_JARS_FROM_SHARED_CONDFIGURATION
                            .toLocalizedString(),
                    e);
        } catch (ClassNotFoundException e) {
            throw new GemFireConfigException(
                    LocalizedStrings.GemFireCache_EXCEPTION_OCCURED_WHILE_DEPLOYING_JARS_FROM_SHARED_CONDFIGURATION
                            .toLocalizedString(),
                    e);
        }
    }

    // When called, clusterProps and serverProps and key could not be null
    public static boolean isMisConfigured(Properties clusterProps, Properties serverProps, String key) {
        String clusterPropValue = clusterProps.getProperty(key);
        String serverPropValue = serverProps.getProperty(key);

        // if this server prop is not specified, this is always OK.
        if (StringUtils.isBlank(serverPropValue))
            return false;

        // server props is not blank, but cluster props is blank, NOT OK.
        if (StringUtils.isBlank(clusterPropValue))
            return true;

        // at this point check for eqality
        return !clusterPropValue.equals(serverPropValue);
    }

    public List<String> getSharedConfigLocatorConnectionStringList() {
        List<String> locatorConnectionStringList = new ArrayList<String>();

        Map<InternalDistributedMember, Collection<String>> scl = this.getDistributionManager()
                .getAllHostedLocatorsWithSharedConfiguration();

        // If there are no locators with Shared configuration, that means the system has been started
        // without shared configuration
        // then do not make requests to the locators
        if (!scl.isEmpty()) {
            Set<Entry<InternalDistributedMember, Collection<String>>> locs = scl.entrySet();

            for (Entry<InternalDistributedMember, Collection<String>> loc : locs) {
                Collection<String> locStrings = loc.getValue();
                Iterator<String> locStringIter = locStrings.iterator();

                while (locStringIter.hasNext()) {
                    locatorConnectionStringList.add(locStringIter.next());
                }
            }
        }
        return locatorConnectionStringList;
    }

    /**
     * Used by unit tests to force cache creation to use a test generated cache.xml
     */
    public static File testCacheXml = null;

    /**
     * @return true if cache is created using a ClientCacheFactory
     * @see #hasPool()
     */
    public boolean isClient() {
        return this.isClient;
    }

    /**
     * Method to check for GemFire client. In addition to checking for ClientCacheFactory, this method
     * checks for any defined pools.
     *
     * @return true if the cache has pools declared
     */
    public boolean hasPool() {
        return this.isClient || !getAllPools().isEmpty();
    }

    private Collection<Pool> getAllPools() {
        Collection<Pool> pools = PoolManagerImpl.getPMI().getMap().values();
        for (Iterator<Pool> itr = pools.iterator(); itr.hasNext();) {
            PoolImpl pool = (PoolImpl) itr.next();
            if (pool.isUsedByGateway()) {
                itr.remove();
            }
        }
        return pools;
    }

    /**
     * May return null (even on a client).
     */
    public Pool getDefaultPool() {
        return this.defaultPool;
    }

    private void setDefaultPool(Pool v) {
        this.defaultPool = v;
    }

    /**
     * Perform initialization, solve the early escaped reference problem by putting publishing
     * references to this instance in this method (vs. the constructor).
     */
    private void initialize() {
        if (GemFireCacheImpl.instance != null) {
            Assert.assertTrue(GemFireCacheImpl.instance == null, "Cache instance already in place: " + instance);
        }
        GemFireCacheImpl.instance = this;
        GemFireCacheImpl.pdxInstance = this;

        for (Iterator<CacheLifecycleListener> iter = cacheLifecycleListeners.iterator(); iter.hasNext();) {
            CacheLifecycleListener listener = (CacheLifecycleListener) iter.next();
            listener.cacheCreated(this);
        }

        ClassPathLoader.setLatestToDefault();

        // request and check cluster configuration
        ConfigurationResponse configurationResponse = requestSharedConfiguration();
        deployJarsRecevedFromClusterConfiguration(configurationResponse);

        // apply the cluster's properties configuration and initialize security using that configuration
        ClusterConfigurationLoader.applyClusterPropertiesConfiguration(this, configurationResponse,
                system.getConfig());

        // first initialize the security service using the security properties
        securityService.initSecurity(system.getConfig().getSecurityProps());
        // secondly if cacheConfig has a securityManager, use that instead
        if (cacheConfig.getSecurityManager() != null) {
            securityService.setSecurityManager(cacheConfig.getSecurityManager());
        }
        // if cacheConfig has a postProcessor, use that instead
        if (cacheConfig.getPostProcessor() != null) {
            securityService.setPostProcessor(cacheConfig.getPostProcessor());
        }

        SystemMemberCacheEventProcessor.send(this, Operation.CACHE_CREATE);
        this.resourceAdvisor.initializationGate();

        // Register function that we need to execute to fetch available REST service endpoints in DS
        FunctionService.registerFunction(new FindRestEnabledServersFunction());

        // moved this after initializeDeclarativeCache because in the future
        // distributed system creation will not happen until we have read
        // cache.xml file.
        // For now this needs to happen before cache.xml otherwise
        // we will not be ready for all the events that cache.xml
        // processing can deliver (region creation, etc.).
        // This call may need to be moved inside initializeDeclarativeCache.
        /** Entry to GemFire Management service **/
        this.jmxAdvisor.initializationGate();

        // this starts up the ManagementService, register and federate the internal beans
        system.handleResourceEvent(ResourceEvent.CACHE_CREATE, this);

        boolean completedCacheXml = false;

        initializeServices();

        try {
            // Deploy all the jars from the deploy working dir.
            new JarDeployer(this.system.getConfig().getDeployWorkingDir()).loadPreviouslyDeployedJars();
            ClusterConfigurationLoader.applyClusterXmlConfiguration(this, configurationResponse,
                    system.getConfig());
            initializeDeclarativeCache();
            completedCacheXml = true;
        } finally {
            if (!completedCacheXml) {
                // so initializeDeclarativeCache threw an exception
                try {
                    close(); // fix for bug 34041
                } catch (Throwable ignore) {
                    // I don't want init to throw an exception that came from the close.
                    // I want it to throw the original exception that came from initializeDeclarativeCache.
                }
            }
        }

        this.clientpf = null;

        startColocatedJmxManagerLocator();

        startMemcachedServer();

        startRedisServer();

        startRestAgentServer(this);

        int time = Integer.getInteger(DistributionConfig.GEMFIRE_PREFIX + "CLIENT_FUNCTION_TIMEOUT",
                DEFAULT_CLIENT_FUNCTION_TIMEOUT);
        clientFunctionTimeout = time >= 0 ? time : DEFAULT_CLIENT_FUNCTION_TIMEOUT;

        isInitialized = true;
    }

    /**
     * Initialize any services that provided as extensions to the cache using the service loader
     * mechanism.
     */
    private void initializeServices() {
        ServiceLoader<CacheService> loader = ServiceLoader.load(CacheService.class);
        for (CacheService service : loader) {
            service.init(this);
            this.services.put(service.getInterface(), service);
            system.handleResourceEvent(ResourceEvent.CACHE_SERVICE_CREATE, service);
        }
    }

    private boolean isNotJmxManager() {
        return (this.system.getConfig().getJmxManagerStart() != true);
    }

    private boolean isServerNode() {
        return (this.system.getDistributedMember().getVmKind() != DistributionManager.LOCATOR_DM_TYPE
                && this.system.getDistributedMember().getVmKind() != DistributionManager.ADMIN_ONLY_DM_TYPE
                && !isClient());
    }

    private void startRestAgentServer(GemFireCacheImpl cache) {
        if (this.system.getConfig().getStartDevRestApi() && isNotJmxManager() && isServerNode()) {
            this.restAgent = new RestAgent(this.system.getConfig());
            restAgent.start(cache);
        } else {
            this.restAgent = null;
        }
    }

    private void startMemcachedServer() {
        int port = system.getConfig().getMemcachedPort();
        if (port != 0) {
            String protocol = system.getConfig().getMemcachedProtocol();
            assert protocol != null;
            String bindAddress = system.getConfig().getMemcachedBindAddress();
            assert bindAddress != null;
            if (bindAddress.equals(DistributionConfig.DEFAULT_MEMCACHED_BIND_ADDRESS)) {
                logger.info(LocalizedMessage.create(
                        LocalizedStrings.GemFireCacheImpl_STARTING_GEMFIRE_MEMCACHED_SERVER_ON_PORT_0_FOR_1_PROTOCOL,
                        new Object[] { port, protocol }));
            } else {
                logger.info(LocalizedMessage.create(
                        LocalizedStrings.GemFireCacheImpl_STARTING_GEMFIRE_MEMCACHED_SERVER_ON_BIND_ADDRESS_0_PORT_1_FOR_2_PROTOCOL,
                        new Object[] { bindAddress, port, protocol }));
            }
            this.memcachedServer = new GemFireMemcachedServer(bindAddress, port,
                    Protocol.valueOf(protocol.toUpperCase()));
            this.memcachedServer.start();
        }
    }

    private void startRedisServer() {
        int port = system.getConfig().getRedisPort();
        if (port != 0) {
            String bindAddress = system.getConfig().getRedisBindAddress();
            assert bindAddress != null;
            if (bindAddress.equals(DistributionConfig.DEFAULT_REDIS_BIND_ADDRESS)) {
                getLoggerI18n().info(LocalizedStrings.GemFireCacheImpl_STARTING_GEMFIRE_REDIS_SERVER_ON_PORT_0,
                        new Object[] { port });
            } else {
                getLoggerI18n().info(
                        LocalizedStrings.GemFireCacheImpl_STARTING_GEMFIRE_REDIS_SERVER_ON_BIND_ADDRESS_0_PORT_1,
                        new Object[] { bindAddress, port });
            }
            this.redisServer = new GeodeRedisServer(bindAddress, port);
            this.redisServer.start();
        }
    }

    public URL getCacheXmlURL() {
        if (this.getMyId().getVmKind() == DistributionManager.LOCATOR_DM_TYPE) {
            return null;
        }
        File xmlFile = testCacheXml;
        if (xmlFile == null) {
            xmlFile = this.system.getConfig().getCacheXmlFile();
        }
        if ("".equals(xmlFile.getName())) {
            return null;
        }

        URL url = null;
        if (!xmlFile.exists() || !xmlFile.isFile()) {
            // do a resource search
            String resource = xmlFile.getPath();
            resource = resource.replaceAll("\\\\", "/");
            if (resource.length() > 1 && resource.startsWith("/")) {
                resource = resource.substring(1);
            }
            url = ClassPathLoader.getLatest().getResource(getClass(), resource);
        } else {
            try {
                url = xmlFile.toURL();
            } catch (IOException ex) {
                throw new CacheXmlException(LocalizedStrings.GemFireCache_COULD_NOT_CONVERT_XML_FILE_0_TO_AN_URL
                        .toLocalizedString(xmlFile), ex);
            }
        }
        if (url == null) {
            File defaultFile = DistributionConfig.DEFAULT_CACHE_XML_FILE;
            if (!xmlFile.equals(defaultFile)) {
                if (!xmlFile.exists()) {
                    throw new CacheXmlException(
                            LocalizedStrings.GemFireCache_DECLARATIVE_CACHE_XML_FILERESOURCE_0_DOES_NOT_EXIST
                                    .toLocalizedString(xmlFile));
                } else /* if (!xmlFile.isFile()) */ {
                    throw new CacheXmlException(LocalizedStrings.GemFireCache_DECLARATIVE_XML_FILE_0_IS_NOT_A_FILE
                            .toLocalizedString(xmlFile));
                }
            }
        }

        return url;
    }

    /**
     * Initializes the contents of this <code>Cache</code> according to the declarative caching XML
     * file specified by the given <code>DistributedSystem</code>. Note that this operation cannot be
     * performed in the constructor because creating regions in the cache, etc. uses the cache itself
     * (which isn't initialized until the constructor returns).
     *
     * @throws CacheXmlException If something goes wrong while parsing the declarative caching XML
     *         file.
     * @throws TimeoutException If a {@link org.apache.geode.cache.Region#put(Object, Object)}times
     *         out while initializing the cache.
     * @throws CacheWriterException If a <code>CacheWriterException</code> is thrown while
     *         initializing the cache.
     * @throws RegionExistsException If the declarative caching XML file desribes a region that
     *         already exists (including the root region).
     * @throws GatewayException If a <code>GatewayException</code> is thrown while initializing the
     *         cache.
     * 
     * @see #loadCacheXml
     */
    private void initializeDeclarativeCache()
            throws TimeoutException, CacheWriterException, GatewayException, RegionExistsException {
        URL url = getCacheXmlURL();
        String cacheXmlDescription = this.cacheConfig.getCacheXMLDescription();
        if (url == null && cacheXmlDescription == null) {
            if (isClient()) {
                determineDefaultPool();
                initializeClientRegionShortcuts(this);
            } else {
                initializeRegionShortcuts(this);
            }
            initializePdxRegistry();
            readyDynamicRegionFactory();
            return; // nothing needs to be done
        }

        try {
            logCacheXML(url, cacheXmlDescription);
            InputStream stream = null;
            if (cacheXmlDescription != null) {
                if (logger.isTraceEnabled()) {
                    logger.trace("initializing cache with generated XML: {}", cacheXmlDescription);
                }
                stream = new StringBufferInputStream(cacheXmlDescription);
            } else {
                stream = url.openStream();
            }
            loadCacheXml(stream);
            try {
                stream.close();
            } catch (IOException ignore) {
            }
        } catch (IOException ex) {
            throw new CacheXmlException(
                    LocalizedStrings.GemFireCache_WHILE_OPENING_CACHE_XML_0_THE_FOLLOWING_ERROR_OCCURRED_1
                            .toLocalizedString(new Object[] { url.toString(), ex }));

        } catch (CacheXmlException ex) {
            CacheXmlException newEx = new CacheXmlException(
                    LocalizedStrings.GemFireCache_WHILE_READING_CACHE_XML_0_1
                            .toLocalizedString(new Object[] { url, ex.getMessage() }));
            newEx.setStackTrace(ex.getStackTrace());
            newEx.initCause(ex.getCause());
            throw newEx;
        }
    }

    private void logCacheXML(URL url, String cacheXmlDescription) {
        if (cacheXmlDescription == null) {
            StringBuilder sb = new StringBuilder();
            try {
                final String EOLN = System.getProperty("line.separator");
                BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
                String l = br.readLine();
                while (l != null) {
                    if (!l.isEmpty()) {
                        sb.append(EOLN).append(l);
                    }
                    l = br.readLine();
                }
                br.close();
            } catch (IOException ignore) {
            }
            logger.info(LocalizedMessage.create(LocalizedStrings.GemFireCache_INITIALIZING_CACHE_USING__0__1,
                    new Object[] { url.toString(), sb.toString() }));
        } else {
            logger.info(LocalizedMessage.create(LocalizedStrings.GemFireCache_INITIALIZING_CACHE_USING__0__1,
                    new Object[] { "generated description from old cache", cacheXmlDescription }));
        }
    }

    public synchronized void initializePdxRegistry() {
        if (this.pdxRegistry == null) {
            // The member with locator is initialized with a NullTypePdxRegistration
            if (this.getMyId().getVmKind() == DistributionManager.LOCATOR_DM_TYPE) {
                this.pdxRegistry = new TypeRegistry(this, true);
            } else {
                this.pdxRegistry = new TypeRegistry(this, false);
            }
            this.pdxRegistry.initialize();
        }
    }

    /**
     * Call to make this vm's dynamic region factory ready. Public so it can be called from
     * CacheCreation during xml processing
     */
    public void readyDynamicRegionFactory() {
        try {
            ((DynamicRegionFactoryImpl) DynamicRegionFactory.get()).internalInit(this);
        } catch (CacheException ce) {
            throw new GemFireCacheException(
                    LocalizedStrings.GemFireCache_DYNAMIC_REGION_INITIALIZATION_FAILED.toLocalizedString(), ce);
        }
    }

    /**
     * create diskstore factory with default attributes
     *
     * @since GemFire prPersistSprint2
     */
    public DiskStoreFactory createDiskStoreFactory() {
        return new DiskStoreFactoryImpl(this);
    }

    /**
     * create diskstore factory with predefined attributes
     *
     * @since GemFire prPersistSprint2
     */
    public DiskStoreFactory createDiskStoreFactory(DiskStoreAttributes attrs) {
        return new DiskStoreFactoryImpl(this, attrs);
    }

    protected class Stopper extends CancelCriterion {

        /*
         * (non-Javadoc)
         *
         * @see org.apache.geode.CancelCriterion#cancelInProgress()
         */
        @Override
        public String cancelInProgress() {
            String reason = GemFireCacheImpl.this.getDistributedSystem().getCancelCriterion().cancelInProgress();
            if (reason != null) {
                return reason;
            }
            if (GemFireCacheImpl.this.disconnectCause != null) {
                return disconnectCause.getMessage();
            }
            if (GemFireCacheImpl.this.isClosing) {
                return "The cache is closed."; // this + ": closed";
            }
            return null;
        }

        /*
         * (non-Javadoc)
         *
         * @see org.apache.geode.CancelCriterion#generateCancelledException(java.lang.Throwable)
         */
        @Override
        public RuntimeException generateCancelledException(Throwable e) {
            String reason = cancelInProgress();
            if (reason == null) {
                return null;
            }
            RuntimeException result = getDistributedSystem().getCancelCriterion().generateCancelledException(e);
            if (result != null) {
                return result;
            }
            if (GemFireCacheImpl.this.disconnectCause == null) {
                // No root cause, specify the one given and be done with it.
                return new CacheClosedException(reason, e);
            }

            if (e == null) {
                // Caller did not specify any root cause, so just use our own.
                return new CacheClosedException(reason, GemFireCacheImpl.this.disconnectCause);
            }

            // Attempt to stick rootCause at tail end of the exception chain.
            Throwable nt = e;
            while (nt.getCause() != null) {
                nt = nt.getCause();
            }
            try {
                nt.initCause(GemFireCacheImpl.this.disconnectCause);
                return new CacheClosedException(reason, e);
            } catch (IllegalStateException e2) {
                // Bug 39496 (Jrockit related) Give up. The following
                // error is not entirely sane but gives the correct general picture.
                return new CacheClosedException(reason, GemFireCacheImpl.this.disconnectCause);
            }
        }
    }

    private final Stopper stopper = new Stopper();

    public CancelCriterion getCancelCriterion() {
        return stopper;
    }

    /** return true if the cache was closed due to being shunned by other members */
    public boolean forcedDisconnect() {
        return this.forcedDisconnect || this.system.forcedDisconnect();
    }

    /** return a CacheClosedException with the given reason */
    public CacheClosedException getCacheClosedException(String reason, Throwable cause) {
        CacheClosedException result;
        if (cause != null) {
            result = new CacheClosedException(reason, cause);
        } else if (this.disconnectCause != null) {
            result = new CacheClosedException(reason, this.disconnectCause);
        } else {
            result = new CacheClosedException(reason);
        }
        return result;
    }

    /** if the cache was forcibly closed this exception will reflect the cause */
    public Throwable getDisconnectCause() {
        return this.disconnectCause;
    }

    /**
     * Set to true during a cache close if user requested durable subscriptions to be kept.
     *
     * @since GemFire 5.7
     */
    private boolean keepAlive;

    /**
     * Returns true if durable subscriptions (registrations and queries) should be preserved.
     *
     * @since GemFire 5.7
     */
    public boolean keepDurableSubscriptionsAlive() {
        return this.keepAlive;
    }

    /**
     * break any potential circularity in {@link #loadEmergencyClasses()}
     */
    private static volatile boolean emergencyClassesLoaded = false;

    /**
     * Ensure that all the necessary classes for closing the cache are loaded
     *
     * @see SystemFailure#loadEmergencyClasses()
     */
    static public void loadEmergencyClasses() {
        if (emergencyClassesLoaded)
            return;
        emergencyClassesLoaded = true;
        InternalDistributedSystem.loadEmergencyClasses();
        AcceptorImpl.loadEmergencyClasses();
        PoolManagerImpl.loadEmergencyClasses();
    }

    /**
     * Close the distributed system, cache servers, and gateways. Clears the rootRegions and
     * partitionedRegions map. Marks the cache as closed.
     *
     * @see SystemFailure#emergencyClose()
     */
    static public void emergencyClose() {
        final boolean DEBUG = SystemFailure.TRACE_CLOSE;

        GemFireCacheImpl inst = GemFireCacheImpl.instance;
        if (inst == null) {
            if (DEBUG) {
                System.err.println("GemFireCache#emergencyClose: no instance");
            }
            return;
        }

        GemFireCacheImpl.instance = null;
        GemFireCacheImpl.pdxInstance = null;
        // leave the PdxSerializer set if we have one to prevent 43412
        // TypeRegistry.setPdxSerializer(null);

        // Shut down messaging first
        InternalDistributedSystem ids = inst.system;
        if (ids != null) {
            if (DEBUG) {
                System.err.println("DEBUG: emergencyClose InternalDistributedSystem");
            }
            ids.emergencyClose();
        }

        inst.disconnectCause = SystemFailure.getFailure();
        inst.isClosing = true;

        // Clear cache servers
        if (DEBUG) {
            System.err.println("DEBUG: Close cache servers");
        }
        {
            Iterator allCacheServersItr = inst.allCacheServers.iterator();
            while (allCacheServersItr.hasNext()) {
                CacheServerImpl bs = (CacheServerImpl) allCacheServersItr.next();
                AcceptorImpl ai = bs.getAcceptor();
                if (ai != null) {
                    ai.emergencyClose();
                }
            }
        }

        if (DEBUG) {
            System.err.println("DEBUG: closing client resources");
        }
        PoolManagerImpl.emergencyClose();

        if (DEBUG) {
            System.err.println("DEBUG: closing gateway hubs");
        }

        // These are synchronized sets -- avoid potential deadlocks
        // instance.pathToRegion.clear(); // garbage collection
        // instance.gatewayHubs.clear();

        // rootRegions is intentionally *not* synchronized. The
        // implementation of clear() does not currently allocate objects.
        inst.rootRegions.clear();
        // partitionedRegions is intentionally *not* synchronized, The
        // implementation of clear() does not currently allocate objects.
        inst.partitionedRegions.clear();
        if (DEBUG) {
            System.err.println("DEBUG: done with cache emergency close");
        }
    }

    public boolean isCacheAtShutdownAll() {
        return isShutDownAll.get();
    }

    /**
     * Number of threads used to close PRs in shutdownAll. By default is the number of PRs in the
     * cache
     */
    private static final int shutdownAllPoolSize = Integer
            .getInteger(DistributionConfig.GEMFIRE_PREFIX + "SHUTDOWN_ALL_POOL_SIZE", -1);

    void shutdownSubTreeGracefully(Map<String, PartitionedRegion> prSubMap) {
        for (final PartitionedRegion pr : prSubMap.values()) {
            shutDownOnePRGracefully(pr);
        }
    }

    public void shutDownAll() {
        if (LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER) {
            try {
                CacheObserverHolder.getInstance().beforeShutdownAll();
            } finally {
                LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = false;
            }
        }
        if (!this.isShutDownAll.compareAndSet(false, true)) {
            // it's already doing shutdown by another thread
            try {
                this.shutDownAllFinished.await();
            } catch (InterruptedException e) {
                logger.debug("Shutdown all interrupted while waiting for another thread to do the shutDownAll");
                Thread.currentThread().interrupt();
            }
            return;
        }
        synchronized (GemFireCacheImpl.class) {
            try {
                boolean testIGE = Boolean.getBoolean("TestInternalGemFireError");

                if (testIGE) {
                    InternalGemFireError assErr = new InternalGemFireError(
                            LocalizedStrings.GemFireCache_UNEXPECTED_EXCEPTION.toLocalizedString());
                    throw assErr;
                }

                // bug 44031 requires multithread shutdownall should be grouped
                // by root region. However, shutDownAllDuringRecovery.conf test revealed that
                // we have to close colocated child regions first.
                // Now check all the PR, if anyone has colocate-with attribute, sort all the
                // PRs by colocation relationship and close them sequentially, otherwise still
                // group them by root region.
                TreeMap<String, Map<String, PartitionedRegion>> prTrees = getPRTrees();
                if (prTrees.size() > 1 && shutdownAllPoolSize != 1) {
                    ExecutorService es = getShutdownAllExecutorService(prTrees.size());
                    for (final Map<String, PartitionedRegion> prSubMap : prTrees.values()) {
                        es.execute(new Runnable() {
                            public void run() {
                                ConnectionTable.threadWantsSharedResources();
                                shutdownSubTreeGracefully(prSubMap);
                            }
                        });
                    } // for each root
                    es.shutdown();
                    try {
                        es.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                    } catch (InterruptedException e) {
                        logger.debug("Shutdown all interrupted while waiting for PRs to be shutdown gracefully.");
                    }

                } else {
                    for (final Map<String, PartitionedRegion> prSubMap : prTrees.values()) {
                        shutdownSubTreeGracefully(prSubMap);
                    }
                }

                close("Shut down all members", null, false, true);
            } finally {
                this.shutDownAllFinished.countDown();
            }
        }
    }

    private ExecutorService getShutdownAllExecutorService(int size) {
        final ThreadGroup thrGrp = LoggingThreadGroup.createThreadGroup("ShutdownAllGroup", logger);
        ThreadFactory thrFactory = new ThreadFactory() {
            private final AtomicInteger threadCount = new AtomicInteger(1);

            public Thread newThread(Runnable r) {
                Thread t = new Thread(thrGrp, r, "ShutdownAll-" + threadCount.getAndIncrement());
                t.setDaemon(true);
                return t;
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(shutdownAllPoolSize == -1 ? size : shutdownAllPoolSize,
                thrFactory);
        return es;
    }

    private void shutDownOnePRGracefully(PartitionedRegion pr) {
        boolean acquiredLock = false;
        try {
            pr.acquireDestroyLock();
            acquiredLock = true;

            synchronized (pr.getRedundancyProvider()) {
                if (pr.isDataStore() && pr.getDataStore() != null
                        && pr.getDataPolicy() == DataPolicy.PERSISTENT_PARTITION) {
                    int numBuckets = pr.getTotalNumberOfBuckets();
                    Map<InternalDistributedMember, PersistentMemberID> bucketMaps[] = new Map[numBuckets];
                    PartitionedRegionDataStore prds = pr.getDataStore();

                    // lock all the primary buckets
                    Set<Entry<Integer, BucketRegion>> bucketEntries = prds.getAllLocalBuckets();
                    for (Map.Entry e : bucketEntries) {
                        BucketRegion br = (BucketRegion) e.getValue();
                        if (br == null || br.isDestroyed) {
                            // bucket region could be destroyed in race condition
                            continue;
                        }
                        br.getBucketAdvisor().tryLockIfPrimary();

                        // get map <InternalDistriutedMemeber, persistentID> for this bucket's
                        // remote members
                        bucketMaps[br.getId()] = br.getBucketAdvisor().adviseInitializedPersistentMembers();
                        if (logger.isDebugEnabled()) {
                            logger.debug("shutDownAll: PR {}: initialized persistent members for {}:{}",
                                    pr.getName(), br.getId(), bucketMaps[br.getId()]);
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("shutDownAll: All buckets for PR {} are locked.", pr.getName());
                    }

                    // send lock profile update to other members
                    pr.setShutDownAllStatus(PartitionedRegion.PRIMARY_BUCKETS_LOCKED);
                    new UpdateAttributesProcessor(pr).distribute(false);
                    pr.getRegionAdvisor().waitForProfileStatus(PartitionedRegion.PRIMARY_BUCKETS_LOCKED);
                    if (logger.isDebugEnabled()) {
                        logger.debug("shutDownAll: PR {}: all bucketlock profiles received.", pr.getName());
                    }

                    // if async write, do flush
                    if (!pr.getAttributes().isDiskSynchronous()) {
                        // several PRs might share the same diskstore, we will only flush once
                        // even flush is called several times.
                        pr.getDiskStore().forceFlush();
                        // send flush profile update to other members
                        pr.setShutDownAllStatus(PartitionedRegion.DISK_STORE_FLUSHED);
                        new UpdateAttributesProcessor(pr).distribute(false);
                        pr.getRegionAdvisor().waitForProfileStatus(PartitionedRegion.DISK_STORE_FLUSHED);
                        if (logger.isDebugEnabled()) {
                            logger.debug("shutDownAll: PR {}: all flush profiles received.", pr.getName());
                        }
                    } // async write

                    // persist other members to OFFLINE_EQUAL for each bucket region
                    // iterate through all the bucketMaps and exclude the items whose
                    // idm is no longer online
                    Set<InternalDistributedMember> membersToPersistOfflineEqual = pr.getRegionAdvisor()
                            .adviseDataStore();
                    for (Map.Entry e : bucketEntries) {
                        BucketRegion br = (BucketRegion) e.getValue();
                        if (br == null || br.isDestroyed) {
                            // bucket region could be destroyed in race condition
                            continue;
                        }
                        Map<InternalDistributedMember, PersistentMemberID> persistMap = getSubMapForLiveMembers(pr,
                                membersToPersistOfflineEqual, bucketMaps[br.getId()]);
                        if (persistMap != null) {
                            br.getPersistenceAdvisor().persistMembersOfflineAndEqual(persistMap);
                            if (logger.isDebugEnabled()) {
                                logger.debug("shutDownAll: PR {}: pesisting bucket {}:{}", pr.getName(), br.getId(),
                                        persistMap);
                            }
                        }
                    }

                    // send persited profile update to other members, let all members to persist
                    // before close the region
                    pr.setShutDownAllStatus(PartitionedRegion.OFFLINE_EQUAL_PERSISTED);
                    new UpdateAttributesProcessor(pr).distribute(false);
                    pr.getRegionAdvisor().waitForProfileStatus(PartitionedRegion.OFFLINE_EQUAL_PERSISTED);
                    if (logger.isDebugEnabled()) {
                        logger.debug("shutDownAll: PR {}: all offline_equal profiles received.", pr.getName());
                    }
                } // datastore

                // after done all steps for buckets, close pr
                // close accessor directly
                RegionEventImpl event = new RegionEventImpl(pr, Operation.REGION_CLOSE, null, false, getMyId(),
                        true);
                try {
                    // not to acquire lock
                    pr.basicDestroyRegion(event, false, false, true);
                } catch (CacheWriterException e) {
                    // not possible with local operation, CacheWriter not called
                    throw new Error(
                            LocalizedStrings.LocalRegion_CACHEWRITEREXCEPTION_SHOULD_NOT_BE_THROWN_IN_LOCALDESTROYREGION
                                    .toLocalizedString(),
                            e);
                } catch (TimeoutException e) {
                    // not possible with local operation, no distributed locks possible
                    throw new Error(
                            LocalizedStrings.LocalRegion_TIMEOUTEXCEPTION_SHOULD_NOT_BE_THROWN_IN_LOCALDESTROYREGION
                                    .toLocalizedString(),
                            e);
                }
                // pr.close();
            } // synchronized
        } catch (CacheClosedException cce) {
            logger.debug("Encounter CacheClosedException when shutDownAll is closing PR: {}:{}", pr.getFullPath(),
                    cce.getMessage());
        } catch (CancelException ce) {
            logger.debug("Encounter CancelException when shutDownAll is closing PR: {}:{}", pr.getFullPath(),
                    ce.getMessage());
        } catch (RegionDestroyedException rde) {
            logger.debug("Encounter CacheDestroyedException when shutDownAll is closing PR: {}:{}",
                    pr.getFullPath(), rde.getMessage());
        } finally {
            if (acquiredLock) {
                pr.releaseDestroyLock();
            }
        }
    }

    private Map<InternalDistributedMember, PersistentMemberID> getSubMapForLiveMembers(PartitionedRegion pr,
            Set<InternalDistributedMember> membersToPersistOfflineEqual,
            Map<InternalDistributedMember, PersistentMemberID> bucketMap) {
        if (bucketMap == null) {
            return null;
        }
        Map<InternalDistributedMember, PersistentMemberID> persistMap = new HashMap();
        Iterator itor = membersToPersistOfflineEqual.iterator();
        while (itor.hasNext()) {
            InternalDistributedMember idm = (InternalDistributedMember) itor.next();
            if (bucketMap.containsKey(idm)) {
                persistMap.put(idm, bucketMap.get(idm));
            }
        }
        return persistMap;
    }

    public void close() {
        close(false);
    }

    public void close(String reason, boolean keepalive, boolean keepDS) {
        close(reason, null, keepalive, keepDS);
    }

    public void close(boolean keepalive) {
        close("Normal disconnect", null, keepalive, false);
    }

    public void close(String reason, Throwable optionalCause) {
        close(reason, optionalCause, false, false);
    }

    /**
     * Gets or lazily creates the PartitionedRegion distributed lock service. This call will
     * synchronize on this GemFireCache.
     *
     * @return the PartitionedRegion distributed lock service
     */
    protected DistributedLockService getPartitionedRegionLockService() {
        synchronized (this.prLockServiceLock) {
            stopper.checkCancelInProgress(null);
            if (this.prLockService == null) {
                try {
                    this.prLockService = DLockService.create(PartitionedRegionHelper.PARTITION_LOCK_SERVICE_NAME,
                            getDistributedSystem(), true /* distributed */, true /* destroyOnDisconnect */,
                            true /* automateFreeResources */);
                } catch (IllegalArgumentException e) {
                    this.prLockService = DistributedLockService
                            .getServiceNamed(PartitionedRegionHelper.PARTITION_LOCK_SERVICE_NAME);
                    if (this.prLockService == null) {
                        throw e; // PARTITION_LOCK_SERVICE_NAME must be illegal!
                    }
                }
            }
            return this.prLockService;
        }
    }

    /**
     * Gets or lazily creates the GatewaySender distributed lock service.
     * 
     * @return the GatewaySender distributed lock service
     */
    public DistributedLockService getGatewaySenderLockService() {
        if (this.gatewayLockService == null) {
            synchronized (this.gatewayLockServiceLock) {
                stopper.checkCancelInProgress(null);
                if (this.gatewayLockService == null) {
                    try {
                        this.gatewayLockService = DLockService.create(AbstractGatewaySender.LOCK_SERVICE_NAME,
                                getDistributedSystem(), true /* distributed */, true /* destroyOnDisconnect */,
                                true /* automateFreeResources */);
                    } catch (IllegalArgumentException e) {
                        this.gatewayLockService = DistributedLockService
                                .getServiceNamed(AbstractGatewaySender.LOCK_SERVICE_NAME);
                        if (this.gatewayLockService == null) {
                            throw e; // AbstractGatewaySender.LOCK_SERVICE_NAME must be illegal!
                        }
                    }
                }
            }
        }
        return this.gatewayLockService;
    }

    /**
     * Destroys the PartitionedRegion distributed lock service when closing the cache. Caller must be
     * synchronized on this GemFireCache.
     */
    private void destroyPartitionedRegionLockService() {
        try {
            DistributedLockService.destroy(PartitionedRegionHelper.PARTITION_LOCK_SERVICE_NAME);
        } catch (IllegalArgumentException e) {
            // DistributedSystem.disconnect may have already destroyed the DLS
        }
    }

    /**
     * Destroys the GatewaySender distributed lock service when closing the cache. Caller must be
     * synchronized on this GemFireCache.
     */
    private void destroyGatewaySenderLockService() {
        if (DistributedLockService.getServiceNamed(AbstractGatewaySender.LOCK_SERVICE_NAME) != null) {
            try {
                DistributedLockService.destroy(AbstractGatewaySender.LOCK_SERVICE_NAME);
            } catch (IllegalArgumentException e) {
                // DistributedSystem.disconnect may have already destroyed the DLS
            }
        }
    }

    public HeapEvictor getHeapEvictor() {
        synchronized (this.heapEvictorLock) {
            stopper.checkCancelInProgress(null);
            if (this.heapEvictor == null) {
                this.heapEvictor = new HeapEvictor(this);
            }
            return this.heapEvictor;
        }
    }

    public OffHeapEvictor getOffHeapEvictor() {
        synchronized (this.offHeapEvictorLock) {
            stopper.checkCancelInProgress(null);
            if (this.offHeapEvictor == null) {
                this.offHeapEvictor = new OffHeapEvictor(this);
            }
            return this.offHeapEvictor;
        }
    }

    public PersistentMemberManager getPersistentMemberManager() {
        return persistentMemberManager;
    }

    public ClientMetadataService getClientMetadataService() {
        synchronized (this.clientMetaDatServiceLock) {
            stopper.checkCancelInProgress(null);
            if (this.clientMetadatService == null) {
                this.clientMetadatService = new ClientMetadataService(this);
            }
            return this.clientMetadatService;
        }
    }

    private final boolean DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE = Boolean
            .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE");

    /**
     * close the cache
     *
     * @param reason the reason the cache is being closed
     * @param systemFailureCause whether this member was ejected from the distributed system
     * @param keepalive whoever added this should javadoc it
     */
    public void close(String reason, Throwable systemFailureCause, boolean keepalive) {
        close(reason, systemFailureCause, keepalive, false);
    }

    public void close(String reason, Throwable systemFailureCause, boolean keepalive, boolean keepDS) {
        securityService.close();

        if (isClosed()) {
            return;
        }
        final boolean isDebugEnabled = logger.isDebugEnabled();

        synchronized (GemFireCacheImpl.class) {
            // bugfix for bug 36512 "GemFireCache.close is not thread safe"
            // ALL CODE FOR CLOSE SHOULD NOW BE UNDER STATIC SYNCHRONIZATION
            // OF synchronized (GemFireCache.class) {
            // static synchronization is necessary due to static resources
            if (isClosed()) {
                return;
            }

            /**
             * First close the ManagementService as it uses a lot of infra which will be closed by
             * cache.close()
             **/
            system.handleResourceEvent(ResourceEvent.CACHE_REMOVE, this);
            if (this.listener != null) {
                this.system.removeResourceListener(listener);
                this.listener = null;
            }

            if (systemFailureCause != null) {
                this.forcedDisconnect = systemFailureCause instanceof ForcedDisconnectException;
                if (this.forcedDisconnect) {
                    this.disconnectCause = new ForcedDisconnectException(reason);
                } else {
                    this.disconnectCause = systemFailureCause;
                }
            }

            this.keepAlive = keepalive;
            isClosing = true;
            logger.info(LocalizedMessage.create(LocalizedStrings.GemFireCache_0_NOW_CLOSING, this));

            // Before anything else...make sure that this instance is not
            // available to anyone "fishing" for a cache...
            if (GemFireCacheImpl.instance == this) {
                GemFireCacheImpl.instance = null;
            }

            // we don't clear the prID map if there is a system failure. Other
            // threads may be hung trying to communicate with the map locked
            if (systemFailureCause == null) {
                PartitionedRegion.clearPRIdMap();
            }
            TXStateProxy tx = null;
            try {

                if (this.txMgr != null) {
                    tx = this.txMgr.internalSuspend();
                }

                // do this before closing regions
                resourceManager.close();

                try {
                    this.resourceAdvisor.close();
                } catch (CancelException e) {
                    // ignore
                }
                try {
                    this.jmxAdvisor.close();
                } catch (CancelException e) {
                    // ignore
                }

                GatewaySenderAdvisor advisor = null;
                for (GatewaySender sender : this.getAllGatewaySenders()) {
                    try {
                        sender.stop();
                        advisor = ((AbstractGatewaySender) sender).getSenderAdvisor();
                        if (advisor != null) {
                            if (isDebugEnabled) {
                                logger.debug("Stopping the GatewaySender advisor");
                            }
                            advisor.close();
                        }
                    } catch (CancelException ce) {
                    }
                }

                destroyGatewaySenderLockService();

                if (this.eventThreadPool != null) {
                    if (isDebugEnabled) {
                        logger.debug("{}: stopping event thread pool...", this);
                    }
                    this.eventThreadPool.shutdown();
                }

                /*
                 * IMPORTANT: any operation during shut down that can time out (create a CancelException)
                 * must be inside of this try block. If all else fails, we *must* ensure that the cache gets
                 * closed!
                 */
                try {
                    this.stopServers();

                    stopMemcachedServer();

                    stopRedisServer();

                    // no need to track PR instances since we won't create any more
                    // cacheServers or gatewayHubs
                    if (this.partitionedRegions != null) {
                        if (isDebugEnabled) {
                            logger.debug("{}: clearing partitioned regions...", this);
                        }
                        synchronized (this.partitionedRegions) {
                            int prSize = -this.partitionedRegions.size();
                            this.partitionedRegions.clear();
                            getCachePerfStats().incPartitionedRegions(prSize);
                        }
                    }

                    prepareDiskStoresForClose();
                    if (GemFireCacheImpl.pdxInstance == this) {
                        GemFireCacheImpl.pdxInstance = null;
                    }

                    List rootRegionValues = null;
                    synchronized (this.rootRegions) {
                        rootRegionValues = new ArrayList(this.rootRegions.values());
                    }
                    {
                        final Operation op;
                        if (this.forcedDisconnect) {
                            op = Operation.FORCED_DISCONNECT;
                        } else if (isReconnecting()) {
                            op = Operation.CACHE_RECONNECT;
                        } else {
                            op = Operation.CACHE_CLOSE;
                        }

                        LocalRegion prRoot = null;

                        for (Iterator itr = rootRegionValues.iterator(); itr.hasNext();) {
                            LocalRegion lr = (LocalRegion) itr.next();
                            if (isDebugEnabled) {
                                logger.debug("{}: processing region {}", this, lr.getFullPath());
                            }
                            if (PartitionedRegionHelper.PR_ROOT_REGION_NAME.equals(lr.getName())) {
                                prRoot = lr;
                            } else {
                                if (lr.getName().contains(ParallelGatewaySenderQueue.QSTRING)) {
                                    continue; // this region will be closed internally by parent region
                                }
                                if (isDebugEnabled) {
                                    logger.debug("{}: closing region {}...", this, lr.getFullPath());
                                }
                                try {
                                    lr.handleCacheClose(op);
                                } catch (Exception e) {
                                    if (isDebugEnabled || !forcedDisconnect) {
                                        logger.warn(LocalizedMessage.create(
                                                LocalizedStrings.GemFireCache_0_ERROR_CLOSING_REGION_1,
                                                new Object[] { this, lr.getFullPath() }), e);
                                    }
                                }
                            }
                        } // for

                        try {
                            if (isDebugEnabled) {
                                logger.debug("{}: finishing partitioned region close...", this);
                            }
                            PartitionedRegion.afterRegionsClosedByCacheClose(this);
                            if (prRoot != null) {
                                // do the PR meta root region last
                                prRoot.handleCacheClose(op);
                            }
                        } catch (CancelException e) {
                            logger.warn(LocalizedMessage.create(
                                    LocalizedStrings.GemFireCache_0_ERROR_IN_LAST_STAGE_OF_PARTITIONEDREGION_CACHE_CLOSE,
                                    this), e);
                        }
                        destroyPartitionedRegionLockService();
                    }

                    closeDiskStores();
                    diskMonitor.close();

                    // Close the CqService Handle.
                    try {
                        if (isDebugEnabled) {
                            logger.debug("{}: closing CQ service...", this);
                        }
                        cqService.close();
                    } catch (Exception ex) {
                        logger.info(LocalizedMessage.create(
                                LocalizedStrings.GemFireCache_FAILED_TO_GET_THE_CQSERVICE_TO_CLOSE_DURING_CACHE_CLOSE_1));
                    }

                    PoolManager.close(keepalive);

                    if (isDebugEnabled) {
                        logger.debug("{}: closing reliable message queue...", this);
                    }
                    try {
                        getReliableMessageQueueFactory().close(true);
                    } catch (CancelException e) {
                        if (isDebugEnabled) {
                            logger.debug("Ignored cancellation while closing reliable message queue", e);
                        }
                    }

                    if (isDebugEnabled) {
                        logger.debug("{}: notifying admins of close...", this);
                    }
                    try {
                        SystemMemberCacheEventProcessor.send(this, Operation.CACHE_CLOSE);
                    } catch (CancelException e) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Ignored cancellation while notifying admins");
                        }
                    }

                    if (isDebugEnabled) {
                        logger.debug("{}: stopping destroyed entries processor...", this);
                    }
                    this.tombstoneService.stop();

                    // NOTICE: the CloseCache message is the *last* message you can send!
                    DM dm = null;
                    try {
                        dm = system.getDistributionManager();
                        dm.removeMembershipListener(this.txMgr);
                    } catch (CancelException e) {
                        // dm = null;
                    }

                    if (dm != null) { // Send CacheClosedMessage (and NOTHING ELSE) here
                        if (isDebugEnabled) {
                            logger.debug("{}: sending CloseCache to peers...", this);
                        }
                        Set otherMembers = dm.getOtherDistributionManagerIds();
                        ReplyProcessor21 processor = new ReplyProcessor21(system, otherMembers);
                        CloseCacheMessage msg = new CloseCacheMessage();
                        msg.setRecipients(otherMembers);
                        msg.setProcessorId(processor.getProcessorId());
                        dm.putOutgoing(msg);
                        try {
                            processor.waitForReplies();
                        } catch (InterruptedException ex) {
                            // Thread.currentThread().interrupt(); // TODO ??? should we reset this bit later?
                            // Keep going, make best effort to shut down.
                        } catch (ReplyException ex) {
                            // keep going
                        }
                        // set closed state after telling others and getting responses
                        // to avoid complications with others still in the process of
                        // sending messages
                    }
                    // NO MORE Distributed Messaging AFTER THIS POINT!!!!

                    {
                        ClientMetadataService cms = this.clientMetadatService;
                        if (cms != null) {
                            cms.close();
                        }
                        HeapEvictor he = this.heapEvictor;
                        if (he != null) {
                            he.close();
                        }
                    }
                } catch (CancelException e) {
                    // make sure the disk stores get closed
                    closeDiskStores();
                    // NO DISTRIBUTED MESSAGING CAN BE DONE HERE!

                    // okay, we're taking too long to do this stuff, so let's
                    // be mean to other processes and skip the rest of the messaging
                    // phase
                    // [bruce] the following code is unnecessary since someone put the
                    // same actions in a finally block
                    // if (!this.closed) {
                    // this.closed = true;
                    // this.txMgr.close();
                    // if (GemFireCache.instance == this) {
                    // GemFireCache.instance = null;
                    // }
                    // ((DynamicRegionFactoryImpl)DynamicRegionFactory.get()).close();
                    // }
                }

                // Close the CqService Handle.
                try {
                    cqService.close();
                } catch (Exception ex) {
                    logger.info(LocalizedMessage.create(
                            LocalizedStrings.GemFireCache_FAILED_TO_GET_THE_CQSERVICE_TO_CLOSE_DURING_CACHE_CLOSE_2));
                }

                this.cachePerfStats.close();
                TXLockService.destroyServices();

                EventTracker.stopTrackerServices(this);

                synchronized (ccpTimerMutex) {
                    if (this.ccpTimer != null) {
                        this.ccpTimer.cancel();
                    }
                }

                this.expirationScheduler.cancel();

                // Stop QueryMonitor if running.
                if (this.queryMonitor != null) {
                    this.queryMonitor.stopMonitoring();
                }
                stopDiskStoreTaskPool();

            } finally {
                // NO DISTRIBUTED MESSAGING CAN BE DONE HERE!
                if (this.txMgr != null) {
                    this.txMgr.close();
                }
                ((DynamicRegionFactoryImpl) DynamicRegionFactory.get()).close();
                if (this.txMgr != null) {
                    this.txMgr.resume(tx);
                }
                TXCommitMessage.getTracker().clearForCacheClose();
            }
            // Added to close the TransactionManager's cleanup thread
            TransactionManagerImpl.refresh();

            if (!keepDS) {
                // keepDS is used by ShutdownAll. It will override DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE
                if (!DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE) {
                    this.system.disconnect();
                }
            }
            TypeRegistry.close();
            // do this late to prevent 43412
            TypeRegistry.setPdxSerializer(null);

            for (Iterator iter = cacheLifecycleListeners.iterator(); iter.hasNext();) {
                CacheLifecycleListener listener = (CacheLifecycleListener) iter.next();
                listener.cacheClosed(this);
            }
            stopRestAgentServer();
            // Fix for #49856
            SequenceLoggerImpl.signalCacheClose();
            SystemFailure.signalCacheClose();

        } // static synchronization on GemFireCache.class

    }

    // see Cache.isReconnecting()
    public boolean isReconnecting() {
        return this.system.isReconnecting();
    }

    // see Cache.waitUntilReconnected(long, TimeUnit)
    public boolean waitUntilReconnected(long time, TimeUnit units) throws InterruptedException {
        boolean systemReconnected = this.system.waitUntilReconnected(time, units);
        if (!systemReconnected) {
            return false;
        }
        GemFireCacheImpl cache = getInstance();
        if (cache == null || !cache.isInitialized()) {
            return false;
        }
        return true;
    }

    // see Cache.stopReconnecting()
    public void stopReconnecting() {
        this.system.stopReconnecting();
    }

    // see Cache.getReconnectedCache()
    public Cache getReconnectedCache() {
        GemFireCacheImpl c = GemFireCacheImpl.getInstance();
        if (c == null) {
            return null;
        }
        if (c == this || !c.isInitialized()) {
            c = null;
        }
        return c;
    }

    private void stopMemcachedServer() {
        if (this.memcachedServer != null) {
            logger.info(LocalizedMessage.create(
                    LocalizedStrings.GemFireCacheImpl_MEMCACHED_SERVER_ON_PORT_0_IS_SHUTTING_DOWN,
                    new Object[] { this.system.getConfig().getMemcachedPort() }));
            this.memcachedServer.shutdown();
        }
    }

    private void stopRedisServer() {
        if (redisServer != null)
            this.redisServer.shutdown();
    }

    private void stopRestAgentServer() {
        if (this.restAgent != null) {
            logger.info(LocalizedMessage.create(
                    LocalizedStrings.GemFireCacheImpl_REST_SERVER_ON_PORT_0_IS_SHUTTING_DOWN,
                    new Object[] { this.system.getConfig().getHttpServicePort() }));
            this.restAgent.stop();
        }
    }

    private void prepareDiskStoresForClose() {
        String pdxDSName = TypeRegistry.getPdxDiskStoreName(this);
        DiskStoreImpl pdxdsi = null;
        for (DiskStoreImpl dsi : this.diskStores.values()) {
            if (dsi.getName().equals(pdxDSName)) {
                pdxdsi = dsi;
            } else {
                dsi.prepareForClose();
            }
        }
        if (pdxdsi != null) {
            pdxdsi.prepareForClose();
        }
    }

    /**
     * Used to guard access to compactorPool and set to true when cache is shutdown.
     */
    private final AtomicBoolean diskStoreTaskSync = new AtomicBoolean(false);
    /**
     * Lazily initialized.
     */
    private ThreadPoolExecutor diskStoreTaskPool = null;

    private void createDiskStoreTaskPool() {
        int MAXT = DiskStoreImpl.MAX_CONCURRENT_COMPACTIONS;
        final ThreadGroup compactThreadGroup = LoggingThreadGroup.createThreadGroup("Oplog Compactor Thread Group",
                logger);
        /*
         * final ThreadFactory compactThreadFactory = new ThreadFactory() { public Thread
         * newThread(Runnable command) { Thread thread = new Thread(compactThreadGroup, command,
         * "Idle OplogCompactor"); thread.setDaemon(true); return thread; } };
         */

        final ThreadFactory compactThreadFactory = GemfireCacheHelper.CreateThreadFactory(compactThreadGroup,
                "Idle OplogCompactor");
        this.diskStoreTaskPool = new ThreadPoolExecutor(MAXT, MAXT, 1, TimeUnit.SECONDS, new LinkedBlockingQueue(),
                compactThreadFactory);
    }

    private final ConcurrentMap<String, DiskStoreImpl> diskStores = new ConcurrentHashMap<String, DiskStoreImpl>();
    private final ConcurrentMap<String, DiskStoreImpl> regionOwnedDiskStores = new ConcurrentHashMap<String, DiskStoreImpl>();

    public void addDiskStore(DiskStoreImpl dsi) {
        this.diskStores.put(dsi.getName(), dsi);
        if (!dsi.isOffline()) {
            getDiskStoreMonitor().addDiskStore(dsi);
        }
    }

    public void removeDiskStore(DiskStoreImpl dsi) {
        this.diskStores.remove(dsi.getName());
        this.regionOwnedDiskStores.remove(dsi.getName());
        /** Added for M&M **/
        if (!dsi.getOwnedByRegion())
            system.handleResourceEvent(ResourceEvent.DISKSTORE_REMOVE, dsi);
    }

    public void addRegionOwnedDiskStore(DiskStoreImpl dsi) {
        this.regionOwnedDiskStores.put(dsi.getName(), dsi);
        if (!dsi.isOffline()) {
            getDiskStoreMonitor().addDiskStore(dsi);
        }
    }

    public void closeDiskStores() {
        Iterator<DiskStoreImpl> it = this.diskStores.values().iterator();
        while (it.hasNext()) {
            try {
                DiskStoreImpl dsi = it.next();
                if (logger.isDebugEnabled()) {
                    logger.debug("closing {}", dsi);
                }
                dsi.close();
                /** Added for M&M **/
                system.handleResourceEvent(ResourceEvent.DISKSTORE_REMOVE, dsi);
            } catch (Exception e) {
                logger.fatal(LocalizedMessage.create(LocalizedStrings.Disk_Store_Exception_During_Cache_Close), e);
            }
            it.remove();
        }
    }

    /**
     * Used by unit tests to allow them to change the default disk store name.
     */
    public static void setDefaultDiskStoreName(String dsName) {
        DEFAULT_DS_NAME = dsName;
    }

    /**
     * Used by unit tests to undo a change to the default disk store name.
     */
    public static void unsetDefaultDiskStoreName() {
        DEFAULT_DS_NAME = DiskStoreFactory.DEFAULT_DISK_STORE_NAME;
    }

    public static String getDefaultDiskStoreName() {
        return DEFAULT_DS_NAME;
    }

    public static String DEFAULT_DS_NAME = DiskStoreFactory.DEFAULT_DISK_STORE_NAME;

    public DiskStoreImpl getOrCreateDefaultDiskStore() {
        DiskStoreImpl result = (DiskStoreImpl) findDiskStore(null);
        if (result == null) {
            synchronized (this) {
                result = (DiskStoreImpl) findDiskStore(null);
                if (result == null) {
                    result = (DiskStoreImpl) createDiskStoreFactory().create(DEFAULT_DS_NAME);
                }
            }
        }
        return result;
    }

    /**
     * Returns the DiskStore by name
     *
     * @since GemFire prPersistSprint2
     */
    public DiskStore findDiskStore(String name) {
        if (name == null) {
            name = DEFAULT_DS_NAME;
        }
        return this.diskStores.get(name);
    }

    /**
     * Returns the DiskStore list
     *
     * @since GemFire prPersistSprint2
     */
    public Collection<DiskStoreImpl> listDiskStores() {
        return Collections.unmodifiableCollection(this.diskStores.values());
    }

    public Collection<DiskStoreImpl> listDiskStoresIncludingDefault() {
        return Collections.unmodifiableCollection(listDiskStores());
    }

    public Collection<DiskStoreImpl> listDiskStoresIncludingRegionOwned() {
        HashSet<DiskStoreImpl> allDiskStores = new HashSet<DiskStoreImpl>();
        allDiskStores.addAll(this.diskStores.values());
        allDiskStores.addAll(this.regionOwnedDiskStores.values());
        return allDiskStores;
    }

    public boolean executeDiskStoreTask(DiskStoreTask r) {
        synchronized (this.diskStoreTaskSync) {
            if (!this.diskStoreTaskSync.get()) {
                if (this.diskStoreTaskPool == null) {
                    createDiskStoreTaskPool();
                }
                try {
                    this.diskStoreTaskPool.execute(r);
                    return true;
                } catch (RejectedExecutionException ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Ignored compact schedule during shutdown", ex);
                    }
                }
            }
        }
        return false;
    }

    /*
     * private static class DiskStoreFuture extends FutureTask { private DiskStoreTask task;
     * 
     * public DiskStoreFuture(DiskStoreTask r) { super(r, null); this.task = r; }
     * 
     * @Override public boolean cancel(boolean mayInterruptIfRunning) { boolean result =
     * super.cancel(mayInterruptIfRunning); if (result) { task.taskCancelled(); } return result; }
     * 
     * }
     */

    private void stopDiskStoreTaskPool() {
        synchronized (this.diskStoreTaskSync) {
            this.diskStoreTaskSync.set(true);
            // All the regions have already been closed
            // so this pool shouldn't be doing anything.
            if (this.diskStoreTaskPool != null) {
                List<Runnable> l = this.diskStoreTaskPool.shutdownNow();
                for (Runnable runnable : l) {
                    if (l instanceof DiskStoreTask) {
                        ((DiskStoreTask) l).taskCancelled();
                    }
                }
            }
            // this.diskStoreTaskPool = null;
        }
    }

    public int stopGatewaySenders(boolean byShutdownAll) {
        final boolean isDebugEnabled = logger.isDebugEnabled();

        int cnt = 0;
        closingGatewaySendersByShutdownAll = byShutdownAll;
        synchronized (allGatewaySendersLock) {
            GatewaySenderAdvisor advisor = null;
            Iterator<GatewaySender> itr = allGatewaySenders.iterator();
            while (itr.hasNext()) {
                GatewaySender sender = itr.next();
                if (isDebugEnabled) {
                    logger.debug("{}: stopping gateway sender {}", this, sender);
                }
                try {
                    sender.stop();
                    advisor = ((AbstractGatewaySender) sender).getSenderAdvisor();
                    if (advisor != null) {
                        if (isDebugEnabled) {
                            logger.debug("Stopping the GatewaySender advisor");
                        }
                        advisor.close();
                    }
                    cnt++;
                } catch (CancelException e) {
                    if (isDebugEnabled) {
                        logger.debug("Ignored cache closure while closing sender {}", sender, e);
                    }
                }
            }
        } // synchronized

        destroyGatewaySenderLockService();

        if (isDebugEnabled) {
            logger.debug("{}: finished stopping {} gateway sender(s), total is {}", this, cnt,
                    allGatewaySenders.size());
        }
        return cnt;
    }

    public int stopGatewayReceivers(boolean byShutdownAll) {
        int cnt = 0;
        closingGatewayReceiversByShutdownAll = byShutdownAll;
        synchronized (allGatewayReceiversLock) {
            Iterator<GatewayReceiver> itr = allGatewayReceivers.iterator();
            while (itr.hasNext()) {
                GatewayReceiver receiver = itr.next();
                if (logger.isDebugEnabled()) {
                    logger.debug("{}: stopping gateway receiver {}", this, receiver);
                }
                try {
                    receiver.stop();
                    cnt++;
                } catch (CancelException e) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Ignored cache closure while closing receiver {}", receiver, e);
                    }
                }
            }
        } // synchronized

        if (logger.isDebugEnabled()) {
            logger.debug("{}: finished stopping {} gateway receiver(s), total is {}", this, cnt,
                    allGatewayReceivers.size());
        }
        return cnt;
    }

    void stopServers() {

        final boolean isDebugEnabled = logger.isDebugEnabled();

        if (isDebugEnabled) {
            logger.debug("{}: stopping cache servers...", this);
        }
        boolean stoppedCacheServer = false;
        Iterator allCacheServersIterator = this.allCacheServers.iterator();
        while (allCacheServersIterator.hasNext()) {
            CacheServerImpl bridge = (CacheServerImpl) allCacheServersIterator.next();
            if (isDebugEnabled) {
                logger.debug("stopping bridge {}", bridge);
            }
            try {
                bridge.stop();
            } catch (CancelException e) {
                if (isDebugEnabled) {
                    logger.debug("Ignored cache closure while closing bridge {}", bridge, e);
                }
            }
            allCacheServers.remove(bridge);
            stoppedCacheServer = true;
        }
        if (stoppedCacheServer) {
            // now that all the cache servers have stopped empty the static pool of commBuffers it might
            // have used.
            ServerConnection.emptyCommBufferPool();
        }

        // stop HA services if they had been started
        if (isDebugEnabled) {
            logger.debug("{}: stopping HA services...", this);
        }
        try {
            HARegionQueue.stopHAServices();
        } catch (CancelException e) {
            if (isDebugEnabled) {
                logger.debug("Ignored cache closure while closing HA services", e);
            }
        }

        if (isDebugEnabled) {
            logger.debug("{}: stopping client health monitor...", this);
        }
        try {
            ClientHealthMonitor.shutdownInstance();
        } catch (CancelException e) {
            if (isDebugEnabled) {
                logger.debug("Ignored cache closure while closing client health monitor", e);
            }
        }

        // Reset the unique id counter for durable clients.
        // If a durable client stops/starts its cache, it needs
        // to maintain the same unique id.
        ClientProxyMembershipID.resetUniqueIdCounter();

    }

    public InternalDistributedSystem getDistributedSystem() {
        return this.system;
    }

    /**
     * Returns the member id of my distributed system
     *
     * @since GemFire 5.0
     */
    public InternalDistributedMember getMyId() {
        return this.system.getDistributedMember();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.geode.cache.Cache#getMembers()
     */
    public Set<DistributedMember> getMembers() {
        return Collections.unmodifiableSet(this.dm.getOtherNormalDistributionManagerIds());
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.geode.cache.Cache#getAdminMembers()
     */
    public Set<DistributedMember> getAdminMembers() {
        return this.dm.getAdminMemberSet();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.geode.cache.Cache#getMembers(org.apache.geode.cache.Region)
     */
    public Set<DistributedMember> getMembers(Region r) {
        if (r instanceof DistributedRegion) {
            DistributedRegion d = (DistributedRegion) r;
            return d.getDistributionAdvisor().adviseCacheOp();
        } else if (r instanceof PartitionedRegion) {
            PartitionedRegion p = (PartitionedRegion) r;
            return p.getRegionAdvisor().adviseAllPRNodes();
        } else {
            return Collections.EMPTY_SET;
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.geode.cache.client.ClientCache#getCurrentServers()
     */
    public Set<InetSocketAddress> getCurrentServers() {
        Map<String, Pool> pools = PoolManager.getAll();
        Set result = null;
        for (Pool p : pools.values()) {
            PoolImpl pi = (PoolImpl) p;
            for (Object o : pi.getCurrentServers()) {
                ServerLocation sl = (ServerLocation) o;
                if (result == null) {
                    result = new HashSet<DistributedMember>();
                }
                result.add(new InetSocketAddress(sl.getHostName(), sl.getPort()));
            }
        }
        if (result == null) {
            return Collections.EMPTY_SET;
        } else {
            return result;
        }
    }

    public LogWriter getLogger() {
        return this.system.getLogWriter();
    }

    public LogWriter getSecurityLogger() {
        return this.system.getSecurityLogWriter();
    }

    public LogWriterI18n getLoggerI18n() {
        return this.system.getInternalLogWriter();
    }

    public LogWriterI18n getSecurityLoggerI18n() {
        return this.system.getSecurityInternalLogWriter();
    }

    public InternalLogWriter getInternalLogWriter() {
        return this.system.getInternalLogWriter();
    }

    public InternalLogWriter getSecurityInternalLogWriter() {
        return this.system.getSecurityInternalLogWriter();
    }

    /**
     * get the threadid/sequenceid sweeper task for this cache
     *
     * @return the sweeper task
     */
    protected EventTracker.ExpiryTask getEventTrackerTask() {
        return this.recordedEventSweeper;
    }

    public CachePerfStats getCachePerfStats() {
        return this.cachePerfStats;
    }

    public String getName() {
        return this.system.getName();
    }

    /**
     * Get the list of all instances of properties for Declarables with the given class name.
     * 
     * @param className Class name of the declarable
     * @return List of all instances of properties found for the given declarable
     */
    public List<Properties> getDeclarableProperties(final String className) {
        List<Properties> propertiesList = new ArrayList<Properties>();
        synchronized (this.declarablePropertiesMap) {
            for (Map.Entry<Declarable, Properties> entry : this.declarablePropertiesMap.entrySet()) {
                if (entry.getKey().getClass().getName().equals(className)) {
                    propertiesList.add(entry.getValue());
                }
            }
        }
        return propertiesList;
    }

    /**
     * Get the properties for the given declarable.
     * 
     * @param declarable The declarable
     * @return Properties found for the given declarable
     */
    public Properties getDeclarableProperties(final Declarable declarable) {
        return this.declarablePropertiesMap.get(declarable);
    }

    /**
     * Returns the date and time that this cache was created.
     *
     * @since GemFire 3.5
     */
    public Date getCreationDate() {
        return this.creationDate;
    }

    /**
     * Returns the number of seconds that have elapsed since the Cache was created.
     *
     * @since GemFire 3.5
     */
    public int getUpTime() {
        return (int) ((System.currentTimeMillis() - this.creationDate.getTime()) / 1000);
    }

    /**
     * All entry and region operations should be using this time rather than
     * System.currentTimeMillis(). Specially all version stamps/tags must be populated with this
     * timestamp.
     * 
     * @return distributed cache time.
     */
    @Override
    public long cacheTimeMillis() {
        if (this.system != null) {
            return this.system.getClock().cacheTimeMillis();
        } else {
            return System.currentTimeMillis();
        }
    }

    public Region createVMRegion(String name, RegionAttributes attrs)
            throws RegionExistsException, TimeoutException {
        return createRegion(name, attrs);
    }

    private PoolFactory createDefaultPF() {
        PoolFactory defpf = PoolManager.createFactory();
        try {
            String localHostName = SocketCreator.getHostName(SocketCreator.getLocalHost());
            defpf.addServer(localHostName, CacheServer.DEFAULT_PORT);
        } catch (UnknownHostException ex) {
            throw new IllegalStateException("Could not determine local host name");
        }
        return defpf;
    }

    /**
     * Used to set the default pool on a new GemFireCache.
     */
    public void determineDefaultPool() {
        if (!isClient()) {
            throw new UnsupportedOperationException();
        }
        Pool pool = null;
        // create the pool if it does not already exist
        if (this.clientpf == null) {
            Map<String, Pool> pools = PoolManager.getAll();
            if (pools.isEmpty()) {
                this.clientpf = createDefaultPF();
            } else if (pools.size() == 1) {
                // otherwise use a singleton.
                pool = pools.values().iterator().next();
            } else {
                if (pool == null) {
                    // act as if the default pool was configured
                    // and see if we can find an existing one that is compatible
                    PoolFactoryImpl pfi = (PoolFactoryImpl) createDefaultPF();
                    for (Pool p : pools.values()) {
                        if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) {
                            pool = p;
                            break;
                        }
                    }
                    if (pool == null) {
                        // if pool is still null then we will not have a default pool for this ClientCache
                        setDefaultPool(null);
                        return;
                    }
                }
            }
        } else {
            PoolFactoryImpl pfi = (PoolFactoryImpl) this.clientpf;
            if (pfi.getPoolAttributes().locators.isEmpty() && pfi.getPoolAttributes().servers.isEmpty()) {
                try {
                    String localHostName = SocketCreator.getHostName(SocketCreator.getLocalHost());
                    pfi.addServer(localHostName, CacheServer.DEFAULT_PORT);
                } catch (UnknownHostException ex) {
                    throw new IllegalStateException("Could not determine local host name");
                }
            }
            // look for a pool that already exists that is compatible with
            // our PoolFactory.
            // If we don't find one we will create a new one that meets our needs.
            Map<String, Pool> pools = PoolManager.getAll();
            for (Pool p : pools.values()) {
                if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) {
                    pool = p;
                    break;
                }
            }
        }
        if (pool == null) {
            // create our pool with a unique name
            String poolName = "DEFAULT";
            int count = 1;
            Map<String, Pool> pools = PoolManager.getAll();
            while (pools.containsKey(poolName)) {
                poolName = "DEFAULT" + count;
                count++;
            }
            pool = this.clientpf.create(poolName);
        }
        setDefaultPool(pool);
    }

    /**
     * Used to see if a existing cache's pool is compatible with us.
     *
     * @return the default pool that is right for us
     */
    public Pool determineDefaultPool(PoolFactory pf) {
        Pool pool = null;
        // create the pool if it does not already exist
        if (pf == null) {
            Map<String, Pool> pools = PoolManager.getAll();
            if (pools.isEmpty()) {
                throw new IllegalStateException("Since a cache already existed a pool should also exist.");
            } else if (pools.size() == 1) {
                // otherwise use a singleton.
                pool = pools.values().iterator().next();
                if (getDefaultPool() != pool) {
                    throw new IllegalStateException(
                            "Existing cache's default pool was not the same as the only existing pool");
                }
            } else {
                // just use the current default pool if one exists
                pool = getDefaultPool();
                if (pool == null) {
                    // act as if the default pool was configured
                    // and see if we can find an existing one that is compatible
                    PoolFactoryImpl pfi = (PoolFactoryImpl) createDefaultPF();
                    for (Pool p : pools.values()) {
                        if (((PoolImpl) p).isCompatible(pfi.getPoolAttributes())) {
                            pool = p;
                            break;
                        }
                    }
                    if (pool == null) {
                        // if pool is still null then we will not have a default pool for this ClientCache
                        return null;
                    }
                }
            }
        } else {
            PoolFactoryImpl pfi = (PoolFactoryImpl) pf;
            if (pfi.getPoolAttributes().locators.isEmpty() && pfi.getPoolAttributes().servers.isEmpty()) {
                try {
                    String localHostName = SocketCreator.getHostName(SocketCreator.getLocalHost());
                    pfi.addServer(localHostName, CacheServer.DEFAULT_PORT);
                } catch (UnknownHostException ex) {
                    throw new IllegalStateException("Could not determine local host name");
                }
            }
            PoolImpl defPool = (PoolImpl) getDefaultPool();
            if (defPool != null && defPool.isCompatible(pfi.getPoolAttributes())) {
                pool = defPool;
            } else {
                throw new IllegalStateException("Existing cache's default pool was not compatible");
            }
        }
        return pool;
    }

    public Region createRegion(String name, RegionAttributes attrs) throws RegionExistsException, TimeoutException {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        return basicCreateRegion(name, attrs);
    }

    public Region basicCreateRegion(String name, RegionAttributes attrs)
            throws RegionExistsException, TimeoutException {
        try {
            InternalRegionArguments ira = new InternalRegionArguments().setDestroyLockFlag(true)
                    .setRecreateFlag(false).setSnapshotInputStream(null).setImageTarget(null);

            if (attrs instanceof UserSpecifiedRegionAttributes) {
                ira.setIndexes(((UserSpecifiedRegionAttributes) attrs).getIndexes());
            }
            return createVMRegion(name, attrs, ira);
        } catch (IOException | ClassNotFoundException e) {
            // only if loading snapshot, not here
            InternalGemFireError assErr = new InternalGemFireError(
                    LocalizedStrings.GemFireCache_UNEXPECTED_EXCEPTION.toLocalizedString());
            assErr.initCause(e);
            throw assErr;
        }
    }

    public <K, V> Region<K, V> createVMRegion(String name, RegionAttributes<K, V> p_attrs,
            InternalRegionArguments internalRegionArgs)
            throws RegionExistsException, TimeoutException, IOException, ClassNotFoundException {
        if (getMyId().getVmKind() == DistributionManager.LOCATOR_DM_TYPE) {
            if (!internalRegionArgs.isUsedForMetaRegion() && internalRegionArgs.getInternalMetaRegion() == null) {
                throw new IllegalStateException("Regions can not be created in a locator.");
            }
        }
        stopper.checkCancelInProgress(null);
        LocalRegion.validateRegionName(name, internalRegionArgs);
        RegionAttributes<K, V> attrs = p_attrs;
        attrs = invokeRegionBefore(null, name, attrs, internalRegionArgs);
        if (attrs == null) {
            throw new IllegalArgumentException(
                    LocalizedStrings.GemFireCache_ATTRIBUTES_MUST_NOT_BE_NULL.toLocalizedString());
        }

        LocalRegion rgn = null;
        // final boolean getDestroyLock = attrs.getDestroyLockFlag();
        final InputStream snapshotInputStream = internalRegionArgs.getSnapshotInputStream();
        InternalDistributedMember imageTarget = internalRegionArgs.getImageTarget();
        final boolean recreate = internalRegionArgs.getRecreateFlag();

        final boolean isPartitionedRegion = attrs.getPartitionAttributes() != null;
        final boolean isReinitCreate = snapshotInputStream != null || imageTarget != null || recreate;

        final String regionPath = LocalRegion.calcFullPath(name, null);

        try {
            for (;;) {
                getCancelCriterion().checkCancelInProgress(null);

                Future future = null;
                synchronized (this.rootRegions) {
                    rgn = (LocalRegion) this.rootRegions.get(name);
                    if (rgn != null) {
                        throw new RegionExistsException(rgn);
                    }
                    // check for case where a root region is being reinitialized and we
                    // didn't
                    // find a region, i.e. the new region is about to be created

                    if (!isReinitCreate) { // fix bug 33523
                        String fullPath = Region.SEPARATOR + name;
                        future = (Future) this.reinitializingRegions.get(fullPath);
                    }
                    if (future == null) {
                        if (internalRegionArgs.getInternalMetaRegion() != null) {
                            rgn = internalRegionArgs.getInternalMetaRegion();
                        } else if (isPartitionedRegion) {
                            rgn = new PartitionedRegion(name, attrs, null, this, internalRegionArgs);
                        } else {
                            /*
                             * for (String senderId : attrs.getGatewaySenderIds()) { if
                             * (getGatewaySender(senderId) != null && getGatewaySender(senderId).isParallel()) {
                             * throw new IllegalStateException( LocalizedStrings.
                             * AttributesFactory_PARALLELGATEWAYSENDER_0_IS_INCOMPATIBLE_WITH_DISTRIBUTED_REPLICATION
                             * .toLocalizedString(senderId)); } }
                             */
                            if (attrs.getScope().isLocal()) {
                                rgn = new LocalRegion(name, attrs, null, this, internalRegionArgs);
                            } else {
                                rgn = new DistributedRegion(name, attrs, null, this, internalRegionArgs);
                            }
                        }

                        this.rootRegions.put(name, rgn);
                        if (isReinitCreate) {
                            regionReinitialized(rgn);
                        }
                        break;
                    }
                } // synchronized

                boolean interrupted = Thread.interrupted();
                try { // future != null
                    LocalRegion region = (LocalRegion) future.get(); // wait on Future
                    throw new RegionExistsException(region);
                } catch (InterruptedException e) {
                    interrupted = true;
                } catch (ExecutionException e) {
                    throw new Error(LocalizedStrings.GemFireCache_UNEXPECTED_EXCEPTION.toLocalizedString(), e);
                } catch (CancellationException e) {
                    // future was cancelled
                } finally {
                    if (interrupted)
                        Thread.currentThread().interrupt();
                }
            } // for

            boolean success = false;
            try {
                setRegionByPath(rgn.getFullPath(), rgn);
                rgn.initialize(snapshotInputStream, imageTarget, internalRegionArgs);
                success = true;
            } catch (CancelException e) {
                // don't print a call stack
                throw e;
            } catch (RedundancyAlreadyMetException e) {
                // don't log this
                throw e;
            } catch (final RuntimeException validationException) {
                logger.warn(
                        LocalizedMessage.create(LocalizedStrings.GemFireCache_INITIALIZATION_FAILED_FOR_REGION_0,
                                rgn.getFullPath()),
                        validationException);
                throw validationException;
            } finally {
                if (!success) {
                    try {
                        // do this before removing the region from
                        // the root set to fix bug 41982.
                        rgn.cleanupFailedInitialization();
                    } catch (VirtualMachineError e) {
                        SystemFailure.initiateFailure(e);
                        throw e;
                    } catch (Throwable t) {
                        SystemFailure.checkFailure();
                        stopper.checkCancelInProgress(t);

                        // bug #44672 - log the failure but don't override the original exception
                        logger.warn(LocalizedMessage.create(
                                LocalizedStrings.GemFireCache_INIT_CLEANUP_FAILED_FOR_REGION_0, rgn.getFullPath()),
                                t);

                    } finally {
                        // clean up if initialize fails for any reason
                        setRegionByPath(rgn.getFullPath(), null);
                        synchronized (this.rootRegions) {
                            Region r = (Region) this.rootRegions.get(name);
                            if (r == rgn) {
                                this.rootRegions.remove(name);
                            }
                        } // synchronized
                    }
                } // success
            }

            rgn.postCreateRegion();
        } catch (RegionExistsException ex) {
            // outside of sync make sure region is initialized to fix bug 37563
            LocalRegion r = (LocalRegion) ex.getRegion();
            r.waitOnInitialization(); // don't give out ref until initialized
            throw ex;
        }

        invokeRegionAfter(rgn);
        /**
         * Added for M&M . Putting the callback here to avoid creating RegionMBean in case of Exception
         **/
        if (!rgn.isInternalRegion()) {
            system.handleResourceEvent(ResourceEvent.REGION_CREATE, rgn);
        }

        return rgn;
    }

    public RegionAttributes invokeRegionBefore(LocalRegion parent, String name, RegionAttributes attrs,
            InternalRegionArguments internalRegionArgs) {
        for (RegionListener listener : regionListeners) {
            attrs = listener.beforeCreate(parent, name, attrs, internalRegionArgs);
        }
        return attrs;
    }

    public void invokeRegionAfter(LocalRegion region) {
        for (RegionListener listener : regionListeners) {
            listener.afterCreate(region);
        }
    }

    public final Region getRegion(String path) {
        return getRegion(path, false);
    }

    /**
     * returns a set of all current regions in the cache, including buckets
     *
     * @since GemFire 6.0
     */
    public Set<LocalRegion> getAllRegions() {
        Set<LocalRegion> result = new HashSet();
        synchronized (this.rootRegions) {
            for (Object r : this.rootRegions.values()) {
                if (r instanceof PartitionedRegion) {
                    PartitionedRegion p = (PartitionedRegion) r;
                    PartitionedRegionDataStore prds = p.getDataStore();
                    if (prds != null) {
                        Set<Entry<Integer, BucketRegion>> bucketEntries = p.getDataStore().getAllLocalBuckets();
                        for (Map.Entry e : bucketEntries) {
                            result.add((LocalRegion) e.getValue());
                        }
                    }
                } else if (r instanceof LocalRegion) {
                    LocalRegion l = (LocalRegion) r;
                    result.add(l);
                    result.addAll(l.basicSubregions(true));
                }
            }
        }
        return result;
    }

    public Set<LocalRegion> getApplicationRegions() {
        Set<LocalRegion> result = new HashSet<LocalRegion>();
        synchronized (this.rootRegions) {
            for (Object r : this.rootRegions.values()) {
                LocalRegion rgn = (LocalRegion) r;
                if (rgn.isSecret() || rgn.isUsedForMetaRegion() || rgn instanceof HARegion
                        || rgn.isUsedForPartitionedRegionAdmin()
                        || rgn.isInternalRegion()/* rgn.isUsedForPartitionedRegionBucket() */) {
                    continue; // Skip administrative PartitionedRegions
                }
                result.add(rgn);
                result.addAll(rgn.basicSubregions(true));
            }
        }
        return result;
    }

    void setRegionByPath(String path, LocalRegion r) {
        if (r == null) {
            this.pathToRegion.remove(path);
        } else {
            this.pathToRegion.put(path, r);
        }
    }

    /**
     * @throws IllegalArgumentException if path is not valid
     */
    private static void validatePath(String path) {
        if (path == null) {
            throw new IllegalArgumentException(
                    LocalizedStrings.GemFireCache_PATH_CANNOT_BE_NULL.toLocalizedString());
        }
        if (path.length() == 0) {
            throw new IllegalArgumentException(
                    LocalizedStrings.GemFireCache_PATH_CANNOT_BE_EMPTY.toLocalizedString());
        }
        if (path.equals(Region.SEPARATOR)) {
            throw new IllegalArgumentException(
                    LocalizedStrings.GemFireCache_PATH_CANNOT_BE_0.toLocalizedString(Region.SEPARATOR));
        }
    }

    public LocalRegion getRegionByPath(String path) {
        validatePath(path); // fix for bug 34892

        { // do this before checking the pathToRegion map
            LocalRegion result = getReinitializingRegion(path);
            if (result != null) {
                return result;
            }
        }
        return (LocalRegion) this.pathToRegion.get(path);
    }

    public LocalRegion getRegionByPathForProcessing(String path) {
        LocalRegion result = getRegionByPath(path);
        if (result == null) {
            stopper.checkCancelInProgress(null);
            int oldLevel = LocalRegion.setThreadInitLevelRequirement(LocalRegion.ANY_INIT); // go through
            // initialization
            // latches
            try {
                String[] pathParts = parsePath(path);
                LocalRegion root;
                synchronized (this.rootRegions) {
                    root = (LocalRegion) this.rootRegions.get(pathParts[0]);
                    if (root == null)
                        return null;
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("GemFireCache.getRegion, calling getSubregion on root({}): {}", pathParts[0],
                            pathParts[1]);
                }
                result = (LocalRegion) root.getSubregion(pathParts[1], true);
            } finally {
                LocalRegion.setThreadInitLevelRequirement(oldLevel);
            }
        }
        return result;
    }

    /**
     * @param returnDestroyedRegion if true, okay to return a destroyed region
     */
    public Region getRegion(String path, boolean returnDestroyedRegion) {
        stopper.checkCancelInProgress(null);
        {
            LocalRegion result = getRegionByPath(path);
            // Do not waitOnInitialization() for PR
            // if (result != null && !(result instanceof PartitionedRegion)) {
            if (result != null) {
                result.waitOnInitialization();
                if (!returnDestroyedRegion && result.isDestroyed()) {
                    stopper.checkCancelInProgress(null);
                    return null;
                } else {
                    return result;
                }
            }
        }

        String[] pathParts = parsePath(path);
        LocalRegion root;
        synchronized (this.rootRegions) {
            root = (LocalRegion) this.rootRegions.get(pathParts[0]);
            if (root == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("GemFireCache.getRegion, no region found for {}", pathParts[0]);
                }
                stopper.checkCancelInProgress(null);
                return null;
            }
            if (!returnDestroyedRegion && root.isDestroyed()) {
                stopper.checkCancelInProgress(null);
                return null;
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("GemFireCache.getRegion, calling getSubregion on root({}): {}", pathParts[0],
                    pathParts[1]);
        }
        return root.getSubregion(pathParts[1], returnDestroyedRegion);
    }

    /**
     * @param returnDestroyedRegion if true, okay to return a destroyed partitioned region
     */
    public final Region getPartitionedRegion(String path, boolean returnDestroyedRegion) {
        stopper.checkCancelInProgress(null);
        {
            LocalRegion result = getRegionByPath(path);
            // Do not waitOnInitialization() for PR
            if (result != null) {
                if (!(result instanceof PartitionedRegion)) {
                    return null;
                } else {
                    return result;
                }
            }
        }

        String[] pathParts = parsePath(path);
        LocalRegion root;
        LogWriterI18n logger = getLoggerI18n();
        synchronized (this.rootRegions) {
            root = (LocalRegion) this.rootRegions.get(pathParts[0]);
            if (root == null) {
                if (logger.fineEnabled()) {
                    logger.fine("GemFireCache.getRegion, no region found for " + pathParts[0]);
                }
                stopper.checkCancelInProgress(null);
                return null;
            }
            if (!returnDestroyedRegion && root.isDestroyed()) {
                stopper.checkCancelInProgress(null);
                return null;
            }
        }
        if (logger.fineEnabled()) {
            logger.fine("GemFireCache.getPartitionedRegion, calling getSubregion on root(" + pathParts[0] + "): "
                    + pathParts[1]);
        }
        Region result = root.getSubregion(pathParts[1], returnDestroyedRegion);
        if (result != null && !(result instanceof PartitionedRegion)) {
            return null;
        } else {
            return result;
        }
    }

    /** Return true if this region is initializing */
    boolean isGlobalRegionInitializing(String fullPath) {
        stopper.checkCancelInProgress(null);
        int oldLevel = LocalRegion.setThreadInitLevelRequirement(LocalRegion.ANY_INIT); // go through
        // initialization
        // latches
        try {
            return isGlobalRegionInitializing((LocalRegion) getRegion(fullPath));
        } finally {
            LocalRegion.setThreadInitLevelRequirement(oldLevel);
        }
    }

    /** Return true if this region is initializing */
    boolean isGlobalRegionInitializing(LocalRegion region) {
        boolean result = region != null && region.scope.isGlobal() && !region.isInitialized();
        if (result) {
            if (logger.isDebugEnabled()) {
                logger.debug("GemFireCache.isGlobalRegionInitializing ({})", region.getFullPath());
            }
        }
        return result;
    }

    public Set rootRegions() {
        return rootRegions(false);
    }

    public final Set rootRegions(boolean includePRAdminRegions) {
        return rootRegions(includePRAdminRegions, true);
    }

    private final Set rootRegions(boolean includePRAdminRegions, boolean waitForInit) {
        stopper.checkCancelInProgress(null);
        Set regions = new HashSet();
        synchronized (this.rootRegions) {
            for (Iterator itr = this.rootRegions.values().iterator(); itr.hasNext();) {
                LocalRegion r = (LocalRegion) itr.next();
                // If this is an internal meta-region, don't return it to end user
                if (r.isSecret() || r.isUsedForMetaRegion() || r instanceof HARegion || !includePRAdminRegions
                        && (r.isUsedForPartitionedRegionAdmin() || r.isUsedForPartitionedRegionBucket())) {
                    continue; // Skip administrative PartitionedRegions
                }
                regions.add(r);
            }
        }
        if (waitForInit) {
            for (Iterator r = regions.iterator(); r.hasNext();) {
                LocalRegion lr = (LocalRegion) r.next();
                // lr.waitOnInitialization();
                if (!lr.checkForInitialization()) {
                    r.remove();
                }
            }
        }
        return Collections.unmodifiableSet(regions);
    }

    /**
     * Called by ccn when a client goes away
     *
     * @since GemFire 5.7
     */
    public void cleanupForClient(CacheClientNotifier ccn, ClientProxyMembershipID client) {
        try {
            if (isClosed())
                return;
            Iterator it = rootRegions(false, false).iterator();
            while (it.hasNext()) {
                LocalRegion lr = (LocalRegion) it.next();
                lr.cleanupForClient(ccn, client);
            }
        } catch (DistributedSystemDisconnectedException ignore) {
        }
    }

    public boolean isInitialized() {
        return this.isInitialized;
    }

    public boolean isClosed() {
        return this.isClosing;
    }

    public int getLockTimeout() {
        return this.lockTimeout;
    }

    public void setLockTimeout(int seconds) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);
        this.lockTimeout = seconds;
    }

    public int getLockLease() {
        return this.lockLease;
    }

    public void setLockLease(int seconds) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);
        this.lockLease = seconds;
    }

    public int getSearchTimeout() {
        return this.searchTimeout;
    }

    public void setSearchTimeout(int seconds) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);
        this.searchTimeout = seconds;
    }

    public int getMessageSyncInterval() {
        return HARegionQueue.getMessageSyncInterval();
    }

    public void setMessageSyncInterval(int seconds) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);
        if (seconds < 0) {
            throw new IllegalArgumentException(
                    LocalizedStrings.GemFireCache_THE_MESSAGESYNCINTERVAL_PROPERTY_FOR_CACHE_CANNOT_BE_NEGATIVE
                            .toLocalizedString());
        }
        HARegionQueue.setMessageSyncInterval(seconds);
    }

    /**
     * Get a reference to a Region that is reinitializing, or null if that Region is not
     * reinitializing or this thread is interrupted. If a reinitializing region is found, then this
     * method blocks until reinitialization is complete and then returns the region.
     */
    LocalRegion getReinitializingRegion(String fullPath) {
        Future future = (Future) this.reinitializingRegions.get(fullPath);
        if (future == null) {
            return null;
        }
        try {
            LocalRegion region = (LocalRegion) future.get();
            region.waitOnInitialization();
            if (logger.isDebugEnabled()) {
                logger.debug("Returning manifested future for: {}", fullPath);
            }
            return region;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } catch (ExecutionException e) {
            throw new Error(LocalizedStrings.GemFireCache_UNEXPECTED_EXCEPTION.toLocalizedString(), e);
        } catch (CancellationException e) {
            // future was cancelled
            logger.debug("future cancelled, returning null");
            return null;
        }
    }

    /**
     * Register the specified region name as reinitializing, creating and adding a Future for it to
     * the map.
     *
     * @throws IllegalStateException if there is already a region by that name registered.
     */
    void regionReinitializing(String fullPath) {
        Object old = this.reinitializingRegions.putIfAbsent(fullPath, new FutureResult(this.stopper));
        if (old != null) {
            throw new IllegalStateException(
                    LocalizedStrings.GemFireCache_FOUND_AN_EXISTING_REINITALIZING_REGION_NAMED_0
                            .toLocalizedString(fullPath));
        }
    }

    /**
     * Set the reinitialized region and unregister it as reinitializing.
     *
     * @throws IllegalStateException if there is no region by that name registered as reinitializing.
     */
    void regionReinitialized(Region region) {
        String regionName = region.getFullPath();
        FutureResult future = (FutureResult) this.reinitializingRegions.get(regionName);
        if (future == null) {
            throw new IllegalStateException(
                    LocalizedStrings.GemFireCache_COULD_NOT_FIND_A_REINITIALIZING_REGION_NAMED_0
                            .toLocalizedString(regionName));
        }
        future.set(region);
        unregisterReinitializingRegion(regionName);
    }

    /**
     * Clear a reinitializing region, e.g. reinitialization failed.
     *
     * @throws IllegalStateException if cannot find reinitializing region registered by that name.
     */
    void unregisterReinitializingRegion(String fullPath) {
        /* Object previous = */this.reinitializingRegions.remove(fullPath);
        // if (previous == null) {
        // throw new IllegalStateException("Could not find a reinitializing region
        // named " +
        // fullPath);
        // }
    }

    // /////////////////////////////////////////////////////////////

    /**
     * Returns true if get should give a copy; false if a reference.
     *
     * @since GemFire 4.0
     */
    final boolean isCopyOnRead() {
        return this.copyOnRead;
    }

    /**
     * Implementation of {@link org.apache.geode.cache.Cache#setCopyOnRead}
     *
     * @since GemFire 4.0
     */
    public void setCopyOnRead(boolean copyOnRead) {
        this.copyOnRead = copyOnRead;
    }

    /**
     * Implementation of {@link org.apache.geode.cache.Cache#getCopyOnRead}
     *
     * @since GemFire 4.0
     */
    final public boolean getCopyOnRead() {
        return this.copyOnRead;
    }

    /**
     * Remove the specified root region
     *
     * @param rootRgn the region to be removed
     * @return true if root region was removed, false if not found
     */
    boolean removeRoot(LocalRegion rootRgn) {
        synchronized (this.rootRegions) {
            String rgnName = rootRgn.getName();
            LocalRegion found = (LocalRegion) this.rootRegions.get(rgnName);
            if (found == rootRgn) {
                LocalRegion previous = (LocalRegion) this.rootRegions.remove(rgnName);
                Assert.assertTrue(previous == rootRgn);
                return true;
            } else
                return false;
        }
    }

    /**
     * @return array of two Strings, the root name and the relative path from root If there is no
     *         relative path from root, then String[1] will be an empty string
     */
    static String[] parsePath(String p_path) {
        String path = p_path;
        validatePath(path);
        String[] result = new String[2];
        result[1] = "";
        // strip off root name from path
        int slashIndex = path.indexOf(Region.SEPARATOR_CHAR);
        if (slashIndex == 0) {
            path = path.substring(1);
            slashIndex = path.indexOf(Region.SEPARATOR_CHAR);
        }
        result[0] = path;
        if (slashIndex > 0) {
            result[0] = path.substring(0, slashIndex);
            result[1] = path.substring(slashIndex + 1);
        }
        return result;
    }

    /**
     * Makes note of a <code>CacheLifecycleListener</code>
     */
    public static void addCacheLifecycleListener(CacheLifecycleListener l) {
        synchronized (GemFireCacheImpl.class) {
            cacheLifecycleListeners.add(l);
        }
    }

    /**
     * Removes a <code>CacheLifecycleListener</code>
     *
     * @return Whether or not the listener was removed
     */
    public static boolean removeCacheLifecycleListener(CacheLifecycleListener l) {
        synchronized (GemFireCacheImpl.class) {
            return cacheLifecycleListeners.remove(l);
        }
    }

    public void addRegionListener(RegionListener l) {
        this.regionListeners.add(l);
    }

    public void removeRegionListener(RegionListener l) {
        this.regionListeners.remove(l);
    }

    @SuppressWarnings("unchecked")
    public <T extends CacheService> T getService(Class<T> clazz) {
        return (T) services.get(clazz);
    }

    /**
     * Creates the single instance of the Transation Manager for this cache. Returns the existing one
     * upon request.
     *
     * @return the CacheTransactionManager instance.
     *
     * @since GemFire 4.0
     */
    public CacheTransactionManager getCacheTransactionManager() {
        return this.txMgr;
    }

    /**
     * @see CacheClientProxy
     * @guarded.By {@link #ccpTimerMutex}
     */
    private SystemTimer ccpTimer;

    /**
     * @see #ccpTimer
     */
    private final Object ccpTimerMutex = new Object();

    /**
     * Get cache-wide CacheClientProxy SystemTimer
     *
     * @return the timer, lazily created
     */
    public SystemTimer getCCPTimer() {
        synchronized (ccpTimerMutex) {
            if (ccpTimer != null) {
                return ccpTimer;
            }
            ccpTimer = new SystemTimer(getDistributedSystem(), true);
            if (this.isClosing) {
                ccpTimer.cancel(); // poison it, don't throw.
            }
            return ccpTimer;
        }
    }

    /**
     * @see LocalRegion
     */
    private final ExpirationScheduler expirationScheduler;

    /**
     * Get cache-wide ExpirationScheduler
     *
     * @return the scheduler, lazily created
     */
    public ExpirationScheduler getExpirationScheduler() {
        return this.expirationScheduler;
    }

    TXManagerImpl getTXMgr() {
        return this.txMgr;
    }

    /**
     * Returns the <code>Executor</code> (thread pool) that is used to execute cache event listeners.
     * Returns <code>null</code> if no pool exists.
     *
     * @since GemFire 3.5
     */
    Executor getEventThreadPool() {
        return this.eventThreadPool;
    }

    public CacheServer addCacheServer() {
        return addCacheServer(false);
    }

    public CacheServer addCacheServer(boolean isGatewayReceiver) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);

        CacheServerImpl bridge = new CacheServerImpl(this, isGatewayReceiver);
        allCacheServers.add(bridge);

        sendAddCacheServerProfileMessage();
        return bridge;
    }

    public void addGatewaySender(GatewaySender sender) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }

        stopper.checkCancelInProgress(null);

        synchronized (allGatewaySendersLock) {
            if (!allGatewaySenders.contains(sender)) {
                new UpdateAttributesProcessor((AbstractGatewaySender) sender).distribute(true);
                Set<GatewaySender> tmp = new HashSet<GatewaySender>(allGatewaySenders.size() + 1);
                if (!allGatewaySenders.isEmpty()) {
                    tmp.addAll(allGatewaySenders);
                }
                tmp.add(sender);
                this.allGatewaySenders = Collections.unmodifiableSet(tmp);
            } else {
                throw new IllegalStateException(
                        LocalizedStrings.GemFireCache_A_GATEWAYSENDER_WITH_ID_0_IS_ALREADY_DEFINED_IN_THIS_CACHE
                                .toLocalizedString(sender.getId()));
            }
        }

        synchronized (this.rootRegions) {
            Set<LocalRegion> appRegions = getApplicationRegions();
            for (LocalRegion r : appRegions) {
                Set<String> senders = r.getAllGatewaySenderIds();
                if (senders.contains(sender.getId()) && !sender.isParallel()) {
                    r.senderCreated();
                }
            }
        }

        if (!sender.isParallel()) {
            Region dynamicMetaRegion = getRegion(DynamicRegionFactory.dynamicRegionListName);
            if (dynamicMetaRegion == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug(" The dynamic region is null. ");
                }
            } else {
                dynamicMetaRegion.getAttributesMutator().addGatewaySenderId(sender.getId());
            }
        }
        if (!(sender.getRemoteDSId() < 0)) {
            system.handleResourceEvent(ResourceEvent.GATEWAYSENDER_CREATE, sender);
        }
    }

    public void removeGatewaySender(GatewaySender sender) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }

        stopper.checkCancelInProgress(null);

        synchronized (allGatewaySendersLock) {
            if (allGatewaySenders.contains(sender)) {
                new UpdateAttributesProcessor((AbstractGatewaySender) sender, true).distribute(true);
                Set<GatewaySender> tmp = new HashSet<GatewaySender>(allGatewaySenders.size() - 1);
                if (!allGatewaySenders.isEmpty()) {
                    tmp.addAll(allGatewaySenders);
                }
                tmp.remove(sender);
                this.allGatewaySenders = Collections.unmodifiableSet(tmp);
            }
        }
    }

    public void addGatewayReceiver(GatewayReceiver recv) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);
        synchronized (allGatewayReceiversLock) {
            Set<GatewayReceiver> tmp = new HashSet<GatewayReceiver>(allGatewayReceivers.size() + 1);
            if (!allGatewayReceivers.isEmpty()) {
                tmp.addAll(allGatewayReceivers);
            }
            tmp.add(recv);
            this.allGatewayReceivers = Collections.unmodifiableSet(tmp);
        }
    }

    public void addAsyncEventQueue(AsyncEventQueueImpl asyncQueue) {
        this.allAsyncEventQueues.add(asyncQueue);
        if (!asyncQueue.isMetaQueue()) {
            this.allVisibleAsyncEventQueues.add(asyncQueue);
        }
        system.handleResourceEvent(ResourceEvent.ASYNCEVENTQUEUE_CREATE, asyncQueue);
    }

    /**
     * Returns List of GatewaySender (excluding the senders for internal use)
     * 
     * @return List List of GatewaySender objects
     */
    public Set<GatewaySender> getGatewaySenders() {
        Set<GatewaySender> tempSet = new HashSet<GatewaySender>();
        for (GatewaySender sender : allGatewaySenders) {
            if (!((AbstractGatewaySender) sender).isForInternalUse()) {
                tempSet.add(sender);
            }
        }
        return tempSet;
    }

    /**
     * Returns List of all GatewaySenders (including the senders for internal use)
     * 
     * @return List List of GatewaySender objects
     */
    public Set<GatewaySender> getAllGatewaySenders() {
        return this.allGatewaySenders;
    }

    public GatewaySender getGatewaySender(String Id) {
        for (GatewaySender sender : this.allGatewaySenders) {
            if (sender.getId().equals(Id)) {
                return sender;
            }
        }
        return null;
    }

    public Set<GatewayReceiver> getGatewayReceivers() {
        return this.allGatewayReceivers;
    }

    public Set<AsyncEventQueue> getAsyncEventQueues() {
        return this.allVisibleAsyncEventQueues;
    }

    public AsyncEventQueue getAsyncEventQueue(String id) {
        for (AsyncEventQueue asyncEventQueue : this.allAsyncEventQueues) {
            if (asyncEventQueue.getId().equals(id)) {
                return asyncEventQueue;
            }
        }
        return null;
    }

    public void removeAsyncEventQueue(AsyncEventQueue asyncQueue) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        // first remove the gateway sender of the queue
        if (asyncQueue instanceof AsyncEventQueueImpl) {
            removeGatewaySender(((AsyncEventQueueImpl) asyncQueue).getSender());
        }
        // using gateway senders lock since async queue uses a gateway sender
        synchronized (allGatewaySendersLock) {
            this.allAsyncEventQueues.remove(asyncQueue);
            this.allVisibleAsyncEventQueues.remove(asyncQueue);
        }
    }

    /* Cache API - get the conflict resolver for WAN */
    public GatewayConflictResolver getGatewayConflictResolver() {
        synchronized (this.allGatewayHubsLock) {
            return this.gatewayConflictResolver;
        }
    }

    /* Cache API - set the conflict resolver for WAN */
    public void setGatewayConflictResolver(GatewayConflictResolver resolver) {
        synchronized (this.allGatewayHubsLock) {
            this.gatewayConflictResolver = resolver;
        }
    }

    public List<CacheServer> getCacheServers() {
        List cacheServersWithoutReceiver = null;
        if (!allCacheServers.isEmpty()) {
            Iterator allCacheServersIterator = allCacheServers.iterator();
            while (allCacheServersIterator.hasNext()) {
                CacheServerImpl cacheServer = (CacheServerImpl) allCacheServersIterator.next();
                // If CacheServer is a GatewayReceiver, don't return as part of CacheServers
                if (!cacheServer.isGatewayReceiver()) {
                    if (cacheServersWithoutReceiver == null) {
                        cacheServersWithoutReceiver = new ArrayList();
                    }
                    cacheServersWithoutReceiver.add(cacheServer);
                }
            }
        }
        if (cacheServersWithoutReceiver == null) {
            cacheServersWithoutReceiver = Collections.emptyList();
        }
        return cacheServersWithoutReceiver;
    }

    public List getCacheServersAndGatewayReceiver() {
        return allCacheServers;
    }

    /**
     * notify partitioned regions that this cache requires all of their events
     */
    public void requiresPREvents() {
        synchronized (this.partitionedRegions) {
            for (Iterator it = this.partitionedRegions.iterator(); it.hasNext();) {
                ((PartitionedRegion) it.next()).cacheRequiresNotification();
            }
        }
    }

    /**
     * add a partitioned region to the set of tracked partitioned regions. This is used to notify the
     * regions when this cache requires, or does not require notification of all region/entry events.
     */
    public void addPartitionedRegion(PartitionedRegion r) {
        synchronized (this.partitionedRegions) {
            if (r.isDestroyed()) {
                if (logger.isDebugEnabled()) {
                    logger.debug("GemFireCache#addPartitionedRegion did not add destroyed {}", r);
                }
                return;
            }
            if (this.partitionedRegions.add(r)) {
                getCachePerfStats().incPartitionedRegions(1);
            }
        }
    }

    /**
     * Returns a set of all current partitioned regions for test hook.
     */
    public Set<PartitionedRegion> getPartitionedRegions() {
        synchronized (this.partitionedRegions) {
            return new HashSet<PartitionedRegion>(this.partitionedRegions);
        }
    }

    private TreeMap<String, Map<String, PartitionedRegion>> getPRTrees() {
        // prTree will save a sublist of PRs who are under the same root
        TreeMap<String, Map<String, PartitionedRegion>> prTrees = new TreeMap();
        TreeMap<String, PartitionedRegion> prMap = getPartitionedRegionMap();
        boolean hasColocatedRegion = false;
        for (PartitionedRegion pr : prMap.values()) {
            List<PartitionedRegion> childlist = ColocationHelper.getColocatedChildRegions(pr);
            if (childlist != null && childlist.size() > 0) {
                hasColocatedRegion = true;
                break;
            }
        }

        if (hasColocatedRegion) {
            LinkedHashMap<String, PartitionedRegion> orderedPrMap = orderByColocation(prMap);
            prTrees.put("ROOT", orderedPrMap);
        } else {
            for (PartitionedRegion pr : prMap.values()) {
                String rootName = pr.getRoot().getName();
                TreeMap<String, PartitionedRegion> prSubMap = (TreeMap<String, PartitionedRegion>) prTrees
                        .get(rootName);
                if (prSubMap == null) {
                    prSubMap = new TreeMap();
                    prTrees.put(rootName, prSubMap);
                }
                prSubMap.put(pr.getFullPath(), pr);
            }
        }

        return prTrees;
    }

    private TreeMap<String, PartitionedRegion> getPartitionedRegionMap() {
        TreeMap<String, PartitionedRegion> prMap = new TreeMap();
        for (Map.Entry<String, Region> entry : ((Map<String, Region>) pathToRegion).entrySet()) {
            String regionName = (String) entry.getKey();
            Region region = entry.getValue();

            // Don't wait for non partitioned regions
            if (!(region instanceof PartitionedRegion)) {
                continue;
            }
            // Do a getRegion to ensure that we wait for the partitioned region
            // to finish initialization
            try {
                Region pr = getRegion(regionName);
                if (pr instanceof PartitionedRegion) {
                    prMap.put(regionName, (PartitionedRegion) pr);
                }
            } catch (CancelException ce) {
                // if some region throws cancel exception during initialization,
                // then no need to shutdownall them gracefully
            }
        }

        return prMap;
    }

    private LinkedHashMap<String, PartitionedRegion> orderByColocation(TreeMap<String, PartitionedRegion> prMap) {
        LinkedHashMap<String, PartitionedRegion> orderedPrMap = new LinkedHashMap();
        for (PartitionedRegion pr : prMap.values()) {
            addColocatedChildRecursively(orderedPrMap, pr);
        }
        return orderedPrMap;
    }

    private void addColocatedChildRecursively(LinkedHashMap<String, PartitionedRegion> prMap,
            PartitionedRegion pr) {
        for (PartitionedRegion colocatedRegion : ColocationHelper.getColocatedChildRegions(pr)) {
            addColocatedChildRecursively(prMap, colocatedRegion);
        }
        prMap.put(pr.getFullPath(), pr);
    }

    /**
     * check to see if any cache components require notification from a partitioned region.
     * Notification adds to the messaging a PR must do on each put/destroy/invalidate operation and
     * should be kept to a minimum
     *
     * @param r the partitioned region
     * @return true if the region should deliver all of its events to this cache
     */
    protected boolean requiresNotificationFromPR(PartitionedRegion r) {
        boolean hasSerialSenders = hasSerialSenders(r);
        boolean result = hasSerialSenders;
        if (!result) {
            Iterator allCacheServersIterator = allCacheServers.iterator();
            while (allCacheServersIterator.hasNext()) {
                CacheServerImpl server = (CacheServerImpl) allCacheServersIterator.next();
                if (!server.getNotifyBySubscription()) {
                    result = true;
                    break;
                }
            }

        }
        return result;
    }

    private boolean hasSerialSenders(PartitionedRegion r) {
        boolean hasSenders = false;
        Set<String> senders = r.getAllGatewaySenderIds();
        for (String sender : senders) {
            GatewaySender gs = this.getGatewaySender(sender);
            if (gs != null && !gs.isParallel()) {
                hasSenders = true;
                break;
            }
        }
        return hasSenders;
    }

    /**
     * remove a partitioned region from the set of tracked instances.
     *
     * @see #addPartitionedRegion(PartitionedRegion)
     */
    public void removePartitionedRegion(PartitionedRegion r) {
        synchronized (this.partitionedRegions) {
            if (this.partitionedRegions.remove(r)) {
                getCachePerfStats().incPartitionedRegions(-1);
            }
        }
    }

    public void setIsServer(boolean isServer) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        stopper.checkCancelInProgress(null);

        this.isServer = isServer;
    }

    public boolean isServer() {
        if (isClient()) {
            return false;
        }
        stopper.checkCancelInProgress(null);

        if (!this.isServer) {
            return (this.allCacheServers.size() > 0);
        } else {
            return true;
        }
    }

    public QueryService getQueryService() {
        if (isClient()) {
            Pool p = getDefaultPool();
            if (p == null) {
                throw new IllegalStateException(
                        "Client cache does not have a default pool. Use getQueryService(String poolName) instead.");
            } else {
                return p.getQueryService();
            }
        } else {
            return new DefaultQueryService(this);
        }
    }

    public QueryService getLocalQueryService() {
        return new DefaultQueryService(this);
    }

    /**
     * @return Context jndi context associated with the Cache.
     * @since GemFire 4.0
     */
    public Context getJNDIContext() {
        // if (isClient()) {
        // throw new UnsupportedOperationException("operation is not supported on a client cache");
        // }
        return JNDIInvoker.getJNDIContext();
    }

    /**
     * @return JTA TransactionManager associated with the Cache.
     * @since GemFire 4.0
     */
    public javax.transaction.TransactionManager getJTATransactionManager() {
        // if (isClient()) {
        // throw new UnsupportedOperationException("operation is not supported on a client cache");
        // }
        return JNDIInvoker.getTransactionManager();
    }

    /**
     * return the cq/interest information for a given region name, creating one if it doesn't exist
     */
    public FilterProfile getFilterProfile(String regionName) {
        LocalRegion r = (LocalRegion) getRegion(regionName, true);
        if (r != null) {
            return r.getFilterProfile();
        }
        return null;
    }

    public RegionAttributes getRegionAttributes(String id) {
        return (RegionAttributes) this.namedRegionAttributes.get(id);
    }

    public void setRegionAttributes(String id, RegionAttributes attrs) {
        if (attrs == null) {
            this.namedRegionAttributes.remove(id);
        } else {
            this.namedRegionAttributes.put(id, attrs);
        }
    }

    public Map listRegionAttributes() {
        return Collections.unmodifiableMap(this.namedRegionAttributes);
    }

    private static final ThreadLocal xmlCache = new ThreadLocal();

    /**
     * Returns the cache currently being xml initialized by the thread that calls this method. The
     * result will be null if the thread is not initializing a cache.
     */
    public static GemFireCacheImpl getXmlCache() {
        return (GemFireCacheImpl) xmlCache.get();
    }

    public void loadCacheXml(InputStream stream)
            throws TimeoutException, CacheWriterException, GatewayException, RegionExistsException {
        // make this cache available to callbacks being initialized during xml create
        final Object oldValue = xmlCache.get();
        xmlCache.set(this);
        try {
            CacheXmlParser xml;

            if (xmlParameterizationEnabled) {
                char[] buffer = new char[1024];
                Reader reader = new BufferedReader(new InputStreamReader(stream, "ISO-8859-1"));
                Writer stringWriter = new StringWriter();

                int n = -1;
                while ((n = reader.read(buffer)) != -1) {
                    stringWriter.write(buffer, 0, n);
                }

                /**
                 * Now replace all replaceable system properties here using <code>PropertyResolver</code>
                 */
                String replacedXmlString = resolver.processUnresolvableString(stringWriter.toString());

                /*
                 * Turn the string back into the default encoding so that the XML parser can work correctly
                 * in the presence of an "encoding" attribute in the XML prolog.
                 */
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                OutputStreamWriter writer = new OutputStreamWriter(baos, "ISO-8859-1");
                writer.write(replacedXmlString);
                writer.flush();

                xml = CacheXmlParser.parse(new ByteArrayInputStream(baos.toByteArray()));
            } else {
                xml = CacheXmlParser.parse(stream);
            }
            xml.create(this);
        } catch (IOException e) {
            throw new CacheXmlException("Input Stream could not be read for system property substitutions.");
        } finally {
            xmlCache.set(oldValue);
        }
    }

    public void readyForEvents() {
        PoolManagerImpl.readyForEvents(this.system, false);
    }

    /**
     * This cache's reliable message queue factory. Should always have an instance of it.
     */
    private final ReliableMessageQueueFactory rmqFactory;

    private List<File> backupFiles = Collections.emptyList();

    /**
     * Returns this cache's ReliableMessageQueueFactory.
     *
     * @since GemFire 5.0
     */
    public ReliableMessageQueueFactory getReliableMessageQueueFactory() {
        return this.rmqFactory;
    }

    public InternalResourceManager getResourceManager() {
        return getResourceManager(true);
    }

    public InternalResourceManager getResourceManager(boolean checkCancellationInProgress) {
        if (checkCancellationInProgress) {
            stopper.checkCancelInProgress(null);
        }
        return this.resourceManager;
    }

    public void setBackupFiles(List<File> backups) {
        this.backupFiles = backups;
    }

    public List<File> getBackupFiles() {
        return Collections.unmodifiableList(this.backupFiles);
    }

    public BackupManager startBackup(InternalDistributedMember sender) throws IOException {
        BackupManager manager = new BackupManager(sender, this);
        if (!this.backupManager.compareAndSet(null, manager)) {
            // TODO prpersist internationalize this
            throw new IOException("Backup already in progress");
        }
        manager.start();
        return manager;
    }

    public void clearBackupManager() {
        this.backupManager.set(null);
    }

    public BackupManager getBackupManager() {
        return this.backupManager.get();
    }

    // //////////////////// Inner Classes //////////////////////

    // TODO make this a simple int guarded by riWaiters and get rid of the double-check
    private final AtomicInteger registerInterestsInProgress = new AtomicInteger();

    private final ArrayList<SimpleWaiter> riWaiters = new ArrayList<SimpleWaiter>();

    private TypeRegistry pdxRegistry; // never changes but is currently only
                                      // initialized in constructor by unit tests

    /**
     * update stats for completion of a registerInterest operation
     */
    public void registerInterestCompleted() {
        // Don't do a cancellation check, it's just a moot point, that's all
        // GemFireCache.this.getCancelCriterion().checkCancelInProgress(null);
        if (GemFireCacheImpl.this.isClosing) {
            return; // just get out, all of the SimpleWaiters will die of their own accord
        }
        int cv = registerInterestsInProgress.decrementAndGet();
        if (logger.isDebugEnabled()) {
            logger.debug("registerInterestCompleted: new value = {}", cv);
        }
        if (cv == 0) {
            synchronized (riWaiters) {
                // TODO double-check
                cv = registerInterestsInProgress.get();
                if (cv == 0) { // all clear
                    if (logger.isDebugEnabled()) {
                        logger.debug("registerInterestCompleted: Signalling end of register-interest");
                    }
                    Iterator it = riWaiters.iterator();
                    while (it.hasNext()) {
                        SimpleWaiter sw = (SimpleWaiter) it.next();
                        sw.doNotify();
                    }
                    riWaiters.clear();
                } // all clear
            } // synchronized
        }
    }

    public void registerInterestStarted() {
        // Don't do a cancellation check, it's just a moot point, that's all
        // GemFireCache.this.getCancelCriterion().checkCancelInProgress(null);
        int newVal = registerInterestsInProgress.incrementAndGet();
        if (logger.isDebugEnabled()) {
            logger.debug("registerInterestsStarted: new count = {}", newVal);
        }
    }

    /**
     * update stats for initiation of a registerInterest operation
     */
    /**
     * Blocks until no register interests are in progress.
     */
    public void waitForRegisterInterestsInProgress() {
        // In *this* particular context, let the caller know that
        // his cache has been cancelled. doWait below would do that as
        // well, so this is just an early out.
        GemFireCacheImpl.this.getCancelCriterion().checkCancelInProgress(null);

        int count = registerInterestsInProgress.get();
        SimpleWaiter sw = null;
        if (count > 0) {
            synchronized (riWaiters) {
                // TODO double-check
                count = registerInterestsInProgress.get();
                if (count > 0) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("waitForRegisterInterestsInProgress: count ={}", count);
                    }
                    sw = new SimpleWaiter();
                    riWaiters.add(sw);
                }
            } // synchronized
            if (sw != null) {
                sw.doWait();
            }
        }
    }

    /**
     * Wait for given sender queue to flush for given timeout.
     * 
     * @param id ID of GatewaySender or AsyncEventQueue
     * @param isAsyncListener true if this is for an AsyncEventQueue and false if for a GatewaySender
     * @param maxWaitTime maximum time to wait in seconds; zero or -ve means infinite wait
     * 
     * @return zero if maxWaitTime was not breached, -1 if queue could not be found or is closed, and
     *         elapsed time if timeout was breached
     */
    public int waitForSenderQueueFlush(String id, boolean isAsyncListener, int maxWaitTime) {
        getCancelCriterion().checkCancelInProgress(null);
        AbstractGatewaySender gatewaySender = null;
        if (isAsyncListener) {
            AsyncEventQueueImpl asyncQueue = (AsyncEventQueueImpl) getAsyncEventQueue(id);
            if (asyncQueue != null) {
                gatewaySender = (AbstractGatewaySender) asyncQueue.getSender();
            }
        } else {
            gatewaySender = (AbstractGatewaySender) getGatewaySender(id);
        }
        RegionQueue rq;
        final long startTime = System.currentTimeMillis();
        long elapsedTime;
        if (maxWaitTime <= 0) {
            maxWaitTime = Integer.MAX_VALUE;
        }
        while (gatewaySender != null && gatewaySender.isRunning() && (rq = gatewaySender.getQueue()) != null) {
            if (rq.size() == 0) {
                // return zero since it was not a timeout
                return 0;
            }
            try {
                Thread.sleep(500);
                getCancelCriterion().checkCancelInProgress(null);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                getCancelCriterion().checkCancelInProgress(ie);
            }
            // clear interrupted flag before retry
            Thread.interrupted();
            elapsedTime = System.currentTimeMillis() - startTime;
            if (elapsedTime >= (maxWaitTime * 1000L)) {
                // return elapsed time
                return (int) (elapsedTime / 1000L);
            }
        }
        return -1;
    }

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
    public void setQueryMonitorRequiredForResourceManager(boolean required) {
        QUERY_MONITOR_REQUIRED_FOR_RESOURCE_MANAGER = required;
    }

    public boolean isQueryMonitorDisabledForLowMemory() {
        return QUERY_MONITOR_DISABLED_FOR_LOW_MEM;
    }

    /**
     * Returns the QueryMonitor instance based on system property MAX_QUERY_EXECUTION_TIME.
     * 
     * @since GemFire 6.0
     */
    public QueryMonitor getQueryMonitor() {
        // Check to see if monitor is required if ResourceManager critical heap percentage is set
        // @see org.apache.geode.cache.control.ResourceManager#setCriticalHeapPercentage(int)
        // or whether we override it with the system variable;
        boolean monitorRequired = !QUERY_MONITOR_DISABLED_FOR_LOW_MEM
                && QUERY_MONITOR_REQUIRED_FOR_RESOURCE_MANAGER;
        // Added for DUnit test purpose, which turns-on and off the this.TEST_MAX_QUERY_EXECUTION_TIME.
        if (!(this.MAX_QUERY_EXECUTION_TIME > 0 || this.TEST_MAX_QUERY_EXECUTION_TIME > 0 || monitorRequired)) {
            // if this.TEST_MAX_QUERY_EXECUTION_TIME is set, send the QueryMonitor.
            // Else send null, so that the QueryMonitor is turned-off.
            return null;
        }

        // Return the QueryMonitor service if MAX_QUERY_EXECUTION_TIME is set or it is required by the
        // ResourceManager and not overriden by system property.
        if ((this.MAX_QUERY_EXECUTION_TIME > 0 || this.TEST_MAX_QUERY_EXECUTION_TIME > 0 || monitorRequired)
                && this.queryMonitor == null) {
            synchronized (queryMonitorLock) {
                if (this.queryMonitor == null) {
                    int maxTime = MAX_QUERY_EXECUTION_TIME > TEST_MAX_QUERY_EXECUTION_TIME
                            ? MAX_QUERY_EXECUTION_TIME
                            : TEST_MAX_QUERY_EXECUTION_TIME;

                    if (monitorRequired && maxTime < 0) {
                        // this means that the resource manager is being used and we need to monitor query
                        // memory usage
                        // If no max execution time has been set, then we will default to five hours
                        maxTime = FIVE_HOURS;
                    }

                    this.queryMonitor = new QueryMonitor(maxTime);
                    final LoggingThreadGroup group = LoggingThreadGroup
                            .createThreadGroup("QueryMonitor Thread Group", logger);
                    Thread qmThread = new Thread(group, this.queryMonitor, "QueryMonitor Thread");
                    qmThread.setDaemon(true);
                    qmThread.start();
                    if (logger.isDebugEnabled()) {
                        logger.debug("QueryMonitor thread started.");
                    }
                }
            }
        }
        return this.queryMonitor;
    }

    /**
     * Simple class to allow waiters for register interest. Has at most one thread that ever calls
     * wait.
     *
     * @since GemFire 5.7
     */
    private class SimpleWaiter {
        private boolean notified = false;

        SimpleWaiter() {
        }

        public void doWait() {
            synchronized (this) {
                while (!this.notified) {
                    GemFireCacheImpl.this.getCancelCriterion().checkCancelInProgress(null);
                    boolean interrupted = Thread.interrupted();
                    try {
                        this.wait(1000);
                    } catch (InterruptedException ex) {
                        interrupted = true;
                    } finally {
                        if (interrupted) {
                            Thread.currentThread().interrupt();
                        }
                    }
                }
            }
        }

        public void doNotify() {
            synchronized (this) {
                this.notified = true;
                this.notifyAll();
            }
        }
    }

    private void sendAddCacheServerProfileMessage() {
        DM dm = this.getDistributedSystem().getDistributionManager();
        Set otherMembers = dm.getOtherDistributionManagerIds();
        AddCacheServerProfileMessage msg = new AddCacheServerProfileMessage();
        msg.operateOnLocalCache(this);
        if (!otherMembers.isEmpty()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Sending add cache server profile message to other members.");
            }
            ReplyProcessor21 rp = new ReplyProcessor21(dm, otherMembers);
            msg.setRecipients(otherMembers);
            msg.processorId = rp.getProcessorId();
            dm.putOutgoing(msg);

            // Wait for replies.
            try {
                rp.waitForReplies();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public TXManagerImpl getTxManager() {
        return this.txMgr;
    }

    /**
     * @since GemFire 6.5
     */
    public <K, V> RegionFactory<K, V> createRegionFactory(RegionShortcut atts) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        } else {
            return new RegionFactoryImpl<K, V>(this, atts);
        }
    }

    /**
     * @since GemFire 6.5
     */
    public <K, V> RegionFactory<K, V> createRegionFactory() {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        return new RegionFactoryImpl<K, V>(this);
    }

    /**
     * @since GemFire 6.5
     */
    public <K, V> RegionFactory<K, V> createRegionFactory(String regionAttributesId) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        return new RegionFactoryImpl<K, V>(this, regionAttributesId);
    }

    /**
     * @since GemFire 6.5
     */
    public <K, V> RegionFactory<K, V> createRegionFactory(RegionAttributes<K, V> regionAttributes) {
        if (isClient()) {
            throw new UnsupportedOperationException("operation is not supported on a client cache");
        }
        return new RegionFactoryImpl<K, V>(this, regionAttributes);
    }

    /**
     * @since GemFire 6.5
     */
    public <K, V> ClientRegionFactory<K, V> createClientRegionFactory(ClientRegionShortcut atts) {
        return new ClientRegionFactoryImpl<K, V>(this, atts);
    }

    public <K, V> ClientRegionFactory<K, V> createClientRegionFactory(String refid) {
        return new ClientRegionFactoryImpl<K, V>(this, refid);
    }

    /**
     * @since GemFire 6.5
     */
    public QueryService getQueryService(String poolName) {
        Pool p = PoolManager.find(poolName);
        if (p == null) {
            throw new IllegalStateException("Could not find a pool named " + poolName);
        } else {
            return p.getQueryService();
        }
    }

    public RegionService createAuthenticatedView(Properties properties) {
        Pool pool = getDefaultPool();
        if (pool == null) {
            throw new IllegalStateException("This cache does not have a default pool");
        }
        return createAuthenticatedCacheView(pool, properties);
    }

    public RegionService createAuthenticatedView(Properties properties, String poolName) {
        Pool pool = PoolManager.find(poolName);
        if (pool == null) {
            throw new IllegalStateException("Pool " + poolName + " does not exist");
        }
        return createAuthenticatedCacheView(pool, properties);
    }

    public RegionService createAuthenticatedCacheView(Pool pool, Properties properties) {
        if (pool.getMultiuserAuthentication()) {
            return ((PoolImpl) pool).createAuthenticatedCacheView(properties);
        } else {
            throw new IllegalStateException(
                    "The pool " + pool.getName() + " did not have multiuser-authentication set to true");
        }
    }

    public static void initializeRegionShortcuts(Cache c) {
        for (RegionShortcut pra : RegionShortcut.values()) {
            switch (pra) {
            case PARTITION: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                af.setPartitionAttributes(paf.create());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_REDUNDANT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setRedundantCopies(1);
                af.setPartitionAttributes(paf.create());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_PERSISTENT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                af.setPartitionAttributes(paf.create());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_REDUNDANT_PERSISTENT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setRedundantCopies(1);
                af.setPartitionAttributes(paf.create());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                af.setPartitionAttributes(paf.create());
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_REDUNDANT_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setRedundantCopies(1);
                af.setPartitionAttributes(paf.create());
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_PERSISTENT_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                af.setPartitionAttributes(paf.create());
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_REDUNDANT_PERSISTENT_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setRedundantCopies(1);
                af.setPartitionAttributes(paf.create());
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_HEAP_LRU: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                af.setPartitionAttributes(paf.create());
                af.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_REDUNDANT_HEAP_LRU: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setRedundantCopies(1);
                af.setPartitionAttributes(paf.create());
                af.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case REPLICATE: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.REPLICATE);
                af.setScope(Scope.DISTRIBUTED_ACK);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case REPLICATE_PERSISTENT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
                af.setScope(Scope.DISTRIBUTED_ACK);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case REPLICATE_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.REPLICATE);
                af.setScope(Scope.DISTRIBUTED_ACK);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case REPLICATE_PERSISTENT_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
                af.setScope(Scope.DISTRIBUTED_ACK);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case REPLICATE_HEAP_LRU: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.REPLICATE);
                af.setScope(Scope.DISTRIBUTED_ACK);
                af.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setScope(Scope.LOCAL);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_PERSISTENT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
                af.setScope(Scope.LOCAL);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_HEAP_LRU: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setScope(Scope.LOCAL);
                af.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setScope(Scope.LOCAL);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_PERSISTENT_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
                af.setScope(Scope.LOCAL);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_PROXY: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setLocalMaxMemory(0);
                af.setPartitionAttributes(paf.create());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PARTITION_PROXY_REDUNDANT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PARTITION);
                PartitionAttributesFactory paf = new PartitionAttributesFactory();
                paf.setLocalMaxMemory(0);
                paf.setRedundantCopies(1);
                af.setPartitionAttributes(paf.create());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case REPLICATE_PROXY: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.EMPTY);
                af.setScope(Scope.DISTRIBUTED_ACK);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            default:
                throw new IllegalStateException("unhandled enum " + pra);
            }
        }
    }

    public static void initializeClientRegionShortcuts(Cache c) {
        for (ClientRegionShortcut pra : ClientRegionShortcut.values()) {
            switch (pra) {
            case LOCAL: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_PERSISTENT: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_HEAP_LRU: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes());
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case LOCAL_PERSISTENT_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                c.setRegionAttributes(pra.toString(), af.create());
                break;
            }
            case PROXY: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.EMPTY);
                UserSpecifiedRegionAttributes ra = (UserSpecifiedRegionAttributes) af.create();
                ra.requiresPoolName = true;
                c.setRegionAttributes(pra.toString(), ra);
                break;
            }
            case CACHING_PROXY: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                UserSpecifiedRegionAttributes ra = (UserSpecifiedRegionAttributes) af.create();
                ra.requiresPoolName = true;
                c.setRegionAttributes(pra.toString(), ra);
                break;
            }
            case CACHING_PROXY_HEAP_LRU: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes());
                UserSpecifiedRegionAttributes ra = (UserSpecifiedRegionAttributes) af.create();
                ra.requiresPoolName = true;
                c.setRegionAttributes(pra.toString(), ra);
                break;
            }
            case CACHING_PROXY_OVERFLOW: {
                AttributesFactory af = new AttributesFactory();
                af.setDataPolicy(DataPolicy.NORMAL);
                af.setEvictionAttributes(
                        EvictionAttributes.createLRUHeapAttributes(null, EvictionAction.OVERFLOW_TO_DISK));
                UserSpecifiedRegionAttributes ra = (UserSpecifiedRegionAttributes) af.create();
                ra.requiresPoolName = true;
                c.setRegionAttributes(pra.toString(), ra);
                break;
            }
            default:
                throw new IllegalStateException("unhandled enum " + pra);
            }
        }
    }

    public void beginDestroy(String path, DistributedRegion region) {
        this.regionsInDestroy.putIfAbsent(path, region);
    }

    public void endDestroy(String path, DistributedRegion region) {
        this.regionsInDestroy.remove(path, region);
    }

    public DistributedRegion getRegionInDestroy(String path) {
        return this.regionsInDestroy.get(path);
    }

    public TombstoneService getTombstoneService() {
        return this.tombstoneService;
    }

    public TypeRegistry getPdxRegistry() {
        return this.pdxRegistry;
    }

    public boolean getPdxReadSerialized() {
        return this.cacheConfig.pdxReadSerialized;
    }

    public PdxSerializer getPdxSerializer() {
        return this.cacheConfig.pdxSerializer;
    }

    public String getPdxDiskStore() {
        return this.cacheConfig.pdxDiskStore;
    }

    public boolean getPdxPersistent() {
        return this.cacheConfig.pdxPersistent;
    }

    public boolean getPdxIgnoreUnreadFields() {
        return this.cacheConfig.pdxIgnoreUnreadFields;
    }

    /**
     * Returns true if any of the GemFire services prefers PdxInstance. And application has not
     * requested getObject() on the PdxInstance.
     *
     */
    public boolean getPdxReadSerializedByAnyGemFireServices() {
        if ((getPdxReadSerialized() || DefaultQuery.getPdxReadSerialized())
                && PdxInstanceImpl.getPdxReadSerialized()) {
            return true;
        }
        return false;
    }

    public CacheConfig getCacheConfig() {
        return this.cacheConfig;
    }

    public DM getDistributionManager() {
        return this.dm;
    }

    public GatewaySenderFactory createGatewaySenderFactory() {
        return WANServiceProvider.createGatewaySenderFactory(this);
    }

    public GatewayReceiverFactory createGatewayReceiverFactory() {
        return WANServiceProvider.createGatewayReceiverFactory(this);
    }

    public AsyncEventQueueFactory createAsyncEventQueueFactory() {
        return new AsyncEventQueueFactoryImpl(this);
    }

    public DistributionAdvisor getDistributionAdvisor() {
        return getResourceAdvisor();
    }

    public ResourceAdvisor getResourceAdvisor() {
        return resourceAdvisor;
    }

    public Profile getProfile() {
        return resourceAdvisor.createProfile();
    }

    public DistributionAdvisee getParentAdvisee() {
        return null;
    }

    public InternalDistributedSystem getSystem() {
        return this.system;
    }

    public String getFullPath() {
        return "ResourceManager";
    }

    public void fillInProfile(Profile profile) {
        resourceManager.fillInProfile(profile);
    }

    public int getSerialNumber() {
        return this.serialNumber;
    }

    public TXEntryStateFactory getTXEntryStateFactory() {
        return this.txEntryStateFactory;
    }

    // test hook
    public void setPdxSerializer(PdxSerializer v) {
        this.cacheConfig.setPdxSerializer(v);
        basicSetPdxSerializer(v);
    }

    private void basicSetPdxSerializer(PdxSerializer v) {
        TypeRegistry.setPdxSerializer(v);
        if (v instanceof ReflectionBasedAutoSerializer) {
            AutoSerializableManager asm = (AutoSerializableManager) ((ReflectionBasedAutoSerializer) v)
                    .getManager();
            if (asm != null) {
                asm.setRegionService(this);
            }
        }
    }

    // test hook
    public void setReadSerialized(boolean v) {
        this.cacheConfig.setPdxReadSerialized(v);
    }

    public void setDeclarativeCacheConfig(CacheConfig cacheConfig) {
        this.cacheConfig.setDeclarativeConfig(cacheConfig);
        basicSetPdxSerializer(this.cacheConfig.getPdxSerializer());
    }

    /**
     * Add to the map of declarable properties. Any properties that exactly match existing properties
     * for a class in the list will be discarded (no duplicate Properties allowed).
     * 
     * @param mapOfNewDeclarableProps Map of the declarable properties to add
     */
    public void addDeclarableProperties(final Map<Declarable, Properties> mapOfNewDeclarableProps) {
        synchronized (this.declarablePropertiesMap) {
            for (Map.Entry<Declarable, Properties> newEntry : mapOfNewDeclarableProps.entrySet()) {
                // Find and remove a Declarable from the map if an "equal" version is already stored
                Class clazz = newEntry.getKey().getClass();

                Object matchingDeclarable = null;
                for (Map.Entry<Declarable, Properties> oldEntry : this.declarablePropertiesMap.entrySet()) {
                    if (clazz.getName().equals(oldEntry.getKey().getClass().getName()) && (newEntry.getValue()
                            .equals(oldEntry.getValue())
                            || ((newEntry.getKey() instanceof Identifiable) && (((Identifiable) oldEntry.getKey())
                                    .getId().equals(((Identifiable) newEntry.getKey()).getId()))))) {
                        matchingDeclarable = oldEntry.getKey();
                        break;
                    }
                }
                if (matchingDeclarable != null) {
                    this.declarablePropertiesMap.remove(matchingDeclarable);
                }

                // Now add the new/replacement properties to the map
                this.declarablePropertiesMap.put(newEntry.getKey(), newEntry.getValue());
            }
        }
    }

    public static boolean isXmlParameterizationEnabled() {
        return xmlParameterizationEnabled;
    }

    public static void setXmlParameterizationEnabled(boolean isXmlParameterizationEnabled) {
        xmlParameterizationEnabled = isXmlParameterizationEnabled;
    }

    private Declarable initializer;
    private Properties initializerProps;

    /**
     * A factory for temporary result sets than can overflow to disk.
     */
    private TemporaryResultSetFactory resultSetFactory;

    public Declarable getInitializer() {
        return this.initializer;
    }

    public Properties getInitializerProps() {
        return this.initializerProps;
    }

    public void setInitializer(Declarable initializer, Properties initializerProps) {
        this.initializer = initializer;
        this.initializerProps = initializerProps;
    }

    public PdxInstanceFactory createPdxInstanceFactory(String className) {
        return PdxInstanceFactoryImpl.newCreator(className, true);
    }

    public PdxInstanceFactory createPdxInstanceFactory(String className, boolean b) {
        return PdxInstanceFactoryImpl.newCreator(className, b);
    }

    public PdxInstance createPdxEnum(String className, String enumName, int enumOrdinal) {
        return PdxInstanceFactoryImpl.createPdxEnum(className, enumName, enumOrdinal, this);
    }

    public JmxManagerAdvisor getJmxManagerAdvisor() {
        return this.jmxAdvisor;
    }

    public CacheSnapshotService getSnapshotService() {
        return new CacheSnapshotServiceImpl(this);
    }

    private void startColocatedJmxManagerLocator() {
        InternalLocator loc = InternalLocator.getLocator();
        if (loc != null) {
            loc.startJmxManagerLocationService(this);
        }
    }

    public TemporaryResultSetFactory getResultSetFactory() {
        return this.resultSetFactory;
    }

    public MemoryAllocator getOffHeapStore() {
        return this.getSystem().getOffHeapStore();
    }

    public DiskStoreMonitor getDiskStoreMonitor() {
        return diskMonitor;
    }

    /**
     * @see Extensible#getExtensionPoint()
     * @since GemFire 8.1
     */
    @Override
    public ExtensionPoint<Cache> getExtensionPoint() {
        return extensionPoint;
    }

    public static int getClientFunctionTimeout() {
        return clientFunctionTimeout;
    }

    public CqService getCqService() {
        return this.cqService;
    }
}