Skip to content
This repository was archived by the owner on Aug 13, 2026. It is now read-only.
This repository was archived by the owner on Aug 13, 2026. It is now read-only.

Detect non-existing keys for CRDTs [JIRA: CLIENTS-552] #536

Description

@TimurFayruzov

There is a semantic difference between non-existing key and a default value may me important for downstream consumers. However, CRDT queries return default values: 0 for a counter and empty set for a set. My following examples are in Scala:

val fetchOp = new FetchCounter.Builder(location).build()
val c = client.execute(fetchOp).getDatatype // if I get 0, does the key exist in store?

For counters, there is a workaround that involves an additional query:

val fetchOp = new FetchValue.Builder(location).withOption(FetchValue.Option.HEAD, java.lang.Boolean.TRUE).build()
val res = client.execute(fetchOp) // res.isNotFound should equal(true). 
// Why isNotFound not supported by CRDTs?

For sets, there seem to be a hack that a context object should be null if set did not exist before (not sure if it's a valid way though).

The concept of non-existing key is important enough to support it explicitly (like with regular objects in the snippet above).

Activity

  1. changed the title [-]Detect non-existing keys for CRDTs[/-] [+]Detect non-existing keys for CRDTs [JIRA: CLIENTS-552][/+] on Aug 24, 2015
  2. alexmoore commented on Aug 5, 2016

    @alexmoore
    Contributor

    So another way around this for now is to set the "NotFoundOK" option on the command/operation to false, and then check the status of the future when it returns.

    Location location = new Location(new Namespace(mapBucketType, bucketName), "404");
    DtFetchOperation fetch = new DtFetchOperation.Builder(location).withNotFoundOK(false).build();
    final RiakFuture<DtFetchOperation.Response, Location> future = cluster.execute(fetch);
    
    future.await();
    assertFalse(future.isSuccess()); // isSuccess = false because notFound is not ok
    assertNotNull(future.get()); // Still returns new object.

    If you set .withNotFoundOK(false), the isSuccess() property should be false for a "new" dataType, but future.get() will still return the new datatype object.

  3. alexmoore commented on Aug 5, 2016

    @alexmoore
    Contributor

    Digging into the implementation a little more today:

    https://github.com/basho/riak_pb/blob/develop/src/riak_dt.proto#L113-L132

    When the value field is missing from the message, the client should interpret it as a "not found".

    Right now we just grab the value without seeing if it's there or not, which gives us the default value that the PB lib provides:

    public RiakDatatype convert(RiakDtPB.DtFetchResp response)
    {
    RiakDatatype element;
    switch (response.getType())
    {
    case COUNTER:
    element = new RiakCounter(response.getValue().getCounterValue());
    break;
    case MAP:
    element = parseMap(response.getValue().getMapValueList());
    break;
    case SET:
    element = parseSet(response.getValue().getSetValueList());
    break;
    default:
    throw new IllegalStateException("No known datatype returned");
    }
    return element;
    }

    I'll add a "notFound" parameter to the response object and check that property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions