Search in sources :

Example 1 with Intent

use of io.lettuce.core.cluster.ClusterConnectionProvider.Intent in project lettuce-core by lettuce-io.

the class ClusterDistributionChannelWriter method getIntent.

/**
 * Optimization: Determine command intents and optimize for bulk execution preferring one node.
 * <p>
 * If there is only one intent, then we take the intent derived from the commands. If there is more than one intent, then
 * use {@link Intent#WRITE}.
 *
 * @param commands {@link Collection} of {@link RedisCommand commands}.
 * @return the intent.
 */
static Intent getIntent(Collection<? extends RedisCommand<?, ?, ?>> commands) {
    boolean w = false;
    boolean r = false;
    Intent singleIntent = Intent.WRITE;
    for (RedisCommand<?, ?, ?> command : commands) {
        if (command instanceof ClusterCommand) {
            continue;
        }
        singleIntent = getIntent(command.getType());
        if (singleIntent == Intent.READ) {
            r = true;
        }
        if (singleIntent == Intent.WRITE) {
            w = true;
        }
        if (r && w) {
            return Intent.WRITE;
        }
    }
    return singleIntent;
}
Also used : Intent(io.lettuce.core.cluster.ClusterConnectionProvider.Intent)

Example 2 with Intent

use of io.lettuce.core.cluster.ClusterConnectionProvider.Intent in project lettuce-core by lettuce-io.

the class ClusterDistributionChannelWriter method write.

@SuppressWarnings("unchecked")
@Override
public <K, V> Collection<RedisCommand<K, V, ?>> write(Collection<? extends RedisCommand<K, V, ?>> commands) {
    LettuceAssert.notNull(commands, "Commands must not be null");
    if (closed) {
        commands.forEach(it -> it.completeExceptionally(new RedisException("Connection is closed")));
        return (Collection<RedisCommand<K, V, ?>>) commands;
    }
    List<ClusterCommand<K, V, ?>> clusterCommands = new ArrayList<>(commands.size());
    List<ClusterCommand<K, V, ?>> defaultCommands = new ArrayList<>(commands.size());
    Map<SlotIntent, List<ClusterCommand<K, V, ?>>> partitions = new HashMap<>();
    // TODO: Retain order or retain Intent preference?
    // Currently: Retain order
    Intent intent = getIntent(commands);
    for (RedisCommand<K, V, ?> cmd : commands) {
        if (cmd instanceof ClusterCommand) {
            clusterCommands.add((ClusterCommand) cmd);
            continue;
        }
        CommandArgs<K, V> args = cmd.getArgs();
        ByteBuffer firstEncodedKey = args != null ? args.getFirstEncodedKey() : null;
        if (firstEncodedKey == null) {
            defaultCommands.add(new ClusterCommand<>(cmd, this, executionLimit));
            continue;
        }
        int hash = getSlot(args.getFirstEncodedKey());
        List<ClusterCommand<K, V, ?>> commandPartition = partitions.computeIfAbsent(SlotIntent.of(intent, hash), slotIntent -> new ArrayList<>());
        commandPartition.add(new ClusterCommand<>(cmd, this, executionLimit));
    }
    for (Map.Entry<SlotIntent, List<ClusterCommand<K, V, ?>>> entry : partitions.entrySet()) {
        SlotIntent slotIntent = entry.getKey();
        RedisChannelHandler<K, V> connection = (RedisChannelHandler<K, V>) clusterConnectionProvider.getConnection(slotIntent.intent, slotIntent.slotHash);
        RedisChannelWriter channelWriter = connection.getChannelWriter();
        if (channelWriter instanceof ClusterDistributionChannelWriter) {
            ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) channelWriter;
            channelWriter = writer.defaultWriter;
        }
        if (channelWriter != null && channelWriter != this && channelWriter != defaultWriter) {
            channelWriter.write(entry.getValue());
        }
    }
    clusterCommands.forEach(this::write);
    defaultCommands.forEach(defaultWriter::write);
    return (Collection) commands;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) RedisChannelHandler(io.lettuce.core.RedisChannelHandler) RedisException(io.lettuce.core.RedisException) ArrayList(java.util.ArrayList) List(java.util.List) RedisChannelWriter(io.lettuce.core.RedisChannelWriter) Intent(io.lettuce.core.cluster.ClusterConnectionProvider.Intent) ByteBuffer(java.nio.ByteBuffer) DefaultEndpoint(io.lettuce.core.protocol.DefaultEndpoint) Collection(java.util.Collection) HashMap(java.util.HashMap) Map(java.util.Map)

