Search in sources :

Example 6 with StoreException

use of com.github.ambry.store.StoreException in project ambry by linkedin.

the class CloudBlobStoreTest method testExceptionRetry.

/* Test retry behavior */
@Test
public void testExceptionRetry() throws Exception {
    CloudDestination exDest = mock(CloudDestination.class);
    long retryDelay = 5;
    MockMessageWriteSet messageWriteSet = new MockMessageWriteSet();
    BlobId blobId = CloudTestUtil.addBlobToMessageSet(messageWriteSet, SMALL_BLOB_SIZE, Utils.Infinite_Time, refAccountId, refContainerId, false, false, partitionId, operationTime, isVcr);
    List<StoreKey> keys = Collections.singletonList(blobId);
    CloudBlobMetadata metadata = new CloudBlobMetadata(blobId, operationTime, Utils.Infinite_Time, 1024, null);
    CloudStorageException retryableException = new CloudStorageException("Server unavailable", null, 500, true, retryDelay);
    when(exDest.uploadBlob(any(BlobId.class), anyLong(), any(), any(InputStream.class))).thenAnswer((invocation -> {
        consumeStream(invocation);
        throw retryableException;
    })).thenAnswer(invocation -> {
        consumeStream(invocation);
        return true;
    });
    when(exDest.deleteBlob(any(BlobId.class), anyLong(), anyShort(), any(CloudUpdateValidator.class))).thenThrow(retryableException).thenReturn(true);
    when(exDest.updateBlobExpiration(any(BlobId.class), anyLong(), any(CloudUpdateValidator.class))).thenThrow(retryableException).thenReturn((short) 1);
    when(exDest.getBlobMetadata(anyList())).thenThrow(retryableException).thenReturn(Collections.singletonMap(metadata.getId(), metadata));
    doThrow(retryableException).doNothing().when(exDest).downloadBlob(any(BlobId.class), any());
    Properties props = new Properties();
    setBasicProperties(props);
    props.setProperty(CloudConfig.VCR_REQUIRE_ENCRYPTION, "false");
    props.setProperty(CloudConfig.CLOUD_BLOB_CRYPTO_AGENT_FACTORY_CLASS, TestCloudBlobCryptoAgentFactory.class.getName());
    vcrMetrics = new VcrMetrics(new MetricRegistry());
    CloudBlobStore exStore = spy(new CloudBlobStore(new VerifiableProperties(props), partitionId, exDest, clusterMap, vcrMetrics));
    exStore.start();
    // Run all operations, they should be retried and succeed second time.
    int expectedCacheLookups = 0, expectedCacheRemoves = 0, expectedRetries = 0;
    // PUT
    exStore.put(messageWriteSet);
    expectedRetries++;
    expectedCacheLookups++;
    // UPDATE_TTL
    exStore.updateTtl(messageWriteSet.getMessageSetInfo());
    expectedRetries++;
    expectedCacheRemoves++;
    expectedCacheLookups += 2;
    // DELETE
    exStore.delete(messageWriteSet.getMessageSetInfo());
    expectedRetries++;
    expectedCacheRemoves++;
    if (isVcr) {
        // no cache lookup in case of delete for frontend.
        expectedCacheLookups += 2;
    }
    // GET
    exStore.get(keys, EnumSet.noneOf(StoreGetOptions.class));
    expectedRetries++;
    exStore.downloadBlob(metadata, blobId, new ByteArrayOutputStream());
    expectedRetries++;
    // Expect retries for all ops, cache lookups for the first three
    assertEquals("Unexpected retry count", expectedRetries, vcrMetrics.retryCount.getCount());
    assertEquals("Unexpected wait time", expectedRetries * retryDelay, vcrMetrics.retryWaitTimeMsec.getCount());
    verifyCacheHits(expectedCacheLookups, 0);
    verify(exStore, times(expectedCacheRemoves)).removeFromCache(eq(blobId.getID()));
    // Rerun the first three, should all skip due to cache hit
    messageWriteSet.resetBuffers();
    int expectedCacheHits = 0;
    try {
        exStore.put(messageWriteSet);
    } catch (StoreException ex) {
        assertEquals(ex.getErrorCode(), StoreErrorCodes.Already_Exist);
    }
    expectedCacheHits++;
    exStore.addToCache(blobId.getID(), (short) 0, CloudBlobStore.BlobState.TTL_UPDATED);
    exStore.updateTtl(messageWriteSet.getMessageSetInfo());
    expectedCacheHits++;
    exStore.addToCache(blobId.getID(), (short) 0, CloudBlobStore.BlobState.DELETED);
    try {
        exStore.delete(messageWriteSet.getMessageSetInfo());
    } catch (StoreException ex) {
        assertEquals(ex.getErrorCode(), StoreErrorCodes.ID_Deleted);
    }
    if (isVcr) {
        expectedCacheHits++;
    }
    verifyCacheHits(expectedCacheLookups + expectedCacheHits, expectedCacheHits);
}
Also used : VerifiableProperties(com.github.ambry.config.VerifiableProperties) MetricRegistry(com.codahale.metrics.MetricRegistry) StoreGetOptions(com.github.ambry.store.StoreGetOptions) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Properties(java.util.Properties) VerifiableProperties(com.github.ambry.config.VerifiableProperties) StoreKey(com.github.ambry.store.StoreKey) StoreException(com.github.ambry.store.StoreException) MockMessageWriteSet(com.github.ambry.store.MockMessageWriteSet) BlobId(com.github.ambry.commons.BlobId) ReplicationTest(com.github.ambry.replication.ReplicationTest) Test(org.junit.Test)

