Search in sources :

Example 6 with QuotaResource

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

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

the class StorageQuotaEnforcerTest method testInitStorageUsage.

/**
 * Test to initialize the storage usage with non-empty map.
 */
@Test
public void testInitStorageUsage() throws Exception {
    Map<String, Map<String, Long>> containerUsage = TestUtils.makeStorageMap(10, 10, 1000, 100);
    InMemAccountService accountService = new InMemAccountService(false, false);
    Map<QuotaResource, Long> expectedStorageUsages = new HashMap<>();
    // Account and container id's base is 1, not 0
    for (int i = 1; i <= 10; i++) {
        QuotaResourceType resourceType = i <= containerUsage.size() / 2 ? QuotaResourceType.CONTAINER : QuotaResourceType.ACCOUNT;
        AccountBuilder accountBuilder = new AccountBuilder((short) i, String.valueOf(i), Account.AccountStatus.ACTIVE, resourceType);
        for (int j = 1; j <= 10; j++) {
            accountBuilder.addOrUpdateContainer(new ContainerBuilder((short) j, String.valueOf(j), Container.ContainerStatus.ACTIVE, "", (short) i).build());
        }
        accountService.updateAccounts(Collections.singleton(accountBuilder.build()));
        if (resourceType == QuotaResourceType.ACCOUNT) {
            expectedStorageUsages.put(QuotaResource.fromAccountId((short) i), containerUsage.get(String.valueOf(i)).values().stream().mapToLong(Long::longValue).sum());
        } else {
            for (Map.Entry<String, Long> containerEntry : containerUsage.get(String.valueOf(i)).entrySet()) {
                expectedStorageUsages.put(QuotaResource.fromContainerId((short) i, Short.valueOf(containerEntry.getKey())), containerEntry.getValue());
            }
        }
    }
    StorageQuotaEnforcer enforcer = new StorageQuotaEnforcer(config, new JSONStringStorageQuotaSource(new HashMap<>(), accountService), (StorageUsageRefresher) null);
    enforcer.initStorageUsage(containerUsage);
    assertEquals(expectedStorageUsages, enforcer.getStorageUsages());
}
Also used : HashMap(java.util.HashMap) QuotaResource(com.github.ambry.quota.QuotaResource) InMemAccountService(com.github.ambry.account.InMemAccountService) QuotaResourceType(com.github.ambry.quota.QuotaResourceType) ContainerBuilder(com.github.ambry.account.ContainerBuilder) AccountBuilder(com.github.ambry.account.AccountBuilder) HashMap(java.util.HashMap) Map(java.util.Map) Test(org.junit.Test)

Example 8 with QuotaResource

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

the class AmbryCUQuotaEnforcer method charge.

@Override
public QuotaRecommendation charge(RestRequest restRequest, Map<QuotaName, Double> requestCostMap) throws QuotaException {
    final QuotaName quotaName = QuotaUtils.getCUQuotaName(restRequest);
    if (requestCostMap.isEmpty() || !requestCostMap.containsKey(quotaName)) {
        String errorMessage = String.format("No %s cost provided for request %s. Nothing to charge", quotaName.name(), RestUtils.convertToStr(restRequest));
        throw new QuotaException(errorMessage, true);
    }
    final QuotaResource quotaResource = QuotaResource.fromRestRequest(restRequest);
    doAndHandleException(() -> {
        quotaSource.chargeUsage(quotaResource, quotaName, requestCostMap.get(quotaName));
        return null;
    }, String.format("Could not charge for request %s due to", restRequest));
    return recommend(restRequest);
}
Also used : QuotaName(com.github.ambry.quota.QuotaName) QuotaException(com.github.ambry.quota.QuotaException) QuotaResource(com.github.ambry.quota.QuotaResource)

Example 9 with QuotaResource

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

the class AmbryCUQuotaEnforcer method recommend.

@Override
public QuotaRecommendation recommend(RestRequest restRequest) throws QuotaException {
    final QuotaName quotaName = QuotaUtils.getCUQuotaName(restRequest);
    float usage = doAndHandleException(() -> {
        final QuotaResource quotaResource = QuotaResource.fromRestRequest(restRequest);
        return quotaSource.getUsage(quotaResource, quotaName);
    }, String.format("Could not recommend for request %s due to", restRequest));
    return buildQuotaRecommendation(usage, quotaName);
}
Also used : QuotaName(com.github.ambry.quota.QuotaName) QuotaResource(com.github.ambry.quota.QuotaResource)

Example 10 with QuotaResource

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

the class AmbryCUQuotaSourceTest method testCreation.

