Search in sources :

Example 6 with ByteBufferAsyncWritableChannel

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

the class GetBlobOperationTest method testMissingDataChunkException.

/**
 * Test when data chunks are missing, the getBlob should return RestServiceException.
 * @throws Exception
 */
@Test
public void testMissingDataChunkException() throws Exception {
    // Make sure we have two data chunks
    blobSize = maxChunkSize + maxChunkSize / 2;
    doPut();
    // Now remove the all the data chunks, first collect data chunk ids and remove blob id
    Set<String> dataChunkIds = new HashSet<>();
    mockServerLayout.getMockServers().forEach(server -> dataChunkIds.addAll(server.getBlobs().keySet()));
    dataChunkIds.remove(blobIdStr);
    Assert.assertEquals(2, dataChunkIds.size());
    // We can't just delete the data chunks by calling router.deleteBlob, we have to remove them from the mock servers.
    mockServerLayout.getMockServers().forEach(server -> dataChunkIds.forEach(chunkId -> server.getBlobs().remove(chunkId)));
    GetBlobResult result = router.getBlob(blobIdStr, new GetBlobOptionsBuilder().build()).get();
    Future<Long> future = result.getBlobDataChannel().readInto(new ByteBufferAsyncWritableChannel(), null);
    try {
        future.get();
        Assert.fail("Should fail with exception");
    } catch (Exception e) {
        Throwable cause = e.getCause();
        Assert.assertTrue(cause instanceof RestServiceException);
        Assert.assertEquals(RestServiceErrorCode.InternalServerError, ((RestServiceException) cause).getErrorCode());
        Assert.assertTrue(((RestServiceException) cause).shouldIncludeExceptionMessageInResponse());
    }
}
Also used : ResponseInfo(com.github.ambry.network.ResponseInfo) GetOption(com.github.ambry.protocol.GetOption) Arrays(java.util.Arrays) BlobProperties(com.github.ambry.messageformat.BlobProperties) ByteBufferReadableStreamChannel(com.github.ambry.commons.ByteBufferReadableStreamChannel) BlobAll(com.github.ambry.messageformat.BlobAll) Random(java.util.Random) ByteBuffer(java.nio.ByteBuffer) GetResponse(com.github.ambry.protocol.GetResponse) Future(java.util.concurrent.Future) ByteArrayInputStream(java.io.ByteArrayInputStream) NetworkClientErrorCode(com.github.ambry.network.NetworkClientErrorCode) TestUtils(com.github.ambry.utils.TestUtils) Map(java.util.Map) After(org.junit.After) Counter(com.codahale.metrics.Counter) NettyByteBufLeakHelper(com.github.ambry.utils.NettyByteBufLeakHelper) GetRequest(com.github.ambry.protocol.GetRequest) EnumSet(java.util.EnumSet) Parameterized(org.junit.runners.Parameterized) PartitionState(com.github.ambry.clustermap.PartitionState) RestServiceErrorCode(com.github.ambry.rest.RestServiceErrorCode) Set(java.util.Set) Utils(com.github.ambry.utils.Utils) MockPartitionId(com.github.ambry.clustermap.MockPartitionId) PooledByteBufAllocator(io.netty.buffer.PooledByteBufAllocator) Collectors(java.util.stream.Collectors) CryptoServiceConfig(com.github.ambry.config.CryptoServiceConfig) BlobInfo(com.github.ambry.messageformat.BlobInfo) RouterConfig(com.github.ambry.config.RouterConfig) CountDownLatch(java.util.concurrent.CountDownLatch) StoreKey(com.github.ambry.store.StoreKey) List(java.util.List) RestServiceException(com.github.ambry.rest.RestServiceException) MockTime(com.github.ambry.utils.MockTime) MessageFormatFlags(com.github.ambry.messageformat.MessageFormatFlags) QuotaTestUtils(com.github.ambry.quota.QuotaTestUtils) Callback(com.github.ambry.commons.Callback) LoggingNotificationSystem(com.github.ambry.commons.LoggingNotificationSystem) BlobType(com.github.ambry.messageformat.BlobType) InMemAccountService(com.github.ambry.account.InMemAccountService) PartitionId(com.github.ambry.clustermap.PartitionId) BlobId(com.github.ambry.commons.BlobId) ResponseHandler(com.github.ambry.commons.ResponseHandler) CompositeBlobInfo(com.github.ambry.messageformat.CompositeBlobInfo) PartitionRequestInfo(com.github.ambry.protocol.PartitionRequestInfo) Histogram(com.codahale.metrics.Histogram) DataInputStream(java.io.DataInputStream) ByteBufferChannel(com.github.ambry.utils.ByteBufferChannel) 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) HashSet(java.util.HashSet) PutManagerTest(com.github.ambry.router.PutManagerTest) ByteBuf(io.netty.buffer.ByteBuf) SocketNetworkClient(com.github.ambry.network.SocketNetworkClient) Assume(org.junit.Assume) PutRequest(com.github.ambry.protocol.PutRequest) Before(org.junit.Before) MockDataNodeId(com.github.ambry.clustermap.MockDataNodeId) Properties(java.util.Properties) Iterator(java.util.Iterator) ByteBufferAsyncWritableChannel(com.github.ambry.commons.ByteBufferAsyncWritableChannel) VerifiableProperties(com.github.ambry.config.VerifiableProperties) RouterTestHelpers(com.github.ambry.router.RouterTestHelpers) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) MetadataContentSerDe(com.github.ambry.messageformat.MetadataContentSerDe) IOException(java.io.IOException) Test(org.junit.Test) BlobIdFactory(com.github.ambry.commons.BlobIdFactory) RequestInfo(com.github.ambry.network.RequestInfo) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) KMSConfig(com.github.ambry.config.KMSConfig) ReplicaId(com.github.ambry.clustermap.ReplicaId) ByteBufferInputStream(com.github.ambry.utils.ByteBufferInputStream) MessageFormatRecord(com.github.ambry.messageformat.MessageFormatRecord) Assert(org.junit.Assert) Collections(java.util.Collections) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) RestServiceException(com.github.ambry.rest.RestServiceException) AtomicLong(java.util.concurrent.atomic.AtomicLong) ByteBufferAsyncWritableChannel(com.github.ambry.commons.ByteBufferAsyncWritableChannel) RestServiceException(com.github.ambry.rest.RestServiceException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) HashSet(java.util.HashSet) PutManagerTest(com.github.ambry.router.PutManagerTest) Test(org.junit.Test)

