Optimistic Concurrency

The Content Store relies on a technique called optimistic concurrency to deal with concurrent updates to content items. Clients are expected to co-ordinate updates between themselves using optimistic concurrency mechanisms. For background information about this technique, see http://www.w3.org/1999/04/Editing/.

Clients are required to either make active use of optimistic concurrency when updating content, or explicitly bypass it (not recommended), so you need to understand this section in order to make a client that will update content items.

Optimistic concurrency works as follows:

  1. Each client that wants to make a modification to a content item downloads a copy of it. Each item is accompanied by an HTTP header called ETag. An Etag header is a unique identifier generated by the web service, and looks something like this:

    ETag: "129694559e911ee4c6d04212982"
  2. Each client remembers the ETag associated with the content item it is modifying.

  3. After modifying the content item, the client performs a PUT operation to return it to the web service, including its ETag in an If-Match header. Note that an ETag value includes its enclosing quote marks. A correct PUT operation executed with curl would therefore look something like this:

    curl --include -u user:password -X PUT -H 'If-Match: "129694559e911ee4c6d04212982"' \
    > -H "Content-Type: application/atom+xml" http://host-ip-address/webservice/escenic/content/4 \
    > --upload-file my-edited-article.xml
  4. The web service checks the supplied Etag to see if it matches the current copy of the content item. For the first client to return changes, this will be the case, and the PUT operation will succeed. For all other clients that have been working on the content item, the Etag will not match and the web service will return a 412 PRECONDITION FAILED response.

When a client receives a 412 PRECONDITION FAILED response it should download the latest copy of the content item (with its new ETag), re-apply its changes to the new copy, and then PUT it back, hopefully succeeding this time. If more than two clients are working on the same copy, however, this might not be the case. In the worst case a client might need to retry many times. Clients should be able to handle a certain number of retries, back off after a few retries, and lower the rate of retry, and possibly even request human intervention.

A client can circumvent the optimistic concurrency mechanism by sending the header "If-Match: *" in its PUT operations. This header specifies that the operation should succeed no matter which version is current. The web service will then accept the PUT request without performing any concurrency checks. The consequence of doing so is that any changes made to the content item by other clients will be overwritten. Your client should therefore never do this unless you know the consequences and are certain that it will not cause problems.