Search in sources :

Example 26 with Partitions

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

the class RedisClusterClient method connectClusterPubSubAsync.

/**
 * Create a clustered 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<StatefulRedisClusterPubSubConnection<K, V>> connectClusterPubSubAsync(RedisCodec<K, V> codec) {
    if (partitions == null) {
        return Futures.failed(new IllegalStateException("Partitions not initialized. Initialize via RedisClusterClient.getPartitions()."));
    }
    topologyRefreshScheduler.activateTopologyRefreshIfNeeded();
    logger.debug("connectClusterPubSub(" + initialUris + ")");
    PubSubClusterEndpoint<K, V> endpoint = new PubSubClusterEndpoint<>(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);
    ClusterPubSubConnectionProvider<K, V> pooledClusterConnectionProvider = new ClusterPubSubConnectionProvider<>(this, clusterWriter, codec, endpoint.getUpstreamListener(), topologyRefreshScheduler);
    StatefulRedisClusterPubSubConnectionImpl<K, V> connection = new StatefulRedisClusterPubSubConnectionImpl<>(endpoint, pooledClusterConnectionProvider, clusterWriter, codec, getFirstUri().getTimeout());
    clusterWriter.setClusterConnectionProvider(pooledClusterConnectionProvider);
    connection.setPartitions(partitions);
    Supplier<CommandHandler> commandHandlerSupplier = () -> new PubSubCommandHandler<>(getClusterClientOptions(), getResources(), codec, endpoint);
    Mono<SocketAddress> socketAddressSupplier = getSocketAddressSupplier(connection::getPartitions, TopologyComparators::sortByClientCount);
    Mono<StatefulRedisClusterPubSubConnectionImpl<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 -> (StatefulRedisClusterPubSubConnection<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) CommandHandler(io.lettuce.core.protocol.CommandHandler) PubSubCommandHandler(io.lettuce.core.pubsub.PubSubCommandHandler) PubSubEndpoint(io.lettuce.core.pubsub.PubSubEndpoint) DefaultEndpoint(io.lettuce.core.protocol.DefaultEndpoint) StatefulRedisClusterPubSubConnection(io.lettuce.core.cluster.pubsub.StatefulRedisClusterPubSubConnection) PubSubCommandHandler(io.lettuce.core.pubsub.PubSubCommandHandler) SocketAddress(java.net.SocketAddress)

Example 27 with Partitions

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

the class DefaultClusterTopologyRefresh method loadViews.

/**
 * Load partition views from a collection of {@link RedisURI}s and return the view per {@link RedisURI}. Partitions contain
 * an ordered list of {@link RedisClusterNode}s. The sort key is latency. Nodes with lower latency come first.
 *
 * @param seed collection of {@link RedisURI}s
 * @param connectTimeout connect timeout
 * @param discovery {@code true} to discover additional nodes
 * @return mapping between {@link RedisURI} and {@link Partitions}
 */
@Override
public CompletionStage<Map<RedisURI, Partitions>> loadViews(Iterable<RedisURI> seed, Duration connectTimeout, boolean discovery) {
    if (!isEventLoopActive()) {
        return CompletableFuture.completedFuture(Collections.emptyMap());
    }
    long commandTimeoutNs = getCommandTimeoutNs(seed);
    ConnectionTracker tracker = new ConnectionTracker();
    long connectionTimeout = commandTimeoutNs + connectTimeout.toNanos();
    openConnections(tracker, seed, connectionTimeout, TimeUnit.NANOSECONDS);
    CompletableFuture<NodeTopologyViews> composition = tracker.whenComplete(map -> {
        return new Connections(clientResources, map);
    }).thenCompose(connections -> {
        Requests requestedTopology = connections.requestTopology(commandTimeoutNs, TimeUnit.NANOSECONDS);
        Requests requestedInfo = connections.requestInfo(commandTimeoutNs, TimeUnit.NANOSECONDS);
        return CompletableFuture.allOf(requestedTopology.allCompleted(), requestedInfo.allCompleted()).thenApplyAsync(ignore -> getNodeSpecificViews(requestedTopology, requestedInfo), clientResources.eventExecutorGroup()).thenCompose(views -> {
            if (discovery && isEventLoopActive()) {
                Set<RedisURI> allKnownUris = views.getClusterNodes();
                Set<RedisURI> discoveredNodes = difference(allKnownUris, toSet(seed));
                if (discoveredNodes.isEmpty()) {
                    return CompletableFuture.completedFuture(views);
                }
                openConnections(tracker, discoveredNodes, connectionTimeout, TimeUnit.NANOSECONDS);
                return tracker.whenComplete(map -> {
                    return new Connections(clientResources, map).retainAll(discoveredNodes);
                }).thenCompose(newConnections -> {
                    Requests additionalTopology = newConnections.requestTopology(commandTimeoutNs, TimeUnit.NANOSECONDS).mergeWith(requestedTopology);
                    Requests additionalInfo = newConnections.requestInfo(commandTimeoutNs, TimeUnit.NANOSECONDS).mergeWith(requestedInfo);
                    return CompletableFuture.allOf(additionalTopology.allCompleted(), additionalInfo.allCompleted()).thenApplyAsync(ignore2 -> getNodeSpecificViews(additionalTopology, additionalInfo), clientResources.eventExecutorGroup());
                });
            }
            return CompletableFuture.completedFuture(views);
        }).whenComplete((ignore, throwable) -> {
            if (throwable != null) {
                try {
                    tracker.close();
                } catch (Exception e) {
                    logger.debug("Cannot close ClusterTopologyRefresh connections", e);
                }
            }
        }).thenCompose((it) -> tracker.close().thenApply(ignore -> it)).thenCompose(it -> {
            if (it.isEmpty()) {
                Exception exception = tryFail(requestedTopology, tracker, seed);
                return Futures.failed(exception);
            }
            return CompletableFuture.completedFuture(it);
        });
    });
    return composition.thenApply(NodeTopologyViews::toMap);
}
Also used : ClientResources(io.lettuce.core.resource.ClientResources) SocketAddress(java.net.SocketAddress) Partitions(io.lettuce.core.cluster.models.partitions.Partitions) StringCodec(io.lettuce.core.codec.StringCodec) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) StatefulConnection(io.lettuce.core.api.StatefulConnection) Function(java.util.function.Function) TreeSet(java.util.TreeSet) Futures(io.lettuce.core.internal.Futures) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Future(java.util.concurrent.Future) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) StatefulRedisConnection(io.lettuce.core.api.StatefulRedisConnection) Duration(java.time.Duration) Map(java.util.Map) StreamSupport(java.util.stream.StreamSupport) ExceptionFactory(io.lettuce.core.internal.ExceptionFactory) Timeout(io.netty.util.Timeout) RedisException(io.lettuce.core.RedisException) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) Exceptions(io.lettuce.core.internal.Exceptions) Set(java.util.Set) IOException(java.io.IOException) CompletionException(java.util.concurrent.CompletionException) EventExecutorGroup(io.netty.util.concurrent.EventExecutorGroup) Collectors(java.util.stream.Collectors) SystemPropertyUtil(io.netty.util.internal.SystemPropertyUtil) TimeUnit(java.util.concurrent.TimeUnit) RedisURI(io.lettuce.core.RedisURI) List(java.util.List) CompletionStage(java.util.concurrent.CompletionStage) RedisConnectionException(io.lettuce.core.RedisConnectionException) LettuceStrings(io.lettuce.core.internal.LettuceStrings) StringJoiner(java.util.StringJoiner) InternalLogger(io.netty.util.internal.logging.InternalLogger) ConnectionFuture(io.lettuce.core.ConnectionFuture) InternalLoggerFactory(io.netty.util.internal.logging.InternalLoggerFactory) Collections(java.util.Collections) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Set(java.util.Set) RedisException(io.lettuce.core.RedisException) IOException(java.io.IOException) CompletionException(java.util.concurrent.CompletionException) RedisConnectionException(io.lettuce.core.RedisConnectionException)

Example 28 with Partitions

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

the class RoundRobinSocketAddressSupplier method get.

@Override
public SocketAddress get() {
    Partitions partitions = this.partitions.get();
    if (!roundRobin.isConsistent(partitions)) {
        resetRoundRobin(partitions);
    }
    RedisClusterNode redisClusterNode = roundRobin.next();
    return getSocketAddress(redisClusterNode);
}
Also used : Partitions(io.lettuce.core.cluster.models.partitions.Partitions) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode)

Example 29 with Partitions

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

the class AdvancedClusterClientIntegrationTests method routeCommandToForbiddenHostOnRedirect.

@Test
@Inject
void routeCommandToForbiddenHostOnRedirect(@Connection(requiresNew = true) StatefulRedisClusterConnection<String, String> connectionUnderTest) {
    RedisAdvancedClusterCommands<String, String> sync = connectionUnderTest.sync();
    try {
        Partitions partitions = clusterClient.getPartitions();
        for (RedisClusterNode partition : partitions) {
            partition.setSlots(Collections.singletonList(0));
            if (partition.getUri().getPort() == 7380) {
                partition.setSlots(Collections.singletonList(6373));
            } else {
                partition.setUri(RedisURI.create("redis://non.existent.host:1234"));
            }
        }
        partitions.updateCache();
        // 6373
        sync.set("A", "value");
    } catch (Exception e) {
        assertThat(e).isInstanceOf(RedisException.class).hasMessageContaining("not allowed");
    } finally {
        clusterClient.getPartitions().clear();
        clusterClient.reloadPartitions();
    }
}
Also used : Partitions(io.lettuce.core.cluster.models.partitions.Partitions) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) Inject(javax.inject.Inject) Test(org.junit.jupiter.api.Test)

Example 30 with Partitions

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

the class AdvancedClusterClientIntegrationTests method routeCommandToNoAddrPartition.

@Test
@Inject
void routeCommandToNoAddrPartition(@New StatefulRedisClusterConnection<String, String> connectionUnderTest) {
    RedisAdvancedClusterCommands<String, String> sync = connectionUnderTest.sync();
    try {
        Partitions partitions = clusterClient.getPartitions();
        for (RedisClusterNode partition : partitions) {
            partition.setUri(RedisURI.create("redis://non.existent.host:1234"));
        }
        // 6373
        sync.set("A", "value");
    } catch (Exception e) {
        assertThat(e).isInstanceOf(RedisException.class).hasMessageContaining("Unable to connect to");
    } finally {
        clusterClient.getPartitions().clear();
        clusterClient.reloadPartitions();
    }
}
Also used : Partitions(io.lettuce.core.cluster.models.partitions.Partitions) RedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode) Inject(javax.inject.Inject) Test(org.junit.jupiter.api.Test)

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