Search in sources :

Example 91 with MockClusterMap

use of com.github.ambry.clustermap.MockClusterMap in project ambry by linkedin.

the class NonBlockingRouterTest method testSuccessfulPutDataChunkDelete.

/**
 * Test that even when a composite blob put succeeds, the slipped put data chunks are deleted.
 */
@Test
public void testSuccessfulPutDataChunkDelete() throws Exception {
    try {
        // This test is somehow probabilistic. Since it is not possible to devise a mocking to enforce the occurrence of
        // slipped puts given we cannot control the order of the hosts requests are sent and not all requests are sent when
        // put requests are guaranteed to fail/succeed. So, we are setting the number of chunks and max attempts high enough
        // to guarantee that slipped puts would eventually happen and operation would succeed.
        maxPutChunkSize = PUT_CONTENT_SIZE / 8;
        final int NUM_MAX_ATTEMPTS = 100;
        Properties props = getNonBlockingRouterProperties("DC1");
        props.setProperty("router.max.slipped.put.attempts", Integer.toString(NUM_MAX_ATTEMPTS));
        VerifiableProperties verifiableProperties = new VerifiableProperties((props));
        RouterConfig routerConfig = new RouterConfig(verifiableProperties);
        MockClusterMap mockClusterMap = new MockClusterMap();
        MockTime mockTime = new MockTime();
        MockServerLayout mockServerLayout = new MockServerLayout(mockClusterMap);
        // Since this test wants to ensure that successfully put data chunks are deleted when the overall put operation
        // succeeds but some chunks succeed only after a retry, it uses a notification system to track the deletions.
        final CountDownLatch deletesDoneLatch = new CountDownLatch(1);
        final Map<String, String> blobsThatAreDeleted = new HashMap<>();
        LoggingNotificationSystem deleteTrackingNotificationSystem = new LoggingNotificationSystem() {

            @Override
            public void onBlobDeleted(String blobId, String serviceId, Account account, Container container) {
                blobsThatAreDeleted.put(blobId, serviceId);
                deletesDoneLatch.countDown();
            }
        };
        router = new NonBlockingRouter(routerConfig, new NonBlockingRouterMetrics(mockClusterMap, routerConfig), new MockNetworkClientFactory(verifiableProperties, mockSelectorState, MAX_PORTS_PLAIN_TEXT, MAX_PORTS_SSL, CHECKOUT_TIMEOUT_MS, mockServerLayout, mockTime), deleteTrackingNotificationSystem, mockClusterMap, kms, cryptoService, cryptoJobHandler, accountService, mockTime, MockClusterMap.DEFAULT_PARTITION_CLASS);
        setOperationParams();
        // In each DC, set up the servers such that one node always succeeds and the other nodes return an unknown_error and
        // no_error alternately. This will make it with a very high probability that there will at least be a time that a
        // put will succeed on a node but will fail on the other two.
        List<DataNodeId> dataNodeIds = mockClusterMap.getDataNodeIds();
        List<ServerErrorCode> serverErrorList = new ArrayList<>();
        for (int i = 0; i < NUM_MAX_ATTEMPTS; i++) {
            serverErrorList.add(ServerErrorCode.Unknown_Error);
            serverErrorList.add(ServerErrorCode.No_Error);
        }
        Set<String> healthyNodeDC = new HashSet<>();
        for (DataNodeId dataNodeId : dataNodeIds) {
            MockServer server = mockServerLayout.getMockServer(dataNodeId.getHostname(), dataNodeId.getPort());
            if (healthyNodeDC.contains(dataNodeId.getDatacenterName())) {
                server.setServerErrors(serverErrorList);
            } else {
                server.resetServerErrors();
            }
            healthyNodeDC.add(dataNodeId.getDatacenterName());
        }
        // Submit the put operation and wait for it to succeed.
        String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
        // Now, wait until at least one delete happens within AWAIT_TIMEOUT_MS.
        Assert.assertTrue("Some blobs should have been deleted within " + AWAIT_TIMEOUT_MS, deletesDoneLatch.await(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
        // Wait for the rest of the deletes to finish.
        long waitStart = SystemTime.getInstance().milliseconds();
        while (router.getBackgroundOperationsCount() != 0 && SystemTime.getInstance().milliseconds() < waitStart + AWAIT_TIMEOUT_MS) {
            Thread.sleep(1000);
        }
        for (Map.Entry<String, String> blobIdAndServiceId : blobsThatAreDeleted.entrySet()) {
            Assert.assertNotSame("We should not be deleting the valid blob by mistake", blobId, blobIdAndServiceId.getKey());
            Assert.assertEquals("Unexpected service ID for deleted blob", BackgroundDeleteRequest.SERVICE_ID_PREFIX + putBlobProperties.getServiceId(), blobIdAndServiceId.getValue());
        }
    } finally {
        if (router != null) {
            router.close();
            assertClosed();
        }
    }
}
Also used : Account(com.github.ambry.account.Account) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) BlobProperties(com.github.ambry.messageformat.BlobProperties) Properties(java.util.Properties) VerifiableProperties(com.github.ambry.config.VerifiableProperties) Container(com.github.ambry.account.Container) MockTime(com.github.ambry.utils.MockTime) HashSet(java.util.HashSet) VerifiableProperties(com.github.ambry.config.VerifiableProperties) CountDownLatch(java.util.concurrent.CountDownLatch) RouterConfig(com.github.ambry.config.RouterConfig) ServerErrorCode(com.github.ambry.server.ServerErrorCode) LoggingNotificationSystem(com.github.ambry.commons.LoggingNotificationSystem) DataNodeId(com.github.ambry.clustermap.DataNodeId) MockDataNodeId(com.github.ambry.clustermap.MockDataNodeId) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) Test(org.junit.Test)

