Search in sources :

Example 1 with QuotaChargeCallback

use of com.github.ambry.quota.QuotaChargeCallback 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 2 with QuotaChargeCallback

use of com.github.ambry.quota.QuotaChargeCallback in project ambry by linkedin.

the class MockReadableStreamChannel method testBadCallback.

/**
 * Test that a bad user defined callback will not crash the router.
 * @throws Exception
 */
@Test
public void testBadCallback() throws Exception {
    RequestAndResult req = new RequestAndResult(chunkSize * 5 + random.nextInt(chunkSize - 1) + 1);
    router = getNonBlockingRouter();
    final CountDownLatch callbackCalled = new CountDownLatch(1);
    requestAndResultsList.clear();
    for (int i = 0; i < 4; i++) {
        requestAndResultsList.add(new RequestAndResult(chunkSize + random.nextInt(5) * random.nextInt(chunkSize)));
    }
    instantiateNewRouterForPuts = false;
    ReadableStreamChannel putChannel = new ByteBufferReadableStreamChannel(ByteBuffer.wrap(req.putContent));
    Future future = router.putBlob(req.putBlobProperties, req.putUserMetadata, putChannel, req.options, (result, exception) -> {
        callbackCalled.countDown();
        throw new RuntimeException("Throwing an exception in the user callback");
    }, new QuotaChargeCallback() {

        @Override
        public void charge(long chunkSize) {
        }

        @Override
        public void charge() {
        }

        @Override
        public boolean check() {
            return false;
        }

        @Override
        public boolean quotaExceedAllowed() {
            return false;
        }

        @Override
        public QuotaResource getQuotaResource() throws QuotaException {
            return null;
        }

        @Override
        public QuotaMethod getQuotaMethod() {
            return null;
        }
    });
    submitPutsAndAssertSuccess(false);
    // future.get() for operation with bad callback should still succeed
    future.get();
    Assert.assertTrue("Callback not called.", callbackCalled.await(MAX_WAIT_MS, TimeUnit.MILLISECONDS));
    assertEquals("All operations should be finished.", 0, router.getOperationsCount());
    Assert.assertTrue("Router should not be closed", router.isOpen());
    // Test that PutManager is still operational
    requestAndResultsList.clear();
    requestAndResultsList.add(new RequestAndResult(chunkSize + random.nextInt(5) * random.nextInt(chunkSize)));
    instantiateNewRouterForPuts = false;
    submitPutsAndAssertSuccess(true);
}
Also used : ByteBufferReadableStreamChannel(com.github.ambry.commons.ByteBufferReadableStreamChannel) CountDownLatch(java.util.concurrent.CountDownLatch) QuotaResource(com.github.ambry.quota.QuotaResource) QuotaMethod(com.github.ambry.quota.QuotaMethod) ByteBufferReadableStreamChannel(com.github.ambry.commons.ByteBufferReadableStreamChannel) Future(java.util.concurrent.Future) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) QuotaException(com.github.ambry.quota.QuotaException) Test(org.junit.Test)

Example 3 with QuotaChargeCallback

use of com.github.ambry.quota.QuotaChargeCallback in project ambry by linkedin.

the class NonBlockingRouterQuotaCallbackTest method testRouterWithQuotaCallback.

/**
 * Test Router with single scaling unit for correct accounting in {@link QuotaChargeCallback}.
 */
@Test
public void testRouterWithQuotaCallback() throws Exception {
    try {
        setRouter();
        assertExpectedThreadCounts(2, 1);
        AtomicLong listenerCalledCount = new AtomicLong(0);
        int expectedChargeCallbackCount = 0;
        // create a quota charge listener that increments an atomic counter everytime its called.
        // Also tests that in case quota if charged in tracking mode with throttleInProgress config set to false
        // then the requests go through even in case of exception.
        QuotaChargeCallback quotaChargeCallback = new QuotaChargeCallback() {

            @Override
            public void charge(long chunkSize) throws QuotaException {
                listenerCalledCount.addAndGet(chunkSize);
                throw new QuotaException("exception during check and charge", new RouterException("Quota exceeded.", RouterErrorCode.TooManyRequests), false);
            }

            @Override
            public void charge() throws QuotaException {
                charge(quotaAccountingSize);
            }

            @Override
            public boolean check() {
                return false;
            }

            @Override
            public boolean quotaExceedAllowed() {
                return false;
            }

            @Override
            public QuotaResource getQuotaResource() {
                return null;
            }

            @Override
            public QuotaMethod getQuotaMethod() {
                return null;
            }
        };
        // test for a composite blob.
        int blobSize = 3000;
        setOperationParams(blobSize, TTL_SECS);
        String compositeBlobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, PutBlobOptions.DEFAULT, null, quotaChargeCallback).get();
        expectedChargeCallbackCount += blobSize;
        assertEquals(expectedChargeCallbackCount, listenerCalledCount.get());
        RetainingAsyncWritableChannel retainingAsyncWritableChannel = new RetainingAsyncWritableChannel();
        router.getBlob(compositeBlobId, new GetBlobOptionsBuilder().build(), null, quotaChargeCallback).get().getBlobDataChannel().readInto(retainingAsyncWritableChannel, null).get();
        expectedChargeCallbackCount += blobSize;
        // read out all the chunks to make sure all the chunks are consumed and accounted for.
        retainingAsyncWritableChannel.consumeContentAsInputStream().close();
        assertEquals(expectedChargeCallbackCount, listenerCalledCount.get());
        // test for regular blobs.
        setOperationParams();
        List<String> blobIds = new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            setOperationParams();
            String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, PutBlobOptions.DEFAULT, null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += PUT_CONTENT_SIZE, listenerCalledCount.get());
            logger.info("Put blob {}", blobId);
            blobIds.add(blobId);
        }
        setOperationParams();
        for (String blobId : blobIds) {
            router.getBlob(blobId, new GetBlobOptionsBuilder().build(), null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += PUT_CONTENT_SIZE, listenerCalledCount.get());
            router.updateBlobTtl(blobId, null, Utils.Infinite_Time, null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += quotaAccountingSize, listenerCalledCount.get());
            router.getBlob(blobId, new GetBlobOptionsBuilder().build(), null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += PUT_CONTENT_SIZE, listenerCalledCount.get());
            router.getBlob(blobId, new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.BlobInfo).build(), null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += quotaAccountingSize, listenerCalledCount.get());
            router.deleteBlob(blobId, null, null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += quotaAccountingSize, listenerCalledCount.get());
            try {
                router.getBlob(blobId, new GetBlobOptionsBuilder().build(), null, quotaChargeCallback).get();
                fail("Get blob should fail");
            } catch (ExecutionException e) {
                RouterException r = (RouterException) e.getCause();
                Assert.assertEquals("BlobDeleted error is expected", RouterErrorCode.BlobDeleted, r.getErrorCode());
                assertEquals(expectedChargeCallbackCount, listenerCalledCount.get());
            }
            router.getBlob(blobId, new GetBlobOptionsBuilder().getOption(GetOption.Include_Deleted_Blobs).build(), null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += PUT_CONTENT_SIZE, listenerCalledCount.get());
            router.getBlob(blobId, new GetBlobOptionsBuilder().getOption(GetOption.Include_All).build(), null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += PUT_CONTENT_SIZE, listenerCalledCount.get());
        }
        // test for stitched blobs.
        blobIds = new ArrayList<>();
        int stitchedBlobCount = 2;
        for (int i = 0; i < stitchedBlobCount; i++) {
            setOperationParams();
            String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, PutBlobOptions.DEFAULT, null, quotaChargeCallback).get();
            assertEquals(expectedChargeCallbackCount += PUT_CONTENT_SIZE, listenerCalledCount.get());
            logger.info("Put blob {}", blobId);
            blobIds.add(blobId);
        }
        String stitchedBlobId = router.stitchBlob(putBlobProperties, putUserMetadata, blobIds.stream().map(blobId -> new ChunkInfo(blobId, PUT_CONTENT_SIZE, Utils.Infinite_Time)).collect(Collectors.toList()), null, quotaChargeCallback).get();
        assertEquals(expectedChargeCallbackCount, listenerCalledCount.get());
        retainingAsyncWritableChannel = new RetainingAsyncWritableChannel();
        router.getBlob(stitchedBlobId, new GetBlobOptionsBuilder().build(), null, quotaChargeCallback).get().getBlobDataChannel().readInto(retainingAsyncWritableChannel, null).get();
        // read out all the chunks to make sure all the chunks are consumed and accounted for.
        retainingAsyncWritableChannel.consumeContentAsInputStream().close();
        assertEquals(expectedChargeCallbackCount += (PUT_CONTENT_SIZE * stitchedBlobCount), listenerCalledCount.get());
        router.updateBlobTtl(stitchedBlobId, null, Utils.Infinite_Time, null, quotaChargeCallback).get();
        assertEquals(expectedChargeCallbackCount += quotaAccountingSize, listenerCalledCount.get());
        router.deleteBlob(stitchedBlobId, null, null, quotaChargeCallback).get();
        assertEquals(expectedChargeCallbackCount + quotaAccountingSize, listenerCalledCount.get());
    } finally {
        router.close();
        assertExpectedThreadCounts(0, 0);
        // submission after closing should return a future that is already done.
        assertClosed();
    }
}
Also used : GetOption(com.github.ambry.protocol.GetOption) Arrays(java.util.Arrays) RunWith(org.junit.runner.RunWith) LoggerFactory(org.slf4j.LoggerFactory) AccountService(com.github.ambry.account.AccountService) QuotaManager(com.github.ambry.quota.QuotaManager) ArrayList(java.util.ArrayList) QuotaConfig(com.github.ambry.config.QuotaConfig) QuotaMode(com.github.ambry.quota.QuotaMode) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) QuotaResource(com.github.ambry.quota.QuotaResource) TestUtils(com.github.ambry.utils.TestUtils) Map(java.util.Map) QuotaAction(com.github.ambry.quota.QuotaAction) RetainingAsyncWritableChannel(com.github.ambry.commons.RetainingAsyncWritableChannel) QuotaMethod(com.github.ambry.quota.QuotaMethod) Parameterized(org.junit.runners.Parameterized) MetricRegistry(com.codahale.metrics.MetricRegistry) Properties(java.util.Properties) Logger(org.slf4j.Logger) VerifiableProperties(com.github.ambry.config.VerifiableProperties) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) Utils(com.github.ambry.utils.Utils) Test(org.junit.Test) Collectors(java.util.stream.Collectors) AccountStatsStore(com.github.ambry.accountstats.AccountStatsStore) QuotaUtils(com.github.ambry.quota.QuotaUtils) ExecutionException(java.util.concurrent.ExecutionException) AmbryQuotaManager(com.github.ambry.quota.AmbryQuotaManager) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) QuotaException(com.github.ambry.quota.QuotaException) QuotaMetrics(com.github.ambry.quota.QuotaMetrics) QuotaRecommendationMergePolicy(com.github.ambry.quota.QuotaRecommendationMergePolicy) QuotaName(com.github.ambry.quota.QuotaName) SimpleQuotaRecommendationMergePolicy(com.github.ambry.quota.SimpleQuotaRecommendationMergePolicy) MessageFormatRecord(com.github.ambry.messageformat.MessageFormatRecord) Assert(org.junit.Assert) RestRequest(com.github.ambry.rest.RestRequest) RetainingAsyncWritableChannel(com.github.ambry.commons.RetainingAsyncWritableChannel) ArrayList(java.util.ArrayList) AtomicLong(java.util.concurrent.atomic.AtomicLong) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) QuotaException(com.github.ambry.quota.QuotaException) ExecutionException(java.util.concurrent.ExecutionException) Test(org.junit.Test)

