Consistent read
Until the February 24, 2010 release SimpleDB only supported eventually
consistent reads. This meant that a read (using Select or GetAttributes) might
not reflect the result of a recently completed write (using
PutAttributes, BatchPutAttributes or DeleteAttributes) for a small
period of time, usually about a second. Yet there is a class of
applications that needs a read to reflect the outcome of the most
recent, successfully completed write. In order to facilitate
building such applications SimpleDB now also supports consistent
read (using Select or GetAttributes with ConsistentRead=true)
that returns a result that reflects all writes that received
a successful response (HTTP status code 200) prior to the read.
API changes:
Select & GetAttributes request parameters are enhanced to
include an optional Boolean flag ConsistentRead set to false by
default.
If ConsistentRead is absent or set to false, SimpleDB will
default to eventually consistent read.
If ConsistentRead is set to true, SimpleDB will return a
consistent read.
Consistent read vs. eventually consistent read
To illustrate SimpleDB’s consistent read and eventually
consistent read semantics in the context of concurrent applications,
let us consider the following three scenarios where two independent
SimpleDB clients (1, 2) (they can be processes or threads) issue
concurrent PutAttributes (W1, W2) and GetAttributes (R1, R2) calls on
the time-line shown below as seen by the client application.
The details of the concurrent calls using REST syntax (pseudo
code):
W1
https://sdb.us-west-1.amazonaws.com?Action=PutAttributes&
DomainName=MyDomain&ItemName=Item1&
Attribute.1.Name=Attr1&Attribute.1.Value=10&
Attribute.1.Replace=true&...
W2
https://sdb.us-west-1.amazonaws.com?Action=PutAttributes&
DomainName=MyDomain&ItemName=Item1&
Attribute.1.Name=Attr1&Attribute.1.Value=20&
Attribute.1.Replace=true&...
Consistent reads (R1, R2)
https://sdb.us-west-1.amazonaws.com?Action=GetAttributes&
DomainName=MyDomain&ItemName=Iteam1&
AttributeName.1=Attr1&ConsistentRead=true&...
Eventually consistent reads (R1, R2)
https://sdb.us-west-1.amazonaws.com?Action=GetAttributes&
DomainName=MyDomain&ItemName=Iteam1&
AttributeName.1=Attr1&...
Scenario 1: no R/W or W/W overlap

Results:
If R1 and R1 are consistent reads then both R1 and R2 will
return Att1 = 20.
If R1 and R2 are eventually consistent reads then R1 and R2
may return Attr1 = 10 or Attr1 = 20 or no results
(<GetAttributesResult/>). Plus R1 and R2 may return different
results or the same results.
Scenario 2: R/W overlap
Client 1 receives a success on write W1 before it issues R1.
There is an overlap between W2 & R1.
Client 2 receives a success on write W2 before it issues R2.
There is no overlap between W1 and W2.

Results:
If R1 is a consistent read then it will return either Attr1 =
10 or Attr1 = 20 since there is an overlap between R1 and W2. If R2
is a consistent read, it will return Attr1 = 20 since there is no
overlap between W2 and R2 or between W1 and W2.
If R1 and R2 are eventually consistent reads then R1 and R2
may return Attr1 = 10 or Attr1 = 20 or no results
(<GetAttributesResult/>). Plus R1 and R2 may return different
results or the same results.
Scenario3: W/W overlap

Results:
If R1 and R2 are consistent reads then both R1 and R2 will
return the same results but it can be either Attr1 = 10 or Attr1 =
20 since there is an overlap between W1 and W2.
If R1 and R2 are eventually consistent reads then R1 and R2
may return Attr1 = 10 or Attr1 = 20 or no results
(<GetAttributesResult/>). Plus R1 and R2 may return different
results or the same result.
Note:
When two clients make a request that operates on the same set of items
before one of them receives a response, the requests are considered “overlapped”.
When there is a R/W or W/W overlap the clients have no control over the
order in which SimpleDB may receive/process their requests.
For example, in scenario 3, even though from a client's perspective
W1 is issued before W2, due to network latency issues SimpleDB may
receive W2 first. In which case W1 will overwrite W2 and the consistent
reads R1 and R2 will return Attr1 = 10. Similarly in Scenario 2,
SimpleDB may receive consistent read R1 before W2 resulting in
Attr1 = 10 for R1. Therefore the client perception of which came
first may not necessarily equal server side processing.
The table below summarizes the characteristics of the two SimpleDB
read consistency options:
| Eventually consistent read |
Consistent read |
|
Stale reads possible Lowest read latency Highest read
throughput
|
No stale reads Potential higher read latency Potential
lower read throughput
|
Since consistent reads can potentially incur higher latency and
lower read throughput it is best to use them only when an application
scenario mandates that a read operation absolutely needs to read all
writes that received a successful response prior to that read. For
all other scenarios eventually consistent reads will yield
the best performance.
Conditional put and delete
Many developers have asked for primitives in SimpleDB for
implementing optimistic concurrency control, counters, etc. The new
conditional put and delete features in SimpleDB enable building these
primitives.
Conditional put allows inserting or replacing one or more
attributes of an item if the current consistent value of a
single-valued attribute (Expected.1.Name) of the item has a specified
expected value (Expected.1.Value) or if the attribute does not exist
(Expected.1.Exists = false).
Conditional delete allows deleting an item or one or more
attributes of an item if the current consistent value of a
single-valued attribute (Expected.1.Name) of the item has a specified
expected value (Expected.1.Value) or if the attribute does not exist
(Expected.1.Exists = false).
API changes:
PutAttributes and DeleteAttributes APIs are enhanced to
support an optional update condition (Expected.1.Name = [AttributeName] and
(Expected.1.Value = [AttributeValue] or Expected.1.Exists =
[true/false]).
The Expected.1.Value or Expected.1.Exists parameter can be
populated by an application from a prior read. Since a conditional
put/delete ensures that the condition check happens with a
current consistent value of Expected.1.Name attribute,
Expected.1.Value or Expected.1.Exist can be populated by a prior
eventually consistent read or a fully consistent read. Eventually
consistent read is strongly recommended given that the subsequent
conditional update or delete will enforce consistency.
If the update condition is satisfied then PutAttributes or
DeleteAttributes action is performed.
The Expected.1.Exists parameter allows a developer to test if
an attribute exists.If Expected.1.Exists is set to false,
then the attribute must not exist at all for the item for the
conditional put/delete to succeed. Pass in Expected.1.Name, but not
Expected.1.Value.
If Expected.1.Exists is set to true, then the
attribute must contain a particular value. Pass in Expected.1.Name
and Expected.1.Value.
If the current value does not match the expected value or if
the current value is multi-valued the conditional put/delete is
rejected with SimpleDB error code ConditionalCheckFailed or
MultiValuedAttribute (HTTP status code 409). If the attribute is
gone altogether, the put/delete is rejected with SimpleDB error code
AttributeDoesNotExist (HTTP status code 404). See appendix for a
complete list of static and dynamic errors.
Note: The condition check can be
performed on only one attribute in the current release.
Sample usage scenarios
Persistant application state
A developer can store application in-memory state in SimpleDB. As
the value of the application state changes, the application can
update SimpleDB. If the application goes down and needs to be
restarted then the application can issue a consistent GetAttributes
or Select call to SimpleDB to obtain the last updated application
state.
Update Application1's State
https://sdb.us-west-1.amazonaws.com?Action=PutAttributes&
Version=2009-04-15&DomainName=MyDomain&
ItemName=Application1&Attribute.1.Name=State&
Attribute.1.Value=1&Attribute.1.Replace=true&...
Get
application state with ConsistentRead=true
https://sdb.us-west-1.amazonaws.com?Action=GetAttributes&
Version=2009-04-15&DomainName=MyDomain&
ItemName=Application1&AttributeName.1=State&
ConsistentRead=true&...
Get response
<?xml version="1.0"encoding="UTF-8"?>
<GetAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
<GetAttributesResult>
<Attribute> <Name>State</Name> <Value>1</Value></Attribute>
</GetAttributesResult>
<ResponseMetadata>
<RequestId>acf9a4a6-b909-fc71-6ec0-fb1adc952670</RequestId>
<BoxUsage>0.0000093222</BoxUsage>
</ResponseMetadata>
</GetAttributesResponse>
Optimistic concurrency control
An application can implement optimistic concurrency
control (OCC) by maintaining a version number (or a timestamp)
attribute as part of an item and by performing a conditional put/delete
based on the value of this version number attribute.
Eventually consistent "select * from MyDomain
where itemName() = 'I1'"
https://sdb.us-west-1.amazonaws.com?Action=Select&
Version=2009-04-15&
SelectExpression=select%20*%20from%20MyDomain%20where%20itemName()%20%3D%20'I1'&
ConsistentRead=false&...
Select response
<?xml version="1.0"?>
<SelectResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
<SelectResult>
<Item>
<Name>I1</Name>
<Attribute><Name>A1</Name><Value>V1</Value></Attribute>
<Attribute><Name>VersionNumber</Name><Value>30</Value>
</Attribute>
</Item>
</SelectResult>
<ResponseMetadata>
<RequestId>97bbd6e2-9151-583e-b744-f6337a6e7fd6</RequestId>
<BoxUsage>0.0000228616</BoxUsage>
</ResponseMetadata>
</SelectResponse>
Conditional put
https://sdb.us-west-1.amazonaws.com?Action=PutAttributes&
Version=2009-04-15&DomainName=MyDomain&ItemName=I1&
Attribute.1.Name=A1&Attribute.1.Value=V2&Attribute.1.Replace=true&
Attribute.2.Name=VersionNumber&Attribute.2.Value=31&
Attribute.2.Replace=true&
Expected.1.Name=VersionNumber&Expected.1.Value=30&...
In the example above the application does a conditional put of an
item I1 and sets the value of attribute A1 to V2 only if the
VersionNumber has a value of 30. This application reads the value of
VersionNumber (30) as part of a prior eventually consistent select of
this item I1. The conditional put will fail if another application changed
I1, in which case it would have changed the value of VersionNumber to
something other than 30.
Thus, conditional put/delete can ensure that there will be no lost
updates when concurrent writers write to the same item/attribute.
However for OCC to work correctly, all writes should use
conditional puts or deletes. Otherwise, there may be lost updates.
Counters
Conditional put can also be used to implement counters. For
example the application could issue a GetAttributes call to retrieve
the current page hits for the www.amazon.com web page (121), and then
write the new value 122 using the PutAttributes API only if no one
else has updated it in the meanwhile:
Get PageHits
https://sdb.us-west-1.amazonaws.com?Action=GetAttributes&
Version=2009-04-15&DomainName=MyDomain&
ItemName=www.amazon.com&AttributeName.1=PageHits&...
Get response
<?xml version="1.0"?>
<GetAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
<GetAttributesResult>
<Attribute>
<Name>PageHits</Name><Value>120</Value>
</Attribute>
</GetAttributesResult>
<ResponseMetadata>
<RequestId>15621753-0330-6df0-040e-2a5d0cadee65</RequestId>
<BoxUsage>0.0000093222</BoxUsage>
</ResponseMetadata>
</GetAttributesResponse>
Conditionally put PageHits=121 only if PageHits = 120
https://sdb.us-west-1.amazonaws.com?SignatureVersion=1&
Action=PutAttributes&Version=2009-04-15&
DomainName=MyDomain&ItemName=www.amazon.com&
Attribute.1.Name=PageHits&Attribute.1.Value=121&
Attribute.1.Replace=true&
Expected.1.Name=PageHits&Expected.Value=120&...
Notice that the GetAttributes API call that retrieves the current
counter does not need to be a consistent read. If a stale value was
to be read, the subsequent write would be rejected by the system. If
the counter is updated frequently it might be necessary to retry,
re-reading the updated counter value upon failure.
Delete item if an attribute matches a certain value
For example, an application could delete an item I1 from Inventory
only as long as the balance attribute has value equal to 0 by issuing
a DeleteAttributes call with the following parameters:
https://sdb.us-west-1.amazonaws.com?Action=DeleteAttributes&
Version=2009-04-15&DomainName=MyDomain&ItemName=I1&
Expected.1.Name=balance&Expected.1.Value=0&...
Insert an item only if it does not exist
In the example below item Item1 is inserted only if item Item1
does not have an attribute Attr1. If the application logic ensures
that all items have a value for attribute Attr1, then this operation
will succeed if and only if item Item1 does not exist already.
https://sdb.us-west-1.amazonaws.com?Action=PutAttributes&
Version=2009-04-15&DomainName=MyDomain&
ItemName=Item1&Attribute.1.Name=Attr1&
Attribute.1.Value=20&
Expected.Name=Attr1&Expected.Exists=false&...
Conclusion
The strong consistency exposed by SimpleDB via consistent read and
conditional put/delete complements eventually consistent reads
and makes it easier to program key database application scenarios
with SimpleDB. In addition to high availability and scale, SimpleDB
developers can now pick the right level of read consistency and build
richer applications.
Appendix: List of static and dynamic errors for conditional put
and delete
Static Errors
| # |
Example |
Http status |
SimpleDB error code |
SimpleDB error message |
Notes |
|
1
|
Expected.1.Name = Attr1 Expected.1.Value =
10 Expected.1.Exists = false
|
400
|
ExistsAndExpectedValue
|
Expected.Exists=false and Expected.Value cannot be
specified together
|
Expected Value and Exists cannot be specified together.
|
|
2
|
Expected.1.Name = Attr1 Expected.1.Value = (not set)
Expected.1.Exists = true
|
400
|
IncompleteExpectedValue
|
If Expected.Exists = true or unspecified, then
Expected.Value has to be specified
|
Cannot perform a conditional put/delete on existence of an
attribute without specifying the value.
|
|
3
|
Expected.1.Name = (not set) Expected.1.Value = some value
Expected.1.Exists = true/false
|
400
|
MissingParameter
|
The request must contain the parameter Name
|
Expected Name is missing.
|
|
4
|
Expected.1.Name = Attr1 Expected.1.Value = 10
Expected.1.Exists = (value other than true or false)
|
400
|
InvalidParameterValue
|
Value (x) for parameter Expected.Exists is invalid.
Expected.Exists should be either true or false.
|
Value for Exists must be either true or false.
It is case insensitive.
|
|
5
|
Expected.1.Name = Attr1 Expected.2.Name = Attr2
Expected.1.Value = 10 Expected.1.Exists = true (or not
set)
|
400
|
MultipleExpectedNames
|
Only one Expected.Name can be specified
|
In this release we allow conditional check on only one single
valued attribute.
|
|
6
|
Expected.1.Name = Attr1 Expected.1.Value = 20
Expected.2.Value = 10 Expected.1.Exists = true (or not
set)
|
400
|
MultipleExpectedValues
|
Only one Expected.Value can be specified
|
In this release we allow conditional check on only one single
valued attribute.
|
|
7
|
Expected.1.Name = Attr1 Expected.1.Value = 20
Expected.1.Exists = true Expected.2.Exists = true
|
400
|
MultipleExistsConditions
|
Only one Exists condition can be specified
|
In this release we allow conditional check on only one single
valued attribute.
|
|
8
|
Expected.1.Name = Attr1 Expected.1.Value = 10
Expected.1.Exists = true (or not set)
|
400
|
InvalidWSDLVersion
|
Parameter (" + parameterName +") is only
supported in WSDL version 2009-04-15 or beyond. Please upgrade to
new version
|
Conditional put/delete is not allowed from WSDL version
2007-11-07. Upgrade to 2009-04-15.
|
|
9
|
Expected.1.Name = Attr1 Expected.1.Value = (value >
1024 bytes) Expected.1.Exists = true (or not set)
|
400
|
InvalidParameterValue
|
Value (" + value + ") for parameter Value is
invalid. Value exceeds maximum length of 1024
|
Attribute value cannot be greater than 1024 bytes.
|
|
10
|
Expected.1.Name = (empty) Expected.1.Value = 10
Expected.1.Exists = true (or not set)
|
400
|
InvalidParameterValue
|
- Value (" + value + ") for parameter Name is
invalid.The empty string is an illegal attribute name
|
Expected Name cannot be an empty string. It has to be a valid
attribute name.
|
Dynamic Errors
| # |
Example |
Http status |
SimpleDB error code |
SimpleDB error message |
Notes |
|
1
|
Expected.1.Name = Attr1 Expected.1.Value = 10
Expected.1.Exists = true (or not set)
|
404
|
AttributeDoesNotExist
|
Attribute (Attr1) does not exist
|
If Attr1 does not exists then a conditional check will fail.
|
|
2
|
Expected.1.Name = Attr1 Expected.1.Value = 10
Expected.1.Exists = true (or not set)
|
409
|
MultiValuedAttribute
|
Attribute (Attr1) is multi valued. Conditional check can
only be performed on a single-valued attribute
|
If Attr1 is multi-valued then a conditional put/delete will fail.
|
|
3
|
Expected.1.Name = Attr1 Expected.1.Value = 20
Expected.1.Exists = true (or not set)
|
409
|
ConditionalCheckFailed
|
Conditional check failed. Attribute (Attr1) value is (10)
but was expected (20)
|
Attr1's value is 10 so the conditional check failed.
|
|
4
|
Expected.1.Name = Attr1 Expected.1.Value = (not set)
Expected.1.Exists = false
|
409
|
ConditionalCheckFailed
|
ConditionalCheckFailed: Conditional check failed. Attribute
(Attr1) value exists
|
Attr1 exists so the conditional put/delete failed.
|
|