All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.lettuce.core.masterreplica.Connections Maven / Gradle / Ivy

Go to download

Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and much more.

The newest version!
package io.lettuce.core.masterreplica;

import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import io.lettuce.core.RedisConnectionException;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.AsyncCloseable;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.codec.StringCodec;
import io.lettuce.core.internal.Futures;
import io.lettuce.core.models.role.RedisNodeDescription;
import io.lettuce.core.output.StatusOutput;
import io.lettuce.core.protocol.Command;
import io.lettuce.core.protocol.CommandArgs;
import io.lettuce.core.protocol.CommandKeyword;
import io.lettuce.core.protocol.CommandType;

/**
 * Connection collector with non-blocking synchronization. This synchronizer emits itself through a {@link Mono} as soon as it
 * gets synchronized via either receiving connects/exceptions from all connections or timing out.
 * 

* It can be used only once via {@link #getOrTimeout(Duration, ScheduledExecutorService)}. *

* Synchronizer uses a gate to determine whether it was already emitted or awaiting incoming events (exceptions, successful * connects). Connections arriving after closing the gate are discarded. * * @author Mark Paluch */ class Connections extends CompletableEventLatchSupport>, Connections> implements AsyncCloseable { private final Lock lock = new ReentrantLock(); private final Map> connections = new TreeMap<>( ReplicaUtils.RedisURIComparator.INSTANCE); private final List exceptions = new CopyOnWriteArrayList<>(); private final List nodes; private volatile boolean closed = false; public Connections(int expectedConnectionCount, List nodes) { super(expectedConnectionCount); this.nodes = nodes; } @Override protected void onAccept(Tuple2> value) { if (this.closed) { value.getT2().closeAsync(); return; } try { lock.lock(); this.connections.put(value.getT1(), value.getT2()); } finally { lock.unlock(); } } @Override protected void onError(Throwable value) { this.exceptions.add(value); } @Override protected void onDrop(Tuple2> value) { value.getT2().closeAsync(); } @Override protected void onDrop(Throwable value) { } @Override protected void onEmit(Emission emission) { if (getExpectedCount() != 0 && this.connections.isEmpty() && !this.exceptions.isEmpty()) { RedisConnectionException collector = new RedisConnectionException( "Unable to establish a connection to Redis Master/Replica"); this.exceptions.forEach(collector::addSuppressed); emission.error(collector); } else { emission.success(this); } } /** * @return {@code true} if no connections present. */ public boolean isEmpty() { try { lock.lock(); return this.connections.isEmpty(); } finally { lock.unlock(); } } /* * Initiate {@code PING} on all connections and return the {@link Requests}. * @return the {@link Requests}. */ public Requests requestPing() { Set>> entries = new LinkedHashSet<>( this.connections.entrySet()); Requests requests = new Requests(entries.size(), this.nodes); for (Map.Entry> entry : entries) { CommandArgs args = new CommandArgs<>(StringCodec.ASCII).add(CommandKeyword.NODES); Command command = new Command<>(CommandType.PING, new StatusOutput<>(StringCodec.ASCII), args); TimedAsyncCommand timedCommand = new TimedAsyncCommand<>(command); entry.getValue().dispatch(timedCommand); requests.addRequest(entry.getKey(), timedCommand); } return requests; } /** * Close all connections. */ public CompletableFuture closeAsync() { List> close = new ArrayList<>(this.connections.size()); List toRemove = new ArrayList<>(this.connections.size()); this.closed = true; for (Map.Entry> entry : this.connections.entrySet()) { toRemove.add(entry.getKey()); close.add(entry.getValue().closeAsync()); } for (RedisURI redisURI : toRemove) { this.connections.remove(redisURI); } return Futures.allOf(close); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy