Search in sources :

Example 1 with BatchResult

use of org.redisson.api.BatchResult in project redisson by redisson.

the class RedissonBaseLock method evalWriteAsync.

protected <T> RFuture<T> evalWriteAsync(String key, Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object... params) {
    MasterSlaveEntry entry = commandExecutor.getConnectionManager().getEntry(getRawName());
    int availableSlaves = entry.getAvailableSlaves();
    CommandBatchService executorService = createCommandBatchService(availableSlaves);
    RFuture<T> result = executorService.evalWriteAsync(key, codec, evalCommandType, script, keys, params);
    if (commandExecutor instanceof CommandBatchService) {
        return result;
    }
    RFuture<BatchResult<?>> future = executorService.executeAsync();
    CompletionStage<T> f = future.handle((res, ex) -> {
        if (ex != null) {
            throw new CompletionException(ex);
        }
        if (commandExecutor.getConnectionManager().getCfg().isCheckLockSyncedSlaves() && res.getSyncedSlaves() < availableSlaves) {
            throw new CompletionException(new IllegalStateException("Only " + res.getSyncedSlaves() + " of " + availableSlaves + " slaves were synced"));
        }
        return result.getNow();
    });
    return new CompletableFutureWrapper<>(f);
}
Also used : CompletableFutureWrapper(org.redisson.misc.CompletableFutureWrapper) MasterSlaveEntry(org.redisson.connection.MasterSlaveEntry) CommandBatchService(org.redisson.command.CommandBatchService) BatchResult(org.redisson.api.BatchResult)

Example 2 with BatchResult

use of org.redisson.api.BatchResult in project redisson by redisson.

the class RedissonClusterConnection method del.

@Override
public Long del(byte[]... keys) {
    if (isQueueing() || isPipelined()) {
        for (byte[] key : keys) {
            write(key, LongCodec.INSTANCE, RedisCommands.DEL, key);
        }
        return null;
    }
    CommandBatchService es = new CommandBatchService(executorService);
    for (byte[] key : keys) {
        es.writeAsync(key, StringCodec.INSTANCE, RedisCommands.DEL, key);
    }
    BatchResult<Long> b = (BatchResult<Long>) es.execute();
    return b.getResponses().stream().collect(Collectors.summarizingLong(v -> v)).getSum();
}
Also used : CommandBatchService(org.redisson.command.CommandBatchService) BatchResult(org.redisson.api.BatchResult)

Example 3 with BatchResult

use of org.redisson.api.BatchResult in project redisson by redisson.

the class RedissonClusterConnection method mGet.

@Override
public List<byte[]> mGet(byte[]... keys) {
    if (isQueueing() || isPipelined()) {
        for (byte[] key : keys) {
            read(key, ByteArrayCodec.INSTANCE, RedisCommands.GET, key);
        }
        return null;
    }
    CommandBatchService es = new CommandBatchService(executorService);
    for (byte[] key : keys) {
        es.readAsync(key, ByteArrayCodec.INSTANCE, RedisCommands.GET, key);
    }
    BatchResult<byte[]> r = (BatchResult<byte[]>) es.execute();
    return r.getResponses();
}
Also used : CommandBatchService(org.redisson.command.CommandBatchService) BatchResult(org.redisson.api.BatchResult)

Example 4 with BatchResult

use of org.redisson.api.BatchResult in project redisson by redisson.

the class CommandBatchService method executeRedisBasedQueue.