Example 7 with StoreException

use of com.github.ambry.store.StoreException in project ambry by linkedin.

the class CloudBlobStoreTest method testStoreTtlUpdates.

/**
 * Test the CloudBlobStore updateTtl method.
 */
@Test
public void testStoreTtlUpdates() throws Exception {
    setupCloudStore(false, true, defaultCacheLimit, true);
    MockMessageWriteSet messageWriteSet = new MockMessageWriteSet();
    int count = 10;
    for (int j = 0; j < count; j++) {
        CloudTestUtil.addBlobToMessageSet(messageWriteSet, SMALL_BLOB_SIZE, -1, refAccountId, refContainerId, true, false, partitionId, operationTime, isVcr);
    }
    store.updateTtl(messageWriteSet.getMessageSetInfo());
    verify(dest, times(count)).updateBlobExpiration(any(BlobId.class), anyLong(), any(CloudUpdateValidator.class));
    verifyCacheHits(count, 0);
    // Call second time, If isVcr, should be cached causing updates to be skipped.
    store.updateTtl(messageWriteSet.getMessageSetInfo());
    int expectedCount = isVcr ? count : count * 2;
    verify(dest, times(expectedCount)).updateBlobExpiration(any(BlobId.class), anyLong(), any(CloudUpdateValidator.class));
    verifyCacheHits(count * 2, count);
    // test that if a blob is deleted and then undeleted, the ttlupdate status is preserved in cache.
    MessageInfo messageInfo = messageWriteSet.getMessageSetInfo().get(0);
    store.delete(Collections.singletonList(messageInfo));
    verify(dest, times(1)).deleteBlob(any(BlobId.class), anyLong(), anyShort(), any(CloudUpdateValidator.class));
    store.undelete(messageInfo);
    verify(dest, times(1)).undeleteBlob(any(BlobId.class), anyShort(), any(CloudUpdateValidator.class));
    store.updateTtl(Collections.singletonList(messageInfo));
    expectedCount = isVcr ? expectedCount : expectedCount + 1;
    verify(dest, times(expectedCount)).updateBlobExpiration(any(BlobId.class), anyLong(), any(CloudUpdateValidator.class));
    if (isVcr) {
        verifyCacheHits((count * 2) + 3, count + 1);
    } else {
        // delete and undelete should not cause cache lookup for frontend.
        verifyCacheHits((count * 2) + 1, count + 1);
    }
    // test that ttl update with non infinite expiration time fails
    messageWriteSet = new MockMessageWriteSet();
    CloudTestUtil.addBlobToMessageSet(messageWriteSet, SMALL_BLOB_SIZE, System.currentTimeMillis() + 20000, refAccountId, refContainerId, true, false, partitionId, operationTime, isVcr);
    try {
        store.updateTtl(messageWriteSet.getMessageSetInfo());
    } catch (StoreException ex) {
        assertEquals(ex.getErrorCode(), StoreErrorCodes.Update_Not_Allowed);
    }
}
Also used : MockMessageWriteSet(com.github.ambry.store.MockMessageWriteSet) BlobId(com.github.ambry.commons.BlobId) MessageInfo(com.github.ambry.store.MessageInfo) StoreException(com.github.ambry.store.StoreException) ReplicationTest(com.github.ambry.replication.ReplicationTest) Test(org.junit.Test)

Example 8 with StoreException

use of com.github.ambry.store.StoreException in project ambry by linkedin.

the class CloudBlobStoreTest method testStorePuts.

/**
 * Test the CloudBlobStore put method with specified encryption.
 * @param requireEncryption true for encrypted puts. false otherwise.
 */
