Atomic list updates

#1

Newbee question:
How can multiple clients fetch a value from the shared list of values without two clients having a chance to fetch the same one?

#2

Could you perhaps rephrase the question or offer a use case? I’m not sure I understand what you’re trying to do based on the topic. The title for the topic mentions updates but then the question itself is about fetching. Also, what is the development language and version of SDK you’re using? Then I can be a bit more specific.

I’m guessing, but I think what you’ll want to look into is operations that use CAS. This may be an update() in the 2.0 SDKs and a cas() or set() with CAS argument operation in some of the 1.x SDKs.

#3

Latest NodeJS as a client.
Suppose you have a list of resources (item1 … item10).
Upcoming clients claim any available resource, use them for some pretty long time and return to the pool.
No two clients are allowed to use the same resource at the same time.

If I just put the list of the “still available” resources in the document and naively do read/modify/write, then there might be a race condition between two clients claiming the same resource.

I guess there is a mechanism in Couchbase to perform this fetch/update atomically and to avoid the race.

#4

The best way to model this with Couchbase would be to retrieve/modify/write each resource indicating it’s being used. The modify/write should use a CAS operation.

There are a couple of loopholes there though which can be closed up with some additions.

The first loophole is durability. It’s not guaranteed that a write is durable. You can express more durability requirements by adding the PersistTo and ReplicateTo options to your write.

The second loophole is that what if the client using that resource doesn’t release it withinin a reasonable period of time. One approach for that would be to store some kind of absolute time in the document after which the client will give up that resource. The other approach would be to store it in a separate document with a TTL.

For instance, if you wanted to have item1 taken by a client and then later returned, have two documents, “item1” and “item1:co” (for checkout).

Two actors, A and B, try to retrieve “item1:co”. Failing that, they both try to upsert() a new document named “item1:co” with a TTL of 300 seconds because they both expect to use no more than that amount of time to do their work.

Assume that actor “B” succeeds, and client “A” does not. Actor “B” will be able to do whatever it needs with the resource “item1”. Actor “A” can do a backoff/retry with “item1:co”.

Once actor “B” is done, it can remove the “item1:co” and then others can access that resource.

Failures may need other special handling, but using a TTL and CAS operations will get you most of the way there. Note that the cluster won’t guarantee any kind of locking or prevent mutation by erroneous actors, so that’ll be up to your program (and it’s tests) to verify correctness.

Hopefully that helps!

#5

Thanks, it definitely helps.