Search in sources :

Example 1 with Callback

use of com.github.ambry.commons.Callback in project ambry by linkedin.

the class GetBlobOperationTest method testEarlyReadableStreamChannelClose.

/**
 * Test that the operation is completed and an exception with the error code {@link RouterErrorCode#ChannelClosed} is
 * set when the {@link ReadableStreamChannel} is closed before all chunks are read for a specific blob size and
 * number of chunks to read.
 * @param numChunksInBlob the number of chunks in the blob to put/get.
 * @param numChunksToRead the number of chunks to read from the {@link AsyncWritableChannel} before closing the
 *                        {@link ReadableStreamChannel}.
 * @throws Exception
 */
private void testEarlyReadableStreamChannelClose(int numChunksInBlob, final int numChunksToRead) throws Exception {
    final AtomicReference<Exception> callbackException = new AtomicReference<>();
    final AtomicReference<Future<Long>> readIntoFuture = new AtomicReference<>();
    final CountDownLatch readCompleteLatch = new CountDownLatch(1);
    Callback<GetBlobResultInternal> callback = new Callback<GetBlobResultInternal>() {

        @Override
        public void onCompletion(final GetBlobResultInternal result, Exception exception) {
            if (exception != null) {
                callbackException.set(exception);
                readCompleteLatch.countDown();
            } else {
                final ByteBufferAsyncWritableChannel writableChannel = new ByteBufferAsyncWritableChannel();
                readIntoFuture.set(result.getBlobResult.getBlobDataChannel().readInto(writableChannel, null));
                Utils.newThread(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            int chunksLeftToRead = numChunksToRead;
                            while (chunksLeftToRead > 0) {
                                writableChannel.getNextChunk();
                                writableChannel.resolveOldestChunk(null);
                                chunksLeftToRead--;
                            }
                            result.getBlobResult.getBlobDataChannel().close();
                            while (writableChannel.getNextChunk(100) != null) {
                                writableChannel.resolveOldestChunk(null);
                            }
                        } catch (Exception e) {
                            callbackException.set(e);
                        } finally {
                            readCompleteLatch.countDown();
                        }
                    }
                }, false).start();
            }
        }
    };
    blobSize = numChunksInBlob * maxChunkSize;
    doPut();
    GetBlobOperation op = createOperationAndComplete(callback);
    Assert.assertTrue("Timeout waiting for read to complete", readCompleteLatch.await(2, TimeUnit.SECONDS));
    if (callbackException.get() != null) {
        throw callbackException.get();
    }
    try {
        readIntoFuture.get().get();
        Assert.fail("Expected ExecutionException");
    } catch (ExecutionException e) {
        Assert.assertTrue("Unexpected type for exception: " + e.getCause(), e.getCause() instanceof RouterException);
        Assert.assertEquals("Unexpected RouterErrorCode", RouterErrorCode.ChannelClosed, ((RouterException) e.getCause()).getErrorCode());
    }
    Exception operationException = op.getOperationException();
    Assert.assertTrue("Unexpected type for exception: " + operationException, operationException instanceof RouterException);
    Assert.assertEquals("Unexpected RouterErrorCode", RouterErrorCode.ChannelClosed, ((RouterException) operationException).getErrorCode());
}
Also used : AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBufferAsyncWritableChannel(com.github.ambry.commons.ByteBufferAsyncWritableChannel) RestServiceException(com.github.ambry.rest.RestServiceException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) Callback(com.github.ambry.commons.Callback) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) Future(java.util.concurrent.Future) ExecutionException(java.util.concurrent.ExecutionException)

Example 2 with Callback

use of com.github.ambry.commons.Callback in project ambry by linkedin.

the class GetBlobOperationTest method testDataChunkError.

/**
 * Test that an operation is completed with a specified {@link RouterErrorCode} when all gets on data chunks
 * in a multi-part blob return a specified {@link ServerErrorCode}
 * @param serverErrorCode The error code to be returned when fetching data chunks.
 * @param expectedErrorCode The operation's expected error code.
 * @throws Exception
 */
