/*
* 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.ListenerConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.internal.partition.InternalPartition;
import com.hazelcast.internal.partition.InternalPartitionService;
import com.hazelcast.internal.partition.MigrationInfo;
import com.hazelcast.internal.partition.impl.InternalMigrationListenerTest.InternalMigrationListenerImpl;
import com.hazelcast.internal.partition.impl.InternalMigrationListenerTest.MigrationProgressNotification;
import com.hazelcast.nio.Address;
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.test.AssertTask;
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.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static com.hazelcast.internal.partition.MigrationInfo.MigrationStatus.SUCCESS;
import static com.hazelcast.internal.partition.impl.InternalMigrationListenerTest.MigrationProgressEvent.COMMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class MigrationCommitTest extends HazelcastTestSupport {
private static final int PARTITION_COUNT = 2;
private TestHazelcastInstanceFactory factory;
@Before
public void init() {
factory = createHazelcastInstanceFactory(3);
}
@Test
public void shouldCommitMigrationWhenMasterIsMigrationSource() {
HazelcastInstance hz1 = factory.newHazelcastInstance(createConfig());
Config config2 = createConfig();
config2.setLiteMember(true);
HazelcastInstance hz2 = factory.newHazelcastInstance(config2);
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
HazelcastInstance hz3 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz3);
waitAllForSafeState(hz1, hz2, hz3);
InternalPartition hz1Partition = getOwnedPartition(hz1);
InternalPartition hz3Partition = getOwnedPartition(hz3);
assertNotNull(hz1Partition);
assertNotNull(hz3Partition);
assertNotEquals(hz1Partition, hz3Partition);
assertFalse(hz1Partition.isMigrating());
assertFalse(hz3Partition.isMigrating());
}
@Test
public void shouldCommitMigrationWhenMasterIsDestination() {
HazelcastInstance hz1 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
hz2.getLifecycleService().terminate();
assertClusterSizeEventually(1, hz1);
waitAllForSafeState(hz1);
InternalPartition partition0 = getPartitionService(hz1).getPartition(0);
InternalPartition partition1 = getPartitionService(hz1).getPartition(1);
assertEquals(getAddress(hz1), partition0.getOwnerOrNull());
assertEquals(getAddress(hz1), partition1.getOwnerOrNull());
assertFalse(partition0.isMigrating());
assertFalse(partition1.isMigrating());
}
@Test
public void shouldCommitMigrationWhenMasterIsNotMigrationEndpoint() {
Config config1 = createConfig();
config1.setLiteMember(true);
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
HazelcastInstance hz3 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz3);
waitAllForSafeState(hz1, hz2, hz3);
InternalPartition hz2Partition = getOwnedPartition(hz2);
InternalPartition hz3Partition = getOwnedPartition(hz3);
assertNotNull(hz2Partition);
assertNotNull(hz3Partition);
assertNotEquals(hz2Partition, hz3Partition);
assertFalse(hz2Partition.isMigrating());
assertFalse(hz3Partition.isMigrating());
}
@Test
public void shouldRollbackMigrationWhenMasterCrashesBeforeCommit() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
final TerminateOtherMemberOnMigrationComplete listener3
= new TerminateOtherMemberOnMigrationComplete(migrationStartLatch);
listener3.other = hz1;
migrationStartLatch.countDown();
Config config3 = createConfig();
config3.addListenerConfig(new ListenerConfig(listener3));
HazelcastInstance hz3 = factory.newHazelcastInstance(config3);
assertClusterSizeEventually(2, hz2);
assertClusterSize(2, hz3);
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
assertTrue(listener3.rollback);
}
});
waitAllForSafeState(hz2, hz3);
factory.terminateAll();
}
@Test
public void shouldRollbackMigrationWhenDestinationCrashesBeforeCommit() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
TerminateOtherMemberOnMigrationComplete masterListener = new TerminateOtherMemberOnMigrationComplete(
migrationStartLatch);
config1.addListenerConfig(new ListenerConfig(masterListener));
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
HazelcastInstance hz3 = factory.newHazelcastInstance(createConfig());
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
masterListener.other = hz3;
migrationStartLatch.countDown();
sleepAtLeastSeconds(10);
waitAllForSafeState(hz1, hz2);
InternalPartition partition0 = getPartitionService(hz2).getPartition(0);
InternalPartition partition1 = getPartitionService(hz2).getPartition(1);
assertEquals(getAddress(hz2), partition0.getOwnerOrNull());
assertEquals(getAddress(hz2), partition1.getOwnerOrNull());
assertFalse(partition0.isMigrating());
assertFalse(partition1.isMigrating());
assertTrue(masterListener.rollback);
}
@Test
public void shouldCommitMigrationWhenMasterCrashesAfterDestinationCommit() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
Config config2 = createConfig();
final CollectMigrationTaskOnCommit sourceListener = new CollectMigrationTaskOnCommit();
config2.addListenerConfig(new ListenerConfig(sourceListener));
HazelcastInstance hz2 = factory.newHazelcastInstance(config2);
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
Config config3 = createConfig();
TerminateOtherMemberOnMigrationCommit destinationListener = new TerminateOtherMemberOnMigrationCommit(
migrationStartLatch);
destinationListener.other = hz1;
config3.addListenerConfig(new ListenerConfig(destinationListener));
HazelcastInstance hz3 = factory.newHazelcastInstance(config3);
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
migrationStartLatch.countDown();
waitAllForSafeState(hz2, hz3);
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
assertTrue(sourceListener.commit);
}
});
InternalPartition hz2Partition = getOwnedPartition(hz2);
InternalPartition hz3Partition = getOwnedPartition(hz3);
assertNotNull(hz2Partition);
assertNotNull(hz3Partition);
assertNotEquals(hz2Partition, hz3Partition);
assertFalse(hz2Partition.isMigrating());
assertFalse(hz3Partition.isMigrating());
}
@Test
public void shouldCommitMigrationWhenSourceFailsDuringCommit() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
TerminateOtherMemberOnMigrationComplete masterListener = new TerminateOtherMemberOnMigrationComplete(migrationStartLatch);
config1.addListenerConfig(new ListenerConfig(masterListener));
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
Config config3 = createConfig();
InternalMigrationListenerImpl targetListener = new InternalMigrationListenerImpl();
config3.addListenerConfig(new ListenerConfig(targetListener));
HazelcastInstance hz3 = factory.newHazelcastInstance(config3);
masterListener.other = hz2;
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
migrationStartLatch.countDown();
waitAllForSafeState(hz1, hz3);
InternalPartition partition0 = getPartitionService(hz3).getPartition(0);
InternalPartition partition1 = getPartitionService(hz3).getPartition(1);
assertEquals(getAddress(hz3), partition0.getOwnerOrNull());
assertEquals(getAddress(hz3), partition1.getOwnerOrNull());
assertFalse(partition0.isMigrating());
assertFalse(partition1.isMigrating());
assertFalse(masterListener.rollback);
List<MigrationProgressNotification> notifications = targetListener.getNotifications();
assertFalse(notifications.isEmpty());
assertEquals(COMMIT, notifications.get(notifications.size() - 1).event);
}
@Test
public void shouldRollbackMigrationWhenDestinationCrashesDuringCommit() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
DelayMigrationStartOnMaster masterListener = new DelayMigrationStartOnMaster(migrationStartLatch);
config1.addListenerConfig(new ListenerConfig(masterListener));
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
CountDownLatch terminationLatch = new CountDownLatch(1);
TerminateOnMigrationCommit memberListener = new TerminateOnMigrationCommit(terminationLatch);
Config config3 = createConfig();
config3.addListenerConfig(new ListenerConfig(memberListener));
HazelcastInstance hz3 = factory.newHazelcastInstance(config3);
warmUpPartitions(hz1, hz2, hz3);
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
migrationStartLatch.countDown();
waitAllForSafeState(hz1, hz2);
InternalPartition partition0 = getPartitionService(hz1).getPartition(0);
InternalPartition partition1 = getPartitionService(hz1).getPartition(1);
assertEquals(getAddress(hz2), partition0.getOwnerOrNull());
assertEquals(getAddress(hz2), partition1.getOwnerOrNull());
assertFalse(partition0.isMigrating());
assertFalse(partition1.isMigrating());
assertTrue(masterListener.rollback.get());
terminationLatch.countDown();
}
@Test
public void shouldRetryMigrationIfParticipantPartitionTableVersionFallsBehind() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
final IncrementPartitionTableOnMigrationStart masterListener
= new IncrementPartitionTableOnMigrationStart(migrationStartLatch);
config1.addListenerConfig(new ListenerConfig(masterListener));
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
Config config3 = createConfig();
InternalMigrationListenerImpl targetListener = new InternalMigrationListenerImpl();
config3.addListenerConfig(new ListenerConfig(targetListener));
HazelcastInstance hz3 = factory.newHazelcastInstance(config3);
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
migrationStartLatch.countDown();
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
assertTrue(masterListener.failed);
}
});
waitAllForSafeState(hz1, hz2, hz3);
}
@Test
public void shouldEvictCompletedMigrationsWhenAllMembersAckPublishedPartitionTableAfterSuccessfulMigration() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
final CollectMigrationTaskOnCommit masterListener = new CollectMigrationTaskOnCommit();
config1.addListenerConfig(new ListenerConfig(masterListener));
HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(hz1);
final MigrationManager migrationManager = partitionService.getMigrationManager();
HazelcastInstance hz2 = factory.newHazelcastInstance(createConfig());
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
Config config3 = createConfig();
DelayMigrationStart destinationListener = new DelayMigrationStart(migrationStartLatch);
config3.addListenerConfig(new ListenerConfig(destinationListener));
HazelcastInstance hz3 = factory.newHazelcastInstance(config3);
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
migrationStartLatch.countDown();
waitAllForSafeState(hz1, hz2, hz3);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertTrue(masterListener.commit);
assertTrue(migrationManager.getCompletedMigrationsCopy().isEmpty());
}
});
}
@Test
public void shouldNotEvictCompletedMigrationsWhenSomeMembersDoNotAckPublishedPartitionTableAfterSuccessfulMigration() {
CountDownLatch migrationStartLatch = new CountDownLatch(1);
CountDownLatch migrationCommitLatch = new CountDownLatch(1);
Config config1 = createConfig();
config1.setLiteMember(true);
config1.addListenerConfig(new ListenerConfig(new DelayMigrationStart(migrationStartLatch)));
final HazelcastInstance hz1 = factory.newHazelcastInstance(config1);
Config config2 = createConfig();
config2.addListenerConfig(new ListenerConfig(new DelayMigrationCommit(migrationCommitLatch)));
HazelcastInstance hz2 = factory.newHazelcastInstance(config2);
warmUpPartitions(hz1, hz2);
waitAllForSafeState(hz1, hz2);
final HazelcastInstance hz3 = factory.newHazelcastInstance(createConfig());
assertClusterSize(3, hz1, hz3);
assertClusterSizeEventually(3, hz2);
migrationStartLatch.countDown();
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(hz1);
boolean found = false;
for (MigrationInfo migrationInfo : partitionService.getMigrationManager().getCompletedMigrationsCopy()) {
if (migrationInfo.getStatus() == SUCCESS && migrationInfo.getDestination().equals(getAddress(hz3))) {
found = true;
}
}
assertTrue(found);
}
});
assertTrueAllTheTime(new AssertTask() {
@Override
public void run()
throws Exception {
InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(hz1);
assertFalse(partitionService.getMigrationManager().getCompletedMigrationsCopy().isEmpty());
}
}, 10);
migrationCommitLatch.countDown();
}
private Config createConfig() {
Config config = new Config();
config.setProperty(GroupProperty.PARTITION_MAX_PARALLEL_REPLICATIONS.getName(), "0");
config.setProperty(GroupProperty.PARTITION_COUNT.getName(), String.valueOf(PARTITION_COUNT));
return config;
}
private InternalPartition getOwnedPartition(HazelcastInstance instance) {
InternalPartitionService partitionService = getPartitionService(instance);
Address address = getAddress(instance);
if (address.equals(partitionService.getPartitionOwner(0))) {
return partitionService.getPartition(0);
} else if (address.equals(partitionService.getPartitionOwner(1))) {
return partitionService.getPartition(1);
}
return null;
}
static void resetInternalMigrationListener(HazelcastInstance instance) {
InternalPartitionServiceImpl partitionService = (InternalPartitionServiceImpl) getPartitionService(instance);
partitionService.resetInternalMigrationListener();
}
private static class IncrementPartitionTableOnMigrationStart
extends InternalMigrationListener implements HazelcastInstanceAware {
private final AtomicReference<MigrationInfo> migrationInfoRef = new AtomicReference<MigrationInfo>();
private final CountDownLatch migrationStartLatch;
private HazelcastInstance instance;
private volatile boolean failed;
IncrementPartitionTableOnMigrationStart(CountDownLatch migrationStartLatch) {
this.migrationStartLatch = migrationStartLatch;
}
@Override
public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) {
if (failed) {
System.err.println("Ignoring new migration start: " + migrationInfo + " as participant: " + participant
+ " since expected migration is already committed");
return;
}
assertOpenEventually(migrationStartLatch);
if (migrationInfoRef.compareAndSet(null, migrationInfo)) {
InternalPartitionServiceImpl partitionService
= (InternalPartitionServiceImpl) getPartitionService(instance);
PartitionStateManager partitionStateManager = partitionService.getPartitionStateManager();
partitionStateManager.incrementVersion();
} else {
System.err.println("COLLECT COMMIT START FAILED! curr: " + migrationInfoRef.get() + " new: " + migrationInfo);
}
}
@Override
public void onMigrationComplete(MigrationParticipant participant, MigrationInfo migrationInfo, boolean success) {
if (failed) {
System.err.println("Ignoring new migration complete: " + migrationInfo + " as participant: " + participant
+ " since expected migration is already completed");
return;
}
MigrationInfo collected = migrationInfoRef.get();
failed = !success && migrationInfo.equals(collected);
if (failed) {
resetInternalMigrationListener(instance);
} else {
System.err.println(
"collect complete failed! collected migration: " + collected + " rollback migration: " + migrationInfo
+ " participant: " + participant + " success: " + success);
}
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class DelayMigrationCommit extends InternalMigrationListener implements HazelcastInstanceAware {
private final CountDownLatch migrationCommitLatch;
private volatile HazelcastInstance instance;
DelayMigrationCommit(CountDownLatch migrationCommitLatch) {
this.migrationCommitLatch = migrationCommitLatch;
}
@Override
public void onMigrationCommit(MigrationParticipant participant, MigrationInfo migrationInfo) {
assertOpenEventually(migrationCommitLatch);
resetInternalMigrationListener(instance);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class DelayMigrationStart extends InternalMigrationListener implements HazelcastInstanceAware {
private final CountDownLatch migrationStartLatch;
private volatile HazelcastInstance instance;
DelayMigrationStart(CountDownLatch migrationStartLatch) {
this.migrationStartLatch = migrationStartLatch;
}
@Override
public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) {
assertOpenEventually(migrationStartLatch);
resetInternalMigrationListener(instance);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class DelayMigrationStartOnMaster extends InternalMigrationListener implements HazelcastInstanceAware {
private final AtomicBoolean rollback = new AtomicBoolean();
private final CountDownLatch migrationStartLatch;
private volatile HazelcastInstance instance;
DelayMigrationStartOnMaster(CountDownLatch migrationStartLatch) {
this.migrationStartLatch = migrationStartLatch;
}
@Override
public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) {
assertOpenEventually(migrationStartLatch);
}
@Override
public void onMigrationRollback(MigrationParticipant participant, MigrationInfo migrationInfo) {
rollback.compareAndSet(false, true);
resetInternalMigrationListener(instance);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class TerminateOtherMemberOnMigrationComplete
extends InternalMigrationListener implements HazelcastInstanceAware {
private final CountDownLatch migrationStartLatch;
private volatile boolean rollback;
private volatile HazelcastInstance instance;
private volatile HazelcastInstance other;
TerminateOtherMemberOnMigrationComplete(CountDownLatch migrationStartLatch) {
this.migrationStartLatch = migrationStartLatch;
}
@Override
public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) {
assertOpenEventually(migrationStartLatch);
}
@Override
public void onMigrationComplete(MigrationParticipant participant, MigrationInfo migrationInfo, boolean success) {
if (!success) {
System.err.println("ERR: migration is not successful");
}
int memberCount = instance.getCluster().getMembers().size();
spawn(new Runnable() {
@Override
public void run() {
other.getLifecycleService().terminate();
}
});
assertClusterSizeEventually(memberCount - 1, instance);
}
@Override
public void onMigrationCommit(MigrationParticipant participant, MigrationInfo migrationInfo) {
System.out.println(getAddress(instance) + " > commit " + migrationInfo + " as " + participant);
}
@Override
public void onMigrationRollback(MigrationParticipant participant, MigrationInfo migrationInfo) {
rollback = true;
resetInternalMigrationListener(instance);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class TerminateOtherMemberOnMigrationCommit
extends InternalMigrationListener implements HazelcastInstanceAware {
private final CountDownLatch migrationStartLatch;
private volatile HazelcastInstance instance;
private volatile HazelcastInstance other;
TerminateOtherMemberOnMigrationCommit(CountDownLatch migrationStartLatch) {
this.migrationStartLatch = migrationStartLatch;
}
@Override
public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) {
assertOpenEventually(migrationStartLatch);
}
@Override
public void onMigrationCommit(MigrationParticipant participant, MigrationInfo migrationInfo) {
int memberCount = instance.getCluster().getMembers().size();
spawn(new Runnable() {
@Override
public void run() {
other.getLifecycleService().terminate();
}
});
assertClusterSizeEventually(memberCount - 1, instance);
resetInternalMigrationListener(instance);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class TerminateOnMigrationCommit extends InternalMigrationListener implements HazelcastInstanceAware {
private final CountDownLatch latch;
private volatile HazelcastInstance instance;
TerminateOnMigrationCommit(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void onMigrationCommit(MigrationParticipant participant, MigrationInfo migrationInfo) {
spawn(new Runnable() {
@Override
public void run() {
instance.getLifecycleService().terminate();
}
});
assertOpenEventually(latch);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
private static class CollectMigrationTaskOnCommit extends InternalMigrationListener implements HazelcastInstanceAware {
private final AtomicReference<MigrationInfo> migrationInfoRef = new AtomicReference<MigrationInfo>();
private volatile boolean commit;
private volatile HazelcastInstance instance;
@Override
public void onMigrationStart(MigrationParticipant participant, MigrationInfo migrationInfo) {
if (commit) {
System.err.println("Ignoring new migration start: " + migrationInfo + " as participant: " + participant
+ " since expected migration is already committed");
return;
}
if (!migrationInfoRef.compareAndSet(null, migrationInfo)) {
System.err.println("COLLECT COMMIT START FAILED! curr: " + migrationInfoRef.get() + " new: " + migrationInfo);
}
}
@Override
public void onMigrationCommit(MigrationParticipant participant, MigrationInfo migrationInfo) {
if (commit) {
System.err.println("Ignoring new migration commit: " + migrationInfo + " as participant: " + participant
+ " since expected migration is already committed");
return;
}
MigrationInfo collected = migrationInfoRef.get();
commit = migrationInfo.equals(collected);
if (commit) {
resetInternalMigrationListener(instance);
} else {
System.err.println(
"collect commit failed! collected migration: " + collected + " rollback migration: " + migrationInfo
+ " participant: " + participant);
}
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
}