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