private void testDataChunkError(ServerErrorCode serverErrorCode, final RouterErrorCode expectedErrorCode) throws Exception {
    blobSize = maxChunkSize * 2 + 1;
    doPut();
    final CountDownLatch readCompleteLatch = new CountDownLatch(1);
    final AtomicReference<Exception> readCompleteException = new AtomicReference<>(null);
    final ByteBufferAsyncWritableChannel asyncWritableChannel = new ByteBufferAsyncWritableChannel();
    mockServerLayout.getMockServers().forEach(mockServer -> mockServer.setGetErrorOnDataBlobOnly(true));
    RouterTestHelpers.testWithErrorCodes(Collections.singletonMap(serverErrorCode, 9), mockServerLayout, expectedErrorCode, new ErrorCodeChecker() {

        @Override
        public void testAndAssert(RouterErrorCode expectedError) throws Exception {
            Callback<GetBlobResultInternal> callback = new Callback<GetBlobResultInternal>() {

                @Override
                public void onCompletion(final GetBlobResultInternal result, final Exception exception) {
                    if (exception != null) {
                        asyncWritableChannel.close();
                        readCompleteLatch.countDown();
                    } else {
                        Utils.newThread(new Runnable() {

                            @Override
                            public void run() {
                                try {
                                    result.getBlobResult.getBlobDataChannel().readInto(asyncWritableChannel, new Callback<Long>() {

                                        @Override
                                        public void onCompletion(Long result, Exception exception) {
                                            asyncWritableChannel.close();
                                        }
                                    });
                                    asyncWritableChannel.getNextChunk();
                                } catch (Exception e) {
                                    readCompleteException.set(e);
                                } finally {
                                    readCompleteLatch.countDown();
                                }
                            }
                        }, false).start();
                    }
                }
            };
            GetBlobOperation op = createOperationAndComplete(callback);
            Assert.assertTrue(readCompleteLatch.await(2, TimeUnit.SECONDS));
            Assert.assertTrue("Operation should be complete at this time", op.isOperationComplete());
            if (readCompleteException.get() != null) {
                throw readCompleteException.get();
            }
            Assert.assertFalse("AsyncWriteableChannel should have been closed.", asyncWritableChannel.isOpen());
            assertFailureAndCheckErrorCode(op, expectedError);
        }
    });
}
Also used : AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBufferAsyncWritableChannel(com.github.ambry.commons.ByteBufferAsyncWritableChannel) RestServiceException(com.github.ambry.rest.RestServiceException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) Callback(com.github.ambry.commons.Callback) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) AtomicLong(java.util.concurrent.atomic.AtomicLong)

Example 3 with Callback

use of com.github.ambry.commons.Callback in project ambry by linkedin.

the class MockRouterCallback method testInstantiation.

/**
 * Test {@link GetBlobInfoOperation} instantiation and validate the get methods.
 */
@Test
public void testInstantiation() {
    BlobId blobId = new BlobId(routerConfig.routerBlobidCurrentVersion, BlobId.BlobIdType.NATIVE, ClusterMap.UNKNOWN_DATACENTER_ID, Utils.getRandomShort(random), Utils.getRandomShort(random), mockClusterMap.getWritablePartitionIds(MockClusterMap.DEFAULT_PARTITION_CLASS).get(0), false, BlobId.BlobDataType.DATACHUNK);
    Callback<GetBlobResultInternal> getOperationCallback = (result, exception) -> {
    // no op.
    };
    // test a good case
    GetBlobInfoOperation op = new GetBlobInfoOperation(routerConfig, routerMetrics, mockClusterMap, responseHandler, blobId, options, getOperationCallback, routerCallback, kms, cryptoService, cryptoJobHandler, time, false, quotaChargeCallback);
    Assert.assertEquals("Callback must match", getOperationCallback, op.getCallback());
    Assert.assertEquals("Blob ids must match", blobId.getID(), op.getBlobIdStr());
    // test the case where the tracker type is bad
    Properties properties = getNonBlockingRouterProperties(true);
    properties.setProperty("router.get.operation.tracker.type", "NonExistentTracker");
    RouterConfig badConfig = new RouterConfig(new VerifiableProperties(properties));
    try {
        new GetBlobInfoOperation(badConfig, routerMetrics, mockClusterMap, responseHandler, blobId, options, getOperationCallback, routerCallback, kms, cryptoService, cryptoJobHandler, time, false, quotaChargeCallback);
        Assert.fail("Instantiation of GetBlobInfoOperation with an invalid tracker type must fail");
    } catch (IllegalArgumentException e) {
    // expected. Nothing to do.
    }
}
Also used : ResponseInfo(com.github.ambry.network.ResponseInfo) Arrays(java.util.Arrays) BlobProperties(com.github.ambry.messageformat.BlobProperties) ByteBufferReadableStreamChannel(com.github.ambry.commons.ByteBufferReadableStreamChannel) Random(java.util.Random) ByteBuffer(java.nio.ByteBuffer) GetResponse(com.github.ambry.protocol.GetResponse) GeneralSecurityException(java.security.GeneralSecurityException) NetworkClientErrorCode(com.github.ambry.network.NetworkClientErrorCode) TestUtils(com.github.ambry.utils.TestUtils) Map(java.util.Map) After(org.junit.After) NettyByteBufLeakHelper(com.github.ambry.utils.NettyByteBufLeakHelper) EnumSet(java.util.EnumSet) Parameterized(org.junit.runners.Parameterized) Utils(com.github.ambry.utils.Utils) CryptoServiceConfig(com.github.ambry.config.CryptoServiceConfig) BlobInfo(com.github.ambry.messageformat.BlobInfo) RouterConfig(com.github.ambry.config.RouterConfig) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) MockTime(com.github.ambry.utils.MockTime) QuotaTestUtils(com.github.ambry.quota.QuotaTestUtils) Callback(com.github.ambry.commons.Callback) LoggingNotificationSystem(com.github.ambry.commons.LoggingNotificationSystem) InMemAccountService(com.github.ambry.account.InMemAccountService) BlobId(com.github.ambry.commons.BlobId) ResponseHandler(com.github.ambry.commons.ResponseHandler) ServerErrorCode(com.github.ambry.server.ServerErrorCode) RunWith(org.junit.runner.RunWith) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayList(java.util.ArrayList) NettyByteBufDataInputStream(com.github.ambry.utils.NettyByteBufDataInputStream) PutManagerTest(com.github.ambry.router.PutManagerTest) SocketNetworkClient(com.github.ambry.network.SocketNetworkClient) Assume(org.junit.Assume) Before(org.junit.Before) Properties(java.util.Properties) VerifiableProperties(com.github.ambry.config.VerifiableProperties) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) ClusterMap(com.github.ambry.clustermap.ClusterMap) IOException(java.io.IOException) Test(org.junit.Test) RequestInfo(com.github.ambry.network.RequestInfo) TimeUnit(java.util.concurrent.TimeUnit) KMSConfig(com.github.ambry.config.KMSConfig) ReplicaId(com.github.ambry.clustermap.ReplicaId) Assert(org.junit.Assert) Collections(java.util.Collections) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) VerifiableProperties(com.github.ambry.config.VerifiableProperties) BlobProperties(com.github.ambry.messageformat.BlobProperties) Properties(java.util.Properties) VerifiableProperties(com.github.ambry.config.VerifiableProperties) BlobId(com.github.ambry.commons.BlobId) RouterConfig(com.github.ambry.config.RouterConfig) PutManagerTest(com.github.ambry.router.PutManagerTest) Test(org.junit.Test)

