private static void atomicUpdate(KeyValueClient kv, String key, Function<String, String> mutator) throws IOException { while (true) { final ConsulResponse<Value> r = kv.getConsulResponseWithValue(key).orElse(null); if (r == null) { // Don't automatically create the document, because it might need to be associated with another node's session. // For example, an RPC endpoint doc is updated by both client and server, but is tied to the server session. throw new IOException("Can't update non-existent document: " + key); } final BigInteger index = r.getIndex(); final String oldValue = r.getResponse().getValueAsString(UTF_8).orElse(missingDocumentValue); final String newValue = mutator.apply(oldValue); if (Objects.equals(newValue, oldValue)) { return; } final PutOptions options = ImmutablePutOptions.builder().cas(index.longValue()).build(); boolean success = kv.putValue(key, newValue, 0, options, UTF_8); if (success) { return; } // todo truncated exponential backoff, please! Die if timeout! //MILLISECONDS.sleep(100); } }
public static void atomicUpdate(KeyValueClient kv, ConsulResponse<Value> initialResponse, Function<String, String> mutator) throws IOException { final Value v = initialResponse.getResponse(); final String key = v.getKey(); LOGGER.debug("Updating key {}", key); final String oldValue = v.getValueAsString(UTF_8).orElse(missingDocumentValue); final String newValue = mutator.apply(oldValue); if (Objects.equals(newValue, oldValue)) { return; } final long index = initialResponse.getIndex().longValue(); final PutOptions options = ImmutablePutOptions.builder().cas(index).build(); boolean success = kv.putValue(key, newValue, 0, options, UTF_8); if (!success) { LOGGER.info("Failed to put new document (optimistic locking failure?); reloading and retrying"); atomicUpdate(kv, key, mutator); } }
/** * Creates an immutable copy of a {@link PutOptions} value. * Uses accessors to get values to initialize the new immutable instance. * If an instance is already immutable, it is returned as is. * @param instance The instance to copy * @return A copied immutable PutOptions instance */ public static ImmutablePutOptions copyOf(PutOptions instance) { if (instance instanceof ImmutablePutOptions) { return (ImmutablePutOptions) instance; } return ImmutablePutOptions.builder() .from(instance) .build(); }
/** * Releases the lock for a given service and session. * * GET /v1/kv/{key}?release={sessionId} * * @param key identifying the service. * @param sessionId * * @return {@link SessionInfo}. */ public boolean releaseLock(final String key, final String sessionId) { return putValue(key, "", 0, ImmutablePutOptions.builder().release(sessionId).build()); }
/** * Aquire a lock for a given key. * * PUT /v1/kv/{key}?acquire={session} * * @param key The key to acquire the lock. * @param session The session to acquire lock. * @param value key value (usually - application specific info about the lock requester) * @return true if the lock is acquired successfully, false otherwise. */ public boolean acquireLock(final String key, final String value, final String session) { return putValue(key, value, 0, ImmutablePutOptions.builder().acquire(session).build()); }
/** * Creates a builder for {@link ImmutablePutOptions ImmutablePutOptions}. * @return A new ImmutablePutOptions builder */ public static ImmutablePutOptions.Builder builder() { return new ImmutablePutOptions.Builder(); }