Skip to content

Conditional PUTs - PB vs HTTP API #1849

Description

@martinsumner

The Protocol Buffers API supports conditional PUT using two options:

  • if_none_match; which will allow a PUT if an existing object is not present for that key.
  • if_not_modified; which will allow a PUT if an existing object is present for that key has the same vector clock as the inbound request.

These are not strict conditions. If either of these condition PUT options are present a GET request will be made before the riak-kv_put_fsm is started, and the conditional will be checked prior to the PUT. Parallel requests to update the same key will still lead to sibling objects (depending on allow_mult configuration). The conditions are a pre-PUT validation stage, not a strongly consistent constraint.

The HTTP API uses the standard webmachine REST workflow. This will support standard HTTP logic with regards to conditional PUTs:

One issue with implementation with the standard webmachine REST workflow, is that workflow will pass through the Resource Exists question for all HTTP methods (decision G7 in v3 of the workflow).

The resource_exists function in riak_kv_wm_object will attempt to GET the object in order to return the required boolean() response. However, in the case of a PUT, POST or DELETE without a conditional request header, fetching the resource is unnecessary.

There is also the issue of building the new object to replace the old. Regardless of any options provided in the request, the PB API will always start an empty object, and then replace each part with the information passed in. However, on the HTTP API it will start with the existing object, and then replace each part. These two methods are equivalent, but implementing them differently introduces risk of future variance in behaviour between the APIs. The majority of external testing uses the PB API - so it would be preferable wherever possible for the HTTP API to follow the same path.

There are three changes proposed:

  • Remove the fetch of the object in the HTTP API where conditional request headers are not provided on PUT/POST/DELETE.
  • Introduce a bespoke HTTP header X-Riak-If-Not-Modified: <encoded_vclock> which will behave precisely as the PB if_not_modified option.
  • Always start the building of a replacement object from an empty object within the HTTP API.

There is some additional complication with the first change in that the GET workflow for Riak requires the resource to be fetched prior to the resource_exists decision point (as the encoding of the will be as stored, so knowledge of this is required to validate the request). This will also need to be bypassed for PUT/POST/DELETE,

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions