Search in sources :

Example 1 with CloudUpdateValidator

use of com.github.ambry.cloud.CloudUpdateValidator 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)

Aggregations

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 BlobRequestConditions (com.azure.storage.blob.models.BlobRequestConditions)1 BlobStorageException (com.azure.storage.blob.models.BlobStorageException)1 Timer (com.codahale.metrics.Timer)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 UncheckedIOException (java.io.UncheckedIOException)1