Example 92 with MockClusterMap

use of com.github.ambry.clustermap.MockClusterMap in project ambry by linkedin.

the class NonBlockingRouterTest method testRequestResponseHandlerThreadExitFlow.

/**
 * Test RequestResponseHandler thread exit flow. If the RequestResponseHandlerThread exits on its own (due to a
 * Throwable), then the router gets closed immediately along with the completion of all the operations.
 */
@Test
public void testRequestResponseHandlerThreadExitFlow() throws Exception {
    nettyByteBufLeakHelper.setDisabled(true);
    Properties props = getNonBlockingRouterProperties("DC1");
    VerifiableProperties verifiableProperties = new VerifiableProperties((props));
    RouterConfig routerConfig = new RouterConfig(verifiableProperties);
    MockClusterMap mockClusterMap = new MockClusterMap();
    MockTime mockTime = new MockTime();
    router = new NonBlockingRouter(routerConfig, new NonBlockingRouterMetrics(mockClusterMap, routerConfig), new MockNetworkClientFactory(verifiableProperties, mockSelectorState, MAX_PORTS_PLAIN_TEXT, MAX_PORTS_SSL, CHECKOUT_TIMEOUT_MS, new MockServerLayout(mockClusterMap), mockTime), new LoggingNotificationSystem(), mockClusterMap, kms, cryptoService, cryptoJobHandler, accountService, mockTime, MockClusterMap.DEFAULT_PARTITION_CLASS);
    assertExpectedThreadCounts(2, 1);
    setOperationParams();
    mockSelectorState.set(MockSelectorState.ThrowExceptionOnAllPoll);
    Future future = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build());
    try {
        while (!future.isDone()) {
            mockTime.sleep(1000);
            Thread.yield();
        }
        future.get();
        Assert.fail("The operation should have failed");
    } catch (ExecutionException e) {
        Assert.assertEquals(RouterErrorCode.OperationTimedOut, ((RouterException) e.getCause()).getErrorCode());
    }
    setOperationParams();
    mockSelectorState.set(MockSelectorState.ThrowThrowableOnSend);
    future = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build());
    Thread requestResponseHandlerThreadRegular = TestUtils.getThreadByThisName("RequestResponseHandlerThread-0");
    Thread requestResponseHandlerThreadBackground = TestUtils.getThreadByThisName("RequestResponseHandlerThread-backgroundDeleter");
    if (requestResponseHandlerThreadRegular != null) {
        requestResponseHandlerThreadRegular.join(NonBlockingRouter.SHUTDOWN_WAIT_MS);
    }
    if (requestResponseHandlerThreadBackground != null) {
        requestResponseHandlerThreadBackground.join(NonBlockingRouter.SHUTDOWN_WAIT_MS);
    }
    try {
        future.get();
        Assert.fail("The operation should have failed");
    } catch (ExecutionException e) {
        Assert.assertEquals(RouterErrorCode.RouterClosed, ((RouterException) e.getCause()).getErrorCode());
    }
    assertClosed();
    // Ensure that both operations failed and with the right exceptions.
    Assert.assertEquals("No ChunkFiller Thread should be running after the router is closed", 0, TestUtils.numThreadsByThisName("ChunkFillerThread"));
    Assert.assertEquals("No RequestResponseHandler should be running after the router is closed", 0, TestUtils.numThreadsByThisName("RequestResponseHandlerThread"));
    Assert.assertEquals("All operations should have completed", 0, router.getOperationsCount());
}
Also used : VerifiableProperties(com.github.ambry.config.VerifiableProperties) BlobProperties(com.github.ambry.messageformat.BlobProperties) Properties(java.util.Properties) VerifiableProperties(com.github.ambry.config.VerifiableProperties) RouterConfig(com.github.ambry.config.RouterConfig) LoggingNotificationSystem(com.github.ambry.commons.LoggingNotificationSystem) Future(java.util.concurrent.Future) ExecutionException(java.util.concurrent.ExecutionException) MockTime(com.github.ambry.utils.MockTime) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) Test(org.junit.Test)

