use of org.apache.geode.internal.cache.partitioned.rebalance.PartitionedRegionLoadModel in project geode by apache.
the class PartitionedRegionRebalanceOp method buildModel.
/**
* Build a model of the load on the partitioned region, which can determine which buckets to move,
* etc.
*
* @param detailsMap
* @param resourceManager
*/
private PartitionedRegionLoadModel buildModel(BucketOperator operator, Map<PartitionedRegion, InternalPRInfo> detailsMap, InternalResourceManager resourceManager) {
PartitionedRegionLoadModel model;
final boolean isDebugEnabled = logger.isDebugEnabled();
final DM dm = leaderRegion.getDistributionManager();
AddressComparor comparor = new AddressComparor() {
public boolean areSameZone(InternalDistributedMember member1, InternalDistributedMember member2) {
return dm.areInSameZone(member1, member2);
}
public boolean enforceUniqueZones() {
return dm.enforceUniqueZone();
}
};
int redundantCopies = leaderRegion.getRedundantCopies();
int totalNumberOfBuckets = leaderRegion.getTotalNumberOfBuckets();
Set<InternalDistributedMember> criticalMembers = resourceManager.getResourceAdvisor().adviseCritialMembers();
;
boolean removeOverRedundancy = true;
debug("Building Model for rebalancing " + leaderRegion + ". redundantCopies=" + redundantCopies + ", totalNumBuckets=" + totalNumberOfBuckets + ", criticalMembers=" + criticalMembers + ", simulate=" + simulate);
model = new PartitionedRegionLoadModel(operator, redundantCopies, totalNumberOfBuckets, comparor, criticalMembers, leaderRegion);
for (Map.Entry<PartitionedRegion, InternalPRInfo> entry : detailsMap.entrySet()) {
PartitionedRegion region = entry.getKey();
InternalPRInfo details = entry.getValue();
OfflineMemberDetails offlineDetails;
if (replaceOfflineData) {
offlineDetails = OfflineMemberDetails.EMPTY_DETAILS;
} else {
offlineDetails = details.getOfflineMembers();
}
boolean enforceLocalMaxMemory = !region.isEntryEvictionPossible();
debug("Added Region to model region=" + region + ", offlineDetails=" + offlineDetails + ", enforceLocalMaxMemory=" + enforceLocalMaxMemory);
for (PartitionMemberInfo memberDetails : details.getPartitionMemberInfo()) {
debug("For Region: " + region + ", Member: " + memberDetails.getDistributedMember() + "LOAD=" + ((InternalPartitionDetails) memberDetails).getPRLoad() + ", equivalentMembers=" + dm.getMembersInSameZone((InternalDistributedMember) memberDetails.getDistributedMember()));
}
Set<InternalPartitionDetails> memberDetailSet = details.getInternalPartitionDetails();
model.addRegion(region.getFullPath(), memberDetailSet, offlineDetails, enforceLocalMaxMemory);
}
model.initialize();
debug("Rebalancing {} starting. Model:\n{}", leaderRegion, model);
return model;
}
use of org.apache.geode.internal.cache.partitioned.rebalance.PartitionedRegionLoadModel in project geode by apache.
the class PartitionedRegionRebalanceOp method execute.
/**
* Do the actual rebalance
*
* @return the details of the rebalance.
*/
public Set<PartitionRebalanceInfo> execute() {
long start = System.nanoTime();
InternalResourceManager resourceManager = InternalResourceManager.getInternalResourceManager(leaderRegion.getCache());
MembershipListener listener = new MembershipChangeListener();
if (isRebalance) {
InternalResourceManager.getResourceObserver().rebalancingStarted(targetRegion);
} else {
InternalResourceManager.getResourceObserver().recoveryStarted(targetRegion);
}
RecoveryLock lock = null;
try {
if (!checkAndSetColocatedRegions()) {
return Collections.emptySet();
}
// have full redundancy.
if (!isRebalanceNecessary()) {
return Collections.emptySet();
}
if (!simulate) {
lock = leaderRegion.getRecoveryLock();
lock.lock();
}
// have fixed it already.
if (!isRebalanceNecessary()) {
return Collections.emptySet();
}
// register a listener to notify us if the new members leave or join.
// When a membership change occurs, we want to restart the rebalancing
// from the beginning.
// TODO rebalance - we should really add a membership listener to ALL of
// the colocated regions.
leaderRegion.getRegionAdvisor().addMembershipListener(listener);
PartitionedRegionLoadModel model = null;
InternalCache cache = leaderRegion.getCache();
Map<PartitionedRegion, InternalPRInfo> detailsMap = fetchDetails(cache);
BucketOperatorWrapper serialOperator = getBucketOperator(detailsMap);
ParallelBucketOperator parallelOperator = new ParallelBucketOperator(MAX_PARALLEL_OPERATIONS, cache.getDistributionManager().getWaitingThreadPool(), serialOperator);
model = buildModel(parallelOperator, detailsMap, resourceManager);
for (PartitionRebalanceDetailsImpl details : serialOperator.getDetailSet()) {
details.setPartitionMemberDetailsBefore(model.getPartitionedMemberDetails(details.getRegionPath()));
}
director.initialize(model);
for (; ; ) {
if (cancelled.get()) {
return Collections.emptySet();
}
if (membershipChange) {
membershipChange = false;
// refetch the partitioned region details after
// a membership change.
debug("Rebalancing {} detected membership changes. Refetching details", leaderRegion);
if (this.stats != null) {
this.stats.incRebalanceMembershipChanges(1);
}
model.waitForOperations();
detailsMap = fetchDetails(cache);
model = buildModel(parallelOperator, detailsMap, resourceManager);
director.membershipChanged(model);
}
leaderRegion.checkClosed();
cache.getCancelCriterion().checkCancelInProgress(null);
if (logger.isDebugEnabled()) {
logger.debug("Rebalancing {} Model:{}\n", leaderRegion, model);
}
if (!director.nextStep()) {
// Stop when the director says we can't rebalance any more.
break;
}
}
debug("Rebalancing {} complete. Model:{}\n", leaderRegion, model);
long end = System.nanoTime();
for (PartitionRebalanceDetailsImpl details : serialOperator.getDetailSet()) {
if (!simulate) {
details.setTime(end - start);
}
details.setPartitionMemberDetailsAfter(model.getPartitionedMemberDetails(details.getRegionPath()));
}
return Collections.<PartitionRebalanceInfo>unmodifiableSet(serialOperator.getDetailSet());
} finally {
if (lock != null) {
try {
lock.unlock();
} catch (CancelException e) {
// lock service has been destroyed
} catch (Exception e) {
logger.error(LocalizedMessage.create(LocalizedStrings.PartitionedRegionRebalanceOp_UNABLE_TO_RELEASE_RECOVERY_LOCK), e);
}
}
try {
if (isRebalance) {
InternalResourceManager.getResourceObserver().rebalancingFinished(targetRegion);
} else {
InternalResourceManager.getResourceObserver().recoveryFinished(targetRegion);
}
} catch (Exception e) {
logger.error(LocalizedMessage.create(LocalizedStrings.PartitionedRegionRebalanceOp_ERROR_IN_RESOURCE_OBSERVER), e);
}
try {
leaderRegion.getRegionAdvisor().removeMembershipListener(listener);
} catch (Exception e) {
logger.error(LocalizedMessage.create(LocalizedStrings.PartitionedRegionRebalanceOp_ERROR_IN_RESOURCE_OBSERVER), e);
}
}
}
use of org.apache.geode.internal.cache.partitioned.rebalance.PartitionedRegionLoadModel in project geode by apache.
the class PartitionedRegionLoadModelJUnitTest method testFoolGreedyAlgorithm.
/**
* Test which illustrates the problem with our greedy algorithm. It doesn't necessarily end up
* with a balanced result.
*
* TODO rebalance - change this test or fix the algorithm?
*/
@Ignore
@Test
public void testFoolGreedyAlgorithm() throws Exception {
PartitionedRegionLoadModel model = new PartitionedRegionLoadModel(bucketOperator, 1, 50, getAddressComparor(false), Collections.<InternalDistributedMember>emptySet(), null);
InternalDistributedMember member1 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 1);
InternalDistributedMember member2 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 2);
InternalDistributedMember member3 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 3);
PartitionMemberInfoImpl details1 = buildDetails(member1, 500, 500, new long[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, new long[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
PartitionMemberInfoImpl details2 = buildDetails(member2, 500, 500, new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 });
PartitionMemberInfoImpl details3 = buildDetails(member3, 500, 500, new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
model.addRegion("a", Arrays.asList(details1, details2, details3), new FakeOfflineDetails(), true);
doMoves(new CompositeDirector(true, true, false, false), model);
// will have 15 and 2 and 3 will have 17 and 18.
for (PartitionMemberInfo details : model.getPartitionedMemberDetails("a")) {
assertEquals(20, details.getBucketCount());
}
}
use of org.apache.geode.internal.cache.partitioned.rebalance.PartitionedRegionLoadModel in project geode by apache.
the class PartitionedRegionLoadModelJUnitTest method testMovePrimariesWithWeights.
/**
* Test of moving primaries when nodes are weighted relative to each other
*/
@Test
public void testMovePrimariesWithWeights() throws Exception {
PartitionedRegionLoadModel model = new PartitionedRegionLoadModel(bucketOperator, 2, 4, getAddressComparor(false), Collections.<InternalDistributedMember>emptySet(), null);
InternalDistributedMember member1 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 1);
InternalDistributedMember member2 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 2);
// member 1 has a lower weight, and all of the primaries
PartitionMemberInfoImpl details1 = buildDetails(member1, 1, 500, new long[] { 1, 1, 1, 1 }, new long[] { 1, 1, 1, 1 });
// member 2 has a higher weight
PartitionMemberInfoImpl details2 = buildDetails(member2, 3, 500, new long[] { 1, 1, 1, 1 }, new long[] { 0, 0, 0, 0 });
model.addRegion("a", Arrays.asList(details1, details2), new FakeOfflineDetails(), true);
assertEquals(3, doMoves(new CompositeDirector(false, false, false, true), model));
assertEquals(Collections.emptyList(), bucketOperator.creates);
// Three of the primaries should move to member2, because it has a higher weight
List<Move> expectedMoves = new ArrayList<Move>();
expectedMoves.add(new Move(member1, member2));
expectedMoves.add(new Move(member1, member2));
expectedMoves.add(new Move(member1, member2));
assertEquals(expectedMoves, bucketOperator.primaryMoves);
}
use of org.apache.geode.internal.cache.partitioned.rebalance.PartitionedRegionLoadModel in project geode by apache.
the class PartitionedRegionLoadModelJUnitTest method testMoveBucketsEnforceRemoteIp.
@Test
public void testMoveBucketsEnforceRemoteIp() throws Exception {
PartitionedRegionLoadModel model = new PartitionedRegionLoadModel(bucketOperator, 0, 3, getAddressComparor(true), Collections.<InternalDistributedMember>emptySet(), null);
InternalDistributedMember member1 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 1);
InternalDistributedMember member2 = new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), 2);
// Create some buckets with low redundancy on members 1
PartitionMemberInfoImpl details1 = buildDetails(member1, 500, 500, new long[] { 30, 30, 30 }, new long[] { 1, 1, 1 });
PartitionMemberInfoImpl details2 = buildDetails(member2, 500, 500, new long[] { 0, 0, 0 }, new long[] { 0, 0, 0 });
model.addRegion("a", Arrays.asList(details1, details2), new FakeOfflineDetails(), true);
// we expect 0 moves, because we're enforcing that we can't create
// copies on the same IP.
assertEquals(1, doMoves(new CompositeDirector(true, true, true, true), model));
List<Move> expectedMoves = new ArrayList<Move>();
expectedMoves.add(new Move(member1, member2));
assertEquals(expectedMoves, bucketOperator.bucketMoves);
}
Aggregations