use of com.github.ambry.clustermap.MockDataNodeId in project ambry by linkedin.
the class StorageManagerTest method residualDirDeletionTest.
/**
* Test that residual directory associated with removed replica is deleted correctly during OFFLINE -> DROPPED transition.
* @throws Exception
*/
@Test
public void residualDirDeletionTest() throws Exception {
MockDataNodeId localNode = clusterMap.getDataNodes().get(0);
List<ReplicaId> replicas = clusterMap.getReplicaIds(localNode);
MockClusterParticipant mockHelixParticipant = Mockito.spy(new MockClusterParticipant());
doNothing().when(mockHelixParticipant).setPartitionDisabledState(anyString(), anyBoolean());
// create an extra store dir at one of the mount paths
String mountPath = replicas.get(0).getMountPath();
String extraPartitionName = "1000";
File extraStoreDir = new File(mountPath, extraPartitionName);
assertTrue("Can't create an extra store dir", extraStoreDir.mkdir());
StorageManager storageManager = createStorageManager(localNode, metricRegistry, Collections.singletonList(mockHelixParticipant));
storageManager.start();
// failure case: IOException when deleting store dir
File invalidDir = new File(extraStoreDir.getAbsolutePath(), "invalidDir");
invalidDir.deleteOnExit();
assertTrue("Couldn't create dir within store dir", invalidDir.mkdir());
assertTrue("Could not make unreadable", invalidDir.setReadable(false));
try {
mockHelixParticipant.onPartitionBecomeDroppedFromOffline(extraPartitionName);
fail("should fail because there is IOException when deleting store dir");
} catch (StateTransitionException e) {
assertEquals("Error code is not expected", ReplicaOperationFailure, e.getErrorCode());
}
assertTrue("Could not make readable", invalidDir.setReadable(true));
// trigger OFFLINE -> DROPPED transition on extra partition. Storage manager should delete residual store dir.
mockHelixParticipant.onPartitionBecomeDroppedFromOffline(extraPartitionName);
verify(mockHelixParticipant).setPartitionDisabledState(extraPartitionName, false);
assertFalse("Extra store dir should not exist", extraStoreDir.exists());
shutdownAndAssertStoresInaccessible(storageManager, replicas);
}
use of com.github.ambry.clustermap.MockDataNodeId in project ambry by linkedin.
the class StorageManagerTest method updateInstanceConfigFailureTest.
/**
* Test failure cases when updating InstanceConfig in Helix for both Offline-To-Bootstrap and Inactive-To-Offline.
*/
@Test
public void updateInstanceConfigFailureTest() throws Exception {
generateConfigs(true, true);
MockDataNodeId localNode = clusterMap.getDataNodes().get(0);
List<ReplicaId> localReplicas = clusterMap.getReplicaIds(localNode);
MockClusterParticipant mockHelixParticipant = new MockClusterParticipant();
StorageManager storageManager = createStorageManager(localNode, metricRegistry, Collections.singletonList(mockHelixParticipant));
storageManager.start();
// create a new partition and get its replica on local node
PartitionId newPartition = clusterMap.createNewPartition(Collections.singletonList(localNode));
// override return value of updateDataNodeInfoInCluster() to mock update InstanceConfig failure
mockHelixParticipant.updateNodeInfoReturnVal = false;
try {
mockHelixParticipant.onPartitionBecomeBootstrapFromOffline(newPartition.toPathString());
fail("should fail because updating InstanceConfig didn't succeed during Offline-To-Bootstrap");
} catch (StateTransitionException e) {
assertEquals("Error code doesn't match", StateTransitionException.TransitionErrorCode.HelixUpdateFailure, e.getErrorCode());
}
try {
mockHelixParticipant.onPartitionBecomeOfflineFromInactive(localReplicas.get(0).getPartitionId().toPathString());
fail("should fail because updating InstanceConfig didn't succeed during Inactive-To-Offline");
} catch (StateTransitionException e) {
assertEquals("Error code doesn't match", StateTransitionException.TransitionErrorCode.HelixUpdateFailure, e.getErrorCode());
}
mockHelixParticipant.updateNodeInfoReturnVal = null;
// mock InstanceConfig not found error (note that MockHelixAdmin is empty by default, so no InstanceConfig is present)
newPartition = clusterMap.createNewPartition(Collections.singletonList(localNode));
try {
mockHelixParticipant.onPartitionBecomeBootstrapFromOffline(newPartition.toPathString());
fail("should fail because InstanceConfig is not found during Offline-To-Bootstrap");
} catch (StateTransitionException e) {
assertEquals("Error code doesn't match", StateTransitionException.TransitionErrorCode.HelixUpdateFailure, e.getErrorCode());
}
try {
mockHelixParticipant.onPartitionBecomeOfflineFromInactive(localReplicas.get(1).getPartitionId().toPathString());
fail("should fail because InstanceConfig is not found during Inactive-To-Offline");
} catch (StateTransitionException e) {
assertEquals("Error code doesn't match", StateTransitionException.TransitionErrorCode.HelixUpdateFailure, e.getErrorCode());
}
shutdownAndAssertStoresInaccessible(storageManager, localReplicas);
}
use of com.github.ambry.clustermap.MockDataNodeId in project ambry by linkedin.
the class StorageManagerTest method addBlobStoreTest.
/**
* Test add new BlobStore with given {@link ReplicaId}.
*/
@Test
public void addBlobStoreTest() throws Exception {
generateConfigs(true, false);
MockDataNodeId localNode = clusterMap.getDataNodes().get(0);
List<ReplicaId> localReplicas = clusterMap.getReplicaIds(localNode);
int newMountPathIndex = 3;
// add new MountPath to local node
File f = File.createTempFile("ambry", ".tmp");
File mountFile = new File(f.getParent(), "mountpathfile" + MockClusterMap.PLAIN_TEXT_PORT_START_NUMBER + newMountPathIndex);
MockClusterMap.deleteFileOrDirectory(mountFile);
assertTrue("Couldn't create mount path directory", mountFile.mkdir());
localNode.addMountPaths(Collections.singletonList(mountFile.getAbsolutePath()));
PartitionId newPartition1 = new MockPartitionId(10L, MockClusterMap.DEFAULT_PARTITION_CLASS, clusterMap.getDataNodes(), newMountPathIndex);
StorageManager storageManager = createStorageManager(localNode, metricRegistry, null);
storageManager.start();
// test add store that already exists, which should fail
assertFalse("Add store which is already existing should fail", storageManager.addBlobStore(localReplicas.get(0)));
// test add store onto a new disk, which should succeed
assertTrue("Add new store should succeed", storageManager.addBlobStore(newPartition1.getReplicaIds().get(0)));
assertNotNull("The store shouldn't be null because new store is successfully added", storageManager.getStore(newPartition1, false));
// test add store whose diskManager is not running, which should fail
PartitionId newPartition2 = new MockPartitionId(11L, MockClusterMap.DEFAULT_PARTITION_CLASS, clusterMap.getDataNodes(), 0);
storageManager.getDiskManager(localReplicas.get(0).getPartitionId()).shutdown();
assertFalse("Add store onto the DiskManager which is not running should fail", storageManager.addBlobStore(newPartition2.getReplicaIds().get(0)));
storageManager.getDiskManager(localReplicas.get(0).getPartitionId()).start();
// test replica addition can correctly handle existing dir (should delete it and create a new one)
// To verify the directory has been recreated, we purposely put a test file in previous dir.
PartitionId newPartition3 = new MockPartitionId(12L, MockClusterMap.DEFAULT_PARTITION_CLASS, clusterMap.getDataNodes(), 0);
ReplicaId replicaToAdd = newPartition3.getReplicaIds().get(0);
File previousDir = new File(replicaToAdd.getReplicaPath());
File testFile = new File(previousDir, "testFile");
MockClusterMap.deleteFileOrDirectory(previousDir);
assertTrue("Cannot create dir for " + replicaToAdd.getReplicaPath(), previousDir.mkdir());
assertTrue("Cannot create test file within previous dir", testFile.createNewFile());
assertTrue("Adding new store should succeed", storageManager.addBlobStore(replicaToAdd));
assertFalse("Test file should not exist", testFile.exists());
assertNotNull("Store associated new added replica should not be null", storageManager.getStore(newPartition3, false));
shutdownAndAssertStoresInaccessible(storageManager, localReplicas);
// test add store but fail to add segment requirements to DiskSpaceAllocator. (This is simulated by inducing
// addRequiredSegments failure to make store inaccessible)
List<String> mountPaths = localNode.getMountPaths();
String diskToFail = mountPaths.get(0);
File reservePoolDir = new File(diskToFail, diskManagerConfig.diskManagerReserveFileDirName);
File storeReserveDir = new File(reservePoolDir, DiskSpaceAllocator.STORE_DIR_PREFIX + newPartition2.toPathString());
StorageManager storageManager2 = createStorageManager(localNode, new MetricRegistry(), null);
storageManager2.start();
Utils.deleteFileOrDirectory(storeReserveDir);
assertTrue("File creation should succeed", storeReserveDir.createNewFile());
assertFalse("Add store should fail if store couldn't start due to initializePool failure", storageManager2.addBlobStore(newPartition2.getReplicaIds().get(0)));
assertNull("New store shouldn't be in in-memory data structure", storageManager2.getStore(newPartition2, false));
shutdownAndAssertStoresInaccessible(storageManager2, localReplicas);
}
use of com.github.ambry.clustermap.MockDataNodeId in project ambry by linkedin.
the class ReplicationTest method onReplicaAddedOrRemovedCallbackTest.
/**
* Test cluster map change callback in {@link ReplicationManager} when any remote replicas are added or removed.
* Test setup: attempt to add 3 replicas and remove 3 replicas respectively. The three replicas are picked as follows:
* (1) 1st replica on current node (should skip)
* (2) 2nd replica on remote node sharing partition with current one (should be added or removed)
* (3) 3rd replica on remote node but doesn't share partition with current one (should skip)
* @throws Exception
*/
@Test
public void onReplicaAddedOrRemovedCallbackTest() throws Exception {
MockClusterMap clusterMap = new MockClusterMap();
ClusterMapConfig clusterMapConfig = new ClusterMapConfig(verifiableProperties);
StoreConfig storeConfig = new StoreConfig(verifiableProperties);
// pick a node with no special partition as current node
Set<DataNodeId> specialPartitionNodes = clusterMap.getSpecialPartition().getReplicaIds().stream().map(ReplicaId::getDataNodeId).collect(Collectors.toSet());
DataNodeId currentNode = clusterMap.getDataNodes().stream().filter(d -> !specialPartitionNodes.contains(d)).findFirst().get();
MockStoreKeyConverterFactory storeKeyConverterFactory = new MockStoreKeyConverterFactory(null, null);
storeKeyConverterFactory.setConversionMap(new HashMap<>());
StorageManager storageManager = new StorageManager(storeConfig, new DiskManagerConfig(verifiableProperties), Utils.newScheduler(1, true), new MetricRegistry(), null, clusterMap, currentNode, null, null, new MockTime(), null, new InMemAccountService(false, false));
storageManager.start();
MockReplicationManager replicationManager = new MockReplicationManager(replicationConfig, clusterMapConfig, storeConfig, storageManager, clusterMap, currentNode, storeKeyConverterFactory, null);
ClusterMapChangeListener clusterMapChangeListener = clusterMap.getClusterMapChangeListener();
// find the special partition (not on current node) and get an irrelevant replica from it
PartitionId absentPartition = clusterMap.getSpecialPartition();
ReplicaId irrelevantReplica = absentPartition.getReplicaIds().get(0);
// find an existing replica on current node and one of its peer replicas on remote node
ReplicaId existingReplica = clusterMap.getReplicaIds(currentNode).get(0);
ReplicaId peerReplicaToRemove = existingReplica.getPartitionId().getReplicaIds().stream().filter(r -> r != existingReplica).findFirst().get();
// create a new node and place a peer of existing replica on it.
MockDataNodeId remoteNode = createDataNode(getListOfPorts(PLAIN_TEXT_PORT_START_NUMBER + 10, SSL_PORT_START_NUMBER + 10, HTTP2_PORT_START_NUMBER + 10), clusterMap.getDatacenterName((byte) 0), 3);
ReplicaId addedReplica = new MockReplicaId(remoteNode.getPort(), (MockPartitionId) existingReplica.getPartitionId(), remoteNode, 0);
// populate added replica and removed replica lists
List<ReplicaId> replicasToAdd = new ArrayList<>(Arrays.asList(existingReplica, addedReplica, irrelevantReplica));
List<ReplicaId> replicasToRemove = new ArrayList<>(Arrays.asList(existingReplica, peerReplicaToRemove, irrelevantReplica));
PartitionInfo partitionInfo = replicationManager.getPartitionToPartitionInfoMap().get(existingReplica.getPartitionId());
assertNotNull("PartitionInfo is not found", partitionInfo);
RemoteReplicaInfo peerReplicaInfo = partitionInfo.getRemoteReplicaInfos().stream().filter(info -> info.getReplicaId() == peerReplicaToRemove).findFirst().get();
// get the replica-thread for this peer replica
ReplicaThread peerReplicaThread = peerReplicaInfo.getReplicaThread();
// Test Case 1: replication manager encountered exception during startup (remote replica addition/removal will be skipped)
replicationManager.startWithException();
clusterMapChangeListener.onReplicaAddedOrRemoved(replicasToAdd, replicasToRemove);
// verify that PartitionInfo stays unchanged
verifyRemoteReplicaInfo(partitionInfo, addedReplica, false);
verifyRemoteReplicaInfo(partitionInfo, peerReplicaToRemove, true);
// Test Case 2: startup latch is interrupted
CountDownLatch initialLatch = replicationManager.startupLatch;
CountDownLatch mockLatch = Mockito.mock(CountDownLatch.class);
doThrow(new InterruptedException()).when(mockLatch).await();
replicationManager.startupLatch = mockLatch;
try {
clusterMapChangeListener.onReplicaAddedOrRemoved(replicasToAdd, replicasToRemove);
fail("should fail because startup latch is interrupted");
} catch (IllegalStateException e) {
// expected
}
replicationManager.startupLatch = initialLatch;
// Test Case 3: replication manager is successfully started
replicationManager.start();
clusterMapChangeListener.onReplicaAddedOrRemoved(replicasToAdd, replicasToRemove);
// verify that PartitionInfo has latest remote replica infos
verifyRemoteReplicaInfo(partitionInfo, addedReplica, true);
verifyRemoteReplicaInfo(partitionInfo, peerReplicaToRemove, false);
verifyRemoteReplicaInfo(partitionInfo, irrelevantReplica, false);
// verify new added replica is assigned to a certain thread
ReplicaThread replicaThread = replicationManager.getDataNodeIdToReplicaThreadMap().get(addedReplica.getDataNodeId());
assertNotNull("There is no ReplicaThread assocated with new replica", replicaThread);
Optional<RemoteReplicaInfo> findResult = replicaThread.getRemoteReplicaInfos().get(remoteNode).stream().filter(info -> info.getReplicaId() == addedReplica).findAny();
assertTrue("New added remote replica info should exist in corresponding thread", findResult.isPresent());
// verify the removed replica info's thread is null
assertNull("Thread in removed replica info should be null", peerReplicaInfo.getReplicaThread());
findResult = peerReplicaThread.getRemoteReplicaInfos().get(peerReplicaToRemove.getDataNodeId()).stream().filter(info -> info.getReplicaId() == peerReplicaToRemove).findAny();
assertFalse("Previous replica thread should not contain RemoteReplicaInfo that is already removed", findResult.isPresent());
storageManager.shutdown();
}
use of com.github.ambry.clustermap.MockDataNodeId in project ambry by linkedin.
the class NonBlockingRouterTest method testWarmUpConnectionFailureHandling.
/**
* Test that Response Handler correctly handles disconnected connections after warming up.
*/
@Test
public void testWarmUpConnectionFailureHandling() throws Exception {
try {
Properties props = getNonBlockingRouterProperties("DC3");
MockServerLayout mockServerLayout = new MockServerLayout(mockClusterMap);
mockSelectorState.set(MockSelectorState.FailConnectionInitiationOnPoll);
setRouter(props, mockServerLayout, new LoggingNotificationSystem());
for (DataNodeId node : mockClusterMap.getDataNodes()) {
assertTrue("Node should be marked as timed out by ResponseHandler.", ((MockDataNodeId) node).isTimedOut());
}
} finally {
if (router != null) {
router.close();
}
mockSelectorState.set(MockSelectorState.Good);
}
}
Aggregations