private void testStorePuts(boolean requireEncryption) throws Exception {
    setupCloudStore(true, requireEncryption, defaultCacheLimit, true);
    // Put blobs with and without expiration and encryption
    MockMessageWriteSet messageWriteSet = new MockMessageWriteSet();
    int count = 5;
    int expectedUploads = 0;
    long expectedBytesUploaded = 0;
    int expectedEncryptions = 0;
    for (int j = 0; j < count; j++) {
        long size = Math.abs(random.nextLong()) % 10000;
        // Permanent and encrypted, should be uploaded and not reencrypted
        CloudTestUtil.addBlobToMessageSet(messageWriteSet, size, Utils.Infinite_Time, refAccountId, refContainerId, true, false, partitionId, operationTime, isVcr);
        expectedUploads++;
        expectedBytesUploaded += size;
        // Permanent and unencrypted
        CloudTestUtil.addBlobToMessageSet(messageWriteSet, size, Utils.Infinite_Time, refAccountId, refContainerId, false, false, partitionId, operationTime, isVcr);
        expectedUploads++;
        expectedBytesUploaded += size;
        if (requireEncryption) {
            expectedEncryptions++;
        }
    }
    store.put(messageWriteSet);
    LatchBasedInMemoryCloudDestination inMemoryDest = (LatchBasedInMemoryCloudDestination) dest;
    assertEquals("Unexpected blobs count", expectedUploads, inMemoryDest.getBlobsUploaded());
    assertEquals("Unexpected byte count", expectedBytesUploaded, inMemoryDest.getBytesUploaded());
    assertEquals("Unexpected encryption count", expectedEncryptions, vcrMetrics.blobEncryptionCount.getCount());
    verifyCacheHits(expectedUploads, 0);
    // Try to put the same blobs again (e.g. from another replica).
    // If isVcr is true, they should already be cached.
    messageWriteSet.resetBuffers();
    for (MessageInfo messageInfo : messageWriteSet.getMessageSetInfo()) {
        try {
            MockMessageWriteSet mockMessageWriteSet = new MockMessageWriteSet();
            CloudTestUtil.addBlobToMessageSet(mockMessageWriteSet, (BlobId) messageInfo.getStoreKey(), messageInfo.getSize(), messageInfo.getExpirationTimeInMs(), operationTime, isVcr);
            store.put(mockMessageWriteSet);
            fail("Uploading already uploaded blob shoudl throw error");
        } catch (StoreException ex) {
            assertEquals(ex.getErrorCode(), StoreErrorCodes.Already_Exist);
        }
    }
    int expectedSkips = isVcr ? expectedUploads : 0;
    assertEquals("Unexpected blobs count", expectedUploads, inMemoryDest.getBlobsUploaded());
    assertEquals("Unexpected byte count", expectedBytesUploaded, inMemoryDest.getBytesUploaded());
    assertEquals("Unexpected skipped count", expectedSkips, vcrMetrics.blobUploadSkippedCount.getCount());
    verifyCacheHits(2 * expectedUploads, expectedUploads);
    // Try to upload a set of blobs containing duplicates
    MessageInfo duplicateMessageInfo = messageWriteSet.getMessageSetInfo().get(messageWriteSet.getMessageSetInfo().size() - 1);
    CloudTestUtil.addBlobToMessageSet(messageWriteSet, (BlobId) duplicateMessageInfo.getStoreKey(), duplicateMessageInfo.getSize(), duplicateMessageInfo.getExpirationTimeInMs(), operationTime, isVcr);
    try {
        store.put(messageWriteSet);
    } catch (IllegalArgumentException iaex) {
    }
    verifyCacheHits(2 * expectedUploads, expectedUploads);
    // Verify that a blob marked as deleted is not uploaded.
    MockMessageWriteSet deletedMessageWriteSet = new MockMessageWriteSet();
    CloudTestUtil.addBlobToMessageSet(deletedMessageWriteSet, 100, Utils.Infinite_Time, refAccountId, refContainerId, true, true, partitionId, operationTime, isVcr);
    store.put(deletedMessageWriteSet);
    expectedSkips++;
    verifyCacheHits(2 * expectedUploads, expectedUploads);
    assertEquals(expectedSkips, vcrMetrics.blobUploadSkippedCount.getCount());
    // Verify that a blob that is expiring soon is not uploaded for vcr but is uploaded for frontend.
    messageWriteSet = new MockMessageWriteSet();
    CloudTestUtil.addBlobToMessageSet(messageWriteSet, 100, operationTime + cloudConfig.vcrMinTtlDays - 1, refAccountId, refContainerId, true, false, partitionId, operationTime, isVcr);
    store.put(messageWriteSet);
    int expectedLookups = (2 * expectedUploads) + 1;
    if (isVcr) {
        expectedSkips++;
    } else {
        expectedUploads++;
    }
    verifyCacheHits(expectedLookups, expectedUploads);
    assertEquals(expectedSkips, vcrMetrics.blobUploadSkippedCount.getCount());
}
Also used : MockMessageWriteSet(com.github.ambry.store.MockMessageWriteSet) MessageInfo(com.github.ambry.store.MessageInfo) StoreException(com.github.ambry.store.StoreException)

