Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.redisson.command.CommandAsyncService Maven / Gradle / Ivy
Go to download
Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC
/**
* Copyright (c) 2013-2020 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.command;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.ReferenceCountUtil;
import org.redisson.RedissonReference;
import org.redisson.SlotCallback;
import org.redisson.api.RFuture;
import org.redisson.api.RedissonClient;
import org.redisson.api.RedissonReactiveClient;
import org.redisson.api.RedissonRxClient;
import org.redisson.cache.LRUCacheMap;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisException;
import org.redisson.client.RedisRedirectException;
import org.redisson.client.RedisTimeoutException;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.codec.ReferenceCodecProvider;
import org.redisson.config.Config;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.NodeSource;
import org.redisson.liveobject.core.RedissonObjectBuilder;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
/**
*
* @author Nikita Koksharov
*
*/
public class CommandAsyncService implements CommandAsyncExecutor {
static final Logger log = LoggerFactory.getLogger(CommandAsyncService.class);
final ConnectionManager connectionManager;
protected RedissonObjectBuilder objectBuilder;
public CommandAsyncService(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
@Override
public ConnectionManager getConnectionManager() {
return connectionManager;
}
@Override
public CommandAsyncExecutor enableRedissonReferenceSupport(RedissonClient redisson) {
enableRedissonReferenceSupport(redisson.getConfig(), redisson, null, null);
return this;
}
@Override
public CommandAsyncExecutor enableRedissonReferenceSupport(RedissonReactiveClient redissonReactive) {
enableRedissonReferenceSupport(redissonReactive.getConfig(), null, redissonReactive, null);
return this;
}
@Override
public CommandAsyncExecutor enableRedissonReferenceSupport(RedissonRxClient redissonRx) {
enableRedissonReferenceSupport(redissonRx.getConfig(), null, null, redissonRx);
return this;
}
private void enableRedissonReferenceSupport(Config config, RedissonClient redisson, RedissonReactiveClient redissonReactive, RedissonRxClient redissonRx) {
Codec codec = config.getCodec();
objectBuilder = new RedissonObjectBuilder(config, redisson, redissonReactive, redissonRx);
ReferenceCodecProvider codecProvider = objectBuilder.getReferenceCodecProvider();
codecProvider.registerCodec((Class) codec.getClass(), codec);
}
private boolean isRedissonReferenceSupportEnabled() {
return objectBuilder != null;
}
@Override
public void syncSubscription(RFuture> future) {
MasterSlaveServersConfig config = connectionManager.getConfig();
try {
int timeout = config.getTimeout() + config.getRetryInterval() * config.getRetryAttempts();
if (!future.await(timeout)) {
((RPromise>) future).tryFailure(new RedisTimeoutException("Subscribe timeout: (" + timeout + "ms). Increase 'subscriptionsPerConnection' and/or 'subscriptionConnectionPoolSize' parameters."));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
future.syncUninterruptibly();
}
@Override
public void syncSubscriptionInterrupted(RFuture> future) throws InterruptedException {
MasterSlaveServersConfig config = connectionManager.getConfig();
int timeout = config.getTimeout() + config.getRetryInterval() * config.getRetryAttempts();
if (!future.await(timeout)) {
((RPromise>) future).tryFailure(new RedisTimeoutException("Subscribe timeout: (" + timeout + "ms). Increase 'subscriptionsPerConnection' and/or 'subscriptionConnectionPoolSize' parameters."));
}
future.sync();
}
@Override
public V get(RFuture future) {
if (Thread.currentThread().getName().startsWith("redisson-netty")) {
throw new IllegalStateException("Sync methods can't be invoked from async/rx/reactive listeners");
}
try {
future.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RedisException(e);
}
if (future.isSuccess()) {
return future.getNow();
}
throw convertException(future);
}
@Override
public V getInterrupted(RFuture future) throws InterruptedException {
try {
future.await();
} catch (InterruptedException e) {
((RPromise) future).tryFailure(e);
throw e;
}
if (future.isSuccess()) {
return future.getNow();
}
throw convertException(future);
}
protected RPromise createPromise() {
return new RedissonPromise();
}
@Override
public RFuture readAsync(RedisClient client, MasterSlaveEntry entry, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
async(true, new NodeSource(entry, client), codec, command, params, mainPromise, false);
return mainPromise;
}
@Override
public RFuture readAsync(RedisClient client, String name, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
int slot = connectionManager.calcSlot(name);
async(true, new NodeSource(slot, client), codec, command, params, mainPromise, false);
return mainPromise;
}
public RFuture readAsync(RedisClient client, byte[] key, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
int slot = connectionManager.calcSlot(key);
async(true, new NodeSource(slot, client), codec, command, params, mainPromise, false);
return mainPromise;
}
@Override
public RFuture readAsync(RedisClient client, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
async(true, new NodeSource(client), codec, command, params, mainPromise, false);
return mainPromise;
}
@Override
public RFuture> readAllAsync(Codec codec, RedisCommand command, Object... params) {
List results = new ArrayList();
return readAllAsync(results, codec, command, params);
}
@Override
public RFuture> readAllAsync(RedisCommand command, Object... params) {
List results = new ArrayList();
return readAllAsync(results, connectionManager.getCodec(), command, params);
}
@Override
public RFuture> readAllAsync(Collection results, Codec codec, RedisCommand command, Object... params) {
RPromise> mainPromise = createPromise();
Collection nodes = connectionManager.getEntrySet();
AtomicInteger counter = new AtomicInteger(nodes.size());
BiConsumer listener = new BiConsumer() {
@Override
public void accept(Object result, Throwable u) {
if (u != null && !(u instanceof RedisRedirectException)) {
mainPromise.tryFailure(u);
return;
}
if (result instanceof Collection) {
synchronized (results) {
results.addAll((Collection) result);
}
} else {
synchronized (results) {
results.add((R) result);
}
}
if (counter.decrementAndGet() == 0
&& !mainPromise.isDone()) {
mainPromise.trySuccess(results);
}
}
};
for (MasterSlaveEntry entry : nodes) {
RPromise promise = new RedissonPromise();
promise.onComplete(listener);
async(true, new NodeSource(entry), codec, command, params, promise, true);
}
return mainPromise;
}
@Override
public RFuture readRandomAsync(Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
List nodes = new ArrayList(connectionManager.getEntrySet());
Collections.shuffle(nodes);
retryReadRandomAsync(codec, command, mainPromise, nodes, params);
return mainPromise;
}
@Override
public RFuture readRandomAsync(MasterSlaveEntry entry, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
retryReadRandomAsync(codec, command, mainPromise, Collections.singletonList(entry), params);
return mainPromise;
}
private void retryReadRandomAsync(Codec codec, RedisCommand command, RPromise mainPromise,
List nodes, Object... params) {
RPromise attemptPromise = new RedissonPromise();
attemptPromise.onComplete((res, e) -> {
if (e == null) {
if (res == null) {
if (nodes.isEmpty()) {
mainPromise.trySuccess(null);
} else {
retryReadRandomAsync(codec, command, mainPromise, nodes, params);
}
} else {
mainPromise.trySuccess(res);
}
} else {
mainPromise.tryFailure(e);
}
});
MasterSlaveEntry entry = nodes.remove(0);
async(true, new NodeSource(entry), codec, command, params, attemptPromise, false);
}
@Override
public RFuture writeAllAsync(RedisCommand command, Object... params) {
return writeAllAsync(command, null, params);
}
@Override
public RFuture writeAllAsync(RedisCommand command, SlotCallback callback, Object... params) {
return allAsync(false, connectionManager.getCodec(), command, callback, params);
}
@Override
public RFuture writeAllAsync(Codec codec, RedisCommand command, SlotCallback callback, Object... params) {
return allAsync(false, codec, command, callback, params);
}
@Override
public RFuture readAllAsync(RedisCommand command, SlotCallback callback, Object... params) {
return allAsync(true, connectionManager.getCodec(), command, callback, params);
}
private RFuture allAsync(boolean readOnlyMode, Codec codec, RedisCommand command, SlotCallback callback, Object... params) {
RPromise mainPromise = new RedissonPromise();
Collection nodes = connectionManager.getEntrySet();
AtomicInteger counter = new AtomicInteger(nodes.size());
BiConsumer listener = new BiConsumer() {
@Override
public void accept(T result, Throwable u) {
if (u != null && !(u instanceof RedisRedirectException)) {
mainPromise.tryFailure(u);
return;
}
if (u instanceof RedisRedirectException) {
result = command.getConvertor().convert(result);
}
if (callback != null) {
callback.onSlotResult(result);
}
if (counter.decrementAndGet() == 0) {
if (callback != null) {
mainPromise.trySuccess(callback.onFinish());
} else {
mainPromise.trySuccess(null);
}
}
}
};
for (MasterSlaveEntry entry : nodes) {
RPromise promise = new RedissonPromise();
promise.onComplete(listener);
async(readOnlyMode, new NodeSource(entry), codec, command, params, promise, true);
}
return mainPromise;
}
public RedisException convertException(RFuture future) {
if (future.cause() instanceof RedisException) {
return (RedisException) future.cause();
}
return new RedisException("Unexpected exception while processing command", future.cause());
}
private NodeSource getNodeSource(String key) {
int slot = connectionManager.calcSlot(key);
return new NodeSource(slot);
}
private NodeSource getNodeSource(byte[] key) {
int slot = connectionManager.calcSlot(key);
return new NodeSource(slot);
}
@Override
public RFuture readAsync(String key, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
NodeSource source = getNodeSource(key);
async(true, source, codec, command, params, mainPromise, false);
return mainPromise;
}
@Override
public RFuture readAsync(byte[] key, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
NodeSource source = getNodeSource(key);
async(true, source, codec, command, params, mainPromise, false);
return mainPromise;
}
public RFuture readAsync(MasterSlaveEntry entry, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
async(true, new NodeSource(entry), codec, command, params, mainPromise, false);
return mainPromise;
}
@Override
public RFuture writeAsync(RedisClient client, Codec codec, RedisCommand command, Object... params) {
MasterSlaveEntry entry = getConnectionManager().getEntry(client);
return writeAsync(entry, codec, command, params);
}
@Override
public RFuture writeAsync(MasterSlaveEntry entry, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
async(false, new NodeSource(entry), codec, command, params, mainPromise, false);
return mainPromise;
}
@Override
public RFuture readAsync(String key, RedisCommand command, Object... params) {
return readAsync(key, connectionManager.getCodec(), command, params);
}
@Override
public RFuture evalReadAsync(String key, Codec codec, RedisCommand evalCommandType, String script, List keys, Object... params) {
NodeSource source = getNodeSource(key);
return evalAsync(source, true, codec, evalCommandType, script, keys, params);
}
@Override
public RFuture evalReadAsync(MasterSlaveEntry entry, Codec codec, RedisCommand evalCommandType, String script, List keys, Object... params) {
return evalAsync(new NodeSource(entry), true, codec, evalCommandType, script, keys, params);
}
@Override
public RFuture evalReadAsync(RedisClient client, String name, Codec codec, RedisCommand evalCommandType, String script, List keys, Object... params) {
int slot = connectionManager.calcSlot(name);
return evalAsync(new NodeSource(slot, client), true, codec, evalCommandType, script, keys, params);
}
@Override
public RFuture evalWriteAsync(String key, Codec codec, RedisCommand evalCommandType, String script, List keys, Object... params) {
NodeSource source = getNodeSource(key);
return evalAsync(source, false, codec, evalCommandType, script, keys, params);
}
public RFuture evalWriteAsync(MasterSlaveEntry entry, Codec codec, RedisCommand evalCommandType, String script, List keys, Object... params) {
return evalAsync(new NodeSource(entry), false, codec, evalCommandType, script, keys, params);
}
@Override
public RFuture evalWriteAllAsync(RedisCommand command, SlotCallback callback, String script, List keys, Object... params) {
return evalAllAsync(false, command, callback, script, keys, params);
}
public RFuture evalAllAsync(boolean readOnlyMode, RedisCommand command, SlotCallback callback, String script, List keys, Object... params) {
RPromise mainPromise = new RedissonPromise();
Collection entries = connectionManager.getEntrySet();
AtomicInteger counter = new AtomicInteger(entries.size());
BiConsumer listener = new BiConsumer() {
@Override
public void accept(T t, Throwable u) {
if (u != null && !(u instanceof RedisRedirectException)) {
mainPromise.tryFailure(u);
return;
}
callback.onSlotResult(t);
if (counter.decrementAndGet() == 0
&& !mainPromise.isDone()) {
mainPromise.trySuccess(callback.onFinish());
}
}
};
List args = new ArrayList(2 + keys.size() + params.length);
args.add(script);
args.add(keys.size());
args.addAll(keys);
args.addAll(Arrays.asList(params));
for (MasterSlaveEntry entry : entries) {
RPromise promise = new RedissonPromise();
promise.onComplete(listener);
async(readOnlyMode, new NodeSource(entry), connectionManager.getCodec(), command, args.toArray(), promise, true);
}
return mainPromise;
}
private RFuture loadScript(RedisClient client, String script) {
MasterSlaveEntry entry = getConnectionManager().getEntry(client);
if (entry.getClient().equals(client)) {
return writeAsync(entry, StringCodec.INSTANCE, RedisCommands.SCRIPT_LOAD, script);
}
return readAsync(client, StringCodec.INSTANCE, RedisCommands.SCRIPT_LOAD, script);
}
protected boolean isEvalCacheActive() {
return getConnectionManager().getCfg().isUseScriptCache();
}
private static final Map SHA_CACHE = new LRUCacheMap(500, 0, 0);
private String calcSHA(String script) {
String digest = SHA_CACHE.get(script);
if (digest == null) {
try {
MessageDigest mdigest = MessageDigest.getInstance("SHA-1");
byte[] s = mdigest.digest(script.getBytes());
digest = ByteBufUtil.hexDump(s);
SHA_CACHE.put(script, digest);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return digest;
}
private Object[] copy(Object[] params) {
List result = new ArrayList();
for (Object object : params) {
if (object instanceof ByteBuf) {
ByteBuf b = (ByteBuf) object;
ByteBuf nb = ByteBufAllocator.DEFAULT.buffer(b.readableBytes());
int ri = b.readerIndex();
nb.writeBytes(b);
b.readerIndex(ri);
result.add(nb);
} else {
result.add(object);
}
}
return result.toArray();
}
private RFuture evalAsync(NodeSource nodeSource, boolean readOnlyMode, Codec codec, RedisCommand evalCommandType, String script, List keys, Object... params) {
if (isEvalCacheActive() && evalCommandType.getName().equals("EVAL")) {
RPromise mainPromise = new RedissonPromise();
Object[] pps = copy(params);
RPromise promise = new RedissonPromise();
String sha1 = calcSHA(script);
RedisCommand cmd = new RedisCommand(evalCommandType, "EVALSHA");
List args = new ArrayList(2 + keys.size() + params.length);
args.add(sha1);
args.add(keys.size());
args.addAll(keys);
args.addAll(Arrays.asList(params));
RedisExecutor executor = new RedisExecutor<>(readOnlyMode, nodeSource, codec, cmd,
args.toArray(), promise, false, connectionManager, objectBuilder);
executor.execute();
promise.onComplete((res, e) -> {
if (e != null) {
if (e.getMessage().startsWith("NOSCRIPT")) {
RFuture loadFuture = loadScript(executor.getRedisClient(), script);
loadFuture.onComplete((r, ex) -> {
if (ex != null) {
free(pps);
mainPromise.tryFailure(ex);
return;
}
RedisCommand command = new RedisCommand(evalCommandType, "EVALSHA");
List newargs = new ArrayList(2 + keys.size() + params.length);
newargs.add(sha1);
newargs.add(keys.size());
newargs.addAll(keys);
newargs.addAll(Arrays.asList(pps));
NodeSource ns = nodeSource;
if (ns.getRedisClient() == null) {
ns = new NodeSource(nodeSource, executor.getRedisClient());
}
async(readOnlyMode, ns, codec, command, newargs.toArray(), mainPromise, false);
});
} else {
free(pps);
mainPromise.tryFailure(e);
}
return;
}
free(pps);
mainPromise.trySuccess(res);
});
return mainPromise;
}
RPromise mainPromise = createPromise();
List args = new ArrayList(2 + keys.size() + params.length);
args.add(script);
args.add(keys.size());
args.addAll(keys);
args.addAll(Arrays.asList(params));
async(readOnlyMode, nodeSource, codec, evalCommandType, args.toArray(), mainPromise, false);
return mainPromise;
}
@Override
public RFuture writeAsync(String key, RedisCommand command, Object... params) {
return writeAsync(key, connectionManager.getCodec(), command, params);
}
@Override
public RFuture writeAsync(String key, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
NodeSource source = getNodeSource(key);
async(false, source, codec, command, params, mainPromise, false);
return mainPromise;
}
public RFuture writeAsync(byte[] key, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = createPromise();
NodeSource source = getNodeSource(key);
async(false, source, codec, command, params, mainPromise, false);
return mainPromise;
}
public void async(boolean readOnlyMode, NodeSource source, Codec codec,
RedisCommand command, Object[] params, RPromise mainPromise,
boolean ignoreRedirect) {
RedisExecutor executor = new RedisExecutor<>(readOnlyMode, source, codec, command, params, mainPromise, ignoreRedirect, connectionManager, objectBuilder);
executor.execute();
}
private void free(Object[] params) {
for (Object obj : params) {
ReferenceCountUtil.safeRelease(obj);
}
}
@Override
public RFuture readBatchedAsync(Codec codec, RedisCommand command, SlotCallback callback, String... keys) {
return executeBatchedAsync(true, codec, command, callback, keys);
}
@Override
public RFuture writeBatchedAsync(Codec codec, RedisCommand command, SlotCallback callback, String... keys) {
return executeBatchedAsync(false, codec, command, callback, keys);
}
private RFuture executeBatchedAsync(boolean readOnly, Codec codec, RedisCommand command, SlotCallback callback, String... keys) {
if (!connectionManager.isClusterMode()) {
if (readOnly) {
return readAsync((String) null, codec, command, keys);
}
return writeAsync((String) null, codec, command, keys);
}
Map> range2key = new HashMap<>();
for (String key : keys) {
int slot = connectionManager.calcSlot(key);
MasterSlaveEntry entry = connectionManager.getEntry(slot);
List list = range2key.computeIfAbsent(entry, k -> new ArrayList<>());
list.add(key);
}
RPromise result = new RedissonPromise<>();
AtomicLong executed = new AtomicLong(keys.length);
AtomicReference failed = new AtomicReference<>();
BiConsumer listener = (res, ex) -> {
if (ex != null) {
failed.set(ex);
} else {
if (res != null) {
callback.onSlotResult(res);
}
}
if (executed.decrementAndGet() == 0) {
if (failed.get() != null) {
result.tryFailure(failed.get());
} else {
result.trySuccess(callback.onFinish());
}
}
};
for (Entry> entry : range2key.entrySet()) {
// executes in batch due to CROSSLOT error
CommandBatchService executorService;
if (this instanceof CommandBatchService) {
executorService = (CommandBatchService) this;
} else {
executorService = new CommandBatchService(connectionManager);
}
for (String key : entry.getValue()) {
RedisCommand c = command;
RedisCommand newCommand = callback.createCommand(key);
if (newCommand != null) {
c = newCommand;
}
if (readOnly) {
RFuture f = executorService.readAsync(entry.getKey(), codec, c, key);
f.onComplete(listener);
} else {
RFuture f = executorService.writeAsync(entry.getKey(), codec, c, key);
f.onComplete(listener);
}
}
if (!(this instanceof CommandBatchService)) {
executorService.executeAsync();
}
}
return result;
}
@Override
public RedissonObjectBuilder getObjectBuilder() {
return objectBuilder;
}
@Override
public ByteBuf encode(Codec codec, Object value) {
if (isRedissonReferenceSupportEnabled()) {
RedissonReference reference = getObjectBuilder().toReference(value);
if (reference != null) {
value = reference;
}
}
try {
return codec.getValueEncoder().encode(value);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public ByteBuf encodeMapKey(Codec codec, Object value) {
if (isRedissonReferenceSupportEnabled()) {
RedissonReference reference = getObjectBuilder().toReference(value);
if (reference != null) {
value = reference;
}
}
try {
return codec.getMapKeyEncoder().encode(value);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public ByteBuf encodeMapValue(Codec codec, Object value) {
if (isRedissonReferenceSupportEnabled()) {
RedissonReference reference = getObjectBuilder().toReference(value);
if (reference != null) {
value = reference;
}
}
try {
return codec.getMapValueEncoder().encode(value);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public RFuture pollFromAnyAsync(String name, Codec codec, RedisCommand command, long secondsTimeout, String... queueNames) {
if (connectionManager.isClusterMode() && queueNames.length > 0) {
RPromise result = new RedissonPromise();
AtomicReference> ref = new AtomicReference>();
List names = new ArrayList();
names.add(name);
names.addAll(Arrays.asList(queueNames));
ref.set(names.iterator());
AtomicLong counter = new AtomicLong(secondsTimeout);
poll(name, codec, result, ref, names, counter, command);
return result;
} else {
List params = new ArrayList(queueNames.length + 1);
params.add(name);
params.addAll(Arrays.asList(queueNames));
params.add(secondsTimeout);
return writeAsync(name, codec, command, params.toArray());
}
}
private void poll(String name, Codec codec, RPromise result, AtomicReference> ref,
List names, AtomicLong counter, RedisCommand command) {
if (ref.get().hasNext()) {
String currentName = ref.get().next().toString();
RFuture future = writeAsync(currentName, codec, command, currentName, 1);
future.onComplete((res, e) -> {
if (e != null) {
result.tryFailure(e);
return;
}
if (res != null) {
result.trySuccess(res);
} else {
if (counter.decrementAndGet() == 0) {
result.trySuccess(null);
return;
}
poll(name, codec, result, ref, names, counter, command);
}
});
} else {
ref.set(names.iterator());
poll(name, codec, result, ref, names, counter, command);
}
}
}