in src/main/java/com/amazonaws/services/dynamodbv2/AmazonDynamoDBLockClient.java [824:915]
public boolean releaseLock(final ReleaseLockOptions options) {
Objects.requireNonNull(options, "ReleaseLockOptions cannot be null");
final LockItem lockItem = options.getLockItem();
final boolean deleteLock = options.isDeleteLock();
final boolean bestEffort = options.isBestEffort();
final Optional<ByteBuffer> data = options.getData();
Objects.requireNonNull(lockItem, "Cannot release null lockItem");
if (!lockItem.getOwnerName().equals(this.ownerName)) {
return false;
}
synchronized (lockItem) {
try {
// Always remove the heartbeat for the lock. The
// caller's intention is to release the lock. Stopping the
// heartbeat alone will do that regardless of whether the Dynamo
// write succeeds or fails.
this.locks.remove(lockItem.getUniqueIdentifier());
//set up expression stuff for DeleteItem or UpdateItem
//basically any changes require:
//1. I own the lock
//2. I know the current version number
//3. The lock already exists (UpdateItem API can cause a new item to be created if you do not condition the primary keys with attribute_exists)
final String conditionalExpression;
final Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(RVN_VALUE_EXPRESSION_VARIABLE, AttributeValue.builder().s(lockItem.getRecordVersionNumber()).build());
expressionAttributeValues.put(OWNER_NAME_VALUE_EXPRESSION_VARIABLE, AttributeValue.builder().s(lockItem.getOwnerName()).build());
final Map<String, String> expressionAttributeNames = new HashMap<>();
expressionAttributeNames.put(PK_PATH_EXPRESSION_VARIABLE, partitionKeyName);
expressionAttributeNames.put(OWNER_NAME_PATH_EXPRESSION_VARIABLE, OWNER_NAME);
expressionAttributeNames.put(RVN_PATH_EXPRESSION_VARIABLE, RECORD_VERSION_NUMBER);
if (this.sortKeyName.isPresent()) {
conditionalExpression = PK_EXISTS_AND_SK_EXISTS_AND_OWNER_NAME_SAME_AND_RVN_SAME_CONDITION;
expressionAttributeNames.put(SK_PATH_EXPRESSION_VARIABLE, sortKeyName.get());
} else {
conditionalExpression = PK_EXISTS_AND_OWNER_NAME_SAME_AND_RVN_SAME_CONDITION;
}
final Map<String, AttributeValue> key = getItemKeys(lockItem);
if (deleteLock) {
final DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder()
.tableName(tableName)
.key(key)
.conditionExpression(conditionalExpression)
.expressionAttributeNames(expressionAttributeNames)
.expressionAttributeValues(expressionAttributeValues)
.build();
this.dynamoDB.deleteItem(deleteItemRequest);
} else {
final String updateExpression;
expressionAttributeNames.put(IS_RELEASED_PATH_EXPRESSION_VARIABLE, IS_RELEASED);
expressionAttributeValues.put(IS_RELEASED_VALUE_EXPRESSION_VARIABLE, IS_RELEASED_ATTRIBUTE_VALUE);
if (data.isPresent()) {
updateExpression = UPDATE_IS_RELEASED_AND_DATA;
expressionAttributeNames.put(DATA_PATH_EXPRESSION_VARIABLE, DATA);
expressionAttributeValues.put(DATA_VALUE_EXPRESSION_VARIABLE, AttributeValue.builder().b(SdkBytes.fromByteBuffer(data.get())).build());
} else {
updateExpression = UPDATE_IS_RELEASED;
}
final UpdateItemRequest updateItemRequest = UpdateItemRequest.builder()
.tableName(this.tableName)
.key(key)
.updateExpression(updateExpression)
.conditionExpression(conditionalExpression)
.expressionAttributeNames(expressionAttributeNames)
.expressionAttributeValues(expressionAttributeValues).build();
this.dynamoDB.updateItem(updateItemRequest);
}
} catch (final ConditionalCheckFailedException conditionalCheckFailedException) {
logger.debug("Someone else acquired the lock before you asked to release it", conditionalCheckFailedException);
return false;
} catch (final SdkClientException sdkClientException) {
if (bestEffort) {
logger.warn("Ignore SdkClientException and continue to clean up", sdkClientException);
} else {
throw sdkClientException;
}
}
// Only remove the session monitor if no exception thrown above.
// While moving the heartbeat removal before the DynamoDB call
// should not cause existing clients problems, there
// may be existing clients that depend on the monitor firing if they
// get exceptions from this method.
this.removeKillSessionMonitor(lockItem.getUniqueIdentifier());
}
return true;
}