Example 3 with Intent

use of io.lettuce.core.cluster.ClusterConnectionProvider.Intent in project lettuce-core by lettuce-io.

the class ClusterDistributionChannelWriter method doWrite.

private <K, V, T> RedisCommand<K, V, T> doWrite(RedisCommand<K, V, T> command) {
    if (command instanceof ClusterCommand && !command.isDone()) {
        ClusterCommand<K, V, T> clusterCommand = (ClusterCommand<K, V, T>) command;
        if (clusterCommand.isMoved() || clusterCommand.isAsk()) {
            HostAndPort target;
            boolean asking;
            ByteBuffer firstEncodedKey = clusterCommand.getArgs().getFirstEncodedKey();
            String keyAsString = null;
            int slot = -1;
            if (firstEncodedKey != null) {
                firstEncodedKey.mark();
                keyAsString = StringCodec.UTF8.decodeKey(firstEncodedKey);
                firstEncodedKey.reset();
                slot = getSlot(firstEncodedKey);
            }
            if (clusterCommand.isMoved()) {
                target = getMoveTarget(clusterCommand.getError());
                clusterEventListener.onMovedRedirection();
                asking = false;
                publish(new MovedRedirectionEvent(clusterCommand.getType().name(), keyAsString, slot, clusterCommand.getError()));
            } else {
                target = getAskTarget(clusterCommand.getError());
                asking = true;
                clusterEventListener.onAskRedirection();
                publish(new AskRedirectionEvent(clusterCommand.getType().name(), keyAsString, slot, clusterCommand.getError()));
            }
            command.getOutput().setError((String) null);
            CompletableFuture<StatefulRedisConnection<K, V>> connectFuture = asyncClusterConnectionProvider.getConnectionAsync(Intent.WRITE, target.getHostText(), target.getPort());
            if (isSuccessfullyCompleted(connectFuture)) {
                writeCommand(command, asking, connectFuture.join(), null);
            } else {
                connectFuture.whenComplete((connection, throwable) -> writeCommand(command, asking, connection, throwable));
            }
            return command;
        }
    }
    ClusterCommand<K, V, T> commandToSend = getCommandToSend(command);
    CommandArgs<K, V> args = command.getArgs();
    // exclude CLIENT commands from cluster routing
    if (args != null && !CommandType.CLIENT.equals(commandToSend.getType())) {
        ByteBuffer encodedKey = args.getFirstEncodedKey();
        if (encodedKey != null) {
            int hash = getSlot(encodedKey);
            Intent intent = getIntent(command.getType());
            CompletableFuture<StatefulRedisConnection<K, V>> connectFuture = ((AsyncClusterConnectionProvider) clusterConnectionProvider).getConnectionAsync(intent, hash);
            if (isSuccessfullyCompleted(connectFuture)) {
                writeCommand(commandToSend, false, connectFuture.join(), null);
            } else {
                connectFuture.whenComplete((connection, throwable) -> writeCommand(commandToSend, false, connection, throwable));
            }
            return commandToSend;
        }
    }
    writeCommand(commandToSend, defaultWriter);
    return commandToSend;
}
Also used : Intent(io.lettuce.core.cluster.ClusterConnectionProvider.Intent) ByteBuffer(java.nio.ByteBuffer) DefaultEndpoint(io.lettuce.core.protocol.DefaultEndpoint) StatefulRedisConnection(io.lettuce.core.api.StatefulRedisConnection) MovedRedirectionEvent(io.lettuce.core.cluster.event.MovedRedirectionEvent) HostAndPort(io.lettuce.core.internal.HostAndPort) AskRedirectionEvent(io.lettuce.core.cluster.event.AskRedirectionEvent)

Aggregations

Intent (io.lettuce.core.cluster.ClusterConnectionProvider.Intent)3 DefaultEndpoint (io.lettuce.core.protocol.DefaultEndpoint)2 ByteBuffer (java.nio.ByteBuffer)2 RedisChannelHandler (io.lettuce.core.RedisChannelHandler)1 RedisChannelWriter (io.lettuce.core.RedisChannelWriter)1 RedisException (io.lettuce.core.RedisException)1 StatefulRedisConnection (io.lettuce.core.api.StatefulRedisConnection)1 AskRedirectionEvent (io.lettuce.core.cluster.event.AskRedirectionEvent)1 MovedRedirectionEvent (io.lettuce.core.cluster.event.MovedRedirectionEvent)1 HostAndPort (io.lettuce.core.internal.HostAndPort)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1