private <R> RFuture<R> executeRedisBasedQueue() {
    RPromise<R> resultPromise = new RedissonPromise<R>();
    long responseTimeout;
    if (options.getResponseTimeout() > 0) {
        responseTimeout = options.getResponseTimeout();
    } else {
        responseTimeout = connectionManager.getConfig().getTimeout();
    }
    Timeout timeout = connectionManager.newTimeout(new TimerTask() {

        @Override
        public void run(Timeout timeout) throws Exception {
            connections.values().forEach(c -> {
                c.getCancelCallback().run();
            });
            resultPromise.tryFailure(new RedisTimeoutException("Response timeout for queued commands " + responseTimeout + ": " + commands.values().stream().flatMap(e -> e.getCommands().stream().map(d -> d.getCommand())).collect(Collectors.toList())));
        }
    }, responseTimeout, TimeUnit.MILLISECONDS);
    CompletableFuture<Void> allFutures = CompletableFuture.allOf(commands.values().stream().flatMap(m -> m.getCommands().stream().map(c -> ((BatchPromise) c.getPromise()).getSentPromise())).toArray(CompletableFuture[]::new));
    allFutures.whenComplete((fr, exc) -> {
        if (!timeout.cancel()) {
            return;
        }
        for (Entry entry : commands.values()) {
            for (BatchCommandData<?, ?> command : entry.getCommands()) {
                if (command.getPromise().isDone() && command.getPromise().isCompletedExceptionally()) {
                    resultPromise.tryFailure(cause(command.getPromise()));
                    break;
                }
            }
        }
        if (resultPromise.isDone()) {
            return;
        }
        Map<MasterSlaveEntry, List<Object>> result = new ConcurrentHashMap<>();
        List<CompletableFuture<Void>> futures = new ArrayList<>(commands.size());
        for (Map.Entry<MasterSlaveEntry, Entry> entry : commands.entrySet()) {
            RFuture<List<Object>> execPromise = async(entry.getValue().isReadOnlyMode(), new NodeSource(entry.getKey()), connectionManager.getCodec(), RedisCommands.EXEC, new Object[] {}, false, false);
            CompletionStage<Void> f = execPromise.thenCompose(r -> {
                BatchCommandData<?, Integer> lastCommand = (BatchCommandData<?, Integer>) entry.getValue().getCommands().peekLast();
                result.put(entry.getKey(), r);
                if (RedisCommands.WAIT.getName().equals(lastCommand.getCommand().getName())) {
                    return lastCommand.getPromise().thenApply(i -> null);
                }
                return CompletableFuture.completedFuture(null);
            });
            futures.add(f.toCompletableFuture());
        }
        CompletableFuture<Void> future = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        future.whenComplete((res, ex) -> {
            executed.set(true);
            if (ex != null) {
                resultPromise.tryFailure(ex);
                return;
            }
            try {
                for (java.util.Map.Entry<MasterSlaveEntry, List<Object>> entry : result.entrySet()) {
                    Entry commandEntry = commands.get(entry.getKey());
                    Iterator<Object> resultIter = entry.getValue().iterator();
                    for (BatchCommandData<?, ?> data : commandEntry.getCommands()) {
                        if (data.getCommand().getName().equals(RedisCommands.EXEC.getName())) {
                            break;
                        }
                        CompletableFuture<Object> promise = (CompletableFuture<Object>) data.getPromise();
                        if (resultIter.hasNext()) {
                            promise.complete(resultIter.next());
                        } else {
                            // fix for https://github.com/redisson/redisson/issues/2212
                            promise.complete(null);
                        }
                    }
                }
                List<BatchCommandData> entries = new ArrayList<>();
                for (Entry e : commands.values()) {
                    entries.addAll(e.getCommands());
                }
                Collections.sort(entries);
                List<Object> responses = new ArrayList<>(entries.size());
                int syncedSlaves = 0;
                for (BatchCommandData<?, ?> commandEntry : entries) {
                    if (isWaitCommand(commandEntry)) {
                        syncedSlaves += (Integer) commandEntry.getPromise().getNow(null);
                    } else if (!commandEntry.getCommand().getName().equals(RedisCommands.MULTI.getName()) && !commandEntry.getCommand().getName().equals(RedisCommands.EXEC.getName())) {
                        Object entryResult = commandEntry.getPromise().getNow(null);
                        if (objectBuilder != null) {
                            entryResult = objectBuilder.tryHandleReference(entryResult, referenceType);
                        }
                        responses.add(entryResult);
                    }
                }
                BatchResult<Object> r = new BatchResult<>(responses, syncedSlaves);
                resultPromise.trySuccess((R) r);
            } catch (Exception e) {
                resultPromise.tryFailure(e);
            }
        });
    });
    return resultPromise;
}
Also used : RPromise(org.redisson.misc.RPromise) java.util(java.util) RedisConnection(org.redisson.client.RedisConnection) Codec(org.redisson.client.codec.Codec) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ExecutionMode(org.redisson.api.BatchOptions.ExecutionMode) RFuture(org.redisson.api.RFuture) NodeSource(org.redisson.connection.NodeSource) CompletableFutureWrapper(org.redisson.misc.CompletableFutureWrapper) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TimerTask(io.netty.util.TimerTask) BatchCommandData(org.redisson.client.protocol.BatchCommandData) Timeout(io.netty.util.Timeout) ConnectionManager(org.redisson.connection.ConnectionManager) java.util.concurrent(java.util.concurrent) RedissonPromise(org.redisson.misc.RedissonPromise) CommandData(org.redisson.client.protocol.CommandData) BatchOptions(org.redisson.api.BatchOptions) RedisTimeoutException(org.redisson.client.RedisTimeoutException) Collectors(java.util.stream.Collectors) BatchResult(org.redisson.api.BatchResult) RedisCommands(org.redisson.client.protocol.RedisCommands) ReferenceCountUtil(io.netty.util.ReferenceCountUtil) MasterSlaveEntry(org.redisson.connection.MasterSlaveEntry) RedisCommand(org.redisson.client.protocol.RedisCommand) RedissonObjectBuilder(org.redisson.liveobject.core.RedissonObjectBuilder) RedissonPromise(org.redisson.misc.RedissonPromise) BatchCommandData(org.redisson.client.protocol.BatchCommandData) BatchResult(org.redisson.api.BatchResult) NodeSource(org.redisson.connection.NodeSource) MasterSlaveEntry(org.redisson.connection.MasterSlaveEntry) TimerTask(io.netty.util.TimerTask) MasterSlaveEntry(org.redisson.connection.MasterSlaveEntry) Timeout(io.netty.util.Timeout) RedisTimeoutException(org.redisson.client.RedisTimeoutException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RedisTimeoutException(org.redisson.client.RedisTimeoutException)

Example 5 with BatchResult

use of org.redisson.api.BatchResult in project redisson by redisson.

the class CommandBatchService method executeAsync.

public RFuture<BatchResult<?>> executeAsync() {
    if (executed.get()) {
        throw new IllegalStateException("Batch already executed!");
    }
    if (commands.isEmpty()) {
        executed.set(true);
        BatchResult<Object> result = new BatchResult<>(Collections.emptyList(), 0);
        return RedissonPromise.newSucceededFuture(result);
    }
    if (isRedisBasedQueue()) {
        return executeRedisBasedQueue();
    }
    if (this.options.getExecutionMode() != ExecutionMode.IN_MEMORY) {
        for (Entry entry : commands.values()) {
            BatchCommandData<?, ?> multiCommand = new BatchCommandData(RedisCommands.MULTI, new Object[] {}, index.incrementAndGet());
            entry.getCommands().addFirst(multiCommand);
            BatchCommandData<?, ?> execCommand = new BatchCommandData(RedisCommands.EXEC, new Object[] {}, index.incrementAndGet());
            entry.getCommands().add(execCommand);
        }
    }
    if (this.options.isSkipResult()) {
        for (Entry entry : commands.values()) {
            BatchCommandData<?, ?> offCommand = new BatchCommandData(RedisCommands.CLIENT_REPLY, new Object[] { "OFF" }, index.incrementAndGet());
            entry.getCommands().addFirst(offCommand);
            BatchCommandData<?, ?> onCommand = new BatchCommandData(RedisCommands.CLIENT_REPLY, new Object[] { "ON" }, index.incrementAndGet());
            entry.getCommands().add(onCommand);
        }
    }
    if (this.options.getSyncSlaves() > 0) {
        for (Entry entry : commands.values()) {
            BatchCommandData<?, ?> waitCommand = new BatchCommandData(RedisCommands.WAIT, new Object[] { this.options.getSyncSlaves(), this.options.getSyncTimeout() }, index.incrementAndGet());
            entry.getCommands().add(waitCommand);
        }
    }
    RPromise<BatchResult<?>> promise = new RedissonPromise<>();
    CompletableFuture<Void> voidPromise = new CompletableFuture<>();
    if (this.options.isSkipResult() && this.options.getSyncSlaves() == 0) {
        voidPromise.whenComplete((res, ex) -> {
            executed.set(true);
            if (ex != null) {
                for (Entry e : commands.values()) {
                    e.getCommands().forEach(t -> t.tryFailure(ex));
                }
                promise.tryFailure(ex);
                commands.clear();
                nestedServices.clear();
                return;
            }
            commands.clear();
            nestedServices.clear();
            promise.trySuccess(new BatchResult<>(Collections.emptyList(), 0));
        });
    } else {
        voidPromise.whenComplete((res, ex) -> {
            executed.set(true);
            if (ex != null) {
                for (Entry e : commands.values()) {
                    e.getCommands().forEach(t -> t.tryFailure(ex));
                }
                promise.tryFailure(ex);
                commands.clear();
                nestedServices.clear();
                return;
            }
            List<BatchCommandData> entries = new ArrayList<BatchCommandData>();
            for (Entry e : commands.values()) {
                entries.addAll(e.getCommands());
            }
            Collections.sort(entries);
            List<Object> responses = new ArrayList<Object>(entries.size());
            int syncedSlaves = 0;
            for (BatchCommandData<?, ?> commandEntry : entries) {
                if (isWaitCommand(commandEntry)) {
                    syncedSlaves = (Integer) commandEntry.getPromise().getNow(null);
                } else if (!commandEntry.getCommand().getName().equals(RedisCommands.MULTI.getName()) && !commandEntry.getCommand().getName().equals(RedisCommands.EXEC.getName()) && !this.options.isSkipResult()) {
                    if (commandEntry.getPromise().isCancelled()) {
                        continue;
                    }
                    Object entryResult = commandEntry.getPromise().getNow(null);
                    try {
                        if (objectBuilder != null) {
                            entryResult = objectBuilder.tryHandleReference(entryResult, referenceType);
                        }
                    } catch (ReflectiveOperationException exc) {
                        log.error("Unable to handle reference from " + entryResult, exc);
                    }
                    responses.add(entryResult);
                }
            }
            BatchResult<Object> result = new BatchResult<Object>(responses, syncedSlaves);
            promise.trySuccess(result);
            commands.clear();
            nestedServices.clear();
        });
    }
    AtomicInteger slots = new AtomicInteger(commands.size());
    for (Map.Entry<RFuture<?>, List<CommandBatchService>> entry : nestedServices.entrySet()) {
        slots.incrementAndGet();
        for (CommandBatchService service : entry.getValue()) {
            service.executeAsync();
        }
        entry.getKey().whenComplete((res, e) -> {
            handle(voidPromise, slots, entry.getKey());
        });
    }
    for (Map.Entry<MasterSlaveEntry, Entry> e : commands.entrySet()) {
        RedisCommonBatchExecutor executor = new RedisCommonBatchExecutor(new NodeSource(e.getKey()), voidPromise, connectionManager, this.options, e.getValue(), slots, referenceType, false);
        executor.execute();
    }
    return promise;
}
Also used : RedissonPromise(org.redisson.misc.RedissonPromise) BatchCommandData(org.redisson.client.protocol.BatchCommandData) BatchResult(org.redisson.api.BatchResult) NodeSource(org.redisson.connection.NodeSource) MasterSlaveEntry(org.redisson.connection.MasterSlaveEntry) MasterSlaveEntry(org.redisson.connection.MasterSlaveEntry) RFuture(org.redisson.api.RFuture) AtomicInteger(java.util.concurrent.atomic.AtomicInteger)

Aggregations

BatchResult (org.redisson.api.BatchResult)5 CommandBatchService (org.redisson.command.CommandBatchService)3 MasterSlaveEntry (org.redisson.connection.MasterSlaveEntry)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 RFuture (org.redisson.api.RFuture)2 BatchCommandData (org.redisson.client.protocol.BatchCommandData)2 NodeSource (org.redisson.connection.NodeSource)2 CompletableFutureWrapper (org.redisson.misc.CompletableFutureWrapper)2 RedissonPromise (org.redisson.misc.RedissonPromise)2 ReferenceCountUtil (io.netty.util.ReferenceCountUtil)1 Timeout (io.netty.util.Timeout)1 TimerTask (io.netty.util.TimerTask)1 java.util (java.util)1 java.util.concurrent (java.util.concurrent)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 Collectors (java.util.stream.Collectors)1 BatchOptions (org.redisson.api.BatchOptions)1 ExecutionMode (org.redisson.api.BatchOptions.ExecutionMode)1 RedisConnection (org.redisson.client.RedisConnection)1 RedisTimeoutException (org.redisson.client.RedisTimeoutException)1