Search in sources :

Example 21 with Partitions

use of io.lettuce.core.cluster.models.partitions.Partitions in project lettuce-core by lettuce-io.

the class TopologyRefreshIntegrationTests method staticSourcesProvidesClientCountForSeedNodes.

@Test
void staticSourcesProvidesClientCountForSeedNodes() {
    ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder().dynamicRefreshSources(false).build();
    clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(topologyRefreshOptions).build());
    RedisAdvancedClusterAsyncCommands<String, String> clusterConnection = clusterClient.connect().async();
    Partitions partitions = clusterClient.getPartitions();
    RedisClusterNodeSnapshot node1 = (RedisClusterNodeSnapshot) partitions.getPartitionBySlot(0);
    assertThat(node1.getConnectedClients()).isGreaterThanOrEqualTo(1);
    RedisClusterNodeSnapshot node2 = (RedisClusterNodeSnapshot) partitions.getPartitionBySlot(15000);
    assertThat(node2.getConnectedClients()).isNull();
    clusterConnection.getStatefulConnection().close();
}
Also used : Partitions(io.lettuce.core.cluster.models.partitions.Partitions) ClusterTopologyRefreshOptions(io.lettuce.core.cluster.ClusterTopologyRefreshOptions) Test(org.junit.jupiter.api.Test)

Example 22 with Partitions

use of io.lettuce.core.cluster.models.partitions.Partitions in project lettuce-core by lettuce-io.

the class PooledClusterConnectionProvider method getWriteConnection.

private CompletableFuture<StatefulRedisConnection<K, V>> getWriteConnection(int slot) {
    // avoid races when reconfiguring partitions.
    CompletableFuture<StatefulRedisConnection<K, V>> writer;
    synchronized (stateLock) {
        writer = writers[slot];
    }
    if (writer == null) {
        RedisClusterNode partition = partitions.getPartitionBySlot(slot);
        if (partition == null) {
            clusterEventListener.onUncoveredSlot(slot);
            return Futures.failed(new PartitionSelectorException("Cannot determine a partition for slot " + slot + ".", partitions.clone()));
        }
        // Use always host and port for slot-oriented operations. We don't want to get reconnected on a different
        // host because the nodeId can be handled by a different host.
        RedisURI uri = partition.getUri();
        ConnectionKey key = new ConnectionKey(Intent.WRITE, uri.getHost(), uri.getPort());
        ConnectionFuture<StatefulRedisConnection<K, V>> future = getConnectionAsync(key);
        return future.thenApply(connection -> {
            synchronized (stateLock) {
                if (writers[slot] == null) {
                    writers[slot] = CompletableFuture.completedFuture(connection);
                }
            }
            return connection;
        }).toCompletableFuture();
    }
    return writer;
}
Also used : Arrays(java.util.Arrays) Partitions(io.lettuce.core.cluster.models.partitions.Partitions) CompletableFuture(java.util.concurrent.CompletableFuture) StatefulConnection(io.lettuce.core.api.StatefulConnection) RedisNodeDescription(io.lettuce.core.models.role.RedisNodeDescription) Function(java.util.function.Function) RedisChannelWriter(io.lettuce.core.RedisChannelWriter) ConnectionKey(io.lettuce.core.cluster.ClusterNodeConnectionFactory.ConnectionKey) Futures(io.lettuce.core.internal.Futures) ArrayList(java.util.ArrayList) LettuceAssert(io.lettuce.core.internal.LettuceAssert) OrderingReadFromAccessor(io.lettuce.core.OrderingReadFromAccessor) StatefulRedisConnection(io.lettuce.core.api.StatefulRedisConnection) PushMessage(io.lettuce.core.api.push.PushMessage) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) RedisFuture(io.lettuce.core.RedisFuture) AsyncConnectionProvider(io.lettuce.core.internal.AsyncConnectionProvider) Iterator(java.util.Iterator) RedisException(io.lettuce.core.RedisException) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) Exceptions(io.lettuce.core.internal.Exceptions) Collection(java.util.Collection) RedisClusterPushListener(io.lettuce.core.cluster.api.push.RedisClusterPushListener) CompletionException(java.util.concurrent.CompletionException) Collectors(java.util.stream.Collectors) RedisCodec(io.lettuce.core.codec.RedisCodec) RedisURI(io.lettuce.core.RedisURI) List(java.util.List) RedisConnectionException(io.lettuce.core.RedisConnectionException) HostAndPort(io.lettuce.core.internal.HostAndPort) ReadFrom(io.lettuce.core.ReadFrom) InternalLogger(io.netty.util.internal.logging.InternalLogger) ConnectionFuture(io.lettuce.core.ConnectionFuture) InternalLoggerFactory(io.netty.util.internal.logging.InternalLoggerFactory) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) RedisURI(io.lettuce.core.RedisURI) ConnectionKey(io.lettuce.core.cluster.ClusterNodeConnectionFactory.ConnectionKey) StatefulRedisConnection(io.lettuce.core.api.StatefulRedisConnection)