Example 93 with MockClusterMap

use of com.github.ambry.clustermap.MockClusterMap in project ambry by linkedin.

the class OperationTrackerTest method useReplicaNotSucceededSendTest.

/**
 * crossColoEnabled = true, successTarget = 1, parallelism = 2.
 * Only 4 local replicas
 *
 * 1. Get 1st local replica to send request (and sent);
 * 2. Get 2nd local replica to send request (and failed to send);
 * 3. Get 3rd local replica to send request (and sent);
 * 4. Receive 2 failed responses from the 1st and 3rd replicas;
 * 5. Get again 2nd local replica to send request (and sent);
 * 6. Get 4th local replica to send request (and failed to send);
 * 7. Receive 1 failed responses from the 2nd replicas;
 * 8. Get again 4th local replica to send request (and sent);
 * 9. Receive 1 successful response from the 4th replica;
 * 10. Operation succeeds.
 */
@Test
public void useReplicaNotSucceededSendTest() {
    int replicaCount = 4;
    List<Port> portList = Collections.singletonList(new Port(PORT, PortType.PLAINTEXT));
    List<String> mountPaths = Collections.singletonList("mockMountPath");
    datanodes = Collections.singletonList(new MockDataNodeId(portList, mountPaths, "dc-0"));
    mockPartition = new MockPartitionId();
    populateReplicaList(replicaCount, ReplicaState.STANDBY);
    localDcName = datanodes.get(0).getDatacenterName();
    mockClusterMap = new MockClusterMap(false, datanodes, 1, Collections.singletonList(mockPartition), localDcName);
    OperationTracker ot = getOperationTracker(true, 1, 2, RouterOperation.GetBlobOperation, true);
    sendRequests(ot, 2, true);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.FAILURE);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.FAILURE);
    assertFalse("Operation should not be done", ot.isDone());
    sendRequests(ot, 1, true);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.FAILURE);
    assertFalse("Operation should not be done", ot.isDone());
    sendRequests(ot, 1, false);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.SUCCESS);
    assertTrue("Operation should have succeeded", ot.hasSucceeded());
    assertTrue("Operation should be done", ot.isDone());
}
Also used : MockPartitionId(com.github.ambry.clustermap.MockPartitionId) Port(com.github.ambry.network.Port) MockDataNodeId(com.github.ambry.clustermap.MockDataNodeId) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) Test(org.junit.Test)

Example 94 with MockClusterMap

use of com.github.ambry.clustermap.MockClusterMap in project ambry by linkedin.

the class OperationTrackerTest method getOperationWithReplicaStateTest.

