Return CASValue on initial set Java SDK 1.1.5 (updated question)

Is there a way to do an initial set with CAS and return a CASValue without having to do an add or set followed by a gets()?

Perhaps there is a util to generate an initial long unique cas id?

1 Answer

« Back to question.

The OperationFuture class has a getCas() function. Call that on the object returned by the initial set and pass that cas into your next operation.

@mikew Thank you. That was exactly what I needed.

OperationFuture future = cache.getNativeCache().set(key, 0, "a value");
long cas = future.getCas();
// Try to update with CAS
CASResponse casResponse = cache.cas(key, cas, "some other value");
assert(casResponse.equals(CASResponse.OK));

I do have a follow on question to this. We are trying to use Couchbase in a dual r/w scenario whereby we are reading and writing to 2 different clusters.

In this type of scenario it appears as though the CAS will not work because there is no way to set an initial value with a CAS either generated from some operation other than Couchbase generating the CAS on initial set/add.

I did create a test whereby I pulled the Long cas value from the initial set and tried to use that to do a cas operation on a non existing key/value in another cluster.

Here is the scenario:

OperationFuture future = cacheCluster1.set("key_1", 0, "a value:);
long cas = future.getCas();
// Try a cas operation on a non existing entity in cluster 2
CASResponse reponse = cacheCluster2.set("key_1", 0, "a value:);
// response will be CASResponse.NOT_FOUND

I understand the NOT_FOUND is the expected behavior, but is there a way to set/add an initial value while providing a unique cas id?

Managing 2 cas values for each key value set to their respective clusters will be cumbersome.

There is not a way to set the cas value to a specific value. I am curious though as to why you plan on keeping the cas value for each key in your application?

"There is not a way to set the cas value to a specific value. I am curious though as to why you plan on keeping the cas value for each key in your application?"

I was thinking that the cas value would be used for subsequent set operations in order to prevent updating a newer value or in other words using the cas in a typical optimistic locking scenario. It sounds like maybe I'm thinking about this the wrong way? If so please advise.

The intention is to set and return the cas to the client so that the client could use the cas in a future set operation and to prevent writing to a newer (dirty) record.

Most of the applications I have seen usually follow a read-modify-update pattern. The problem that cas is trying to solve is if two clients are doing following this pattern on the same key at the same time. Both clients will read a document in its original state and then modify the document. The problem is when they both go to update the document. If both clients update the document differently then whoever writes the document last wins and the client who wrote the document first will lose their changes. The cas value solves this problem. On the initial read both clients get the the same value and both clients supply that value on their subsequent write. The first client will do it's write and succeed and the server will change the cas value. When the second client writes to the same key the write will fail because the cas value is different. The second client will now know that the value for this key has changed and that the operation should be retried. Depending on the application this can mean different things. A user who filled out a form might need to do it again or the application may need to try to resolve conflicts between the two documents on it's own.

If your use case doesn't fit in this model please let me know why and maybe I can suggest a few other ideas I have seen other people using.

Thanks for that explanation.

Our use case could be considered as usage of Couchbase to store HTTP Session related data. This doesn't really fit the read-modify-update pattern as you describe. We have stateless transactions modifying session related data and we want to try to ensure that a write operation will fail if the write operation is trying to modify data that is newer.

Example:

Session is written with version of: v1 and v1 is sent back to the client.

Client 1 has modified session with v1 and writes to couchbase
Client 2 has modified session with v1 and writes to couchbase with the desired result being a failure.

I was hoping to use the cas which may be possible but for our case we need to write and read to 2 Couchbase clusters so I believe the cas is out and we will need to perhaps manage this version within a value wrapper of some type.

If you have any suggestions please do share.