/*
* 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.cluster.ClusterState;
import com.hazelcast.config.Config;
import com.hazelcast.config.ServiceConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.internal.partition.service.TestMigrationAwareService;
import com.hazelcast.internal.partition.service.TestPutOperation;
import com.hazelcast.nio.Address;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.Operation;
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.net.UnknownHostException;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import static com.hazelcast.internal.cluster.impl.AdvancedClusterStateTest.changeClusterStateEventually;
import static com.hazelcast.internal.partition.AntiEntropyCorrectnessTest.setBackupPacketDropFilter;
import static org.junit.Assert.assertEquals;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class PartitionReplicaStateCheckerTest extends HazelcastTestSupport {
@Test
public void shouldBeSafe_whenNotInitialized() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
PartitionServiceState state = replicaStateChecker.getPartitionServiceState();
assertEquals(PartitionServiceState.SAFE, state);
}
@Test
public void shouldBeSafe_whenInitializedOnMaster() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
partitionService.firstArrangement();
PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
PartitionServiceState state = replicaStateChecker.getPartitionServiceState();
assertEquals(PartitionServiceState.SAFE, state);
}
@Test
public void shouldNotBeSafe_whenMissingReplicasPresent() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
partitionService.firstArrangement();
PartitionStateManager partitionStateManager = partitionService.getPartitionStateManager();
InternalPartitionImpl partition = partitionStateManager.getPartitionImpl(0);
Address[] replicaAddresses = partition.getReplicaAddresses();
partition.setReplicaAddresses(new Address[replicaAddresses.length]);
PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
assertEquals(PartitionServiceState.REPLICA_NOT_OWNED, replicaStateChecker.getPartitionServiceState());
partition.setReplicaAddresses(replicaAddresses);
assertEquals(PartitionServiceState.SAFE, replicaStateChecker.getPartitionServiceState());
}
@Test
public void shouldNotBeSafe_whenUnknownReplicaOwnerPresent() throws UnknownHostException {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
partitionService.firstArrangement();
PartitionStateManager partitionStateManager = partitionService.getPartitionStateManager();
InternalPartitionImpl partition = partitionStateManager.getPartitionImpl(0);
Address[] replicaAddresses = partition.getReplicaAddresses();
Address[] illegalReplicaAddresses = Arrays.copyOf(replicaAddresses, replicaAddresses.length);
Address address = new Address(replicaAddresses[0]);
illegalReplicaAddresses[0] = new Address(address.getInetAddress(), address.getPort() + 1000);
partition.setReplicaAddresses(illegalReplicaAddresses);
PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
assertEquals(PartitionServiceState.REPLICA_NOT_OWNED, replicaStateChecker.getPartitionServiceState());
partition.setReplicaAddresses(replicaAddresses);
assertEquals(PartitionServiceState.SAFE, replicaStateChecker.getPartitionServiceState());
}
@Test
public void shouldBeSafe_whenKnownReplicaOwnerPresent_whileNotActive() throws UnknownHostException {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
HazelcastInstance hz2 = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
partitionService.firstArrangement();
changeClusterStateEventually(hz2, ClusterState.FROZEN);
hz2.shutdown();
assertClusterSizeEventually(1, hz);
PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
assertEquals(PartitionServiceState.SAFE, replicaStateChecker.getPartitionServiceState());
}
@Test
public void shouldNotBeSafe_whenUnknownReplicaOwnerPresent_whileNotActive() throws UnknownHostException {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
HazelcastInstance hz2 = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
partitionService.firstArrangement();
changeClusterStateEventually(hz2, ClusterState.FROZEN);
hz2.shutdown();
assertClusterSizeEventually(1, hz);
PartitionStateManager partitionStateManager = partitionService.getPartitionStateManager();
InternalPartitionImpl partition = partitionStateManager.getPartitionImpl(0);
Address[] replicaAddresses = partition.getReplicaAddresses();
Address[] illegalReplicaAddresses = Arrays.copyOf(replicaAddresses, replicaAddresses.length);
Address address = new Address(replicaAddresses[0]);
illegalReplicaAddresses[0] = new Address(address.getInetAddress(), address.getPort() + 1000);
partition.setReplicaAddresses(illegalReplicaAddresses);
PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
assertEquals(PartitionServiceState.REPLICA_NOT_OWNED, replicaStateChecker.getPartitionServiceState());
partition.setReplicaAddresses(replicaAddresses);
assertEquals(PartitionServiceState.SAFE, replicaStateChecker.getPartitionServiceState());
}
@Test
public void shouldNotBeSafe_whenMigrationTasksScheduled() {
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance();
InternalPartitionServiceImpl partitionService = getNode(hz).partitionService;
final CountDownLatch latch = new CountDownLatch(1);
MigrationManager migrationManager = partitionService.getMigrationManager();
migrationManager.schedule(new MigrationRunnable() {
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
final PartitionReplicaStateChecker replicaStateChecker = partitionService.getPartitionReplicaStateChecker();
assertEquals(PartitionServiceState.MIGRATION_LOCAL, replicaStateChecker.getPartitionServiceState());
latch.countDown();
assertEqualsEventually(new Callable<PartitionServiceState>() {
@Override
public PartitionServiceState call() throws Exception {
return replicaStateChecker.getPartitionServiceState();
}
}, PartitionServiceState.SAFE);
}
@Test
public void shouldNotBeSafe_whenReplicasAreNotSync() {
Config config = new Config();
ServiceConfig serviceConfig = TestMigrationAwareService.createServiceConfig(1);
config.getServicesConfig().addServiceConfig(serviceConfig);
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance hz = factory.newHazelcastInstance(config);
HazelcastInstance hz2 = factory.newHazelcastInstance(config);
InternalPartitionServiceImpl partitionService1 = getNode(hz).partitionService;
InternalPartitionServiceImpl partitionService2 = getNode(hz2).partitionService;
drainAllReplicaSyncPermits(partitionService1);
drainAllReplicaSyncPermits(partitionService2);
warmUpPartitions(hz, hz2);
setBackupPacketDropFilter(hz, 100);
setBackupPacketDropFilter(hz2, 100);
NodeEngine nodeEngine = getNode(hz).nodeEngine;
for (int i = 0; i < nodeEngine.getPartitionService().getPartitionCount(); i++) {
Operation op = new TestPutOperationWithAsyncBackup(i);
nodeEngine.getOperationService().invokeOnPartition(null, op, i).join();
}
final PartitionReplicaStateChecker replicaStateChecker1 = partitionService1.getPartitionReplicaStateChecker();
final PartitionReplicaStateChecker replicaStateChecker2 = partitionService2.getPartitionReplicaStateChecker();
assertEquals(PartitionServiceState.REPLICA_NOT_SYNC, replicaStateChecker1.getPartitionServiceState());
assertEquals(PartitionServiceState.REPLICA_NOT_SYNC, replicaStateChecker2.getPartitionServiceState());
addReplicaSyncPermits(partitionService1, 100);
addReplicaSyncPermits(partitionService2, 100);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertEquals(PartitionServiceState.SAFE, replicaStateChecker1.getPartitionServiceState());
assertEquals(PartitionServiceState.SAFE, replicaStateChecker2.getPartitionServiceState());
}
});
}
private void addReplicaSyncPermits(InternalPartitionServiceImpl partitionService, int k) {
PartitionReplicaManager replicaManager = partitionService.getReplicaManager();
for (int i = 0; i < k; i++) {
replicaManager.releaseReplicaSyncPermit();
}
}
private int drainAllReplicaSyncPermits(InternalPartitionServiceImpl partitionService) {
PartitionReplicaManager replicaManager = partitionService.getReplicaManager();
int k = 0;
while (replicaManager.tryToAcquireReplicaSyncPermit()) {
k++;
}
return k;
}
private static class TestPutOperationWithAsyncBackup extends TestPutOperation {
public TestPutOperationWithAsyncBackup() {
}
TestPutOperationWithAsyncBackup(int i) {
super(i);
}
@Override
public int getSyncBackupCount() {
return 0;
}
@Override
public int getAsyncBackupCount() {
return super.getSyncBackupCount();
}
}
}