Example 7 with ByteBufferAsyncWritableChannel

use of com.github.ambry.commons.ByteBufferAsyncWritableChannel 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 8 with ByteBufferAsyncWritableChannel

use of com.github.ambry.commons.ByteBufferAsyncWritableChannel 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 9 with ByteBufferAsyncWritableChannel

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

the class RouterTestHelpers method compareContent.

/**
 * Compare and assert that the content in the given {@link ReadableStreamChannel} is exactly the same as
 * the original content argument.
 * @param originalContent the content array to check against.
 * @param range if non-null, apply this range to {@code originalContent} before comparison.
 * @param readableStreamChannel the {@link ReadableStreamChannel} that is the candidate for comparison.
 */
static void compareContent(byte[] originalContent, ByteRange range, ReadableStreamChannel readableStreamChannel) throws ExecutionException, InterruptedException {
    ByteBuffer putContentBuf = ByteBuffer.wrap(originalContent);
    // If a range is set, compare the result against the specified byte range.
    if (range != null) {
        ByteRange resolvedRange = range.toResolvedByteRange(originalContent.length);
        putContentBuf = ByteBuffer.wrap(originalContent, (int) resolvedRange.getStartOffset(), (int) resolvedRange.getRangeSize());
    }
    ByteBufferAsyncWritableChannel getChannel = new ByteBufferAsyncWritableChannel();
    Future<Long> readIntoFuture = readableStreamChannel.readInto(getChannel, null);
    final int bytesToRead = putContentBuf.remaining();
    int readBytes = 0;
    do {
        ByteBuffer buf = getChannel.getNextChunk();
        int bufLength = buf.remaining();
        assertTrue("total content read should not be greater than length of put content", readBytes + bufLength <= bytesToRead);
        while (buf.hasRemaining()) {
            assertEquals("Get and Put blob content should match", putContentBuf.get(), buf.get());
            readBytes++;
        }
        getChannel.resolveOldestChunk(null);
    } while (readBytes < bytesToRead);
    assertEquals("the returned length in the future should be the length of data written", (long) readBytes, (long) readIntoFuture.get());
    assertNull("There should be no more data in the channel", getChannel.getNextChunk(0));
}
Also used : ByteBuffer(java.nio.ByteBuffer) ByteBufferAsyncWritableChannel(com.github.ambry.commons.ByteBufferAsyncWritableChannel)

