Search in sources :

Example 1 with BlobRequestConditions

use of com.azure.storage.blob.models.BlobRequestConditions in project ambry by linkedin.

the class AzureBlobDataAccessor method updateBlobMetadata.

/**
 * Update the metadata for the specified blob.
 * @param blobId The {@link BlobId} to update.
 * @param updateFields Map of field names and new values to modify.
 * @param cloudUpdateValidator {@link CloudUpdateValidator} validator for the update passed by the caller.
 * @return a {@link AzureCloudDestination.UpdateResponse} with the updated metadata.
 * @throws BlobStorageException if the blob does not exist or an error occurred.
 * @throws IllegalStateException on request timeout.
 */
public AzureCloudDestination.UpdateResponse updateBlobMetadata(BlobId blobId, Map<String, Object> updateFields, CloudUpdateValidator cloudUpdateValidator) throws Exception {
    Objects.requireNonNull(blobId, "BlobId cannot be null");
    updateFields.keySet().forEach(field -> Objects.requireNonNull(updateFields.get(field), String.format("%s cannot be null", field)));
    try {
        Timer.Context storageTimer = azureMetrics.blobUpdateTime.time();
        try {
            BlobProperties blobProperties = storageClient.getPropertiesWithResponse(blobId, defaultRequestConditions, requestTimeout);
            // Note: above throws 404 exception if blob does not exist.
            String etag = blobProperties.getETag();
            Map<String, String> metadata = blobProperties.getMetadata();
            if (!cloudUpdateValidator.validateUpdate(CloudBlobMetadata.fromMap(metadata), blobId, updateFields)) {
                return new AzureCloudDestination.UpdateResponse(false, metadata);
            }
            // Update only if any of the values have changed
            Map<String, String> changedFields = updateFields.entrySet().stream().filter(entry -> !String.valueOf(entry.getValue()).equals(metadata.get(entry.getKey()))).collect(Collectors.toMap(Map.Entry::getKey, entry -> String.valueOf(entry.getValue())));
            if (changedFields.size() > 0) {
                changedFields.forEach(metadata::put);
                if (updateCallback != null) {
                    try {
                        updateCallback.call();
                    } catch (Exception ex) {
                        logger.error("Error in update callback", ex);
                    }
                }
                // Set condition to ensure we don't clobber a concurrent update
                BlobRequestConditions blobRequestConditions = new BlobRequestConditions().setIfMatch(etag);
                storageClient.setMetadataWithResponse(blobId, metadata, blobRequestConditions, requestTimeout, Context.NONE);
                return new AzureCloudDestination.UpdateResponse(true, metadata);
            } else {
                return new AzureCloudDestination.UpdateResponse(false, metadata);
            }
        } finally {
            storageTimer.stop();
        }
    } catch (BlobStorageException e) {
        if (isNotFoundError(e.getErrorCode())) {
            logger.warn("Blob {} not found, cannot update {}.", blobId, updateFields.keySet());
        }
        if (e.getErrorCode() == BlobErrorCode.CONDITION_NOT_MET) {
            azureMetrics.blobUpdateConflictCount.inc();
        }
        throw e;
    }
}
Also used : HttpURLConnection(java.net.HttpURLConnection) Context(com.azure.core.util.Context) BlobStorageException(com.azure.storage.blob.models.BlobStorageException) LoggerFactory(org.slf4j.LoggerFactory) Callable(java.util.concurrent.Callable) ArrayList(java.util.ArrayList) CloudConfig(com.github.ambry.config.CloudConfig) ProxyOptions(com.azure.core.http.ProxyOptions) CloudUpdateValidator(com.github.ambry.cloud.CloudUpdateValidator) BlobRequestConditions(com.azure.storage.blob.models.BlobRequestConditions) Duration(java.time.Duration) Map(java.util.Map) BlobBatchClient(com.azure.storage.blob.batch.BlobBatchClient) BlobLayout(com.github.ambry.cloud.azure.AzureBlobLayoutStrategy.BlobLayout) OutputStream(java.io.OutputStream) BlobProperties(com.azure.storage.blob.models.BlobProperties) Logger(org.slf4j.Logger) Utils(com.github.ambry.utils.Utils) IOException(java.io.IOException) InetSocketAddress(java.net.InetSocketAddress) Collectors(java.util.stream.Collectors) UncheckedIOException(java.io.UncheckedIOException) Objects(java.util.Objects) BlobServiceClient(com.azure.storage.blob.BlobServiceClient) BlobErrorCode(com.azure.storage.blob.models.BlobErrorCode) List(java.util.List) Timer(com.codahale.metrics.Timer) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) Response(com.azure.core.http.rest.Response) BlobId(com.github.ambry.commons.BlobId) InputStream(java.io.InputStream) Timer(com.codahale.metrics.Timer) BlobProperties(com.azure.storage.blob.models.BlobProperties) BlobRequestConditions(com.azure.storage.blob.models.BlobRequestConditions) Map(java.util.Map) BlobStorageException(com.azure.storage.blob.models.BlobStorageException) BlobStorageException(com.azure.storage.blob.models.BlobStorageException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException)