Example 4 with Callback

use of com.github.ambry.commons.Callback in project ambry by linkedin.

the class AmbryServerSecurityServiceTest method validateConnectionTest.

/**
 * Tests for {@link AmbryServerSecurityService#validateConnection(SSLSession, Callback)}
 * @throws Exception
 */
@Test
public void validateConnectionTest() throws Exception {
    // sslSession is null
    TestUtils.assertException(IllegalArgumentException.class, () -> serverSecurityService.validateConnection(null).get(), null);
    // success case
    SSLSession sslSession = Mockito.mock(SSLSession.class);
    serverSecurityService.validateConnection(sslSession, (r, e) -> {
        Assert.assertNull("result not null", r);
        Assert.assertNull("exception not null", e);
    });
    // service is closed
    serverSecurityService.close();
    ThrowingConsumer<ExecutionException> errorAction = e -> {
        Assert.assertTrue("Exception should have been an instance of RestServiceException", e.getCause() instanceof RestServiceException);
        RestServiceException re = (RestServiceException) e.getCause();
        Assert.assertEquals("Unexpected RestServerErrorCode (Future)", RestServiceErrorCode.ServiceUnavailable, re.getErrorCode());
    };
    TestUtils.assertException(ExecutionException.class, () -> serverSecurityService.validateConnection(sslSession).get(), errorAction);
}
Also used : MockRestRequest(com.github.ambry.rest.MockRestRequest) ServerSecurityService(com.github.ambry.rest.ServerSecurityService) MetricRegistry(com.codahale.metrics.MetricRegistry) Properties(java.util.Properties) VerifiableProperties(com.github.ambry.config.VerifiableProperties) RestServiceErrorCode(com.github.ambry.rest.RestServiceErrorCode) ServerConfig(com.github.ambry.config.ServerConfig) Test(org.junit.Test) ThrowingConsumer(com.github.ambry.utils.ThrowingConsumer) ExecutionException(java.util.concurrent.ExecutionException) AmbryRequests(com.github.ambry.protocol.AmbryRequests) Mockito(org.mockito.Mockito) RestServiceException(com.github.ambry.rest.RestServiceException) SSLSession(javax.net.ssl.SSLSession) TestUtils(com.github.ambry.utils.TestUtils) ServerMetrics(com.github.ambry.commons.ServerMetrics) Callback(com.github.ambry.commons.Callback) Assert(org.junit.Assert) RestRequest(com.github.ambry.rest.RestRequest) RestServiceException(com.github.ambry.rest.RestServiceException) SSLSession(javax.net.ssl.SSLSession) ExecutionException(java.util.concurrent.ExecutionException) Test(org.junit.Test)

