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;
}
}
Aggregations