Example 2 with BlobRequestConditions

use of com.azure.storage.blob.models.BlobRequestConditions in project ambry by linkedin.

the class AzureBlobDataAccessor method uploadIfNotExists.

/**
 * Upload the blob to Azure storage if it does not already exist in the designated container.
 * @param blobId the blobId to upload
 * @param inputLength the input stream length, if known (-1 if not)
 * @param cloudBlobMetadata the blob metadata
 * @param blobInputStream the input stream
 * @return {@code true} if the upload was successful, {@code false} if the blob already exists.
 * @throws BlobStorageException for any error on ABS side.
 * @throws IOException for any error with supplied data stream.
 */
public boolean uploadIfNotExists(BlobId blobId, long inputLength, CloudBlobMetadata cloudBlobMetadata, InputStream blobInputStream) throws BlobStorageException, IOException {
    BlobRequestConditions blobRequestConditions = new BlobRequestConditions().setIfNoneMatch("*");
    azureMetrics.blobUploadRequestCount.inc();
    Timer.Context storageTimer = azureMetrics.blobUploadTime.time();
    try {
        Map<String, String> metadata = cloudBlobMetadata.toMap();
        storageClient.uploadWithResponse(blobId, blobInputStream, inputLength, null, metadata, null, null, blobRequestConditions, uploadTimeout);
        logger.debug("Uploaded blob {} to ABS", blobId);
        azureMetrics.blobUploadSuccessCount.inc();
        return true;
    } catch (UncheckedIOException e) {
        // error processing input stream
        throw e.getCause();
    } catch (BlobStorageException e) {
        if (e.getErrorCode() == BlobErrorCode.BLOB_ALREADY_EXISTS) {
            logger.debug("Skipped upload of existing blob {}", blobId);
            azureMetrics.blobUploadConflictCount.inc();
            return false;
        } else {
            throw e;
        }
    } finally {
        storageTimer.stop();
    }
}
Also used : Timer(com.codahale.metrics.Timer) UncheckedIOException(java.io.UncheckedIOException) BlobRequestConditions(com.azure.storage.blob.models.BlobRequestConditions) BlobStorageException(com.azure.storage.blob.models.BlobStorageException)

Aggregations

BlobRequestConditions (com.azure.storage.blob.models.BlobRequestConditions)2 BlobStorageException (com.azure.storage.blob.models.BlobStorageException)2 Timer (com.codahale.metrics.Timer)2 UncheckedIOException (java.io.UncheckedIOException)2 ProxyOptions (com.azure.core.http.ProxyOptions)1 Response (com.azure.core.http.rest.Response)1 Context (com.azure.core.util.Context)1 BlobServiceClient (com.azure.storage.blob.BlobServiceClient)1 BlobBatchClient (com.azure.storage.blob.batch.BlobBatchClient)1 BlobErrorCode (com.azure.storage.blob.models.BlobErrorCode)1 BlobProperties (com.azure.storage.blob.models.BlobProperties)1 CloudBlobMetadata (com.github.ambry.cloud.CloudBlobMetadata)1 CloudUpdateValidator (com.github.ambry.cloud.CloudUpdateValidator)1 BlobLayout (com.github.ambry.cloud.azure.AzureBlobLayoutStrategy.BlobLayout)1 BlobId (com.github.ambry.commons.BlobId)1 CloudConfig (com.github.ambry.config.CloudConfig)1 Utils (com.github.ambry.utils.Utils)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 OutputStream (java.io.OutputStream)1