| /* |
| * 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 static org.apache.geode.cache.Region.SEPARATOR; |
| |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.CancelCriterion; |
| import org.apache.geode.InternalGemFireError; |
| import org.apache.geode.annotations.VisibleForTesting; |
| import org.apache.geode.cache.DiskAccessException; |
| import org.apache.geode.cache.EvictionAttributes; |
| import org.apache.geode.cache.RegionAttributes; |
| import org.apache.geode.cache.persistence.PartitionOfflineException; |
| import org.apache.geode.distributed.DistributedLockService; |
| import org.apache.geode.distributed.DistributedMember; |
| 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.DistributionManager; |
| import org.apache.geode.distributed.internal.InternalDistributedSystem; |
| import org.apache.geode.distributed.internal.membership.InternalDistributedMember; |
| import org.apache.geode.internal.Assert; |
| import org.apache.geode.internal.cache.CacheDistributionAdvisor.CacheProfile; |
| import org.apache.geode.internal.cache.DiskInitFile.DiskRegionFlag; |
| import org.apache.geode.internal.cache.PartitionedRegion.BucketLock; |
| import org.apache.geode.internal.cache.PartitionedRegionDataStore.CreateBucketResult; |
| import org.apache.geode.internal.cache.partitioned.Bucket; |
| import org.apache.geode.internal.cache.persistence.PersistentMemberID; |
| import org.apache.geode.internal.cache.persistence.PersistentMemberManager; |
| import org.apache.geode.internal.cache.persistence.PersistentMembershipView; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| |
| /** |
| * Empty shell for {@link BucketRegion} which exists only to maintain metadata in the form of a |
| * {@link BucketAdvisor} |
| * |
| * @since GemFire 5.1 |
| */ |
| public class ProxyBucketRegion implements Bucket { |
| private static final Logger logger = LogService.getLogger(); |
| |
| private final int serialNumber; |
| private final int bid; |
| private final PartitionedRegion partitionedRegion; |
| private final BucketAdvisor advisor; |
| private final BucketPersistenceAdvisor persistenceAdvisor; |
| private volatile BucketRegion realBucket = null; |
| private final AtomicBoolean bucketSick = new AtomicBoolean(false); |
| private final Set<DistributedMember> sickHosts = new HashSet<>(); |
| private final DiskRegion diskRegion; |
| private final BucketLock bucketLock; |
| private int recoverFromDiskCnt; |
| |
| /** |
| * Note that LocalRegion has a version of this name spelled "NO_PARTITITON". So if code is written |
| * that compares to this constant make sure to also compare to the other one from LocalRegion. The |
| * one in LocalRegion is a typo but has already been persisted in older versions. |
| */ |
| public static final String NO_FIXED_PARTITION_NAME = "NO_PARTITION"; |
| |
| /** |
| * Constructs a new ProxyBucketRegion which has a BucketAdvisor. |
| * |
| * @param bid the bucket id |
| * @param partitionedRegion the PartitionedRegion that owns this bucket |
| * @param internalRegionArgs the internal args which includes RegionAdvisor |
| */ |
| public ProxyBucketRegion(int bid, PartitionedRegion partitionedRegion, |
| InternalRegionArguments internalRegionArgs) { |
| serialNumber = DistributionAdvisor.createSerialNumber(); |
| this.bid = bid; |
| this.partitionedRegion = partitionedRegion; |
| advisor = |
| BucketAdvisor.createBucketAdvisor(this, internalRegionArgs.getPartitionedRegionAdvisor()); |
| |
| bucketLock = this.partitionedRegion.getBucketLock(this.bid); |
| recoverFromDiskCnt = 0; |
| |
| if (this.partitionedRegion.getDataPolicy().withPersistence()) { |
| |
| String regionPath = getFullPath(); |
| PersistentMemberManager memberManager = |
| partitionedRegion.getGemFireCache().getPersistentMemberManager(); |
| DiskRegionStats diskStats = partitionedRegion.getDiskRegionStats(); |
| DistributedLockService dl = |
| partitionedRegion.getGemFireCache().getPartitionedRegionLockService(); |
| DiskStoreImpl ds = partitionedRegion.getDiskStore(); |
| EvictionAttributes ea = partitionedRegion.getAttributes().getEvictionAttributes(); |
| EnumSet<DiskRegionFlag> diskFlags = EnumSet.noneOf(DiskRegionFlag.class); |
| // Add flag if this region has versioning enabled |
| if (partitionedRegion.getConcurrencyChecksEnabled()) { |
| diskFlags.add(DiskRegionFlag.IS_WITH_VERSIONING); |
| } |
| boolean overflowEnabled = ea != null && ea.getAction().isOverflowToDisk(); |
| int startingBucketID = -1; |
| String partitionName = NO_FIXED_PARTITION_NAME; |
| List<FixedPartitionAttributesImpl> fpaList = |
| partitionedRegion.getFixedPartitionAttributesImpl(); |
| if (fpaList != null) { |
| for (FixedPartitionAttributesImpl fpa : fpaList) { |
| if (fpa.hasBucket(bid)) { |
| startingBucketID = fpa.getStartingBucketID(); |
| partitionName = fpa.getPartitionName(); |
| break; |
| } |
| } |
| } |
| diskRegion = |
| DiskRegion.create(ds, regionPath, true, partitionedRegion.getPersistBackup(), |
| overflowEnabled, partitionedRegion.isDiskSynchronous(), |
| partitionedRegion.getDiskRegionStats(), partitionedRegion.getCancelCriterion(), |
| partitionedRegion, partitionedRegion.getAttributes(), diskFlags, partitionName, |
| startingBucketID, partitionedRegion.getCompressor(), partitionedRegion.getOffHeap()); |
| |
| if (fpaList != null) { |
| for (FixedPartitionAttributesImpl fpa : fpaList) { |
| if (fpa.getPartitionName().equals(diskRegion.getPartitionName()) |
| && diskRegion.getStartingBucketId() != -1) { |
| fpa.setStartingBucketID(diskRegion.getStartingBucketId()); |
| partitionedRegion.getPartitionsMap().put(fpa.getPartitionName(), |
| new Integer[] {fpa.getStartingBucketID(), fpa.getNumBuckets()}); |
| } |
| } |
| } |
| |
| persistenceAdvisor = new BucketPersistenceAdvisor(advisor, dl, diskRegion, regionPath, |
| diskStats, memberManager, bucketLock, this); |
| } else { |
| diskRegion = null; |
| persistenceAdvisor = null; |
| } |
| } |
| |
| @Override |
| public CancelCriterion getCancelCriterion() { |
| return partitionedRegion.getCache().getCancelCriterion(); |
| } |
| |
| public void close() { |
| if (persistenceAdvisor != null) { |
| persistenceAdvisor.close(); |
| } |
| advisor.closeAdvisor(); |
| if (diskRegion != null) { |
| diskRegion.close(null); |
| } |
| } |
| |
| @Override |
| public int getSerialNumber() { |
| // always return the serial number for this proxy, NOT the bucket region |
| return serialNumber; |
| } |
| |
| @Override |
| public DistributionManager getDistributionManager() { |
| return getSystem().getDistributionManager(); |
| } |
| |
| @Override |
| public DistributionAdvisor getDistributionAdvisor() { |
| return advisor; |
| } |
| |
| @Override |
| public CacheDistributionAdvisor getCacheDistributionAdvisor() { |
| return advisor; |
| } |
| |
| @Override |
| public Profile getProfile() { |
| return advisor.createProfile(); |
| } |
| |
| @Override |
| public DistributionAdvisee getParentAdvisee() { |
| return partitionedRegion; |
| } |
| |
| @Override |
| public PartitionedRegion getPartitionedRegion() { |
| return partitionedRegion; |
| } |
| |
| @Override |
| public InternalDistributedSystem getSystem() { |
| return partitionedRegion.getCache().getInternalDistributedSystem(); |
| } |
| |
| @Override |
| public String getName() { |
| return getPartitionedRegion().getBucketName(bid); |
| } |
| |
| @Override |
| public String getFullPath() { |
| return SEPARATOR + PartitionedRegionHelper.PR_ROOT_REGION_NAME + SEPARATOR |
| + getPartitionedRegion().getBucketName(bid); |
| } |
| |
| @Override |
| public InternalCache getCache() { |
| return partitionedRegion.getCache(); |
| } |
| |
| @Override |
| public RegionAttributes getAttributes() { |
| return partitionedRegion.getAttributes(); |
| } |
| |
| @Override |
| public BucketAdvisor getBucketAdvisor() { |
| return advisor; |
| } |
| |
| /** |
| * Notify this proxy of the real bucket as its target. Future calls to this instance will then |
| * proxy them back to the real bucket. |
| * |
| * @param br the real bucket which will be the target for this proxy |
| */ |
| public void setBucketRegion(BucketRegion br) { |
| // fix several bugs including 36881... creation of BR may be occurring |
| // at same time another thread is destroying the PR and now that this |
| // BR is visible to the destroy thread we want to prevent sending bogus |
| // CreateRegion or profile update messages |
| partitionedRegion.checkReadiness(); |
| partitionedRegion.checkClosed(); |
| Assert.assertTrue(realBucket == null); |
| Assert.assertTrue(!advisor.isHosting()); |
| realBucket = br; |
| } |
| |
| void clearBucketRegion(BucketRegion br) { |
| Assert.assertTrue(realBucket == br); |
| realBucket = null; |
| } |
| |
| public void setHosting(boolean value) { |
| if (value) { |
| PartitionedRegion region = getPartitionedRegion(); |
| Assert.assertTrue(realBucket != null); |
| Assert.assertTrue(!advisor.isHosting()); |
| if (region.isFixedPartitionedRegion()) { |
| List<FixedPartitionAttributesImpl> list = region.getFixedPartitionAttributesImpl(); |
| if (list != null) { |
| for (FixedPartitionAttributesImpl info : list) { |
| if (info.hasBucket(bid)) { |
| advisor.setHosting(true); |
| break; |
| } |
| } |
| } |
| } else { // normal PR |
| advisor.setHosting(true); |
| } |
| } else { |
| // Assert.assertTrue(!getPartitionedRegion().getDataStore().isManagingBucket(this.bid)); |
| advisor.setHosting(false); |
| realBucket = null; |
| } |
| } |
| |
| public void removeBucket() { |
| realBucket.removeFromPeersAdvisors(true); |
| advisor.removeBucket(); |
| realBucket = null; |
| } |
| |
| /** |
| * Get the redundancy of the this bucket, taking into account the local bucket, if any. |
| * |
| * @return number of redundant copies for a given bucket, or -1 if there are no instances of the |
| * bucket. |
| */ |
| public int getBucketRedundancy() { |
| return getBucketAdvisor().getBucketRedundancy(); |
| } |
| |
| @Override |
| public boolean isPrimary() { |
| return advisor.isPrimary(); |
| } |
| |
| /** |
| * Returns the real BucketRegion if one has been created. This call will return the bucket even if |
| * it is still being initialized. Returns null if the bucket has not been created locally. |
| * |
| * @return the real bucket if currently created or null |
| */ |
| public BucketRegion getCreatedBucketRegion() { |
| return realBucket; |
| } |
| |
| /** |
| * Returns the real BucketRegion that is currently being locally hosted. Returns null if the real |
| * bucket is null or if it is still being initialized. After the bucket is intialized isHosting |
| * will be flagged true and future calls to this method will return the bucket. |
| * |
| * @return the real bucket if currently hosted or null |
| */ |
| public BucketRegion getHostedBucketRegion() { |
| if (advisor.isHosting()) { |
| return realBucket; |
| } else { |
| return null; |
| } |
| } |
| |
| @Override |
| public boolean isHosting() { |
| return advisor.isHosting(); |
| } |
| |
| @Override |
| public void fillInProfile(Profile profile) { |
| if (logger.isDebugEnabled()) { |
| logger.debug("ProxyBucketRegion filling in profile: {}", profile); |
| } |
| BucketRegion bucket = realBucket; |
| if (bucket != null) { |
| bucket.fillInProfile(profile); |
| } |
| } |
| |
| public ProxyBucketRegion initialize() { |
| // dead coded initializationGate to prevent profile exchange |
| // this.advisor.initializationGate(); |
| advisor.setInitialized(); |
| return this; |
| } |
| |
| @Override |
| public Set<InternalDistributedMember> getBucketOwners() { |
| Set<InternalDistributedMember> s = advisor.adviseInitialized(); |
| if (s.isEmpty()) { |
| // getBucketOwners needs to return a modifiable set. |
| // adviseInitialized returns an unmodifiable set when it is empty. |
| s = new HashSet<>(); |
| } |
| if (isHosting()) { |
| s.add(partitionedRegion.getDistributionManager().getId()); |
| } |
| return s; |
| } |
| |
| /** |
| * Returns the total number of datastores hosting an instance of this bucket. |
| * |
| * @return the total number of datastores hosting an instance of this bucket |
| */ |
| public int getBucketOwnersCount() { |
| return advisor.getBucketRedundancy() + 1; |
| } |
| |
| public int getBucketId() { |
| return bid; |
| } |
| |
| @Override |
| public int getId() { |
| return getBucketId(); |
| } |
| |
| public void setBucketSick(DistributedMember member, boolean sick) { |
| synchronized (sickHosts) { |
| if (sick) { |
| sickHosts.add(member); |
| } else { |
| sickHosts.remove(member); |
| } |
| bucketSick.set(sickHosts.size() > 0); |
| } |
| } |
| |
| public boolean isBucketSick() { |
| return bucketSick.get(); |
| } |
| |
| public Set<DistributedMember> getSickMembers() { |
| synchronized (sickHosts) { |
| return Collections.unmodifiableSet(new HashSet<>(sickHosts)); |
| } |
| } |
| |
| void recoverFromDiskRecursively() { |
| recoverFromDisk(); |
| |
| List<PartitionedRegion> colocatedWithList = |
| ColocationHelper.getColocatedChildRegions(partitionedRegion); |
| for (PartitionedRegion childPR : colocatedWithList) { |
| if (childPR.getDataPolicy().withPersistence()) { |
| ProxyBucketRegion[] childBucketArray = childPR.getRegionAdvisor().getProxyBucketArray(); |
| if (childBucketArray != null) { |
| ProxyBucketRegion childBucket = childBucketArray[getBucketId()]; |
| childBucket.recoverFromDisk(); |
| } |
| } |
| } |
| } |
| |
| public void recoverFromDisk() { |
| final boolean isDebugEnabled = logger.isDebugEnabled(); |
| |
| RuntimeException exception = null; |
| if (isDebugEnabled) { |
| logger.debug("{} coming to recover from disk. wasHosting {}", getFullPath(), |
| persistenceAdvisor.wasHosting()); |
| } |
| if (!persistenceAdvisor.isRecovering()) { |
| return; |
| } |
| recoverFromDiskCnt++; |
| |
| try { |
| if (persistenceAdvisor.wasHosting()) { |
| if (isDebugEnabled) { |
| logger.debug("{} used to host data. Attempting to recover.", getFullPath()); |
| } |
| CreateBucketResult result; |
| if (hasPersistentChildRegion()) { |
| // If this is a parent PR, create the bucket, possibly going over |
| // redundancy. We need to do this so that we can create the child |
| // region in this member. This member may have the latest data for the |
| // child region. |
| result = partitionedRegion.getDataStore().grabBucket(bid, |
| getDistributionManager().getDistributionManagerId(), true, true, false, null, true); |
| } else { |
| if (partitionedRegion.isShadowPR() |
| && partitionedRegion.getColocatedWith() != null) { |
| PartitionedRegion colocatedRegion = |
| ColocationHelper.getColocatedRegion(partitionedRegion); |
| |
| if (partitionedRegion.getDataPolicy().withPersistence() |
| && !Objects.requireNonNull(colocatedRegion).getDataPolicy().withPersistence()) { |
| result = colocatedRegion.getDataStore().grabBucket(bid, |
| getDistributionManager().getDistributionManagerId(), true, true, false, null, |
| true); |
| |
| if (result.nowExists()) { |
| result = partitionedRegion.getDataStore().grabBucket(bid, null, true, false, false, |
| null, true); |
| } |
| } else { |
| result = partitionedRegion.getDataStore().grabBucket(bid, null, true, false, false, |
| null, true); |
| } |
| } else { |
| result = partitionedRegion.getDataStore().grabBucket(bid, null, true, false, false, |
| null, true); |
| } |
| |
| } |
| if (result.nowExists()) { |
| return; |
| } else if (result != CreateBucketResult.REDUNDANCY_ALREADY_SATISFIED) { |
| // TODO prpersist - check cache closure, create new error message |
| partitionedRegion.checkReadiness(); |
| throw new InternalGemFireError( |
| "Unable to restore the persistent bucket " + getName()); |
| } |
| |
| if (isDebugEnabled) { |
| logger.debug( |
| "{} redundancy is already satisfied, so discarding persisted data. Current hosts {}", |
| getFullPath(), advisor.adviseReplicates()); |
| } |
| |
| // Destroy the data if we can't create the bucket, or if the redundancy is already satisfied |
| destroyOfflineData(); |
| } |
| |
| if (isDebugEnabled) { |
| logger.debug("{} initializing membership view from peers", getFullPath()); |
| } |
| |
| persistenceAdvisor.initializeMembershipView(); |
| } catch (DiskAccessException dae) { |
| partitionedRegion.handleDiskAccessException(dae); |
| throw dae; |
| } catch (RuntimeException e) { |
| exception = e; |
| throw e; |
| } finally { |
| persistenceAdvisor.recoveryDone(exception); |
| } |
| } |
| |
| @VisibleForTesting |
| public int getRecoverFromDiskCnt() { |
| return recoverFromDiskCnt; |
| } |
| |
| boolean hasPersistentChildRegion() { |
| return ColocationHelper.hasPersistentChildRegion(partitionedRegion); |
| } |
| |
| /** |
| * Destroy the offline data just for this bucket. |
| */ |
| void destroyOfflineData() { |
| Map<InternalDistributedMember, PersistentMemberID> onlineMembers = |
| advisor.adviseInitializedPersistentMembers(); |
| persistenceAdvisor.checkMyStateOnMembers(onlineMembers.keySet()); |
| diskRegion.beginDestroyDataStorage(); |
| persistenceAdvisor.finishPendingDestroy(); |
| if (logger.isDebugEnabled()) { |
| logger.debug("destroyed persistent data for {}" + getFullPath()); |
| } |
| } |
| |
| @Override |
| public BucketPersistenceAdvisor getPersistenceAdvisor() { |
| return persistenceAdvisor; |
| } |
| |
| @Override |
| public DiskRegion getDiskRegion() { |
| return diskRegion; |
| } |
| |
| void finishRemoveBucket() { |
| if (persistenceAdvisor != null) { |
| persistenceAdvisor.bucketRemoved(); |
| } |
| } |
| |
| public BucketLock getBucketLock() { |
| return bucketLock; |
| } |
| |
| void initializePersistenceAdvisor() { |
| persistenceAdvisor.initialize(); |
| |
| List<PartitionedRegion> colocatedWithList = |
| ColocationHelper.getColocatedChildRegions(partitionedRegion); |
| for (PartitionedRegion childPR : colocatedWithList) { |
| ProxyBucketRegion[] childBucketArray = childPR.getRegionAdvisor().getProxyBucketArray(); |
| if (childBucketArray != null) { |
| ProxyBucketRegion childBucket = childBucketArray[getBucketId()]; |
| if (childBucket.persistenceAdvisor != null) { |
| childBucket.persistenceAdvisor.initialize(); |
| } |
| } |
| } |
| } |
| |
| boolean checkBucketRedundancyBeforeGrab(InternalDistributedMember moveSource, |
| boolean replaceOfflineData) { |
| int redundancy = getBucketAdvisor().getBucketRedundancy(); |
| // Skip any checks if this is a colocated bucket. We need to create |
| // the colocated bucket if we managed to create the parent bucket. There are |
| // race conditions where the parent region may know that a member is no longer |
| // hosting the bucket, but the child region doesn't know that yet. |
| PartitionedRegion colocatedRegion = ColocationHelper.getColocatedRegion(partitionedRegion); |
| if (colocatedRegion != null) { |
| return true; |
| } |
| |
| // Check for offline members, if the region has persistence |
| // Even if we intend to replace offline data, we still need to make |
| // sure the bucket isn't completely offline |
| if (!replaceOfflineData || redundancy == -1) { |
| BucketPersistenceAdvisor persistAdvisor = getPersistenceAdvisor(); |
| if (persistAdvisor != null) { |
| // If we haven't finished recovering from disk, don't allow the bucket creation. |
| // if(persistAdvisor.isRecovering()) { |
| // return false; |
| // } |
| // If we previously hosted this bucket, go ahead and initialize |
| // If this bucket never had a primary, go ahead and initialize, |
| // any offline buckets should be empty |
| if (!persistAdvisor.wasHosting() && advisor.getHadPrimary()) { |
| final PersistentMembershipView membershipView = persistAdvisor.getMembershipView(); |
| if (membershipView == null) { |
| // Fix for 42327 - There must be a race where we are being told to create a bucket |
| // before we recover from disk. In that case, the membership view can be null. |
| // Refuse to create the bucket if that is the case. |
| if (logger.isDebugEnabled()) { |
| logger.debug( |
| "grabFreeBucket: Can't create bucket because persistence is not yet initialized {}{}{}", |
| partitionedRegion.getPRId(), PartitionedRegion.BUCKET_ID_SEPARATOR, bid); |
| } |
| return false; |
| } |
| Set<PersistentMemberID> offlineMembers = membershipView.getOfflineMembers(); |
| if (logger.isDebugEnabled()) { |
| logger.debug( |
| "We didn't host the bucket. Checking redundancy level before creating the bucket. Redundancy={} offline members={}", |
| redundancy, offlineMembers); |
| } |
| |
| if (offlineMembers != null && !offlineMembers.isEmpty() && redundancy == -1) { |
| // If there are offline members, and no online members, throw |
| // an exception indicating that we can't create the bucket. |
| String message = String.format( |
| "Region %s bucket %s has persistent data that is no longer online stored at these locations: %s", |
| partitionedRegion.getFullPath(), bid, offlineMembers); |
| throw new PartitionOfflineException((Set) offlineMembers, message); |
| } else { |
| // If there are online and offline members, add the offline |
| // members to the redundancy level. This way we won't create |
| // an extra copy of the bucket. |
| if (offlineMembers != null) { |
| redundancy += offlineMembers.size(); |
| } |
| } |
| } |
| } |
| } |
| |
| if (moveSource == null) { |
| if (redundancy >= partitionedRegion.getRedundantCopies()) { |
| if (logger.isDebugEnabled()) { |
| logger.debug("grabFreeBucket: Bucket already meets redundancy level bucketId={}{}{}", |
| partitionedRegion.getPRId(), PartitionedRegion.BUCKET_ID_SEPARATOR, bid); |
| } |
| |
| return false; |
| } |
| } |
| |
| // Check to see if this bucket is allowed on this source. If this |
| // is a bucket move, we allow the source to be on the same host. |
| if (!PartitionedRegionBucketMgmtHelper.bucketIsAllowedOnThisHost(this, moveSource)) { |
| if (logger.isDebugEnabled()) { |
| logger.debug( |
| "grabFreeBucket: Bucket can't be recovered because we're enforcing that the bucket host must be unique {}{}{}", |
| partitionedRegion.getPRId(), PartitionedRegion.BUCKET_ID_SEPARATOR, bid); |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| void waitForPrimaryPersistentRecovery() { |
| persistenceAdvisor.waitForPrimaryPersistentRecovery(); |
| |
| } |
| |
| void initializePrimaryElector(InternalDistributedMember creationRequestor) { |
| advisor.initializePrimaryElector(creationRequestor); |
| |
| if (persistenceAdvisor != null) { |
| persistenceAdvisor.setAtomicCreation(creationRequestor != null); |
| } |
| } |
| |
| void clearPrimaryElector() { |
| if (persistenceAdvisor != null) { |
| persistenceAdvisor.setAtomicCreation(false); |
| } |
| |
| } |
| |
| @Override |
| public void remoteRegionInitialized(CacheProfile profile) { |
| // no-op for proxy bucket regions, which have no region membership listeners to notify |
| } |
| } |