Example 23 with Partitions

use of io.lettuce.core.cluster.models.partitions.Partitions in project lettuce-core by lettuce-io.

the class RedisAdvancedClusterAsyncCommandsImpl method randomkey.

@Override
public RedisFuture<K> randomkey() {
    Partitions partitions = getStatefulConnection().getPartitions();
    if (partitions.isEmpty()) {
        return super.randomkey();
    }
    int index = ThreadLocalRandom.current().nextInt(partitions.size());
    RedisClusterNode partition = partitions.getPartition(index);
    CompletableFuture<K> future = getConnectionAsync(partition.getUri().getHost(), partition.getUri().getPort()).thenCompose(RedisKeyAsyncCommands::randomkey);
    return new PipelinedRedisFuture<>(future);
}
Also used : Partitions(io.lettuce.core.cluster.models.partitions.Partitions) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) RedisKeyAsyncCommands(io.lettuce.core.api.async.RedisKeyAsyncCommands)

Example 24 with Partitions

use of io.lettuce.core.cluster.models.partitions.Partitions in project lettuce-core by lettuce-io.

the class RedisClusterClient method connectClusterAsync.

/**
 * Create a clustered pub/sub connection with command distributor.
 *
 * @param codec Use this codec to encode/decode keys and values, must not be {@code null}
 * @param <K> Key type
 * @param <V> Value type
 * @return a new connection
 */
private <K, V> CompletableFuture<StatefulRedisClusterConnection<K, V>> connectClusterAsync(RedisCodec<K, V> codec) {
    if (partitions == null) {
        return Futures.failed(new IllegalStateException("Partitions not initialized. Initialize via RedisClusterClient.getPartitions()."));
    }
    topologyRefreshScheduler.activateTopologyRefreshIfNeeded();
    logger.debug("connectCluster(" + initialUris + ")");
    DefaultEndpoint endpoint = new DefaultEndpoint(getClusterClientOptions(), getResources());
    RedisChannelWriter writer = endpoint;
    if (CommandExpiryWriter.isSupported(getClusterClientOptions())) {
        writer = new CommandExpiryWriter(writer, getClusterClientOptions(), getResources());
    }
    if (CommandListenerWriter.isSupported(getCommandListeners())) {
        writer = new CommandListenerWriter(writer, getCommandListeners());
    }
    ClusterDistributionChannelWriter clusterWriter = new ClusterDistributionChannelWriter(writer, getClusterClientOptions(), topologyRefreshScheduler);
    PooledClusterConnectionProvider<K, V> pooledClusterConnectionProvider = new PooledClusterConnectionProvider<>(this, clusterWriter, codec, topologyRefreshScheduler);
    clusterWriter.setClusterConnectionProvider(pooledClusterConnectionProvider);
    StatefulRedisClusterConnectionImpl<K, V> connection = newStatefulRedisClusterConnection(clusterWriter, pooledClusterConnectionProvider, codec, getFirstUri().getTimeout());
    connection.setReadFrom(ReadFrom.UPSTREAM);
    connection.setPartitions(partitions);
    Supplier<CommandHandler> commandHandlerSupplier = () -> new CommandHandler(getClusterClientOptions(), getResources(), endpoint);
    Mono<SocketAddress> socketAddressSupplier = getSocketAddressSupplier(connection::getPartitions, TopologyComparators::sortByClientCount);
    Mono<StatefulRedisClusterConnectionImpl<K, V>> connectionMono = Mono.defer(() -> connect(socketAddressSupplier, endpoint, connection, commandHandlerSupplier));
    for (int i = 1; i < getConnectionAttempts(); i++) {
        connectionMono = connectionMono.onErrorResume(t -> connect(socketAddressSupplier, endpoint, connection, commandHandlerSupplier));
    }
    return connectionMono.doOnNext(c -> connection.registerCloseables(closeableResources, clusterWriter, pooledClusterConnectionProvider)).map(it -> (StatefulRedisClusterConnection<K, V>) it).toFuture();
}
Also used : StatefulRedisClusterPubSubConnection(io.lettuce.core.cluster.pubsub.StatefulRedisClusterPubSubConnection) SocketAddress(java.net.SocketAddress) Partitions(io.lettuce.core.cluster.models.partitions.Partitions) CommandExpiryWriter(io.lettuce.core.protocol.CommandExpiryWriter) Futures(io.lettuce.core.internal.Futures) LettuceAssert(io.lettuce.core.internal.LettuceAssert) StatefulRedisConnection(io.lettuce.core.api.StatefulRedisConnection) Duration(java.time.Duration) Map(java.util.Map) PubSubEndpoint(io.lettuce.core.pubsub.PubSubEndpoint) URI(java.net.URI) CommandHandler(io.lettuce.core.protocol.CommandHandler) LettuceLists(io.lettuce.core.internal.LettuceLists) Exceptions(io.lettuce.core.internal.Exceptions) Predicate(java.util.function.Predicate) Collection(java.util.Collection) RedisCodec(io.lettuce.core.codec.RedisCodec) StatefulRedisClusterConnection(io.lettuce.core.cluster.api.StatefulRedisClusterConnection) TopologyRefreshEvent(io.lettuce.core.cluster.event.TopologyRefreshEvent) StatefulRedisPubSubConnectionImpl(io.lettuce.core.pubsub.StatefulRedisPubSubConnectionImpl) ClusterTopologyChangedEvent(io.lettuce.core.cluster.event.ClusterTopologyChangedEvent) List(java.util.List) CompletionStage(java.util.concurrent.CompletionStage) DefaultEndpoint(io.lettuce.core.protocol.DefaultEndpoint) InternalLogger(io.netty.util.internal.logging.InternalLogger) KeyValueStreamingChannel(io.lettuce.core.output.KeyValueStreamingChannel) io.lettuce.core(io.lettuce.core) NodeSelectionSupport(io.lettuce.core.cluster.api.NodeSelectionSupport) ClusterTopologyRefresh(io.lettuce.core.cluster.topology.ClusterTopologyRefresh) ClientResources(io.lettuce.core.resource.ClientResources) TopologyComparators(io.lettuce.core.cluster.topology.TopologyComparators) StringCodec(io.lettuce.core.codec.StringCodec) PushHandler(io.lettuce.core.protocol.PushHandler) CompletableFuture(java.util.concurrent.CompletableFuture) Function(java.util.function.Function) Supplier(java.util.function.Supplier) RedisAdvancedClusterAsyncCommands(io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands) ArrayList(java.util.ArrayList) Iterator(java.util.Iterator) NodeConnectionFactory(io.lettuce.core.cluster.topology.NodeConnectionFactory) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) RedisAdvancedClusterCommands(io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands) StatefulRedisPubSubConnection(io.lettuce.core.pubsub.StatefulRedisPubSubConnection) PubSubCommandHandler(io.lettuce.core.pubsub.PubSubCommandHandler) Mono(reactor.core.publisher.Mono) EventRecorder(io.lettuce.core.event.jfr.EventRecorder) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) Closeable(java.io.Closeable) InternalLoggerFactory(io.netty.util.internal.logging.InternalLoggerFactory) Collections(java.util.Collections) TopologyComparators(io.lettuce.core.cluster.topology.TopologyComparators) CommandExpiryWriter(io.lettuce.core.protocol.CommandExpiryWriter) DefaultEndpoint(io.lettuce.core.protocol.DefaultEndpoint) CommandHandler(io.lettuce.core.protocol.CommandHandler) PubSubCommandHandler(io.lettuce.core.pubsub.PubSubCommandHandler) PubSubEndpoint(io.lettuce.core.pubsub.PubSubEndpoint) DefaultEndpoint(io.lettuce.core.protocol.DefaultEndpoint) StatefulRedisClusterConnection(io.lettuce.core.cluster.api.StatefulRedisClusterConnection) SocketAddress(java.net.SocketAddress)