Example 5 with Callback

use of com.github.ambry.commons.Callback in project ambry by linkedin.

the class AsyncWritableChannel method write.

/**
 * Write data in {@code src} to the channel and the {@code callback} will be invoked once the write succeeds or fails.
 * This method is the counterpart for {@link ByteBuf}. It shares the same guarantee as the {@link #write(ByteBuffer, Callback)}.
 * Whoever implements this interface, shouldn't release the {@code src}. If releasing is expected after finishing writing
 * to channel, please release this {@link ByteBuf} in the callback method.
 * @param src The data taht needs to be written to the channel.
 * @param callback The {@link Callback} that will be invoked once the write succeeds/fails. This can be null.
 * @return a {@link Future} that will eventually contain the result of the write operation (the number of bytes
 *         written).
 */
default Future<Long> write(ByteBuf src, Callback<Long> callback) {
    if (src == null) {
        throw new IllegalArgumentException("Source ByteBuf cannot be null");
    }
    int numBuffers = src.nioBufferCount();
    FutureResult<Long> futureResult = new FutureResult<>();
    Callback<Long> singleBufferCallback = (result, exception) -> {
        if (result != 0) {
            src.readerIndex(src.readerIndex() + (int) result.longValue());
        }
        futureResult.done(result, exception);
        if (callback != null) {
            callback.onCompletion(result, exception);
        }
    };
    if (numBuffers < 1) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(src.readableBytes());
        src.getBytes(src.readerIndex(), byteBuffer);
        write(byteBuffer, singleBufferCallback);
    } else if (numBuffers == 1) {
        write(src.nioBuffer(), singleBufferCallback);
    } else {
        ByteBuffer[] buffers = src.nioBuffers();
        AtomicLong size = new AtomicLong(0);
        AtomicInteger index = new AtomicInteger(0);
        AtomicBoolean callbackInvoked = new AtomicBoolean(false);
        Callback<Long> cb = (result, exception) -> {
            index.addAndGet(1);
            size.addAndGet(result);
            if (result != 0) {
                src.readerIndex(src.readerIndex() + (int) result.longValue());
            }
            if ((exception != null || index.get() == buffers.length) && callbackInvoked.compareAndSet(false, true)) {
                futureResult.done(size.get(), exception);
                if (callback != null) {
                    callback.onCompletion(size.get(), exception);
                }
            }
        };
        for (int i = 0; i < buffers.length; i++) {
            write(buffers[i], cb);
        }
    }
    return futureResult;
}
Also used : AtomicLong(java.util.concurrent.atomic.AtomicLong) Future(java.util.concurrent.Future) ByteBuf(io.netty.buffer.ByteBuf) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Callback(com.github.ambry.commons.Callback) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ByteBuffer(java.nio.ByteBuffer) Channel(java.nio.channels.Channel) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicLong(java.util.concurrent.atomic.AtomicLong) Callback(com.github.ambry.commons.Callback) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicLong(java.util.concurrent.atomic.AtomicLong) ByteBuffer(java.nio.ByteBuffer)

Aggregations

Callback (com.github.ambry.commons.Callback)13 RestServiceException (com.github.ambry.rest.RestServiceException)9 ExecutionException (java.util.concurrent.ExecutionException)9 IOException (java.io.IOException)8 VerifiableProperties (com.github.ambry.config.VerifiableProperties)7 Properties (java.util.Properties)7 Test (org.junit.Test)7 QuotaChargeCallback (com.github.ambry.quota.QuotaChargeCallback)6 RestServiceErrorCode (com.github.ambry.rest.RestServiceErrorCode)6 CountDownLatch (java.util.concurrent.CountDownLatch)6 Assert (org.junit.Assert)6 BlobId (com.github.ambry.commons.BlobId)5 BlobInfo (com.github.ambry.messageformat.BlobInfo)5 BlobProperties (com.github.ambry.messageformat.BlobProperties)5 TestUtils (com.github.ambry.utils.TestUtils)5 Utils (com.github.ambry.utils.Utils)5 ByteBuffer (java.nio.ByteBuffer)5 Future (java.util.concurrent.Future)5 AccountService (com.github.ambry.account.AccountService)4 InMemAccountService (com.github.ambry.account.InMemAccountService)4