DynamoDB appending to multiple lists atomically












1















I have a record with two lists.
Multiple services are appending to those lists simultaneously, each service updates exactly one of those lists.



this is my code for creating the UpdateItemSpec



private UpdateItemSpec updateList1(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list1 = list_append(if_not_exists(list1, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}

private UpdateItemSpec updateList2(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list2 = list_append(if_not_exists(list2, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}


Given that the updates should get me to the state in which the lists are equal (I don't know how many iterations are needed), my goal is to check if the lists are equal after each update (using the item that returned from the update). Do I need to do anything to make sure that the updates are atomic across the records and I won't miss the iteration in which the lists became equal?



In other words, does the update locks the record entirely, or is it just locks the currently updated field?










share|improve this question

























  • Can you guarantee that no updates are made after the lists become equal?

    – teppic
    Nov 21 '18 at 19:09











  • update doesn’t truly lock anything, but an update to a single item is an atomic operation. What is your higher level goal here? Do you just want to know if the lists are equal, or do you want to take some action on the item in DynamoDB when they are equal?

    – Matthew Pope
    Nov 21 '18 at 19:45











  • Yes, it's guaranteed that no updates are made after the lists became equal. I just want to know when the lists are equal, and when they are, I need to immediately run a different service

    – AvielNiego
    Nov 22 '18 at 7:37
















1















I have a record with two lists.
Multiple services are appending to those lists simultaneously, each service updates exactly one of those lists.



this is my code for creating the UpdateItemSpec



private UpdateItemSpec updateList1(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list1 = list_append(if_not_exists(list1, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}

private UpdateItemSpec updateList2(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list2 = list_append(if_not_exists(list2, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}


Given that the updates should get me to the state in which the lists are equal (I don't know how many iterations are needed), my goal is to check if the lists are equal after each update (using the item that returned from the update). Do I need to do anything to make sure that the updates are atomic across the records and I won't miss the iteration in which the lists became equal?



In other words, does the update locks the record entirely, or is it just locks the currently updated field?










share|improve this question

























  • Can you guarantee that no updates are made after the lists become equal?

    – teppic
    Nov 21 '18 at 19:09











  • update doesn’t truly lock anything, but an update to a single item is an atomic operation. What is your higher level goal here? Do you just want to know if the lists are equal, or do you want to take some action on the item in DynamoDB when they are equal?

    – Matthew Pope
    Nov 21 '18 at 19:45











  • Yes, it's guaranteed that no updates are made after the lists became equal. I just want to know when the lists are equal, and when they are, I need to immediately run a different service

    – AvielNiego
    Nov 22 '18 at 7:37














1












1








1


0






I have a record with two lists.
Multiple services are appending to those lists simultaneously, each service updates exactly one of those lists.



this is my code for creating the UpdateItemSpec



private UpdateItemSpec updateList1(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list1 = list_append(if_not_exists(list1, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}

private UpdateItemSpec updateList2(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list2 = list_append(if_not_exists(list2, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}


Given that the updates should get me to the state in which the lists are equal (I don't know how many iterations are needed), my goal is to check if the lists are equal after each update (using the item that returned from the update). Do I need to do anything to make sure that the updates are atomic across the records and I won't miss the iteration in which the lists became equal?



In other words, does the update locks the record entirely, or is it just locks the currently updated field?










share|improve this question
















I have a record with two lists.
Multiple services are appending to those lists simultaneously, each service updates exactly one of those lists.



this is my code for creating the UpdateItemSpec



private UpdateItemSpec updateList1(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list1 = list_append(if_not_exists(list1, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}

private UpdateItemSpec updateList2(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list2 = list_append(if_not_exists(list2, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}


Given that the updates should get me to the state in which the lists are equal (I don't know how many iterations are needed), my goal is to check if the lists are equal after each update (using the item that returned from the update). Do I need to do anything to make sure that the updates are atomic across the records and I won't miss the iteration in which the lists became equal?



In other words, does the update locks the record entirely, or is it just locks the currently updated field?







java amazon-dynamodb atomic






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 12:36







AvielNiego

















asked Nov 21 '18 at 17:48









AvielNiegoAvielNiego

349313




349313













  • Can you guarantee that no updates are made after the lists become equal?

    – teppic
    Nov 21 '18 at 19:09











  • update doesn’t truly lock anything, but an update to a single item is an atomic operation. What is your higher level goal here? Do you just want to know if the lists are equal, or do you want to take some action on the item in DynamoDB when they are equal?

    – Matthew Pope
    Nov 21 '18 at 19:45











  • Yes, it's guaranteed that no updates are made after the lists became equal. I just want to know when the lists are equal, and when they are, I need to immediately run a different service

    – AvielNiego
    Nov 22 '18 at 7:37



















  • Can you guarantee that no updates are made after the lists become equal?

    – teppic
    Nov 21 '18 at 19:09











  • update doesn’t truly lock anything, but an update to a single item is an atomic operation. What is your higher level goal here? Do you just want to know if the lists are equal, or do you want to take some action on the item in DynamoDB when they are equal?

    – Matthew Pope
    Nov 21 '18 at 19:45











  • Yes, it's guaranteed that no updates are made after the lists became equal. I just want to know when the lists are equal, and when they are, I need to immediately run a different service

    – AvielNiego
    Nov 22 '18 at 7:37

















Can you guarantee that no updates are made after the lists become equal?

– teppic
Nov 21 '18 at 19:09





Can you guarantee that no updates are made after the lists become equal?

– teppic
Nov 21 '18 at 19:09













update doesn’t truly lock anything, but an update to a single item is an atomic operation. What is your higher level goal here? Do you just want to know if the lists are equal, or do you want to take some action on the item in DynamoDB when they are equal?

– Matthew Pope
Nov 21 '18 at 19:45





update doesn’t truly lock anything, but an update to a single item is an atomic operation. What is your higher level goal here? Do you just want to know if the lists are equal, or do you want to take some action on the item in DynamoDB when they are equal?

– Matthew Pope
Nov 21 '18 at 19:45













Yes, it's guaranteed that no updates are made after the lists became equal. I just want to know when the lists are equal, and when they are, I need to immediately run a different service

– AvielNiego
Nov 22 '18 at 7:37





Yes, it's guaranteed that no updates are made after the lists became equal. I just want to know when the lists are equal, and when they are, I need to immediately run a different service

– AvielNiego
Nov 22 '18 at 7:37












1 Answer
1






active

oldest

votes


















1














An update on a single item is atomic, so if you use ReturnValues.ALL_NEW, you will be able to see the full state of the item, and you will not miss it if the lists are equal. (See update documentation.)



Even though you will see when the lists are equal, it is possible that the lists will no longer be equal by the time you are able to react to them being equal. If you want to make sure that the list stays equal until you can react, then you will need a condition expression to prevent further updates or a distributed locking solution.



Edit (2018-11-22)



There is no documentation stating directly that an update on an item happens atomically, but we can reason that all attributes in a single item are updated atomically.



Let's start with the following assumptions:




  1. A conditional write is entirely successful for the item if the condition is true.

  2. A conditional write is rejected if the condition is false.

  3. Conditional writes can be used for
    Optimistic Locking with Version Number.

  4. A write does not update all attributes atomically.


Suppose we have an item with the attributes hashkey, version, and data. Let us say that hashkey=123, data = "Foo", and version = 1.



Suppose also that there are two requests (Request A and Request B) that come in at nearly the same time which are both using optimistic locking and both are trying to set a new value for data.



Here's a possible sequence of events




  • Request A – Check condition version==1

  • Request B – Check condition version==1

  • Request A – data = "Bar"

  • Request B – data = "Bag"

  • Request A – version=version+1

  • Request B – version=version+1


The final state of the item is



hashkey=123
version=3
data="Bag"


This state should not happen because of the optimistic locking.




If you use this strategy, then your database writes are protected from being overwritten by the writes of others — and vice-versa.




Now, you might object that all this shows is that the version increment occurs atomically with the condition evaluation. However, you should also remember that a condition expression can have an arbitrary number of conditions on an arbitrary number of attributes, so then all attributes mentioned in the condition expression would have to be updated atomically along with the condition expression evaluation.



However, this only demonstrates that at least some of the attributes must be updated atomically, not that all of them are. Well, there are two possible implementations here. (1) DynamoDB determines which attributes are present in the condition expression (anywhere from 0 to all of them) and updates only those ones atomically. (2) DynamoDB updates all the attributes for an item atomically. But consider this example in which the attributes not in the ConditionExpression affect the correctness of the update.



Suppose our item has 1 more attribute: canEdit, which is initially true. This time Request A is setting canEdit=false and Request B is setting values = list_append(values, "Bar").



If all attributes are not updated atomically, here's a possible sequence of events:




  • Request A – Check condition version==1 AND data=="Foo"

  • Request A – version = version+1

  • Request A – `data = "Foo"

  • Request B – Check condition canEdit==true

  • Request B – version = version+1

  • Request B – canEdit = true

  • Request A – canEdit = false

  • Request B – data = "Bar"


In both cases, the condition is true when initially evaluated, and in both cases, something the request wrote was overridden by the other request. DynamoDB will not allow both of these conditional updates to succeed, therefore DynamoDB must update all attributes in an item atomically because that is the only way to guarantee that either A or B will fail with a ConditionCheckException.



If my reasoning is correct, then in order for 1-3 to be true, 4 must be false, and all attributes in a single item are updated atomically.






share|improve this answer


























  • Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

    – AvielNiego
    Nov 22 '18 at 7:38













  • It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

    – Matthew Pope
    Nov 22 '18 at 7:42











  • that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

    – AvielNiego
    Nov 22 '18 at 8:21











  • Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

    – Matthew Pope
    Nov 22 '18 at 11:39











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53417879%2fdynamodb-appending-to-multiple-lists-atomically%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














An update on a single item is atomic, so if you use ReturnValues.ALL_NEW, you will be able to see the full state of the item, and you will not miss it if the lists are equal. (See update documentation.)



Even though you will see when the lists are equal, it is possible that the lists will no longer be equal by the time you are able to react to them being equal. If you want to make sure that the list stays equal until you can react, then you will need a condition expression to prevent further updates or a distributed locking solution.



Edit (2018-11-22)



There is no documentation stating directly that an update on an item happens atomically, but we can reason that all attributes in a single item are updated atomically.



Let's start with the following assumptions:




  1. A conditional write is entirely successful for the item if the condition is true.

  2. A conditional write is rejected if the condition is false.

  3. Conditional writes can be used for
    Optimistic Locking with Version Number.

  4. A write does not update all attributes atomically.


Suppose we have an item with the attributes hashkey, version, and data. Let us say that hashkey=123, data = "Foo", and version = 1.



Suppose also that there are two requests (Request A and Request B) that come in at nearly the same time which are both using optimistic locking and both are trying to set a new value for data.



Here's a possible sequence of events




  • Request A – Check condition version==1

  • Request B – Check condition version==1

  • Request A – data = "Bar"

  • Request B – data = "Bag"

  • Request A – version=version+1

  • Request B – version=version+1


The final state of the item is



hashkey=123
version=3
data="Bag"


This state should not happen because of the optimistic locking.




If you use this strategy, then your database writes are protected from being overwritten by the writes of others — and vice-versa.




Now, you might object that all this shows is that the version increment occurs atomically with the condition evaluation. However, you should also remember that a condition expression can have an arbitrary number of conditions on an arbitrary number of attributes, so then all attributes mentioned in the condition expression would have to be updated atomically along with the condition expression evaluation.



However, this only demonstrates that at least some of the attributes must be updated atomically, not that all of them are. Well, there are two possible implementations here. (1) DynamoDB determines which attributes are present in the condition expression (anywhere from 0 to all of them) and updates only those ones atomically. (2) DynamoDB updates all the attributes for an item atomically. But consider this example in which the attributes not in the ConditionExpression affect the correctness of the update.



Suppose our item has 1 more attribute: canEdit, which is initially true. This time Request A is setting canEdit=false and Request B is setting values = list_append(values, "Bar").



If all attributes are not updated atomically, here's a possible sequence of events:




  • Request A – Check condition version==1 AND data=="Foo"

  • Request A – version = version+1

  • Request A – `data = "Foo"

  • Request B – Check condition canEdit==true

  • Request B – version = version+1

  • Request B – canEdit = true

  • Request A – canEdit = false

  • Request B – data = "Bar"


In both cases, the condition is true when initially evaluated, and in both cases, something the request wrote was overridden by the other request. DynamoDB will not allow both of these conditional updates to succeed, therefore DynamoDB must update all attributes in an item atomically because that is the only way to guarantee that either A or B will fail with a ConditionCheckException.



If my reasoning is correct, then in order for 1-3 to be true, 4 must be false, and all attributes in a single item are updated atomically.






share|improve this answer


























  • Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

    – AvielNiego
    Nov 22 '18 at 7:38













  • It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

    – Matthew Pope
    Nov 22 '18 at 7:42











  • that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

    – AvielNiego
    Nov 22 '18 at 8:21











  • Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

    – Matthew Pope
    Nov 22 '18 at 11:39
















1














An update on a single item is atomic, so if you use ReturnValues.ALL_NEW, you will be able to see the full state of the item, and you will not miss it if the lists are equal. (See update documentation.)



Even though you will see when the lists are equal, it is possible that the lists will no longer be equal by the time you are able to react to them being equal. If you want to make sure that the list stays equal until you can react, then you will need a condition expression to prevent further updates or a distributed locking solution.



Edit (2018-11-22)



There is no documentation stating directly that an update on an item happens atomically, but we can reason that all attributes in a single item are updated atomically.



Let's start with the following assumptions:




  1. A conditional write is entirely successful for the item if the condition is true.

  2. A conditional write is rejected if the condition is false.

  3. Conditional writes can be used for
    Optimistic Locking with Version Number.

  4. A write does not update all attributes atomically.


Suppose we have an item with the attributes hashkey, version, and data. Let us say that hashkey=123, data = "Foo", and version = 1.



Suppose also that there are two requests (Request A and Request B) that come in at nearly the same time which are both using optimistic locking and both are trying to set a new value for data.



Here's a possible sequence of events




  • Request A – Check condition version==1

  • Request B – Check condition version==1

  • Request A – data = "Bar"

  • Request B – data = "Bag"

  • Request A – version=version+1

  • Request B – version=version+1


The final state of the item is



hashkey=123
version=3
data="Bag"


This state should not happen because of the optimistic locking.




If you use this strategy, then your database writes are protected from being overwritten by the writes of others — and vice-versa.




Now, you might object that all this shows is that the version increment occurs atomically with the condition evaluation. However, you should also remember that a condition expression can have an arbitrary number of conditions on an arbitrary number of attributes, so then all attributes mentioned in the condition expression would have to be updated atomically along with the condition expression evaluation.



However, this only demonstrates that at least some of the attributes must be updated atomically, not that all of them are. Well, there are two possible implementations here. (1) DynamoDB determines which attributes are present in the condition expression (anywhere from 0 to all of them) and updates only those ones atomically. (2) DynamoDB updates all the attributes for an item atomically. But consider this example in which the attributes not in the ConditionExpression affect the correctness of the update.



Suppose our item has 1 more attribute: canEdit, which is initially true. This time Request A is setting canEdit=false and Request B is setting values = list_append(values, "Bar").



If all attributes are not updated atomically, here's a possible sequence of events:




  • Request A – Check condition version==1 AND data=="Foo"

  • Request A – version = version+1

  • Request A – `data = "Foo"

  • Request B – Check condition canEdit==true

  • Request B – version = version+1

  • Request B – canEdit = true

  • Request A – canEdit = false

  • Request B – data = "Bar"


In both cases, the condition is true when initially evaluated, and in both cases, something the request wrote was overridden by the other request. DynamoDB will not allow both of these conditional updates to succeed, therefore DynamoDB must update all attributes in an item atomically because that is the only way to guarantee that either A or B will fail with a ConditionCheckException.



If my reasoning is correct, then in order for 1-3 to be true, 4 must be false, and all attributes in a single item are updated atomically.






share|improve this answer


























  • Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

    – AvielNiego
    Nov 22 '18 at 7:38













  • It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

    – Matthew Pope
    Nov 22 '18 at 7:42











  • that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

    – AvielNiego
    Nov 22 '18 at 8:21











  • Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

    – Matthew Pope
    Nov 22 '18 at 11:39














1












1








1







An update on a single item is atomic, so if you use ReturnValues.ALL_NEW, you will be able to see the full state of the item, and you will not miss it if the lists are equal. (See update documentation.)



Even though you will see when the lists are equal, it is possible that the lists will no longer be equal by the time you are able to react to them being equal. If you want to make sure that the list stays equal until you can react, then you will need a condition expression to prevent further updates or a distributed locking solution.



Edit (2018-11-22)



There is no documentation stating directly that an update on an item happens atomically, but we can reason that all attributes in a single item are updated atomically.



Let's start with the following assumptions:




  1. A conditional write is entirely successful for the item if the condition is true.

  2. A conditional write is rejected if the condition is false.

  3. Conditional writes can be used for
    Optimistic Locking with Version Number.

  4. A write does not update all attributes atomically.


Suppose we have an item with the attributes hashkey, version, and data. Let us say that hashkey=123, data = "Foo", and version = 1.



Suppose also that there are two requests (Request A and Request B) that come in at nearly the same time which are both using optimistic locking and both are trying to set a new value for data.



Here's a possible sequence of events




  • Request A – Check condition version==1

  • Request B – Check condition version==1

  • Request A – data = "Bar"

  • Request B – data = "Bag"

  • Request A – version=version+1

  • Request B – version=version+1


The final state of the item is



hashkey=123
version=3
data="Bag"


This state should not happen because of the optimistic locking.




If you use this strategy, then your database writes are protected from being overwritten by the writes of others — and vice-versa.




Now, you might object that all this shows is that the version increment occurs atomically with the condition evaluation. However, you should also remember that a condition expression can have an arbitrary number of conditions on an arbitrary number of attributes, so then all attributes mentioned in the condition expression would have to be updated atomically along with the condition expression evaluation.



However, this only demonstrates that at least some of the attributes must be updated atomically, not that all of them are. Well, there are two possible implementations here. (1) DynamoDB determines which attributes are present in the condition expression (anywhere from 0 to all of them) and updates only those ones atomically. (2) DynamoDB updates all the attributes for an item atomically. But consider this example in which the attributes not in the ConditionExpression affect the correctness of the update.



Suppose our item has 1 more attribute: canEdit, which is initially true. This time Request A is setting canEdit=false and Request B is setting values = list_append(values, "Bar").



If all attributes are not updated atomically, here's a possible sequence of events:




  • Request A – Check condition version==1 AND data=="Foo"

  • Request A – version = version+1

  • Request A – `data = "Foo"

  • Request B – Check condition canEdit==true

  • Request B – version = version+1

  • Request B – canEdit = true

  • Request A – canEdit = false

  • Request B – data = "Bar"


In both cases, the condition is true when initially evaluated, and in both cases, something the request wrote was overridden by the other request. DynamoDB will not allow both of these conditional updates to succeed, therefore DynamoDB must update all attributes in an item atomically because that is the only way to guarantee that either A or B will fail with a ConditionCheckException.



If my reasoning is correct, then in order for 1-3 to be true, 4 must be false, and all attributes in a single item are updated atomically.






share|improve this answer















An update on a single item is atomic, so if you use ReturnValues.ALL_NEW, you will be able to see the full state of the item, and you will not miss it if the lists are equal. (See update documentation.)



Even though you will see when the lists are equal, it is possible that the lists will no longer be equal by the time you are able to react to them being equal. If you want to make sure that the list stays equal until you can react, then you will need a condition expression to prevent further updates or a distributed locking solution.



Edit (2018-11-22)



There is no documentation stating directly that an update on an item happens atomically, but we can reason that all attributes in a single item are updated atomically.



Let's start with the following assumptions:




  1. A conditional write is entirely successful for the item if the condition is true.

  2. A conditional write is rejected if the condition is false.

  3. Conditional writes can be used for
    Optimistic Locking with Version Number.

  4. A write does not update all attributes atomically.


Suppose we have an item with the attributes hashkey, version, and data. Let us say that hashkey=123, data = "Foo", and version = 1.



Suppose also that there are two requests (Request A and Request B) that come in at nearly the same time which are both using optimistic locking and both are trying to set a new value for data.



Here's a possible sequence of events




  • Request A – Check condition version==1

  • Request B – Check condition version==1

  • Request A – data = "Bar"

  • Request B – data = "Bag"

  • Request A – version=version+1

  • Request B – version=version+1


The final state of the item is



hashkey=123
version=3
data="Bag"


This state should not happen because of the optimistic locking.




If you use this strategy, then your database writes are protected from being overwritten by the writes of others — and vice-versa.




Now, you might object that all this shows is that the version increment occurs atomically with the condition evaluation. However, you should also remember that a condition expression can have an arbitrary number of conditions on an arbitrary number of attributes, so then all attributes mentioned in the condition expression would have to be updated atomically along with the condition expression evaluation.



However, this only demonstrates that at least some of the attributes must be updated atomically, not that all of them are. Well, there are two possible implementations here. (1) DynamoDB determines which attributes are present in the condition expression (anywhere from 0 to all of them) and updates only those ones atomically. (2) DynamoDB updates all the attributes for an item atomically. But consider this example in which the attributes not in the ConditionExpression affect the correctness of the update.



Suppose our item has 1 more attribute: canEdit, which is initially true. This time Request A is setting canEdit=false and Request B is setting values = list_append(values, "Bar").



If all attributes are not updated atomically, here's a possible sequence of events:




  • Request A – Check condition version==1 AND data=="Foo"

  • Request A – version = version+1

  • Request A – `data = "Foo"

  • Request B – Check condition canEdit==true

  • Request B – version = version+1

  • Request B – canEdit = true

  • Request A – canEdit = false

  • Request B – data = "Bar"


In both cases, the condition is true when initially evaluated, and in both cases, something the request wrote was overridden by the other request. DynamoDB will not allow both of these conditional updates to succeed, therefore DynamoDB must update all attributes in an item atomically because that is the only way to guarantee that either A or B will fail with a ConditionCheckException.



If my reasoning is correct, then in order for 1-3 to be true, 4 must be false, and all attributes in a single item are updated atomically.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 22 '18 at 11:39

























answered Nov 21 '18 at 20:12









Matthew PopeMatthew Pope

1,3921612




1,3921612













  • Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

    – AvielNiego
    Nov 22 '18 at 7:38













  • It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

    – Matthew Pope
    Nov 22 '18 at 7:42











  • that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

    – AvielNiego
    Nov 22 '18 at 8:21











  • Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

    – Matthew Pope
    Nov 22 '18 at 11:39



















  • Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

    – AvielNiego
    Nov 22 '18 at 7:38













  • It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

    – Matthew Pope
    Nov 22 '18 at 7:42











  • that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

    – AvielNiego
    Nov 22 '18 at 8:21











  • Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

    – Matthew Pope
    Nov 22 '18 at 11:39

















Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

– AvielNiego
Nov 22 '18 at 7:38







Thanks! I can't find any evidence in the docs that the update on a single item is atomic. I do not care that the lists change after I found that they are equal

– AvielNiego
Nov 22 '18 at 7:38















It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

– Matthew Pope
Nov 22 '18 at 7:42





It doesn’t directly state that an update is atomic, but in order to make the atomic counter described here, UpdateItem must be an atomic operation. docs.aws.amazon.com/amazondynamodb/latest/developerguide/…

– Matthew Pope
Nov 22 '18 at 7:42













that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

– AvielNiego
Nov 22 '18 at 8:21





that's right, but in this example, there is only one field that is being updated, so I can be sure that this field is locked. But I can't be sure that the whole item gets locked

– AvielNiego
Nov 22 '18 at 8:21













Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

– Matthew Pope
Nov 22 '18 at 11:39





Updated my answer with a slightly more detailed explanation of how I reached my conclusion.

– Matthew Pope
Nov 22 '18 at 11:39


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53417879%2fdynamodb-appending-to-multiple-lists-atomically%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

To store a contact into the json file from server.js file using a class in NodeJS

Redirect URL with Chrome Remote Debugging Android Devices

Dieringhausen