/**
 * Test GET operation is able to try on OFFLINE replicas if routerOperationTrackerIncludeDownReplicas is true.
 */
@Test
public void getOperationWithReplicaStateTest() {
    assumeTrue(replicasStateEnabled);
    List<Port> portList = Collections.singletonList(new Port(PORT, PortType.PLAINTEXT));
    List<String> mountPaths = Collections.singletonList("mockMountPath");
    datanodes = new ArrayList<>(Arrays.asList(new MockDataNodeId(portList, mountPaths, "dc-0"), new MockDataNodeId(portList, mountPaths, "dc-1")));
    mockPartition = new MockPartitionId();
    for (ReplicaState state : EnumSet.of(ReplicaState.BOOTSTRAP, ReplicaState.STANDBY, ReplicaState.LEADER, ReplicaState.INACTIVE, ReplicaState.OFFLINE)) {
        populateReplicaList(1, state);
    }
    localDcName = datanodes.get(0).getDatacenterName();
    mockClusterMap = new MockClusterMap(false, datanodes, 1, Collections.singletonList(mockPartition), localDcName);
    // 1. include down replicas (OFFLINE replicas are eligible for GET)
    OperationTracker ot = getOperationTracker(true, 1, 1, RouterOperation.GetBlobOperation, true);
    // make sure 4 requests fails and last one succeeds. (This is to verify operation tracker adds offline replica into replica pool as well)
    ReplicaId inflightReplica;
    for (int i = 0; i < 4; ++i) {
        sendRequests(ot, 1, false);
        inflightReplica = inflightReplicas.poll();
        // verify that the first 4 replicas are not OFFLINE replica. (OFFLINE replica should be added to the end of queue)
        assertNotSame("Replica state should not be OFFLINE ", mockPartition.replicaAndState.get(inflightReplica), ReplicaState.OFFLINE);
        ot.onResponse(inflightReplica, TrackedRequestFinalState.FAILURE);
        assertFalse("Operation should not complete", ot.isDone());
    }
    sendRequests(ot, 1, false);
    inflightReplica = inflightReplicas.poll();
    assertEquals("The last replica should be OFFLINE", ReplicaState.OFFLINE, mockPartition.replicaAndState.get(inflightReplica));
    ot.onResponse(inflightReplica, TrackedRequestFinalState.SUCCESS);
    assertTrue("Operation should be done", ot.isDone());
    // 2. exclude down replicas
    repetitionTracker.clear();
    ot = getOperationTracker(true, 1, 1, RouterOperation.GetBlobOperation, false);
    for (int i = 0; i < 4; ++i) {
        sendRequests(ot, 1, false);
        inflightReplica = inflightReplicas.poll();
        // verify that none of these replicas is OFFLINE replica.
        assertNotSame("Replica state should not be OFFLINE ", mockPartition.replicaAndState.get(inflightReplica), ReplicaState.OFFLINE);
        ot.onResponse(inflightReplica, TrackedRequestFinalState.FAILURE);
        if (i < 3) {
            assertFalse("Operation should not complete", ot.isDone());
        } else {
            assertTrue("Operation should complete", ot.isDone());
        }
    }
}
Also used : MockPartitionId(com.github.ambry.clustermap.MockPartitionId) Port(com.github.ambry.network.Port) MockDataNodeId(com.github.ambry.clustermap.MockDataNodeId) ReplicaState(com.github.ambry.clustermap.ReplicaState) MockReplicaId(com.github.ambry.clustermap.MockReplicaId) ReplicaId(com.github.ambry.clustermap.ReplicaId) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) Test(org.junit.Test)

Example 95 with MockClusterMap

use of com.github.ambry.clustermap.MockClusterMap in project ambry by linkedin.

the class OperationTrackerTest method sendCrossColoRequestToDcWithMostReplicasTest.

/**
 * Test the case where originating dc name is null and operation tracker will choose dc with most replicas to send
 * cross-colo request.
 * local dc: one replica;
 * remote dc1: three replicas;
 * remote dc2: one replica;
 */