Example 4 with QuotaChargeCallback

use of com.github.ambry.quota.QuotaChargeCallback in project ambry by linkedin.

the class OperationQuotaChargerTest method testCheck.

@Test
public void testCheck() throws Exception {
    // check should return true if quotaChargeCallback is null.
    OperationQuotaCharger operationQuotaCharger = new OperationQuotaCharger(null, BLOBID, "GetOperation");
    Assert.assertTrue("check should return true if quotaChargeCallback is null.", operationQuotaCharger.check());
    QuotaChargeCallback quotaChargeCallback = Mockito.mock(QuotaChargeCallback.class);
    operationQuotaCharger = new OperationQuotaCharger(quotaChargeCallback, BLOBID, "GetOperation");
    // check should return true if quotaChargeCallback returns true.
    Mockito.when(quotaChargeCallback.check()).thenReturn(true);
    Assert.assertTrue("check should return true if quotaChargeCallback returns true.", operationQuotaCharger.check());
    // check should return false if quotaChargeCallback returns false.
    Mockito.when(quotaChargeCallback.check()).thenReturn(false);
    Assert.assertFalse("check should return false if quotaChargeCallback returns false.", operationQuotaCharger.check());
    // check should return false even if quotaChargeCallback returns false when isCharged is true.
    Mockito.doNothing().when(quotaChargeCallback).charge();
    // sets isCharged to true.
    operationQuotaCharger.charge();
    Mockito.when(quotaChargeCallback.check()).thenReturn(false);
    Assert.assertTrue("check should return true even if quotaChargeCallback returns false when isCharged is true.", operationQuotaCharger.check());
}
Also used : QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) Test(org.junit.Test)

