If you need to coordinate shared access on documents, Couchbase
helps you with two approaches. Depending on the application you
may need to use both of them, but in general it is better (if
feasible) to lean towards CAS because it
provides the better performance characteristics.
Optimistic Locking with cas(): Each
document has a unique identifier associated with it (the
CAS value), which changes when the
document itself is mutated. You can fetch the
CAS value for a given key and then use
the cas() operation to update it. The
update will only succeed, when the CAS
value is still the same. This is why it's called optimistic
locking: someone else can still read and try to update the
document, but it will fail once the CAS
value has changed. Here is a example on how to do it with
the Java SDK:
// Reads the document with the CAS value. String key = "eagle_brewing-golden"; CASValue<Object> beerWithCAS = client.gets(key); // Updates the document and tries to store it back. Beer beer = gson.fromJson((String)beerWithCAS.getValue(), Beer.class); beer.name = "Some other Name"; CASResponse cas = client.cas(key, beerWithCAS.getCas(), gson.toJson(beer));
The CASResponse is a ENUM which
identifies the status of the cas()
operation. If it succeeds, CASResponse.OK
is returned. If CASResponse.EXISTS is
returned, the CAS has changed in the meantime. A common
approach is to run the script shown above (the whole
fetch-and-update process) in a loop until the operation did
succeed. Depending on your application, you may need to do
conflict management as well.
Note that this also means that all your application need to
follow the same code path (cooperative locking). If you use
set() somewhere else in the code on the
same document, it will work even if the
CAS itself is out of date (that's because
the normal set() method doesn't care
about those values at all). Of course, the
CAS itself changes then and the
cas() operation would fail afterwards.
Pessimistic Locking with getAndLock(): If
you want to lock a document completely (or an object graph),
you can use the getAndLock() method.
Other threads can still run get() queries
against the document, but set()
operations without a CAS will fail.
// Get with Lock String key = "eagle_brewing-golden"; CASValue<Object> beer = client.getAndLock(key, 20); String beerJson = (String) beer.getValue(); // Try to set without the lock OperationFuture<Boolean> result = client.set(key, 0, beerJson); System.out.println(result.get()); // Prints false // Try to set with the CAS aquired CASResponse cas = client.cas(key, beer.getCas(), beerJson); System.out.println(cas); // Prints OK
Once you update the document, the lock will be released.
There is also the unlock() method
available through which you can unlock the document. You are
required to define how long the lock should be active (the
maximum is 30 seconds).