14

I'm trying to understand if DynamoDB Optimistic Locking is the correct thing for my use case or should I be doing something else.

I'm trying to do the following in my Java method.

function updateItem(String key) {
    Item item = mapper.load(Item.class, key);
    if (some condition) {
        item.setValue(item.getValue() + 1);
        mapper.save(item);
    }
 }

I want to update the same item based on some condition succeeding. I've created a version attribute, so that Optimistic locking works and when I have multiple requests coming in, only one request gets and updates the data.

I'm trying to understand the following:

  1. What happens when some other thread tries to update the value but the version id has changed, I couldn't find any documentation on what exception will be thrown?

  2. Should I be using a synchronized function for this? Considering multiple requests will be coming in? But, to me this seems like it defeats the purpose of optimistic locking, since I don't care which request gets access first.

  3. Is there an alternate solution to this problem?

I've been through the following documentation: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html

3 Answers 3

11

If you need to guarantee that all multiple requests (from different threads / servers) were applied, you could use the following implementation of optimistic locking:

public void updateItem(String key) {
    while (true) {
        try {
            Item item = dynamoDBMapper.load(Item.class, key);
            if (some condition) {
                item.setValue(item.getValue() + 1);
                dynamoDBMapper.save(item);
            }
            break;
        } catch (ConditionalCheckFailedException e) {
            System.out.println("ConditionalCheckFailedException. Retrying again...");
        }
    }
}

Here if item has already been updated by another request, we will receive ConditionalCheckFailedException and trying one more time until changes will be applied.

ConditionalCheckFailedException - this exception is thrown when an expected value does not match what was found in the system (database). This exception will be thrown:

  • if you use optimistic locking with @DynamoDBVersionAttribute, and version value on the server is different from value on the client side;
  • if you specify your own conditional constraints while saving / deleting data using dynamoDBMapper with DynamoDBSaveExpression / DynamoDBDeleteExpression and these constraints are failed.

Regarding @Nawaz question, if you haven’t specified your own conditional constraints (using DynamoDBSaveExpression and DynamoDBDeleteExpression), this exception is due to changed version. If you catch ConditionalCheckFailedException, you will have the following information:

requestId = …
errorCode = ConditionalCheckFailedException
errorType = {AmazonServiceException$ErrorType} "Client"
errorMessage = The conditional request failed
statusCode = 400
serviceName = AmazonDynamoDBv2
Sign up to request clarification or add additional context in comments.

Comments

8
  1. What happens when some other thread tries to update the value but the version id has changed, I couldn't find any documentation on what exception will be thrown?

It appears to throw a ConditionalCheckFailedException if the version ID has changed.

  1. Should I be using a synchronized function for this? Considering multiple requests will be coming in? But, to me this seems like it defeats the purpose of optimistic locking, since I don't care which request gets access first.

You are correct, using a synchronized function would defeat the purpose of optimistic locking. You don't need both. And optimistic locking works in a distributed environment where updates may not be generated by the same servers.

  1. Is there an alternate solution to this problem?

You could use the low-level DynamoDB API and Conditional Updates. I think that's what the Optimistic Locking is using underneath. If you were using a language other than Java or .Net you would have to use the low-level API. Since you are using Java and already working with the high-level API I would stick with that.

3 Comments

Hi Mark. Thanks for this. Could you please link me to the source for the exception? I checked the Javadoc here goo.gl/ZRAzOQ but didn't find anything. This page docs.aws.amazon.com/amazondynamodb/latest/developerguide/… mentions something about it, but it lacks details.
How would I ensure that the failure is because of changed-version, not some other condition? Does ConditionalCheckFailedException says which type of failure it is? Or is there any other means to know that?
Looking at needing to solve this when using golang, one additional thing to note is that synchronized will require you to have some other mechanism to understand if you entered the block after another thread has modified the object. The optimistic locking will provide a version that you could expose to callers who performed gets if it's useful to be able to reject update requests if the object has since been modified by another request. For synchronized probably involves hashing to get the same. So it's worth considering what additional checking you may want to do as well and the overhead
4

Optimistic Locking is officially supported now:

AWS Documentation

You need to add @DynamoDBVersionAttribute to you field. If you need more sophisticated data locks consider Conditional Constraints, they allow lock the data and prevent unwanted modification

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.