Search in sources :

Example 31 with CloudBlobMetadata

use of com.github.ambry.cloud.CloudBlobMetadata in project ambry by linkedin.

the class AzureCloudDestination method getBlobMetadata.

@Override
public Map<String, CloudBlobMetadata> getBlobMetadata(List<BlobId> blobIds) throws CloudStorageException {
    Objects.requireNonNull(blobIds, "blobIds cannot be null");
    if (blobIds.isEmpty()) {
        return Collections.emptyMap();
    }
    // needs to include that store key to replay the upload.
    if (!isVcr && blobIds.size() == 1) {
        CloudBlobMetadata metadata = azureBlobDataAccessor.getBlobMetadata(blobIds.get(0));
        return metadata == null ? Collections.emptyMap() : Collections.singletonMap(metadata.getId(), metadata);
    }
    // CosmosDB has query size limit of 256k chars.
    // Break list into chunks if necessary to avoid overflow.
    List<CloudBlobMetadata> metadataList = new ArrayList<>();
    List<List<BlobId>> chunkedBlobIdList = Utils.partitionList(blobIds, queryBatchSize);
    for (List<BlobId> batchOfBlobs : chunkedBlobIdList) {
        metadataList.addAll(getBlobMetadataChunked(batchOfBlobs));
    }
    return metadataList.stream().collect(Collectors.toMap(CloudBlobMetadata::getId, Function.identity(), (x, y) -> x));
}
Also used : DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException) BlobStorageException(com.azure.storage.blob.models.BlobStorageException) LoggerFactory(org.slf4j.LoggerFactory) VcrMetrics(com.github.ambry.cloud.VcrMetrics) HashMap(java.util.HashMap) Function(java.util.function.Function) CloudDestination(com.github.ambry.cloud.CloudDestination) ArrayList(java.util.ArrayList) CloudConfig(com.github.ambry.config.CloudConfig) StatusCodes(com.microsoft.azure.cosmosdb.internal.HttpConstants.StatusCodes) CloudContainerCompactor(com.github.ambry.cloud.CloudContainerCompactor) CloudUpdateValidator(com.github.ambry.cloud.CloudUpdateValidator) Map(java.util.Map) StoreException(com.github.ambry.store.StoreException) BlobBatchClient(com.azure.storage.blob.batch.BlobBatchClient) BlobLayout(com.github.ambry.cloud.azure.AzureBlobLayoutStrategy.BlobLayout) OutputStream(java.io.OutputStream) Container(com.github.ambry.account.Container) CloudStorageException(com.github.ambry.cloud.CloudStorageException) FindResult(com.github.ambry.cloud.FindResult) MetricRegistry(com.codahale.metrics.MetricRegistry) Properties(java.util.Properties) Logger(org.slf4j.Logger) AsyncDocumentClient(com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient) VerifiableProperties(com.github.ambry.config.VerifiableProperties) Collection(java.util.Collection) ClusterMap(com.github.ambry.clustermap.ClusterMap) Utils(com.github.ambry.utils.Utils) IOException(java.io.IOException) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) BlobServiceClient(com.azure.storage.blob.BlobServiceClient) BlobErrorCode(com.azure.storage.blob.models.BlobErrorCode) HttpConstants(com.microsoft.azure.cosmosdb.internal.HttpConstants) List(java.util.List) Document(com.microsoft.azure.cosmosdb.Document) Timer(com.codahale.metrics.Timer) FindToken(com.github.ambry.replication.FindToken) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) Collections(java.util.Collections) PartitionId(com.github.ambry.clustermap.PartitionId) BlobId(com.github.ambry.commons.BlobId) ResourceResponse(com.microsoft.azure.cosmosdb.ResourceResponse) InputStream(java.io.InputStream) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) BlobId(com.github.ambry.commons.BlobId)

Example 32 with CloudBlobMetadata

use of com.github.ambry.cloud.CloudBlobMetadata in project ambry by linkedin.

the class AzureBlobLayoutStrategyTest method testDefaultStrategy.

/**
 * Test default strategy and make sure it is partition-based
 */
@Test
public void testDefaultStrategy() {
    AzureCloudConfig azureCloudConfig = new AzureCloudConfig(new VerifiableProperties(configProps));
    AzureBlobLayoutStrategy strategy = new AzureBlobLayoutStrategy(clusterName, azureCloudConfig);
    BlobLayout layout = strategy.getDataBlobLayout(blobId);
    // Container name should be main-666
    String expectedContainerName = clusterName + "-" + partitionPath;
    String blobIdStr = blobId.getID();
    String expectedBlobName = blobIdStr.substring(blobIdStr.length() - 4) + "-" + blobIdStr;
    checkLayout(layout, expectedContainerName, expectedBlobName);
    CloudBlobMetadata blobMetadata = new CloudBlobMetadata(blobId, 0, 0, 0, null);
    layout = strategy.getDataBlobLayout(blobMetadata);
    checkLayout(layout, expectedContainerName, expectedBlobName);
    // Tokens should go in same container
    layout = strategy.getTokenBlobLayout(partitionPath, tokenFileName);
    checkLayout(layout, expectedContainerName, tokenFileName);
}
Also used : BlobLayout(com.github.ambry.cloud.azure.AzureBlobLayoutStrategy.BlobLayout) VerifiableProperties(com.github.ambry.config.VerifiableProperties) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) Test(org.junit.Test)