Example 25 with Partitions

use of io.lettuce.core.cluster.models.partitions.Partitions in project lettuce-core by lettuce-io.

the class RedisClusterClient method loadPartitionsAsync.

/**
 * Retrieve partitions. Nodes within {@link Partitions} are ordered by latency. Lower latency nodes come first.
 *
 * @return future that emits {@link Partitions} upon a successful topology lookup.
 * @since 6.0
 */
protected CompletableFuture<Partitions> loadPartitionsAsync() {
    Iterable<RedisURI> topologyRefreshSource = getTopologyRefreshSource();
    CompletableFuture<Partitions> future = new CompletableFuture<>();
    fetchPartitions(topologyRefreshSource).whenComplete((nodes, throwable) -> {
        if (throwable == null) {
            future.complete(nodes);
            return;
        }
        // Attempt recovery using initial seed nodes
        if (useDynamicRefreshSources() && topologyRefreshSource != initialUris) {
            fetchPartitions(initialUris).whenComplete((nextNodes, nextThrowable) -> {
                if (nextThrowable != null) {
                    Throwable exception = Exceptions.unwrap(nextThrowable);
                    exception.addSuppressed(Exceptions.unwrap(throwable));
                    future.completeExceptionally(exception);
                } else {
                    future.complete(nextNodes);
                }
            });
        } else {
            future.completeExceptionally(Exceptions.unwrap(throwable));
        }
    });
    Predicate<RedisClusterNode> nodeFilter = getClusterClientOptions().getNodeFilter();
    if (nodeFilter != ClusterClientOptions.DEFAULT_NODE_FILTER) {
        return future.thenApply(partitions -> {
            List<RedisClusterNode> toRemove = new ArrayList<>();
            for (RedisClusterNode partition : partitions) {
                if (!nodeFilter.test(partition)) {
                    toRemove.add(partition);
                }
            }
            partitions.removeAll(toRemove);
            return partitions;
        });
    }
    return future;
}
Also used : Partitions(io.lettuce.core.cluster.models.partitions.Partitions) CompletableFuture(java.util.concurrent.CompletableFuture) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) ArrayList(java.util.ArrayList)

Aggregations

Partitions (io.lettuce.core.cluster.models.partitions.Partitions)69 Test (org.junit.jupiter.api.Test)50 RedisClusterNode (io.lettuce.core.cluster.models.partitions.RedisClusterNode)36 RedisURI (io.lettuce.core.RedisURI)20 ArrayList (java.util.ArrayList)13 StatefulRedisConnection (io.lettuce.core.api.StatefulRedisConnection)10 PartitionsConsensusTestSupport.createPartitions (io.lettuce.core.cluster.PartitionsConsensusTestSupport.createPartitions)9 RedisCodec (io.lettuce.core.codec.RedisCodec)9 CompletableFuture (java.util.concurrent.CompletableFuture)8 Exceptions (io.lettuce.core.internal.Exceptions)6 Futures (io.lettuce.core.internal.Futures)6 InternalLogger (io.netty.util.internal.logging.InternalLogger)6 InternalLoggerFactory (io.netty.util.internal.logging.InternalLoggerFactory)6 List (java.util.List)6 Function (java.util.function.Function)6 LettuceAssert (io.lettuce.core.internal.LettuceAssert)5 Collection (java.util.Collection)5 Iterator (java.util.Iterator)5 Map (java.util.Map)5 CompletionStage (java.util.concurrent.CompletionStage)5