Why CAS retry count is ignored from MapOptions

Hi, I am using Couchbase client - Java SDK - 3.0.8.
I have noticed my CAS retry count for map operation is ignored (always default of 10).

I am accessing default collection as a map:

defaultCollection().map(docId, Long.class, mapOptions).remove(key)

Here is how I set mapOptions:

return MapOptions.mapOptions()
            .casMismatchRetries(casRetriesCount)

However, when inspecting CouchbaseMap constructor (invoked by that map(…) method)
there, CAS retry count is ignored (excerpt from CouchbaseMap constructor):

MapOptions mapOpts = MapOptions.mapOptions();
optionsIn.copyInto(mapOpts);
this.mapOptions = mapOpts.build();

as copyInto method does:

    public void copyInto(CommonDatastructureOptions<?> c) {
        c.retryStrategy((RetryStrategy)this.retryStrategy().orElse((Object)null));
        c.timeout((Duration)this.timeout().orElse((Object)null));
        c.clientContext(this.clientContext());
    }

Why is this the case? I mean I’d like to allow CB client to perform more retry attempts than default of 10.
I mean, Java SDK documentation topic elaborates on this saying that due to optimistic locking semantics
developers could opt for adjusting retry attempts.

Any help/tip/suggestion/advice is very welcome.

Thanks

I have just inspected other data structure operations and none of them honors
client provided CAS mismatch retries value.

Could someone shed some light on why API allows for this option to be set
but then completely ignores it. That is pretty counter-intuitive in sense of exposed API and it’s usage…

Hi @rastko.soskic, I agree, this appears to be a bug. I’ve filed https://issues.couchbase.com/browse/JCBC-1743 to address it, and thank you for the report.
That said - the default is 10 retries, and honestly if the document is so contended by multiple actors that you are regularly hitting that limit, then you might want to consider something more bespoke, for efficiency.
Under the hood the CouchbaseMap is simply a document that is being written to with Sub-Document mutations. CAS is used (which requires fetching the document’s CAS first, an additional read), as it’s a generic model that needs to be safe for any kind of usage. But if you can instead model a shared document so that multiple actors are guaranteed to not overwrite each other’s changes, you don’t need CAS, and concurrent updates will become more efficient. Any contention will be resolved via retries on the server, so it doesn’t require the network round-trips incurred by application-side retries.
That modelling can be easier said than done of course. One very useful technique is to have each actor writing unique keys (could be UUIDs) into a JSON object/map in the document. And the Sub-Document arrayAppend and arrayAddUnique operations can be helpful too.

1 Like

Thanks @graham.pople, I have turned to other way as per your suggestion.
Turned to doc per agent instead of key per agent. I tried this way first as that
how it was logically fit into application. I will have to revamp app, but what da hell
that is developer’s life :slight_smile:

Marked your answer as solution not because it solves my problem but rather because
of your suggestion which turned me to seek solution other way around :grinning_face_with_smiling_eyes:

Good to hear you have a solution now.