/*
* 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.cluster.impl;
import com.hazelcast.cluster.ClusterState;
import com.hazelcast.config.Config;
import com.hazelcast.config.ServiceConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.instance.Node;
import com.hazelcast.internal.partition.InternalPartition;
import com.hazelcast.internal.partition.InternalPartitionService;
import com.hazelcast.nio.Address;
import com.hazelcast.spi.MigrationAwareService;
import com.hazelcast.spi.Operation;
import com.hazelcast.spi.PartitionMigrationEvent;
import com.hazelcast.spi.PartitionReplicationEvent;
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.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import static com.hazelcast.instance.TestUtil.terminateInstance;
import static com.hazelcast.internal.cluster.impl.AdvancedClusterStateTest.changeClusterStateEventually;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class NoMigrationClusterStateTest extends HazelcastTestSupport {
private final NoReplicationService service = new NoReplicationService();
@Test
public void rebalancing_shouldNotHappen_whenMemberLeaves() {
Config config = newConfigWithMigrationAwareService();
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance[] instances = factory.newInstances(config, 3);
warmUpPartitions(instances);
waitAllForSafeState(instances);
changeClusterStateEventually(instances[1], ClusterState.NO_MIGRATION);
terminateInstance(instances[0]);
final HazelcastInstance hz = factory.newHazelcastInstance(config);
assertTrueAllTheTime(new AssertTask() {
final Node node = getNode(hz);
final InternalPartitionService partitionService = node.getPartitionService();
@Override
public void run() throws Exception {
List<Integer> memberPartitions = partitionService.getMemberPartitions(node.getThisAddress());
assertThat(memberPartitions, empty());
service.assertNoReplication();
}
}, 10);
}
@Test
public void promotions_shouldHappen_whenMemberLeaves() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance[] instances = factory.newInstances(new Config(), 3);
warmUpPartitions(instances);
waitAllForSafeState(instances);
changeClusterStateEventually(instances[1], ClusterState.NO_MIGRATION);
terminateInstance(instances[0]);
assertClusterSizeEventually(2, instances[1]);
assertAllPartitionsAreAssigned(instances[1], 1);
assertClusterSizeEventually(2, instances[2]);
assertAllPartitionsAreAssigned(instances[2], 1);
}
private static void assertAllPartitionsAreAssigned(HazelcastInstance instance, final int replicaCount) {
final ClusterServiceImpl clusterService = getNode(instance).getClusterService();
final InternalPartitionService partitionService = getNode(instance).getPartitionService();
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
InternalPartition[] partitions = partitionService.getInternalPartitions();
for (InternalPartition partition : partitions) {
for (int i = 0; i < replicaCount; i++) {
Address owner = partition.getReplicaAddress(i);
assertNotNull(i + "th replica owner is null: " + partition, owner);
assertNotNull("No member for: " + owner, clusterService.getMember(owner));
}
}
}
});
}
@Test
public void backupReplication_shouldNotHappen_whenMemberLeaves() {
Config config = newConfigWithMigrationAwareService();
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance[] instances = factory.newInstances(config, 3);
warmUpPartitions(instances);
waitAllForSafeState(instances);
changeClusterStateEventually(instances[1], ClusterState.NO_MIGRATION);
terminateInstance(instances[0]);
assertClusterSizeEventually(2, instances[1], instances[2]);
assertTrueAllTheTime(new AssertTask() {
@Override
public void run() throws Exception {
service.assertNoReplication();
}
}, 10);
}
@Test
public void rebalancing_shouldHappen_whenStateBecomesActive() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance[] instances = factory.newInstances(new Config(), 3);
warmUpPartitions(instances);
waitAllForSafeState(instances);
changeClusterStateEventually(instances[1], ClusterState.NO_MIGRATION);
terminateInstance(instances[0]);
assertClusterSizeEventually(2, instances[1], instances[2]);
changeClusterStateEventually(instances[1], ClusterState.ACTIVE);
assertAllPartitionsAreAssigned(instances[1], 2);
assertAllPartitionsAreAssigned(instances[2], 2);
}
@Test
public void rebalancing_shouldNotHappen_whenStateBecomesFrozen() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance[] instances = factory.newInstances(newConfigWithMigrationAwareService(), 3);
warmUpPartitions(instances);
waitAllForSafeState(instances);
changeClusterStateEventually(instances[1], ClusterState.NO_MIGRATION);
terminateInstance(instances[0]);
assertClusterSizeEventually(2, instances[1], instances[2]);
changeClusterStateEventually(instances[1], ClusterState.FROZEN);
assertTrueAllTheTime(new AssertTask() {
@Override
public void run() throws Exception {
service.assertNoReplication();
}
}, 10);
}
private Config newConfigWithMigrationAwareService() {
Config config = new Config();
config.getServicesConfig().addServiceConfig(new ServiceConfig()
.setEnabled(true)
.setName("no-replication-service")
.setImplementation(service));
return config;
}
private static class NoReplicationService implements MigrationAwareService {
private final AtomicReference<AssertionError> replicationRequested = new AtomicReference<AssertionError>();
@Override
public Operation prepareReplicationOperation(PartitionReplicationEvent event) {
AssertionError error = new AssertionError("Replication requested: " + event);
replicationRequested.compareAndSet(null, error);
throw error;
}
@Override
public void beforeMigration(PartitionMigrationEvent event) {
}
@Override
public void commitMigration(PartitionMigrationEvent event) {
}
@Override
public void rollbackMigration(PartitionMigrationEvent event) {
}
void assertNoReplication() {
AssertionError error = replicationRequested.get();
if (error != null) {
throw error;
}
}
}
}