Example 9 with StoreException

use of com.github.ambry.store.StoreException in project ambry by linkedin.

the class LatchBasedInMemoryCloudDestination method getBlobMetadata.

@Override
public Map<String, CloudBlobMetadata> getBlobMetadata(List<BlobId> blobIds) throws CloudStorageException {
    StoreErrorCodes serverError = hardError != null ? hardError : serverErrors.size() > 0 ? serverErrors.poll() : null;
    if (serverError != null) {
        throw new CloudStorageException("getBlobMetadata simulated error", new StoreException("getBlobMetadata simulated error", serverError));
    }
    Map<String, CloudBlobMetadata> result = new HashMap<>();
    for (BlobId blobId : blobIds) {
        if (map.containsKey(blobId)) {
            result.put(blobId.toString(), map.get(blobId).getFirst());
        }
    }
    return result;
}
Also used : HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) StoreErrorCodes(com.github.ambry.store.StoreErrorCodes) BlobId(com.github.ambry.commons.BlobId) StoreException(com.github.ambry.store.StoreException)

Example 10 with StoreException

use of com.github.ambry.store.StoreException in project ambry by linkedin.

the class LatchBasedInMemoryCloudDestination method uploadBlob.

@Override
public synchronized boolean uploadBlob(BlobId blobId, long blobSize, CloudBlobMetadata cloudBlobMetadata, InputStream blobInputStream) throws CloudStorageException {
    StoreErrorCodes serverError = hardError != null ? hardError : serverErrors.size() > 0 ? serverErrors.poll() : null;
    if (serverError != null) {
        throw new CloudStorageException("uploadBlob simulated error", new StoreException("uploadBlob simulated error", serverError));
    }
    if (map.containsKey(blobId)) {
        return false;
    }
    // Note: blobSize can be -1 when we dont know the actual blob size being uploaded.
    // So we have to do buffered reads to handle that case.
    int bufferSz = (blobSize == -1) ? 1024 : (int) blobSize;
    byte[] buffer = new byte[bufferSz];
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        int bytesRead = blobInputStream.read(buffer);
        while (bytesRead > 0) {
            outputStream.write(buffer, 0, bytesRead);
            bytesUploadedCounter.addAndGet(Math.max(bytesRead, 0));
            bytesRead = blobInputStream.read(buffer);
        }
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
    cloudBlobMetadata.setLastUpdateTime(System.currentTimeMillis());
    map.put(blobId, new Pair<>(cloudBlobMetadata, outputStream.toByteArray()));
    changeFeed.add(blobId);
    blobsUploadedCounter.incrementAndGet();
    if (blobIdsToTrack.remove(blobId)) {
        uploadLatch.countDown();
    }
    return true;
}
Also used : ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) StoreErrorCodes(com.github.ambry.store.StoreErrorCodes) StoreException(com.github.ambry.store.StoreException)

Aggregations

StoreException (com.github.ambry.store.StoreException)59 MessageInfo (com.github.ambry.store.MessageInfo)31 IOException (java.io.IOException)22 ArrayList (java.util.ArrayList)17 BlobId (com.github.ambry.commons.BlobId)16 Store (com.github.ambry.store.Store)16 StoreErrorCodes (com.github.ambry.store.StoreErrorCodes)12 StoreKey (com.github.ambry.store.StoreKey)11 MessageFormatException (com.github.ambry.messageformat.MessageFormatException)10 MockMessageWriteSet (com.github.ambry.store.MockMessageWriteSet)10 DataInputStream (java.io.DataInputStream)10 MessageFormatWriteSet (com.github.ambry.messageformat.MessageFormatWriteSet)9 IdUndeletedStoreException (com.github.ambry.store.IdUndeletedStoreException)8 StoreGetOptions (com.github.ambry.store.StoreGetOptions)8 Test (org.junit.Test)8 PartitionId (com.github.ambry.clustermap.PartitionId)7 MessageFormatInputStream (com.github.ambry.messageformat.MessageFormatInputStream)7 StoreInfo (com.github.ambry.store.StoreInfo)7 DeleteMessageFormatInputStream (com.github.ambry.messageformat.DeleteMessageFormatInputStream)6 ServerNetworkResponseMetrics (com.github.ambry.network.ServerNetworkResponseMetrics)6