/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hazelcast.internal.partition.impl; import com.hazelcast.config.Config; import com.hazelcast.config.ServiceConfig; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.internal.partition.NonFragmentedServiceNamespace; import com.hazelcast.internal.partition.InternalPartition; import com.hazelcast.internal.partition.InternalPartitionService; import com.hazelcast.internal.partition.MigrationInfo; import com.hazelcast.internal.partition.service.TestGetOperation; import com.hazelcast.internal.partition.service.TestIncrementOperation; import com.hazelcast.internal.partition.service.TestMigrationAwareService; import com.hazelcast.nio.Address; import com.hazelcast.spi.PartitionMigrationEvent; import com.hazelcast.spi.impl.NodeEngineImpl; import com.hazelcast.spi.impl.PartitionSpecificRunnable; import com.hazelcast.spi.impl.operationservice.InternalOperationService; import com.hazelcast.spi.properties.GroupProperty; import com.hazelcast.test.AssertTask; import com.hazelcast.test.ExpectedRuntimeException; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.TestHazelcastInstanceFactory; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static com.hazelcast.internal.partition.impl.MigrationCommitTest.resetInternalMigrationListener; import static com.hazelcast.spi.partition.MigrationEndpoint.DESTINATION; import static com.hazelcast.spi.partition.MigrationEndpoint.SOURCE; import static com.hazelcast.test.TestPartitionUtils.getDefaultReplicaVersions; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class MigrationCommitServiceTest extends HazelcastTestSupport { private static final int NODE_COUNT = 4; private static final int PARTITION_COUNT = 10; private static final int BACKUP_COUNT = 6; private static final int PARTITION_ID_TO_MIGRATE = 0; private volatile CountDownLatch blockMigrationStartLatch; private TestHazelcastInstanceFactory factory; private HazelcastInstance[] instances; @Before public void setup() throws Exception { blockMigrationStartLatch = new CountDownLatch(1); factory = createHazelcastInstanceFactory(NODE_COUNT); instances = factory.newInstances(createConfig(), NODE_COUNT); warmUpPartitions(instances); waitAllForSafeState(instances); InternalOperationService operationService = getOperationService(instances[0]); for (int partitionId = 0; partitionId < PARTITION_COUNT; partitionId++) { operationService.invokeOnPartition(null, new TestIncrementOperation(), partitionId).get(); } assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { for (int partitionId = 0; partitionId < PARTITION_COUNT; partitionId++) { InternalPartitionService partitionService = getPartitionService(instances[0]); InternalPartition partition = partitionService.getPartition(partitionId); for (int i = 0; i <= BACKUP_COUNT; i++) { Address replicaAddress = partition.getReplicaAddress(i); if (replicaAddress != null) { TestMigrationAwareService service = getService(replicaAddress); assertNotNull(service.get(partitionId)); } } } } }); for (HazelcastInstance instance : instances) { TestMigrationAwareService service = getNodeEngineImpl(instance).getService(TestMigrationAwareService.SERVICE_NAME); service.clearEvents(); } } @After public void after() { blockMigrationStartLatch.countDown(); } @Test public void testPartitionOwnerMoveCommit() throws Exception { int replicaIndexToClear = NODE_COUNT - 1, replicaIndexToMigrate = 0; testSuccessfulMoveMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, replicaIndexToMigrate); } @Test public void testPartitionOwnerMoveRollback() throws Exception { int replicaIndexToClear = NODE_COUNT - 1, replicaIndexToMigrate = 0; testFailedMoveMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, replicaIndexToMigrate); } @Test public void testPartitionBackupMoveCommit() throws Exception { int replicaIndexToClear = NODE_COUNT - 1, replicaIndexToMigrate = NODE_COUNT - 2; testSuccessfulMoveMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, replicaIndexToMigrate); } @Test public void testPartitionBackupMoveRollback() throws Exception { int replicaIndexToClear = NODE_COUNT - 1, replicaIndexToMigrate = NODE_COUNT - 2; testFailedMoveMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, replicaIndexToMigrate); } private void testSuccessfulMoveMigration(int partitionId, int replicaIndexToClear, int replicaIndexToMigrate) throws Exception { Address destination = clearReplicaIndex(partitionId, replicaIndexToClear); MigrationInfo migration = createMoveMigration(partitionId, replicaIndexToMigrate, destination); migrateWithSuccess(migration); assertMigrationSourceCommit(migration); assertMigrationDestinationCommit(migration); assertPartitionDataAfterMigrations(); } private void testFailedMoveMigration(int partitionId, int replicaIndexToClear, int replicaIndexToMigrate) throws Exception { Address destination = clearReplicaIndex(partitionId, replicaIndexToClear); MigrationInfo migration = createMoveMigration(partitionId, replicaIndexToMigrate, destination); migrateWithFailure(migration); assertMigrationSourceRollback(migration); assertMigrationDestinationRollback(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionOwnerShiftDownCommit() throws Exception { int oldReplicaIndex = 0, replicaIndexToClear = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 1; testSuccessfulShiftDownMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, oldReplicaIndex, newReplicaIndex); } @Test public void testPartitionOwnerShiftDownRollback() throws Exception { int oldReplicaIndex = 0, replicaIndexToClear = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 1; testFailedShiftDownMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, oldReplicaIndex, newReplicaIndex); } @Test public void testPartitionBackupShiftDownCommit() throws Exception { int oldReplicaIndex = 1, replicaIndexToClear = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 1; testSuccessfulShiftDownMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, oldReplicaIndex, newReplicaIndex); } @Test public void testPartitionBackupShiftDownRollback() throws Exception { int oldReplicaIndex = 1, replicaIndexToClear = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 1; testFailedShiftDownMigration(PARTITION_ID_TO_MIGRATE, replicaIndexToClear, oldReplicaIndex, newReplicaIndex); } private void testSuccessfulShiftDownMigration(int partitionId, int replicaIndexToClear, int oldReplicaIndex, int newReplicaIndex) throws Exception { Address destination = clearReplicaIndex(partitionId, replicaIndexToClear); MigrationInfo migration = createShiftDownMigration(partitionId, oldReplicaIndex, newReplicaIndex, destination); migrateWithSuccess(migration); assertMigrationSourceCommit(migration); assertMigrationDestinationCommit(migration); assertPartitionDataAfterMigrations(); } private void testFailedShiftDownMigration(int partitionId, int replicaIndexToClear, int oldReplicaIndex, int newReplicaIndex) throws Exception { Address destination = clearReplicaIndex(partitionId, replicaIndexToClear); MigrationInfo migration = createShiftDownMigration(partitionId, oldReplicaIndex, newReplicaIndex, destination); migrateWithFailure(migration); assertMigrationSourceRollback(migration); assertMigrationDestinationRollback(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionBackupCopyCommit() throws Exception { Address destination = clearReplicaIndex(PARTITION_ID_TO_MIGRATE, NODE_COUNT - 1); MigrationInfo migration = createCopyMigration(PARTITION_ID_TO_MIGRATE, NODE_COUNT - 1, destination); migrateWithSuccess(migration); assertMigrationDestinationCommit(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionBackupCopyRollback() throws Exception { Address destination = clearReplicaIndex(PARTITION_ID_TO_MIGRATE, NODE_COUNT - 1); MigrationInfo migration = createCopyMigration(PARTITION_ID_TO_MIGRATE, NODE_COUNT - 1, destination); migrateWithFailure(migration); assertMigrationDestinationRollback(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionBackupShiftUpCommitWithNonNullOwnerOfReplicaIndex() throws Exception { int oldReplicaIndex = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 2; MigrationInfo migration = createShiftUpMigration(PARTITION_ID_TO_MIGRATE, oldReplicaIndex, newReplicaIndex); migrateWithSuccess(migration); assertMigrationSourceCommit(migration); assertMigrationDestinationCommit(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionBackupShiftUpRollbackWithNonNullOwnerOfReplicaIndex() throws Exception { int oldReplicaIndex = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 2; MigrationInfo migration = createShiftUpMigration(PARTITION_ID_TO_MIGRATE, oldReplicaIndex, newReplicaIndex); migrateWithFailure(migration); assertMigrationSourceRollback(migration); assertMigrationDestinationRollback(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionBackupShiftUpCommitWithNullOwnerOfReplicaIndex() throws Exception { int oldReplicaIndex = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 2; clearReplicaIndex(PARTITION_ID_TO_MIGRATE, newReplicaIndex); MigrationInfo migration = createShiftUpMigration(PARTITION_ID_TO_MIGRATE, oldReplicaIndex, newReplicaIndex); migrateWithSuccess(migration); assertMigrationDestinationCommit(migration); assertPartitionDataAfterMigrations(); } @Test public void testPartitionBackupShiftUpRollbackWithNullOwnerOfReplicaIndex() throws Exception { int oldReplicaIndex = NODE_COUNT - 1, newReplicaIndex = NODE_COUNT - 2; clearReplicaIndex(PARTITION_ID_TO_MIGRATE, newReplicaIndex); MigrationInfo migration = createShiftUpMigration(PARTITION_ID_TO_MIGRATE, oldReplicaIndex, newReplicaIndex); migrateWithFailure(migration); assertMigrationDestinationRollback(migration); assertPartitionDataAfterMigrations(); } private MigrationInfo createMoveMigration(int partitionId, int replicaIndex, Address destination) { InternalPartition partition = getPartition(instances[0], partitionId); Address source = partition.getReplicaAddress(replicaIndex); String sourceUuid = getMemberUuid(source); String destinationUuid = getMemberUuid(destination); return new MigrationInfo(partitionId, source, sourceUuid, destination, destinationUuid, replicaIndex, -1, -1, replicaIndex); } private MigrationInfo createShiftDownMigration(int partitionId, int oldReplicaIndex, int newReplicaIndex, Address destination) { InternalPartitionImpl partition = getPartition(instances[0], partitionId); Address source = partition.getReplicaAddress(oldReplicaIndex); String sourceUuid = getMemberUuid(source); String destinationUuid = getMemberUuid(destination); return new MigrationInfo(partitionId, source, sourceUuid, destination, destinationUuid, oldReplicaIndex, newReplicaIndex, -1, oldReplicaIndex); } private MigrationInfo createCopyMigration(int partitionId, int copyReplicaIndex, Address destination) { return new MigrationInfo(partitionId, null, null, destination, getMemberUuid(destination), -1, -1, -1, copyReplicaIndex); } private MigrationInfo createShiftUpMigration(int partitionId, int oldReplicaIndex, int newReplicaIndex) { InternalPartitionImpl partition = getPartition(instances[0], partitionId); Address source = partition.getReplicaAddress(newReplicaIndex); String sourceUuid = getMemberUuid(source); Address destination = partition.getReplicaAddress(oldReplicaIndex); String destinationUuid = getMemberUuid(destination); return new MigrationInfo(partitionId, source, sourceUuid, destination, destinationUuid, newReplicaIndex, -1, oldReplicaIndex, newReplicaIndex); } private String getMemberUuid(Address address) { return address != null ? getNodeEngineImpl(factory.getInstance(address)).getLocalMember().getUuid() : null; } private Address clearReplicaIndex(final int partitionId, int replicaIndexToClear) { final InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(instances[0]); InternalPartitionImpl partition = (InternalPartitionImpl) partitionService.getPartition(partitionId); final Address oldReplicaOwner = partition.getReplicaAddress(replicaIndexToClear); partition.setReplicaAddress(replicaIndexToClear, null); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertTrue(partitionService.syncPartitionRuntimeState()); } }); HazelcastInstance oldReplicaOwnerInstance = factory.getInstance(oldReplicaOwner); ClearReplicaRunnable op = new ClearReplicaRunnable(partitionId, getNodeEngineImpl(oldReplicaOwnerInstance)); getOperationService(oldReplicaOwnerInstance).execute(op); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { long[] replicaVersions = getDefaultReplicaVersions(getNode(factory.getInstance(oldReplicaOwner)), partitionId); assertArrayEquals(new long[InternalPartition.MAX_BACKUP_COUNT], replicaVersions); } }); TestMigrationAwareService migrationAwareService = getService(oldReplicaOwner); migrationAwareService.clearPartitionReplica(partitionId); for (HazelcastInstance instance : instances) { TestMigrationAwareService service = getNodeEngineImpl(instance) .getService(TestMigrationAwareService.SERVICE_NAME); service.clearEvents(); } return oldReplicaOwner; } private void migrateWithSuccess(final MigrationInfo migration) { InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(instances[0]); partitionService.getMigrationManager().scheduleMigration(migration); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { for (HazelcastInstance instance : factory.getAllHazelcastInstances()) { InternalPartitionImpl partition = getPartition(instance, migration.getPartitionId()); assertEquals(partition.getReplicaAddress(migration.getDestinationNewReplicaIndex()), migration.getDestination()); } } }); } private void migrateWithFailure(final MigrationInfo migration) { if (!getAddress(instances[0]).equals(migration.getDestination())) { HazelcastInstance destinationInstance = factory.getInstance(migration.getDestination()); RejectMigrationOnComplete destinationListener = new RejectMigrationOnComplete(destinationInstance); InternalPartitionServiceImpl destinationPartitionService = (InternalPartitionServiceImpl) getPartitionService(destinationInstance); destinationPartitionService.getMigrationManager().setInternalMigrationListener(destinationListener); } InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(instances[0]); CountDownMigrationRollbackOnMaster masterListener = new CountDownMigrationRollbackOnMaster(migration); partitionService.getMigrationManager().setInternalMigrationListener(masterListener); partitionService.getMigrationManager().scheduleMigration(migration); assertOpenEventually(masterListener.latch); } private void assertMigrationSourceCommit(final MigrationInfo migration) { assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { TestMigrationAwareService service = getService(migration.getSource()); String msg = getAssertMessage(migration, service); assertFalse(service.getBeforeEvents().isEmpty()); assertFalse(service.getCommitEvents().isEmpty()); PartitionMigrationEvent beforeEvent = service.getBeforeEvents().get(0); PartitionMigrationEvent sourceCommitEvent = service.getCommitEvents().get(0); assertSourcePartitionMigrationEvent(msg, beforeEvent, migration); assertSourcePartitionMigrationEvent(msg, sourceCommitEvent, migration); assertReplicaVersionsAndServiceData(msg, migration.getSource(), migration.getPartitionId(), migration.getSourceNewReplicaIndex()); } }); } private void assertMigrationSourceRollback(final MigrationInfo migration) { assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { TestMigrationAwareService service = getService(migration.getSource()); String msg = getAssertMessage(migration, service); assertFalse(service.getBeforeEvents().isEmpty()); assertFalse(service.getRollbackEvents().isEmpty()); PartitionMigrationEvent beforeEvent = service.getBeforeEvents().get(0); PartitionMigrationEvent rollbackEvent = service.getRollbackEvents().get(0); assertSourcePartitionMigrationEvent(msg, beforeEvent, migration); assertSourcePartitionMigrationEvent(msg, rollbackEvent, migration); assertReplicaVersionsAndServiceData(msg, migration.getSource(), migration.getPartitionId(), migration.getSourceCurrentReplicaIndex()); } }); } private void assertMigrationDestinationCommit(final MigrationInfo migration) { assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { TestMigrationAwareService service = getService(migration.getDestination()); String msg = getAssertMessage(migration, service); assertFalse(service.getBeforeEvents().isEmpty()); assertFalse(service.getCommitEvents().isEmpty()); PartitionMigrationEvent beforeEvent = service.getBeforeEvents().get(0); PartitionMigrationEvent commitEvent = service.getCommitEvents().get(0); assertDestinationPartitionMigrationEvent(msg, beforeEvent, migration); assertDestinationPartitionMigrationEvent(msg, commitEvent, migration); assertTrue(msg, service.contains(migration.getPartitionId())); assertReplicaVersionsAndServiceData(msg, migration.getDestination(), migration.getPartitionId(), migration.getDestinationNewReplicaIndex()); } }); } private void assertMigrationDestinationRollback(final MigrationInfo migration) { assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { TestMigrationAwareService service = getService(migration.getDestination()); String msg = getAssertMessage(migration, service); assertFalse(service.getBeforeEvents().isEmpty()); assertFalse(service.getRollbackEvents().isEmpty()); PartitionMigrationEvent beforeEvent = service.getBeforeEvents().get(0); PartitionMigrationEvent destinationRollbackEvent = service.getRollbackEvents().get(0); assertDestinationPartitionMigrationEvent(msg, beforeEvent, migration); assertDestinationPartitionMigrationEvent(msg, destinationRollbackEvent, migration); assertReplicaVersionsAndServiceData(msg, migration.getDestination(), migration.getPartitionId(), migration.getDestinationCurrentReplicaIndex()); } }); } private void assertReplicaVersionsAndServiceData(String msg, Address address, int partitionId, int replicaIndex) throws Exception { TestMigrationAwareService service = getService(address); boolean shouldContainData = replicaIndex != -1 && replicaIndex <= BACKUP_COUNT; assertEquals(msg, shouldContainData, service.contains(partitionId)); long[] replicaVersions = getDefaultReplicaVersions(getNode(factory.getInstance(address)), partitionId); msg = msg + " , ReplicaVersions: " + Arrays.toString(replicaVersions); if (shouldContainData) { if (replicaIndex == 0) { assertArrayEquals(msg, replicaVersions, new long[]{1, 1, 1, 1, 1, 1}); } else { for (int i = 1; i < InternalPartition.MAX_BACKUP_COUNT; i++) { if (i < replicaIndex || i > BACKUP_COUNT) { assertEquals(msg + " at index: " + i, 0, replicaVersions[i - 1]); } else { assertEquals(msg + " at index: " + i, 1, replicaVersions[i - 1]); } } } } else { assertArrayEquals(msg, replicaVersions, new long[]{0, 0, 0, 0, 0, 0}); } } private void assertPartitionDataAfterMigrations() throws Exception { InternalOperationService operationService = getOperationService(instances[0]); for (int partitionId = 0; partitionId < PARTITION_COUNT; partitionId++) { assertNotNull(operationService.invokeOnPartition(null, new TestGetOperation(), partitionId) .get(10, TimeUnit.SECONDS)); } } private String getAssertMessage(MigrationInfo migration, TestMigrationAwareService service) { return migration + " -> BeforeEvents: " + service.getBeforeEvents() + ", CommitEvents: " + service.getCommitEvents() + ", RollbackEvents: " + service.getRollbackEvents(); } private void assertSourcePartitionMigrationEvent(String msg, PartitionMigrationEvent event, MigrationInfo migration) { assertEquals(msg, SOURCE, event.getMigrationEndpoint()); assertEquals(msg, migration.getSourceCurrentReplicaIndex(), event.getCurrentReplicaIndex()); assertEquals(msg, migration.getSourceNewReplicaIndex(), event.getNewReplicaIndex()); } private void assertDestinationPartitionMigrationEvent(String msg, PartitionMigrationEvent event, MigrationInfo migration) { assertEquals(msg, DESTINATION, event.getMigrationEndpoint()); assertEquals(msg, migration.getDestinationCurrentReplicaIndex(), event.getCurrentReplicaIndex()); assertEquals(msg, migration.getDestinationNewReplicaIndex(), event.getNewReplicaIndex()); } private Config createConfig() { Config config = new Config(); ServiceConfig serviceConfig = TestMigrationAwareService.createServiceConfig(BACKUP_COUNT); config.getServicesConfig().addServiceConfig(serviceConfig); config.setProperty(GroupProperty.PARTITION_MAX_PARALLEL_REPLICATIONS.getName(), "0"); config.setProperty(GroupProperty.PARTITION_COUNT.getName(), String.valueOf(PARTITION_COUNT)); return config; } private InternalPartitionImpl getPartition(HazelcastInstance instance, int partitionId) { InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(instance); return (InternalPartitionImpl) partitionService.getPartition(partitionId); } private TestMigrationAwareService getService(Address address) { return getNodeEngineImpl(factory.getInstance(address)).getService(TestMigrationAwareService.SERVICE_NAME); } private static class RejectMigrationOnComplete extends InternalMigrationListener { private final HazelcastInstance instance; RejectMigrationOnComplete(HazelcastInstance instance) { this.instance = instance; } @Override public void onMigrationComplete(MigrationParticipant participant, MigrationInfo migrationInfo, boolean success) { resetInternalMigrationListener(instance); throw new ExpectedRuntimeException("migration is failed intentionally on complete"); } } private class CountDownMigrationRollbackOnMaster extends InternalMigrationListener { private final CountDownLatch latch = new CountDownLatch(1); private final MigrationInfo expected; private volatile boolean blockMigrations; CountDownMigrationRollbackOnMaster(MigrationInfo expected) { this.expected = expected; } @Override public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) { if (participant == MigrationParticipant.MASTER && blockMigrations) { assertOpenEventually(blockMigrationStartLatch); } } @Override public void onMigrationComplete(MigrationParticipant participant, MigrationInfo migrationInfo, boolean success) { if (participant == MigrationParticipant.DESTINATION) { throw new ExpectedRuntimeException("migration is failed intentionally on complete"); } } @Override public void onMigrationRollback(MigrationParticipant participant, MigrationInfo migrationInfo) { if (participant == MigrationParticipant.MASTER && expected.equals(migrationInfo)) { blockMigrations = true; latch.countDown(); } } } static final class ClearReplicaRunnable implements PartitionSpecificRunnable { private final int partitionId; private final NodeEngineImpl nodeEngine; ClearReplicaRunnable(int partitionId, NodeEngineImpl nodeEngine) { this.partitionId = partitionId; this.nodeEngine = nodeEngine; } @Override public void run() { InternalPartitionServiceImpl partitionService = nodeEngine.getService(InternalPartitionService.SERVICE_NAME); partitionService.getReplicaManager().cancelReplicaSync(partitionId); partitionService.getReplicaManager().clearPartitionReplicaVersions(partitionId, NonFragmentedServiceNamespace.INSTANCE); } @Override public int getPartitionId() { return partitionId; } } }