@Test
public void testCreation() throws QuotaException {
    Assert.assertEquals(4, ambryCUQuotaSource.getAllQuota().size());
    Assert.assertEquals(1024000000, (long) ambryCUQuotaSource.getQuota(new QuotaResource("101_1", QuotaResourceType.CONTAINER), QuotaName.READ_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(1024000000, (long) ambryCUQuotaSource.getQuota(new QuotaResource("101_1", QuotaResourceType.CONTAINER), QuotaName.WRITE_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(258438456, (long) ambryCUQuotaSource.getQuota(new QuotaResource("101_2", QuotaResourceType.CONTAINER), QuotaName.READ_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(258438456, (long) ambryCUQuotaSource.getQuota(new QuotaResource("101_2", QuotaResourceType.CONTAINER), QuotaName.WRITE_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(1024000000, (long) ambryCUQuotaSource.getQuota(new QuotaResource("102_1", QuotaResourceType.CONTAINER), QuotaName.READ_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(1024000000, (long) ambryCUQuotaSource.getQuota(new QuotaResource("102_1", QuotaResourceType.CONTAINER), QuotaName.WRITE_CAPACITY_UNIT).getQuotaValue());
    try {
        ambryCUQuotaSource.getQuota(new QuotaResource("101", QuotaResourceType.ACCOUNT), QuotaName.WRITE_CAPACITY_UNIT);
        Assert.fail("If quota is not present, it should throw an exception");
    } catch (QuotaException quotaException) {
    }
    try {
        ambryCUQuotaSource.getQuota(new QuotaResource("102", QuotaResourceType.ACCOUNT), QuotaName.WRITE_CAPACITY_UNIT);
        Assert.fail("If quota is not present, it should throw an exception");
    } catch (QuotaException quotaException) {
    }
    Assert.assertEquals(10737418240L, (long) ambryCUQuotaSource.getQuota(new QuotaResource("103", QuotaResourceType.ACCOUNT), QuotaName.READ_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(10737418240L, (long) ambryCUQuotaSource.getQuota(new QuotaResource("103", QuotaResourceType.ACCOUNT), QuotaName.WRITE_CAPACITY_UNIT).getQuotaValue());
    Assert.assertEquals(0, ambryCUQuotaSource.getSystemResourceUsage(QuotaName.READ_CAPACITY_UNIT), 0.01);
    Assert.assertEquals(0, ambryCUQuotaSource.getSystemResourceUsage(QuotaName.READ_CAPACITY_UNIT), 0.01);
    Assert.assertEquals(4, ambryCUQuotaSource.getAllQuotaUsage().size());
    Assert.assertEquals(0, (long) ambryCUQuotaSource.getUsage(new QuotaResource("101_1", QuotaResourceType.CONTAINER), QuotaName.READ_CAPACITY_UNIT));
    Assert.assertEquals(0, (long) ambryCUQuotaSource.getUsage(new QuotaResource("101_1", QuotaResourceType.CONTAINER), QuotaName.WRITE_CAPACITY_UNIT));
    Assert.assertEquals(0, (long) ambryCUQuotaSource.getUsage(new QuotaResource("101_2", QuotaResourceType.CONTAINER), QuotaName.READ_CAPACITY_UNIT));
    Assert.assertEquals(0, (long) ambryCUQuotaSource.getUsage(new QuotaResource("101_2", QuotaResourceType.CONTAINER), QuotaName.WRITE_CAPACITY_UNIT));
    Assert.assertEquals(0, (long) ambryCUQuotaSource.getUsage(new QuotaResource("102_1", QuotaResourceType.CONTAINER), QuotaName.READ_CAPACITY_UNIT));
    Assert.assertEquals(0, (long) ambryCUQuotaSource.getUsage(new QuotaResource("102_1", QuotaResourceType.CONTAINER), QuotaName.WRITE_CAPACITY_UNIT));
}
Also used : QuotaException(com.github.ambry.quota.QuotaException) QuotaResource(com.github.ambry.quota.QuotaResource) Test(org.junit.Test)

Aggregations

QuotaResource (com.github.ambry.quota.QuotaResource)14 QuotaException (com.github.ambry.quota.QuotaException)7 Test (org.junit.Test)7 Account (com.github.ambry.account.Account)3 AccountBuilder (com.github.ambry.account.AccountBuilder)3 ContainerBuilder (com.github.ambry.account.ContainerBuilder)3 InMemAccountService (com.github.ambry.account.InMemAccountService)3 RequestInfo (com.github.ambry.network.RequestInfo)3 QuotaChargeCallback (com.github.ambry.quota.QuotaChargeCallback)3 QuotaName (com.github.ambry.quota.QuotaName)3 QuotaResourceType (com.github.ambry.quota.QuotaResourceType)3 Map (java.util.Map)3 Container (com.github.ambry.account.Container)2 VerifiableProperties (com.github.ambry.config.VerifiableProperties)2 QuotaMethod (com.github.ambry.quota.QuotaMethod)2 Pair (com.github.ambry.utils.Pair)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 AtomicLong (java.util.concurrent.atomic.AtomicLong)2 MetricRegistry (com.codahale.metrics.MetricRegistry)1