Example 10 with ByteBufferAsyncWritableChannel

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

the class RouterServerTestFramework method checkBlob.

/**
 * Check that the blob read from {@code channel} matches {@code opChain.data}.
 * @param channel the {@link ReadableStreamChannel} to check
 * @param opChain the {@link OperationChain} structure to compare against
 * @param operationName a name for the operation being checked
 */
private static void checkBlob(ReadableStreamChannel channel, OperationChain opChain, String operationName) {
    Assert.assertNotNull("Null channel for operation: " + operationName, channel);
    try {
        ByteBufferAsyncWritableChannel getChannel = new ByteBufferAsyncWritableChannel();
        Future<Long> readIntoFuture = channel.readInto(getChannel, null);
        int readBytes = 0;
        do {
            ByteBuffer buf = getChannel.getNextChunk();
            int bufLength = buf.remaining();
            Assert.assertTrue("total content read should not be greater than length of put content, operation: " + operationName, readBytes + bufLength <= opChain.data.length);
            while (buf.hasRemaining()) {
                Assert.assertEquals("Get and Put blob content should match, operation: " + operationName, opChain.data[readBytes++], buf.get());
            }
            getChannel.resolveOldestChunk(null);
        } while (readBytes < opChain.data.length);
        Assert.assertEquals("the returned length in the future should be the length of data written, operation: " + operationName, (long) readBytes, (long) readIntoFuture.get(AWAIT_TIMEOUT, TimeUnit.SECONDS));
        Assert.assertNull("There should be no more data in the channel, operation: " + operationName, getChannel.getNextChunk(0));
    } catch (Exception e) {
        Assert.fail("Exception while reading from getChannel from operation: " + operationName);
    }
}
Also used : ByteBufferAsyncWritableChannel(com.github.ambry.commons.ByteBufferAsyncWritableChannel) ByteBuffer(java.nio.ByteBuffer) IOException(java.io.IOException) RouterException(com.github.ambry.router.RouterException) ExecutionException(java.util.concurrent.ExecutionException)

Aggregations

ByteBufferAsyncWritableChannel (com.github.ambry.commons.ByteBufferAsyncWritableChannel)20 ExecutionException (java.util.concurrent.ExecutionException)11 AsyncWritableChannel (com.github.ambry.router.AsyncWritableChannel)9 DefaultHttpContent (io.netty.handler.codec.http.DefaultHttpContent)9 DefaultLastHttpContent (io.netty.handler.codec.http.DefaultLastHttpContent)9 Channel (io.netty.channel.Channel)8 EmbeddedChannel (io.netty.channel.embedded.EmbeddedChannel)8 HttpContent (io.netty.handler.codec.http.HttpContent)8 LastHttpContent (io.netty.handler.codec.http.LastHttpContent)8 IOException (java.io.IOException)8 Test (org.junit.Test)8 ArrayList (java.util.ArrayList)7 ByteBuffer (java.nio.ByteBuffer)6 CountDownLatch (java.util.concurrent.CountDownLatch)6 AtomicReference (java.util.concurrent.atomic.AtomicReference)6 Callback (com.github.ambry.commons.Callback)5 AtomicLong (java.util.concurrent.atomic.AtomicLong)5 InMemAccountService (com.github.ambry.account.InMemAccountService)3 MockClusterMap (com.github.ambry.clustermap.MockClusterMap)3 PartitionId (com.github.ambry.clustermap.PartitionId)3