use of io.lettuce.core.cluster.models.partitions.RedisClusterNode 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;
}
use of io.lettuce.core.cluster.models.partitions.RedisClusterNode 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);
}
use of io.lettuce.core.cluster.models.partitions.RedisClusterNode in project lettuce-core by lettuce-io.
the class RedisAdvancedClusterReactiveCommandsImpl method executeOnNodes.
/**
* Run a command on all available nodes that match {@code filter}.
*
* @param function function producing the command
* @param filter filter function for the node selection
* @param <T> result type
* @return map of a key (counter) and commands.
*/
protected <T> Map<String, Publisher<T>> executeOnNodes(Function<RedisClusterReactiveCommands<K, V>, ? extends Publisher<T>> function, Predicate<RedisClusterNode> filter) {
Map<String, Publisher<T>> executions = new HashMap<>();
for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) {
if (!filter.test(redisClusterNode)) {
continue;
}
RedisURI uri = redisClusterNode.getUri();
Mono<RedisClusterReactiveCommands<K, V>> connection = getConnectionReactive(uri.getHost(), uri.getPort());
executions.put(redisClusterNode.getNodeId(), connection.flatMapMany(function::apply));
}
return executions;
}
use of io.lettuce.core.cluster.models.partitions.RedisClusterNode in project lettuce-core by lettuce-io.
the class RedisClusterClient method getTopologyRefreshSource.
/**
* Returns the seed {@link RedisURI} for the topology refreshing. This method is called before each topology refresh to
* provide an {@link Iterable} of {@link RedisURI} that is used to perform the next topology refresh.
* <p>
* Subclasses of {@link RedisClusterClient} may override that method.
*
* @return {@link Iterable} of {@link RedisURI} for the next topology refresh.
*/
protected Iterable<RedisURI> getTopologyRefreshSource() {
boolean initialSeedNodes = !useDynamicRefreshSources();
Iterable<RedisURI> seed;
if (initialSeedNodes || partitions == null || partitions.isEmpty()) {
seed = this.initialUris;
} else {
List<RedisURI> uris = new ArrayList<>();
for (RedisClusterNode partition : TopologyComparators.sortByUri(partitions)) {
uris.add(partition.getUri());
}
seed = uris;
}
return seed;
}
use of io.lettuce.core.cluster.models.partitions.RedisClusterNode 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;
}
Aggregations