@Test
public void sendCrossColoRequestToDcWithMostReplicasTest() {
    List<Port> portList = Collections.singletonList(new Port(PORT, PortType.PLAINTEXT));
    List<String> mountPaths = Collections.singletonList("mockMountPath");
    // set up one node per data center for testing
    MockDataNodeId localDcNode = new MockDataNodeId(portList, mountPaths, "dc-0");
    MockDataNodeId remoteDc1Node = new MockDataNodeId(portList, mountPaths, "dc-1");
    MockDataNodeId remoteDc2Node = new MockDataNodeId(portList, mountPaths, "dc-2");
    mockPartition = new MockPartitionId();
    localDcName = localDcNode.getDatacenterName();
    originatingDcName = null;
    chooseDcWithMostReplicas = true;
    mockClusterMap = new MockClusterMap(false, Arrays.asList(localDcNode, remoteDc1Node, remoteDc2Node), 1, Collections.singletonList(mockPartition), localDcName);
    populateReplicaList(1, ReplicaState.STANDBY, Collections.singletonList(localDcNode));
    populateReplicaList(3, ReplicaState.STANDBY, Collections.singletonList(remoteDc1Node));
    populateReplicaList(1, ReplicaState.STANDBY, Collections.singletonList(remoteDc2Node));
    OperationTracker ot = getOperationTracker(true, 1, 1, RouterOperation.GetBlobOperation, true);
    // make local replica return Not_Found
    sendRequests(ot, 1, false);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.NOT_FOUND);
    ReplicaId inflightReplica;
    // next, operation tracker should send request to dc-1 as it has most replicas
    for (int i = 0; i < 3; ++i) {
        sendRequests(ot, 1, false);
        inflightReplica = inflightReplicas.poll();
        assertEquals("The request should be sent to dc-1 with most replicas", "dc-1", inflightReplica.getDataNodeId().getDatacenterName());
        // we deliberately make all replicas in dc-1 return Not_Found to verify that operation won't terminate on not found
        ot.onResponse(inflightReplica, TrackedRequestFinalState.NOT_FOUND);
        assertFalse("Operation should not be done yet", ot.isDone());
    }
    // the last request should go to dc-2 and this time we make it succeed
    sendRequests(ot, 1, false);
    inflightReplica = inflightReplicas.poll();
    assertEquals("The request should be sent to dc-2", "dc-2", inflightReplica.getDataNodeId().getDatacenterName());
    ot.onResponse(inflightReplica, TrackedRequestFinalState.SUCCESS);
    assertTrue("Operation should succeed", ot.hasSucceeded());
    assertTrue("Operation should be done", ot.isDone());
}
Also used : MockPartitionId(com.github.ambry.clustermap.MockPartitionId) Port(com.github.ambry.network.Port) MockDataNodeId(com.github.ambry.clustermap.MockDataNodeId) MockReplicaId(com.github.ambry.clustermap.MockReplicaId) ReplicaId(com.github.ambry.clustermap.ReplicaId) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) Test(org.junit.Test)

Aggregations

MockClusterMap (com.github.ambry.clustermap.MockClusterMap)109 Test (org.junit.Test)78 MockPartitionId (com.github.ambry.clustermap.MockPartitionId)57 VerifiableProperties (com.github.ambry.config.VerifiableProperties)55 Properties (java.util.Properties)50 ArrayList (java.util.ArrayList)44 PartitionId (com.github.ambry.clustermap.PartitionId)42 MockDataNodeId (com.github.ambry.clustermap.MockDataNodeId)40 HashMap (java.util.HashMap)36 Map (java.util.Map)33 BlobId (com.github.ambry.commons.BlobId)32 ClusterMap (com.github.ambry.clustermap.ClusterMap)31 MetricRegistry (com.codahale.metrics.MetricRegistry)30 Port (com.github.ambry.network.Port)29 List (java.util.List)28 DataNodeId (com.github.ambry.clustermap.DataNodeId)26 ReplicaId (com.github.ambry.clustermap.ReplicaId)26 BlobIdFactory (com.github.ambry.commons.BlobIdFactory)26 BlobProperties (com.github.ambry.messageformat.BlobProperties)23 DataInputStream (java.io.DataInputStream)23