Memcached - Get CAS Data
Memcached - Atomic Updates with CAS
Section titled “Memcached - Atomic Updates with CAS”CAS (Check-And-Set) is a powerful Memcached feature that allows you to perform atomic read-modify-write operations. It prevents race conditions where multiple clients might try to update the same key simultaneously, potentially overwriting each other’s changes. The gets command is the first step in a CAS operation; it retrieves an item along with a unique 64-bit ‘CAS token’.
Syntax: The gets Command
Section titled “Syntax: The gets Command”The syntax is the same as get, but the server’s response includes an extra value: the CAS token.
gets keyCommand Line Example
Section titled “Command Line Example”# First, set a value to work withset user:profile 0 900 20{"name":"Alice","visits":10}STORED
# Now, use gets to retrieve the value and its CAS tokengets user:profileVALUE user:profile 0 20 52{"name":"Alice","visits":10}ENDIn the VALUE line, the number 52 is the unique CAS token for the current state of this item. This token must be sent back with the cas command to successfully update the item. If another client modifies the item first, the CAS token will change, and your update will fail.
Implementing a CAS Workflow in Java
Section titled “Implementing a CAS Workflow in Java”The complete Check-And-Set workflow involves three steps: 1) Use gets to retrieve the value and its token. 2) Modify the value in your application code. 3) Use cas to write the new value back, providing the original token. The update will only succeed if the token on the server still matches the one you provided.
Java Example
Section titled “Java Example”import net.spy.memcached.CASValue;import net.spy.memcached.CASResponse;import net.spy.memcached.MemcachedClient;import java.net.InetSocketAddress;
public class CasExample { public static void main(String[] args) { MemcachedClient mcc = null; try { mcc = new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211)); System.out.println("Connection to server successful.");
// 1. Initialize a value we want to modify atomically String key = "user:settings"; mcc.set(key, 900, "theme:dark").get(); // .get() waits for completion System.out.println("Initial value set to: 'theme:dark'");
// --- START of the CAS operation ---
// 2. Get the value and its CAS token CASValue<Object> casValue = mcc.gets(key); if (casValue == null) { System.err.println("Cache miss. Could not find key: " + key); return; // Exit if the key doesn't exist }
System.out.println("Retrieved value: '" + casValue.getValue() + "' with CAS token: " + casValue.getCas());
// 3. Modify the value in our application logic String newValue = "theme:light";
// 4. Attempt to update using the cas() command // The cas method takes: key, original CAS token, expiration, and the new value. CASResponse response = mcc.cas(key, casValue.getCas(), 900, newValue);
System.out.println("Attempting CAS update with new value '" + newValue + "'..."); System.out.println("CAS Operation Result: " + response);
if (response == CASResponse.OK) { System.out.println("Update successful!"); } else { System.out.println("Update failed. The value was likely modified by another client."); }
// To prove it, let's get the final value System.out.println("Final value in cache: " + mcc.get(key));
} catch (Exception e) { System.err.println("An error occurred: " + e.getMessage()); } finally { if (mcc != null) { mcc.shutdown(); } } }}Output
Section titled “Output”Connection to server successful.Initial value set to: 'theme:dark'Retrieved value: 'theme:dark' with CAS token: 53Attempting CAS update with new value 'theme:light'...CAS Operation Result: OKUpdate successful!Final value in cache: theme:lightHandling CAS Failures
Section titled “Handling CAS Failures”When a cas operation returns EXISTS (indicating the data was changed by another process) or NOT_FOUND (indicating the data was deleted), your application should not give up. The standard practice is to implement a retry loop. This loop will re-run the entire gets -> modify -> cas cycle until it either succeeds or a maximum number of retries is reached to prevent an infinite loop.