use of com.github.ambry.config.ClusterMapConfig in project ambry by linkedin.
the class HelixParticipantTest method testMultiParticipants.
/**
* Test instantiating multiple {@link HelixParticipant}(s) in {@link HelixClusterAgentsFactory}
* @throws Exception
*/
@Test
public void testMultiParticipants() throws Exception {
assumeTrue(dataNodeConfigSourceType == DataNodeConfigSourceType.INSTANCE_CONFIG);
JSONArray zkInfosJson = new JSONArray();
// create a new zkJson which contains two zk endpoints in the same data center.
JSONObject zkInfoJson = new JSONObject();
zkInfoJson.put(ClusterMapUtils.DATACENTER_STR, "DC0");
zkInfoJson.put(ClusterMapUtils.DATACENTER_ID_STR, (byte) 0);
zkInfoJson.put(ClusterMapUtils.ZKCONNECT_STR, "localhost:2199" + ZKCONNECT_STR_DELIMITER + "localhost:2299");
zkInfosJson.put(zkInfoJson);
JSONObject jsonObject = new JSONObject().put(ClusterMapUtils.ZKINFO_STR, zkInfosJson);
props.setProperty("clustermap.dcs.zk.connect.strings", jsonObject.toString(2));
ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(props));
try {
List<ClusterParticipant> participants = new HelixClusterAgentsFactory(clusterMapConfig, helixManagerFactory).getClusterParticipants();
assertEquals("Number of participants is not expected", 2, participants.size());
} catch (Exception e) {
throw e;
} finally {
// restore previous setup
props.setProperty("clustermap.dcs.zk.connect.strings", zkJson.toString(2));
}
}
use of com.github.ambry.config.ClusterMapConfig in project ambry by linkedin.
the class HelixParticipantTest method testHelixParticipant.
/**
* Test the good path of instantiation, initialization and termination of the {@link HelixParticipant}
* @throws Exception
*/
@Test
public void testHelixParticipant() throws Exception {
ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(props));
HelixParticipant participant = new HelixParticipant(clusterMapConfig, helixManagerFactory, new MetricRegistry(), getDefaultZkConnectStr(clusterMapConfig), true);
assertTrue(helixManagerFactory.getHelixManager(InstanceType.SPECTATOR).isConnected());
assertFalse(helixManagerFactory.getHelixManager(InstanceType.PARTICIPANT).isConnected());
participant.participate(Collections.emptyList(), null, null);
MockHelixManagerFactory.MockHelixManager helixManager = helixManagerFactory.getHelixManager(InstanceType.PARTICIPANT);
assertTrue(helixManager.isConnected());
assertEquals(stateModelDef, helixManager.getStateModelDef());
assertEquals(AmbryStateModelFactory.class, helixManager.getStateModelFactory().getClass());
participant.close();
assertFalse(helixManager.isConnected());
}
use of com.github.ambry.config.ClusterMapConfig in project ambry by linkedin.
the class HelixParticipantTest method testGetAndSetReplicaSealedState.
/**
* Tests setReplicaSealedState method for {@link HelixParticipant}
* @throws Exception
*/
@Test
public void testGetAndSetReplicaSealedState() throws Exception {
// setup HelixParticipant and dependencies
ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(props));
String instanceName = ClusterMapUtils.getInstanceName("localhost", clusterMapConfig.clusterMapPort);
HelixParticipant helixParticipant = new HelixParticipant(clusterMapConfig, new HelixFactory(), new MetricRegistry(), getDefaultZkConnectStr(clusterMapConfig), true);
ZKHelixAdmin helixAdmin = new ZKHelixAdmin("localhost:" + zkInfo.getPort());
DataNodeConfig dataNodeConfig = getDataNodeConfigInHelix(helixAdmin, instanceName);
Set<String> localPartitionNames = new HashSet<>();
dataNodeConfig.getDiskConfigs().values().forEach(diskConfig -> localPartitionNames.addAll(diskConfig.getReplicaConfigs().keySet()));
String partitionIdStr = localPartitionNames.iterator().next();
String partitionIdStr2 = localPartitionNames.stream().filter(p -> !p.equals(partitionIdStr)).findFirst().get();
ReplicaId replicaId = createMockAmbryReplica(partitionIdStr);
ReplicaId replicaId2 = createMockAmbryReplica(partitionIdStr2);
// Make sure the current sealedReplicas list is empty
List<String> sealedReplicas = helixParticipant.getSealedReplicas();
assertEquals("sealedReplicas should be empty", Collections.emptyList(), sealedReplicas);
String listName = "sealedReplicas";
// Check that invoking setReplicaSealedState with a non-AmbryReplica ReplicaId throws an IllegalArgumentException
ReplicaId notAmbryReplica = createMockNotAmbryReplica(partitionIdStr);
try {
helixParticipant.setReplicaSealedState(notAmbryReplica, true);
fail("Expected an IllegalArgumentException here");
} catch (IllegalArgumentException e) {
// Expected exception
}
// Check that invoking setReplicaSealedState adds the partition to the list of sealed replicas
helixParticipant.setReplicaSealedState(replicaId, true);
sealedReplicas = helixParticipant.getSealedReplicas();
listIsExpectedSize(sealedReplicas, 1, listName);
assertTrue(sealedReplicas.contains(partitionIdStr));
// Seal another replicaId
helixParticipant.setReplicaSealedState(replicaId2, true);
sealedReplicas = helixParticipant.getSealedReplicas();
listIsExpectedSize(sealedReplicas, 2, listName);
assertTrue(sealedReplicas.contains(partitionIdStr2));
assertTrue(sealedReplicas.contains(partitionIdStr));
// Check that sealed replica list doesn't take duplicates (and that dups are detected by partitionId comparison, not
// replicaId object comparison
ReplicaId dup = createMockAmbryReplica(partitionIdStr);
helixParticipant.setReplicaSealedState(dup, true);
helixParticipant.setReplicaSealedState(replicaId2, true);
sealedReplicas = helixParticipant.getSealedReplicas();
listIsExpectedSize(sealedReplicas, 2, listName);
assertTrue(sealedReplicas.contains(partitionIdStr2));
assertTrue(sealedReplicas.contains(partitionIdStr));
// Check that invoking setReplicaSealedState with isSealed == false removes partition from list of sealed replicas
helixParticipant.setReplicaSealedState(replicaId, false);
sealedReplicas = helixParticipant.getSealedReplicas();
listIsExpectedSize(sealedReplicas, 1, listName);
assertTrue(sealedReplicas.contains(partitionIdStr2));
assertFalse(sealedReplicas.contains(partitionIdStr));
// Removing a replicaId that's already been removed doesn't hurt anything
helixParticipant.setReplicaSealedState(replicaId, false);
sealedReplicas = helixParticipant.getSealedReplicas();
listIsExpectedSize(sealedReplicas, 1, listName);
// Removing all replicas yields expected behavior (and removal works by partitionId, not replicaId itself)
dup = createMockAmbryReplica(partitionIdStr2);
helixParticipant.setReplicaSealedState(dup, false);
sealedReplicas = helixParticipant.getSealedReplicas();
listIsExpectedSize(sealedReplicas, 0, listName);
helixAdmin.close();
}
use of com.github.ambry.config.ClusterMapConfig in project ambry by linkedin.
the class HelixParticipantTest method testUpdateNodeInfoInCluster.
/**
* Test both replica info addition and removal cases when updating node info in Helix cluster.
* @throws Exception
*/
@Test
public void testUpdateNodeInfoInCluster() throws Exception {
// override some props for current test
props.setProperty("clustermap.update.datanode.info", Boolean.toString(true));
ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(props));
HelixParticipant participant = new HelixParticipant(clusterMapConfig, new HelixFactory(), new MetricRegistry(), getDefaultZkConnectStr(clusterMapConfig), true);
participant.markDisablePartitionComplete();
// create InstanceConfig for local node. Also, put existing replica into sealed list
String instanceName = ClusterMapUtils.getInstanceName("localhost", clusterMapConfig.clusterMapPort);
ZKHelixAdmin helixAdmin = new ZKHelixAdmin("localhost:" + zkInfo.getPort());
DataNodeConfig dataNodeConfig = getDataNodeConfigInHelix(helixAdmin, instanceName);
DataNodeConfig.DiskConfig diskConfig = dataNodeConfig.getDiskConfigs().values().iterator().next();
String existingReplicaName = diskConfig.getReplicaConfigs().keySet().iterator().next();
PartitionId correspondingPartition = testPartitionLayout.getPartitionLayout().getPartitions(null).stream().filter(p -> p.toPathString().equals(existingReplicaName)).findFirst().get();
ReplicaId existingReplica = correspondingPartition.getReplicaIds().stream().filter(r -> r.getDataNodeId().getPort() == clusterMapConfig.clusterMapPort).findFirst().get();
// generate exactly same config for comparison
DataNodeConfig initialDataNodeConfig = deepCopyDataNodeConfig(dataNodeConfig);
// 1. add existing replica's info to Helix should be no-op
assertTrue("Adding existing replica's info should succeed", participant.updateDataNodeInfoInCluster(existingReplica, true));
assertEquals("DataNodeConfig should stay unchanged", initialDataNodeConfig, getDataNodeConfigInHelix(helixAdmin, instanceName));
// create two new replicas on the same disk of local node
int currentPartitionCount = testPartitionLayout.getPartitionCount();
Partition newPartition1 = new Partition(currentPartitionCount++, DEFAULT_PARTITION_CLASS, PartitionState.READ_WRITE, testPartitionLayout.replicaCapacityInBytes);
Partition newPartition2 = new Partition(currentPartitionCount, DEFAULT_PARTITION_CLASS, PartitionState.READ_WRITE, testPartitionLayout.replicaCapacityInBytes);
Disk disk = (Disk) existingReplica.getDiskId();
// 2. add new partition2 (id = 10, replicaFromPartition2) to Helix
ReplicaId replicaFromPartition2 = new Replica(newPartition2, disk, clusterMapConfig);
assertTrue("Adding new replica info to Helix should succeed.", participant.updateDataNodeInfoInCluster(replicaFromPartition2, true));
// verify new added replica (replicaFromPartition2) info is present in DataNodeConfig
Thread.sleep(50);
dataNodeConfig = getDataNodeConfigInHelix(helixAdmin, instanceName);
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, replicaFromPartition2, true);
// 3. add new partition1 (replicaFromPartition1) into InstanceConfig
ReplicaId replicaFromPartition1 = new Replica(newPartition1, disk, clusterMapConfig);
assertTrue("Adding new replica info into InstanceConfig should succeed.", participant.updateDataNodeInfoInCluster(replicaFromPartition1, true));
Thread.sleep(50);
// verify new added replica (replicaFromPartition1) info is present in InstanceConfig
dataNodeConfig = getDataNodeConfigInHelix(helixAdmin, instanceName);
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, replicaFromPartition1, true);
// ensure previous added replica (replicaFromPartition2) still exists
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, replicaFromPartition2, true);
// 4. remove recently added new replica (replicaFromPartition1)
assertTrue("Removing replica info from InstanceConfig should succeed.", participant.updateDataNodeInfoInCluster(replicaFromPartition1, false));
Thread.sleep(50);
dataNodeConfig = getDataNodeConfigInHelix(helixAdmin, instanceName);
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, replicaFromPartition1, false);
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, replicaFromPartition2, true);
// 5. remove same replica again (id = 9, replicaFromPartition1) should be no-op
assertTrue("Removing non-found replica info from InstanceConfig should succeed.", participant.updateDataNodeInfoInCluster(replicaFromPartition1, false));
// 6. remove recently added new replica (replicaFromPartition2)
assertTrue("Removing replica info from InstanceConfig should succeed.", participant.updateDataNodeInfoInCluster(replicaFromPartition2, false));
Thread.sleep(50);
dataNodeConfig = getDataNodeConfigInHelix(helixAdmin, instanceName);
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, replicaFromPartition2, false);
verifyReplicaInfoInDataNodeConfig(dataNodeConfig, existingReplica, true);
// reset props
props.setProperty("clustermap.update.datanode.info", Boolean.toString(false));
helixAdmin.close();
}
use of com.github.ambry.config.ClusterMapConfig in project ambry by linkedin.
the class ClusterChangeHandlerTest method moveReplicaTest.
/**
* Test the case where a current replica is moved between existing nodes.
*/
@Test
public void moveReplicaTest() throws Exception {
// create a HelixClusterManager with DynamicClusterChangeHandler
Properties properties = new Properties();
properties.putAll(props);
properties.setProperty("clustermap.cluster.change.handler.type", "DynamicClusterChangeHandler");
ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(properties));
HelixClusterManager helixClusterManager = new HelixClusterManager(clusterMapConfig, selfInstanceName, helixManagerFactory, new MetricRegistry());
// pick a partition and move one of its replicas
Partition testPartition = (Partition) testPartitionLayout.getPartitionLayout().getRandomWritablePartition(null, null);
int previousReplicaCnt = testPartition.getReplicaIds().size();
// 1. find out nodes in local dc that host this partition
List<DataNodeId> localDcNodes = getPartitionDataNodesFromDc(testPartition, localDc);
// 2. then find a node in local dc that doesn't host this partition (this is the node we will add replica to)
Datacenter localDatacenter = testHardwareLayout.getHardwareLayout().getDatacenters().stream().filter(dc -> dc.getName().equals(localDc)).findFirst().get();
// since we didn't populate bootstrap replica map, we have to avoid adding replica to currentNode
DataNode nodeToAddReplica = localDatacenter.getDataNodes().stream().filter(node -> !localDcNodes.contains(node) && node != currentNode).findFirst().get();
testPartitionLayout.addReplicaToPartition(nodeToAddReplica, testPartition);
Utils.writeJsonObjectToFile(testPartitionLayout.getPartitionLayout().toJSONObject(), partitionLayoutPath);
// 3. We upgrade helix by adding new replica to the chosen node in local dc. This is to mock "replica addition" on
// chosen node and chosen node updates its instanceConfig in Helix. There should be 7 (= 6+1) replicas in the
// intermediate state.
helixCluster.upgradeWithNewPartitionLayout(partitionLayoutPath, HelixBootstrapUpgradeUtil.HelixAdminOperation.BootstrapCluster);
PartitionId partitionInManager = helixClusterManager.getAllPartitionIds(null).stream().filter(p -> p.toPathString().equals(testPartition.toPathString())).findFirst().get();
assertEquals("Replica count of testing partition is not correct", previousReplicaCnt + 1, partitionInManager.getReplicaIds().size());
// 4. find a replica (from same partition) in local dc that is not just added one
Replica oldReplica = (Replica) testPartition.getReplicaIds().stream().filter(r -> r.getDataNodeId().getDatacenterName().equals(localDc) && r.getDataNodeId() != nodeToAddReplica).findFirst().get();
testPartitionLayout.removeReplicaFromPartition(oldReplica);
Utils.writeJsonObjectToFile(testPartitionLayout.getPartitionLayout().toJSONObject(), partitionLayoutPath);
// 5. disable the replica in Helix to mock replica decommission which will remove it from InstanceConfig but keep it
// in IdealState temporarily.
helixCluster.upgradeWithNewPartitionLayout(partitionLayoutPath, HelixBootstrapUpgradeUtil.HelixAdminOperation.DisablePartition);
Set<ReplicaId> replicasInDifferentStates = new HashSet<>();
for (ReplicaState state : EnumSet.of(ReplicaState.STANDBY, ReplicaState.LEADER, ReplicaState.OFFLINE, ReplicaState.INACTIVE, ReplicaState.BOOTSTRAP)) {
replicasInDifferentStates.addAll(partitionInManager.getReplicaIdsByState(state, null));
}
// verify there is no null replica
replicasInDifferentStates.forEach(r -> assertNotNull("found null replica", r));
// 6. updates the IdealState in Helix. The number of replicas should become 6 again.
helixCluster.upgradeWithNewPartitionLayout(partitionLayoutPath, HelixBootstrapUpgradeUtil.HelixAdminOperation.UpdateIdealState);
assertEquals("Replica count of testing partition is not correct", previousReplicaCnt, partitionInManager.getReplicaIds().size());
helixClusterManager.close();
}
Aggregations