io.vertx.spi.cluster.zookeeper.impl.ZKAsyncMap Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2016 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.spi.cluster.zookeeper.impl;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.impl.VertxInternal;
import io.vertx.core.shareddata.AsyncMap;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorEventType;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.time.Instant;
import java.util.*;
/**
* Created by Stream.Liu
*/
public class ZKAsyncMap extends ZKMap implements AsyncMap {
public ZKAsyncMap(Vertx vertx, CuratorFramework curator, String mapName) {
super(curator, vertx, ZK_PATH_ASYNC_MAP, mapName);
}
@Override
public Future get(K k) {
return assertKeyIsNotNull(k)
.compose(aVoid -> checkExists(k))
.compose(checkResult -> {
Promise promise = Promise.promise();
if (checkResult) {
try {
curator.getData().inBackground((c,e) -> {
if (e.getType() == CuratorEventType.GET_DATA) {
V value = asObject(e.getData());
vertx.runOnContext(aVoid -> promise.complete(value));
}
}).forPath(keyPath(k));
} catch (Exception e) {
promise.fail(e);
}
} else {
//ignore
promise.complete();
}
return promise.future();
});
}
@Override
public Future put(K k, V v) {
return put(k, v, Optional.empty());
}
@Override
public Future put(K k, V v, long ttl) {
return put(k, v, Optional.of(ttl));
}
private Future put(K k, V v, Optional timeoutOptional) {
return assertKeyAndValueAreNotNull(k, v)
.compose(aVoid -> checkExists(k))
.compose(checkResult -> checkResult ? setData(k, v) : create(k, v, timeoutOptional))
.compose(stat -> Future.succeededFuture());
}
@Override
public Future putIfAbsent(K k, V v) {
return putIfAbsent(k, v, Optional.empty());
}
@Override
public Future putIfAbsent(K k, V v, long ttl) {
return putIfAbsent(k, v, Optional.of(ttl));
}
private Future putIfAbsent(K k, V v, Optional timeoutOptional) {
return assertKeyAndValueAreNotNull(k, v)
.compose(aVoid -> get(k))
.compose(value -> {
if (value == null) {
if (timeoutOptional.isPresent()) {
return put(k, v, timeoutOptional).compose(aVoid -> Future.succeededFuture(null));
} else {
return put(k, v).compose(aVoid -> Future.succeededFuture(null));
}
} else {
return Future.succeededFuture(value);
}
});
}
@Override
public Future remove(K k) {
return assertKeyIsNotNull(k).compose(aVoid -> {
Promise promise = Promise.promise();
get(k, promise);
return promise.future();
}).compose(value -> {
Promise promise = Promise.promise();
if (value != null) {
return delete(k, value);
} else {
promise.complete();
}
return promise.future();
});
}
@Override
public Future removeIfPresent(K k, V v) {
return assertKeyAndValueAreNotNull(k, v)
.compose(aVoid -> {
Promise promise = Promise.promise();
get(k, promise);
return promise.future();
})
.compose(value -> {
Promise promise = Promise.promise();
if (Objects.equals(value, v)) {
delete(k, v).onComplete(deleteResult -> {
if (deleteResult.succeeded()) promise.complete(true);
else promise.fail(deleteResult.cause());
});
} else {
promise.complete(false);
}
return promise.future();
});
}
@Override
public Future replace(K k, V v) {
return assertKeyAndValueAreNotNull(k, v)
.compose(aVoid -> {
Promise innerPromise = Promise.promise();
vertx.executeBlocking(future -> {
long startTime = Instant.now().toEpochMilli();
int retries = 0;
for (; ; ) {
try {
Stat stat = new Stat();
String path = keyPath(k);
V currentValue = getData(stat, path);
//do not replace value if previous value is null
if (currentValue == null) {
future.complete(null);
return;
}
if (compareAndSet(startTime, retries++, stat, path, currentValue, v)) {
future.complete(currentValue);
return;
}
} catch (Exception e) {
future.fail(e);
return;
}
}
}, false, innerPromise);
return innerPromise.future();
});
}
@Override
public Future replaceIfPresent(K k, V oldValue, V newValue) {
return assertKeyIsNotNull(k)
.compose(aVoid -> assertValueIsNotNull(oldValue))
.compose(aVoid -> assertValueIsNotNull(newValue))
.compose(aVoid -> {
Promise innerPromise = Promise.promise();
vertx.executeBlocking(future -> {
long startTime = Instant.now().toEpochMilli();
int retries = 0;
for (; ; ) {
try {
Stat stat = new Stat();
String path = keyPath(k);
V currentValue = getData(stat, path);
if (!currentValue.equals(oldValue)) {
future.complete(false);
return;
}
if (compareAndSet(startTime, retries++, stat, path, oldValue, newValue)) {
future.complete(true);
return;
}
} catch (Exception e) {
future.fail(e);
return;
}
}
}, false, innerPromise);
return innerPromise.future();
});
}
@Override
public Future clear() {
//just remove parent node
return delete(mapPath, null).mapEmpty();
}
@Override
public Future size() {
Promise promise = ((VertxInternal)vertx).getOrCreateContext().promise();
try {
curator.getChildren().inBackground((client, event) ->
promise.tryComplete(event.getChildren().size()))
.forPath(mapPath);
} catch (Exception e) {
promise.tryFail(e);
}
return promise.future();
}
@Override
public Future> keys() {
Promise> promise = ((VertxInternal)vertx).getOrCreateContext().promise();
try {
curator.getChildren().inBackground((client, event) -> {
Set keys = new HashSet<>();
for (String base64Key : event.getChildren()) {
byte[] binaryKey = Base64.getUrlDecoder().decode(base64Key);
K key;
try {
key = asObject(binaryKey);
} catch (Exception e) {
promise.tryFail(e);
return;
}
keys.add(key);
}
promise.tryComplete(keys);
}).forPath(mapPath);
} catch (Exception e) {
promise.tryFail(e);
}
return promise.future();
}
@Override
public Future> values() {
Promise> keysPromise = ((VertxInternal)vertx).getOrCreateContext().promise();
keys(keysPromise);
return keysPromise.future().compose(keys -> {
List futures = new ArrayList<>(keys.size());
for (K k : keys) {
Promise valuePromise = Promise.promise();
get(k, valuePromise);
futures.add(valuePromise.future());
}
return CompositeFuture.all(futures).map(compositeFuture -> {
List values = new ArrayList<>(compositeFuture.size());
for (int i = 0; i < compositeFuture.size(); i++) {
values.add(compositeFuture.resultAt(i));
}
return values;
});
});
}
@Override
public Future
© 2015 - 2024 Weber Informatics LLC | Privacy Policy