Example 33 with CloudBlobMetadata

use of com.github.ambry.cloud.CloudBlobMetadata in project ambry by linkedin.

the class AzureBlobLayoutStrategyTest method testContainerStrategy.

/**
 * Test container layout strategy
 */
@Test
public void testContainerStrategy() {
    configProps.setProperty(AzureCloudConfig.AZURE_BLOB_CONTAINER_STRATEGY, "container");
    AzureCloudConfig azureCloudConfig = new AzureCloudConfig(new VerifiableProperties(configProps));
    AzureBlobLayoutStrategy strategy = new AzureBlobLayoutStrategy(clusterName, azureCloudConfig);
    BlobLayout layout = strategy.getDataBlobLayout(blobId);
    // Container name should be main-101-5
    String expectedContainerName = String.format("%s-%d-%d", clusterName, AzureTestUtils.accountId, AzureTestUtils.containerId);
    String blobIdStr = blobId.getID();
    String expectedBlobName = blobIdStr.substring(blobIdStr.length() - 4) + "-" + blobIdStr;
    checkLayout(layout, expectedContainerName, expectedBlobName);
    CloudBlobMetadata blobMetadata = new CloudBlobMetadata(blobId, 0, 0, 0, null);
    layout = strategy.getDataBlobLayout(blobMetadata);
    checkLayout(layout, expectedContainerName, expectedBlobName);
    // Tokens should go in their own container: main_replicaTokens
    layout = strategy.getTokenBlobLayout(partitionPath, tokenFileName);
    expectedContainerName = clusterName + "-" + tokenFileName.toLowerCase();
    expectedBlobName = partitionPath + "/" + tokenFileName;
    checkLayout(layout, expectedContainerName, expectedBlobName);
}
Also used : BlobLayout(com.github.ambry.cloud.azure.AzureBlobLayoutStrategy.BlobLayout) VerifiableProperties(com.github.ambry.config.VerifiableProperties) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) Test(org.junit.Test)

Example 34 with CloudBlobMetadata

use of com.github.ambry.cloud.CloudBlobMetadata in project ambry by linkedin.

the class CloudBlobStore method putBlob.

/**
 * Upload the blob to the cloud destination.
 * @param messageInfo the {@link MessageInfo} containing blob metadata.
 * @param messageBuf the bytes to be uploaded.
 * @param size the number of bytes to upload.
 * @throws CloudStorageException if the upload failed.
 */
private void putBlob(MessageInfo messageInfo, ByteBuffer messageBuf, long size) throws CloudStorageException, IOException, StoreException {
    if (shouldUpload(messageInfo)) {
        BlobId blobId = (BlobId) messageInfo.getStoreKey();
        boolean isRouterEncrypted = isRouterEncrypted(blobId);
        EncryptionOrigin encryptionOrigin = isRouterEncrypted ? EncryptionOrigin.ROUTER : EncryptionOrigin.NONE;
        boolean encryptThisBlob = requireEncryption && !isRouterEncrypted;
        boolean uploaded;
        if (encryptThisBlob) {
            // Need to encrypt the buffer before upload
            long encryptedSize = -1;
            Timer.Context encryptionTimer = vcrMetrics.blobEncryptionTime.time();
            try {
                messageBuf = cryptoAgent.encrypt(messageBuf);
                encryptedSize = messageBuf.remaining();
            } catch (GeneralSecurityException ex) {
                vcrMetrics.blobEncryptionErrorCount.inc();
            } finally {
                encryptionTimer.stop();
            }
            vcrMetrics.blobEncryptionCount.inc();
            CloudBlobMetadata blobMetadata = new CloudBlobMetadata(blobId, messageInfo.getOperationTimeMs(), messageInfo.getExpirationTimeInMs(), messageInfo.getSize(), EncryptionOrigin.VCR, cryptoAgent.getEncryptionContext(), cryptoAgentFactory.getClass().getName(), encryptedSize, messageInfo.getLifeVersion());
            // If buffer was encrypted, we no longer know its size
            long bufferLen = (encryptedSize == -1) ? size : encryptedSize;
            uploaded = uploadWithRetries(blobId, messageBuf, bufferLen, blobMetadata);
        } else {
            // PutRequest lifeVersion from frontend is -1. Should set to 0. (0 is the starting life version number for any data).
            // Put from replication or recovery should use liferVersion as it's.
            short lifeVersion = messageInfo.hasLifeVersion(messageInfo.getLifeVersion()) ? messageInfo.getLifeVersion() : (short) 0;
            CloudBlobMetadata blobMetadata = new CloudBlobMetadata(blobId, messageInfo.getOperationTimeMs(), messageInfo.getExpirationTimeInMs(), messageInfo.getSize(), encryptionOrigin, lifeVersion);
            uploaded = uploadWithRetries(blobId, messageBuf, size, blobMetadata);
        }
        addToCache(blobId.getID(), (short) 0, BlobState.CREATED);
        if (!uploaded && !isVcr) {
            // was uploaded.
            throw new StoreException(String.format("Another blob with same key %s exists in store", blobId.getID()), StoreErrorCodes.Already_Exist);
        }
    } else {
        vcrMetrics.blobUploadSkippedCount.inc();
        // expiring within {@link CloudConfig#vcrMinTtlDays} for vcr to upload.
        if (isVcr && !isExpiringSoon(messageInfo) && !messageInfo.isDeleted()) {
            throw new StoreException(String.format("Another blob with same key %s exists in store", messageInfo.getStoreKey().getID()), StoreErrorCodes.Already_Exist);
        }
    }
}
Also used : Timer(com.codahale.metrics.Timer) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) GeneralSecurityException(java.security.GeneralSecurityException) BlobId(com.github.ambry.commons.BlobId) StoreException(com.github.ambry.store.StoreException)

Example 35 with CloudBlobMetadata

use of com.github.ambry.cloud.CloudBlobMetadata in project ambry by linkedin.

the class AzureBlobDataAccessor method purgeBlobs.

/**
 * Permanently delete the specified blobs in Azure storage.
 * @param blobMetadataList the list of {@link CloudBlobMetadata} referencing the blobs to purge.
 * @return list of {@link CloudBlobMetadata} referencing the blobs successfully purged.
 * @throws BlobStorageException if the purge operation fails.
 * @throws RuntimeException if the request times out before a response is received.
 */
public List<CloudBlobMetadata> purgeBlobs(List<CloudBlobMetadata> blobMetadataList) throws BlobStorageException {
    List<CloudBlobMetadata> deletedBlobs = new ArrayList<>();
    List<List<CloudBlobMetadata>> partitionedLists = Utils.partitionList(blobMetadataList, purgeBatchSize);
    for (List<CloudBlobMetadata> batchOfBlobs : partitionedLists) {
        List<Response<Void>> responseList = storageClient.deleteBatch(batchOfBlobs, batchTimeout);
        for (int j = 0; j < responseList.size(); j++) {
            Response<Void> response = responseList.get(j);
            CloudBlobMetadata blobMetadata = batchOfBlobs.get(j);
            // Note: Response.getStatusCode() throws exception on any error.
            try {
                response.getStatusCode();
            } catch (BlobStorageException bex) {
                int statusCode = bex.getStatusCode();
                // Don't worry if blob is already gone
                if (statusCode != HttpURLConnection.HTTP_NOT_FOUND && statusCode != HttpURLConnection.HTTP_GONE) {
                    logger.error("Deleting blob {} got status {}", blobMetadata.getId(), statusCode);
                    throw bex;
                }
            }
            deletedBlobs.add(blobMetadata);
        }
    }
    return deletedBlobs;
}
Also used : Response(com.azure.core.http.rest.Response) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) BlobStorageException(com.azure.storage.blob.models.BlobStorageException)

Aggregations

CloudBlobMetadata (com.github.ambry.cloud.CloudBlobMetadata)55 BlobId (com.github.ambry.commons.BlobId)27 Test (org.junit.Test)25 ArrayList (java.util.ArrayList)19 Document (com.microsoft.azure.cosmosdb.Document)14 PartitionId (com.github.ambry.clustermap.PartitionId)12 FeedResponse (com.microsoft.azure.cosmosdb.FeedResponse)12 FeedOptions (com.microsoft.azure.cosmosdb.FeedOptions)11 SqlQuerySpec (com.microsoft.azure.cosmosdb.SqlQuerySpec)11 MockPartitionId (com.github.ambry.clustermap.MockPartitionId)10 InputStream (java.io.InputStream)10 VerifiableProperties (com.github.ambry.config.VerifiableProperties)9 ByteArrayInputStream (java.io.ByteArrayInputStream)8 Timer (com.codahale.metrics.Timer)7 FindResult (com.github.ambry.cloud.FindResult)7 MetricRegistry (com.codahale.metrics.MetricRegistry)6 CloudStorageException (com.github.ambry.cloud.CloudStorageException)6 ChangeFeedOptions (com.microsoft.azure.cosmosdb.ChangeFeedOptions)6 DocumentClientException (com.microsoft.azure.cosmosdb.DocumentClientException)6 VcrMetrics (com.github.ambry.cloud.VcrMetrics)5