Example 5 with QuotaChargeCallback

use of com.github.ambry.quota.QuotaChargeCallback in project ambry by linkedin.

the class OperationQuotaChargerTest method testQuotaExceedAllowed.

@Test
public void testQuotaExceedAllowed() throws Exception {
    // quotaExceedAllowed should return true if quotaChargeCallback is null.
    OperationQuotaCharger operationQuotaCharger = new OperationQuotaCharger(null, BLOBID, "GetOperation");
    Assert.assertTrue("quotaExceedAllowed should return true if quotaChargeCallback is null.", operationQuotaCharger.quotaExceedAllowed());
    QuotaChargeCallback quotaChargeCallback = Mockito.mock(QuotaChargeCallback.class);
    operationQuotaCharger = new OperationQuotaCharger(quotaChargeCallback, BLOBID, "GetOperation");
    // quotaExceedAllowed should return true if quotaChargeCallback.quotaExceedAllowed returns true.
    Mockito.when(quotaChargeCallback.quotaExceedAllowed()).thenReturn(true);
    Assert.assertTrue("quotaExceedAllowed should return true if quotaChargeCallback.quotaExceedAllowed returns true.", operationQuotaCharger.quotaExceedAllowed());
    // quotaExceedAllowed should return false if quotaChargeCallback.quotaExceedAllowed returns false.
    Mockito.when(quotaChargeCallback.quotaExceedAllowed()).thenReturn(false);
    Assert.assertFalse("quotaExceedAllowed should return false if quotaChargeCallback.quotaExceedAllowed returns false.", operationQuotaCharger.quotaExceedAllowed());
}
Also used : QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) Test(org.junit.Test)

Aggregations

QuotaChargeCallback (com.github.ambry.quota.QuotaChargeCallback)10 Test (org.junit.Test)9 VerifiableProperties (com.github.ambry.config.VerifiableProperties)4 QuotaException (com.github.ambry.quota.QuotaException)4 Properties (java.util.Properties)4 Callback (com.github.ambry.commons.Callback)3 QuotaResource (com.github.ambry.quota.QuotaResource)3 ArrayList (java.util.ArrayList)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 MetricRegistry (com.codahale.metrics.MetricRegistry)2 BlobId (com.github.ambry.commons.BlobId)2 ByteBufferReadableStreamChannel (com.github.ambry.commons.ByteBufferReadableStreamChannel)2 RetainingAsyncWritableChannel (com.github.ambry.commons.RetainingAsyncWritableChannel)2 QuotaConfig (com.github.ambry.config.QuotaConfig)2 RouterConfig (com.github.ambry.config.RouterConfig)2 BlobProperties (com.github.ambry.messageformat.BlobProperties)2 QuotaMethod (com.github.ambry.quota.QuotaMethod)2 RestServiceException (com.github.ambry.rest.RestServiceException)2 TestUtils (com.github.ambry.utils.TestUtils)2 Utils (com.github.ambry.utils.Utils)2