This page walks you through a simple demonstration of performing compare-and-swap (CAS) in TiKV.

In RawKV, compare-and-swap (CAS) is an atomic instruction to achieve synchronization between multiple threads.

Performing CAS is an atomic equivalent of executing the following code:

  1. prevValue = get(key);
  2. if (prevValue == request.prevValue) {
  3. put(key, request.value);
  4. }
  5. return prevValue;

The atomicity guarantees that the new value is calculated based on the up-to-date information. If the value is updated by another thread at the same time, the write would fail.

Prerequisites

Make sure that you have installed TiUP, jshell, download tikv-client JAR files, and start a TiKV cluster according to TiKV in 5 Minutes.

Verify CAS

To verify whether CAS works, take the following steps.

Step 1: Write the code to test CAS

Save the following script to the test_raw_cas.java file.

  1. import java.util.Optional;
  2. import org.tikv.common.TiConfiguration;
  3. import org.tikv.common.TiSession;
  4. import org.tikv.raw.RawKVClient;
  5. import org.tikv.shade.com.google.protobuf.ByteString;
  6. TiConfiguration conf = TiConfiguration.createRawDefault("127.0.0.1:2379");
  7. // enable AtomicForCAS when using RawKVClient.compareAndSet or RawKVClient.putIfAbsent
  8. conf.setEnableAtomicForCAS(true);
  9. TiSession session = TiSession.create(conf);
  10. RawKVClient client = session.createRawClient();
  11. ByteString key = ByteString.copyFromUtf8("Hello");
  12. ByteString value = ByteString.copyFromUtf8("CAS");
  13. ByteString newValue = ByteString.copyFromUtf8("NewValue");
  14. // put
  15. client.put(key, value);
  16. System.out.println("put key=" + key.toStringUtf8() + " value=" + value.toStringUtf8());
  17. // get
  18. Optional<ByteString> result = client.get(key);
  19. assert(result.isPresent());
  20. assert("CAS".equals(result.get().toStringUtf8()));
  21. System.out.println("get key=" + key.toStringUtf8() + " result=" + result.get().toStringUtf8());
  22. // cas
  23. client.compareAndSet(key, Optional.of(value), newValue);
  24. System.out.println("cas key=" + key.toStringUtf8() + " value=" + value.toStringUtf8() + " newValue=" + newValue.toStringUtf8());
  25. // get
  26. result = client.get(key);
  27. assert(result.isPresent());
  28. assert("NewValue".equals(result.get().toStringUtf8()));
  29. System.out.println("get key=" + key.toStringUtf8() + " result=" + result.get().toStringUtf8());
  30. // close
  31. client.close();
  32. session.close();

Step 2: Run the code

  1. jshell --class-path tikv-client-java.jar:slf4j-api.jar --startup test_raw_cas.java

The example output is as follows:

  1. put key=Hello value=CAS
  2. get key=Hello result=CAS
  3. cas key=Hello value=CAS newValue=NewValue
  4. get key=Hello result=NewValue

As in the example output, after calling compareAndSet, the value CAS is replaced by newValue.

  • To ensure the linearizability of CAS when it is used together with put, delete, batch_put, or batch_delete, you must set conf.setEnableAtomicForCAS(true).

  • To guarantee the atomicity of CAS, write operations such as put or delete in atomic mode take more resources.