DynamoDB appending to multiple lists atomically
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
add a comment |
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
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
add a comment |
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
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
java amazon-dynamodb atomic
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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:
- A conditional write is entirely successful for the item if the condition is true.
- A conditional write is rejected if the condition is false.
- Conditional writes can be used for
Optimistic Locking with Version Number. - 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.
Thanks! I can't find any evidence in the docs that theupdate
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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:
- A conditional write is entirely successful for the item if the condition is true.
- A conditional write is rejected if the condition is false.
- Conditional writes can be used for
Optimistic Locking with Version Number. - 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.
Thanks! I can't find any evidence in the docs that theupdate
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
add a comment |
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:
- A conditional write is entirely successful for the item if the condition is true.
- A conditional write is rejected if the condition is false.
- Conditional writes can be used for
Optimistic Locking with Version Number. - 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.
Thanks! I can't find any evidence in the docs that theupdate
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
add a comment |
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:
- A conditional write is entirely successful for the item if the condition is true.
- A conditional write is rejected if the condition is false.
- Conditional writes can be used for
Optimistic Locking with Version Number. - 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.
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:
- A conditional write is entirely successful for the item if the condition is true.
- A conditional write is rejected if the condition is false.
- Conditional writes can be used for
Optimistic Locking with Version Number. - 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.
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 theupdate
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
add a comment |
Thanks! I can't find any evidence in the docs that theupdate
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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