Amazon SimpleDB Consistency Enhancements

This document outlines the new strong consistency features inSimpleDB - consistent read and conditional put/delete. It alsodemonstrates how they can be used to program key database application scenarios such as persistent application state, concurrency control, item counter,and conditional update/delete.


Submitted By: Craig@AWS
AWS Products Used: Amazon SimpleDB
Created On: February 24, 2010


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

  • Clients 1 and 2 received successful responses on writes W1 and W2 before issuing R1 and R2.

  • There is no overlap between the writes and between the writes and the reads.

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 (). 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 (). Plus R1 and R2 may return different results or the same results.

Scenario3: W/W overlap

  • Clients 1 & 2 receive successful responses from SimpleDB on writes W1 and W2 before issuing R1 & R2 respectively.

  • There is an overlap between W1 and W2.

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 (). 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



  State 1


 acf9a4a6-b909-fc71-6ec0-fb1adc952670
 0.0000093222

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


 
  
   I1
   A1V1
   VersionNumber30
   
  


  97bbd6e2-9151-583e-b744-f6337a6e7fd6
  0.0000228616



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



 
  PageHits120
 


 15621753-0330-6df0-040e-2a5d0cadee65
 0.0000093222



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.