diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 28295f9953..d0832c3f94 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -2399,7 +2399,7 @@ configuration is required for netty and the JDK in We don’t have found a way yet to invoke default interface methods on proxies without `MethodHandle`. Hence the `NodeSelection` API -(`masters()`, `all()` and others on `RedisAdvancedClusterCommands` and +(`primaries()`, `all()` and others on `RedisAdvancedClusterCommands` and `RedisAdvancedClusterAsyncCommands`) do not work. ## Command execution reliability @@ -2596,7 +2596,7 @@ means, if you execute a command twice, each resulting state is different in comparison to the previous. Examples for non-idempotent Redis commands are such as `LPUSH`, `PUBLISH` or `INCR`. -Note: When using master-replica replication, different rules apply to +Note: When using primary-replica replication, different rules apply to *at-least-once* consistency. Replication between Redis nodes works asynchronously. A command can be processed successfully from Lettuce’s client perspective, but the result is not necessarily replicated to the @@ -2659,14 +2659,14 @@ auto-replay of commands. Lettuce sticks in clustered operations to the same rules as for standalone operations but with one exception: -Command execution on master nodes, which is rejected by a `MOVED` +Command execution on primary nodes, which is rejected by a `MOVED` response are tried to re-execute with the appropriate connection. -`MOVED` errors occur on master nodes when a slot’s responsibility is +`MOVED` errors occur on primary nodes when a slot’s responsibility is moved from one cluster node to another node. Afterwards *at-least-once* and *at-most-once* rules apply. When the cluster topology changes, generally spoken, the cluster slots -or master/replica state is reconfigured, following rules apply: +or primary/replica state is reconfigured, following rules apply: - **at-most-once** If the connection is disconnected, queued commands are canceled and buffered commands, which were not sent, are executed @@ -2679,4 +2679,3 @@ or master/replica state is reconfigured, following rules apply: - If the connection is not disconnected, queued commands are finished and buffered commands, which were not sent, are executed by using the new cluster view - diff --git a/docs/ha-sharding.md b/docs/ha-sharding.md index 67c547b65d..36ff63c952 100644 --- a/docs/ha-sharding.md +++ b/docs/ha-sharding.md @@ -1,75 +1,75 @@ # High-Availability and Sharding -## Master/Replica +## Primary/Replica Redis can increase availability and read throughput by using -replication. Lettuce provides dedicated Master/Replica support since 4.2 +replication. Lettuce provides dedicated Primary/Replica support since 4.2 for topologies and ReadFrom-Settings. -Redis Master/Replica can be run standalone or together with Redis -Sentinel, which provides automated failover and master promotion. -Failover and master promotion is supported in Lettuce already since -version 3.1 for master connections. +Redis Primary/Replica can be run standalone or together with Redis +Sentinel, which provides automated failover and primary promotion. +Failover and primary promotion is supported in Lettuce already since +version 3.1 for primary connections. -Connections can be obtained from the `MasterReplica` connection provider +Connections can be obtained from the `PrimaryReplica` connection provider by supplying the client, Codec, and one or multiple RedisURIs. ### Redis Sentinel -Master/Replica using Redis Sentinel uses Redis +Primary/Replica using Redis Sentinel uses Redis Sentinel as registry and notification source for topology events. -Details about the master and its replicas are obtained from Redis +Details about the primary and its replicas are obtained from Redis Sentinel. Lettuce subscribes to Redis Sentinel events for notifications to all supplied Sentinels. -### Standalone Master/Replica +### Standalone Primary/Replica -Running a Standalone Master/Replica setup requires one seed address to +Running a Standalone Primary/Replica setup requires one seed address to establish a Redis connection. Providing one `RedisURI` will discover -other nodes which belong to the Master/Replica setup and use the +other nodes which belong to the Primary/Replica setup and use the discovered addresses for connections. The initial URI can point either -to a master or a replica node. +to a primary or a replica node. -### Static Master/Replica with predefined node addresses +### Static Primary/Replica with predefined node addresses In some cases, topology discovery shouldn’t be enabled, or the discovered Redis addresses are not suited for connections. AWS ElastiCache falls into this category. Lettuce allows to specify one or more Redis addresses as `List` and predefine the node topology. -Master/Replica URIs will be treated in this case as static topology, and +Primary/Replica URIs will be treated in this case as static topology, and no additional hosts are discovered in such case. Redis Standalone -Master/Replica will discover the roles of the supplied `RedisURI`s and +Primary/Replica will discover the roles of the supplied `RedisURI`s and issue commands to the appropriate node. ### Topology discovery -Master-Replica topologies are either static or semi-static. Redis +Primary-Replica topologies are either static or semi-static. Redis Standalone instances with attached replicas provide no failover/HA mechanism. Redis Sentinel managed instances are controlled by Redis -Sentinel and allow failover (which include master promotion). The -`MasterReplica` API supports both mechanisms. The topology is provided +Sentinel and allow failover (which include primary promotion). The +`PrimaryReplica` API supports both mechanisms. The topology is provided by a `TopologyProvider`: -- `MasterReplicaTopologyProvider`: Dynamic topology lookup using the +- `ReplicaTopologyProvider`: Dynamic topology lookup using the `INFO REPLICATION` output. Replicas are listed as replicaN=…​ entries. - The initial connection can either point to a master or a replica, and + The initial connection can either point to a primary or a replica, and the topology provider will discover nodes. The connection needs to be - re-established outside of Lettuce in a case of a Master/Replica + re-established outside of Lettuce in a case of a Primary/Replica failover or topology changes. - `StaticMasterReplicaTopologyProvider`: Topology is defined by the list - of URIs and the ROLE output. MasterReplica uses only the supplied + of URIs and the ROLE output. PrimaryReplica uses only the supplied nodes and won’t discover additional nodes in the setup. The connection needs to be re-established outside of Lettuce in case of a - Master/Replica failover or topology changes. + Primary/Replica failover or topology changes. - `SentinelTopologyProvider`: Dynamic topology lookup using the Redis Sentinel API. In particular, `SENTINEL MASTER` and `SENTINEL REPLICAS` - output. Master/Replica failover is handled by Lettuce. + output. Primary/Replica failover is handled by Lettuce. ### Topology Updates -- Standalone Master/Replica: Performs a one-time topology lookup which +- Standalone Primary/Replica: Performs a one-time topology lookup which remains static afterward - Redis Sentinel: Subscribes to all Sentinels and listens for Pub/Sub @@ -78,7 +78,7 @@ by a `TopologyProvider`: #### Transactions Since version 5.1, transactions and commands during a transaction are -routed to the master node to ensure atomic transaction execution on a +routed to the primary node to ensure atomic transaction execution on a single node. Transactions can contain read- and write-operations so the driver cannot decide upfront which node can be used to run the actual transaction. @@ -88,9 +88,9 @@ transaction. ``` java RedisClient redisClient = RedisClient.create(); -StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(redisClient, StringCodec.UTF8, +StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect(redisClient, StringCodec.UTF8, RedisURI.create("redis://localhost")); -connection.setReadFrom(ReadFrom.MASTER_PREFERRED); +connection.setReadFrom(ReadFrom.PRIMARY_PREFERRED); System.out.println("Connected to Redis"); @@ -101,9 +101,9 @@ redisClient.shutdown(); ``` java RedisClient redisClient = RedisClient.create(); -StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(redisClient, StringCodec.UTF8, - RedisURI.create("redis-sentinel://localhost:26379,localhost:26380/0#mymaster")); -connection.setReadFrom(ReadFrom.MASTER_PREFERRED); +StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect(redisClient, StringCodec.UTF8, + RedisURI.create("redis-sentinel://localhost:26379,localhost:26380/0#myprimary")); +connection.setReadFrom(ReadFrom.PRIMARY_PREFERRED); System.out.println("Connected to Redis"); @@ -118,9 +118,9 @@ List nodes = Arrays.asList(RedisURI.create("redis://host1"), RedisURI.create("redis://host2"), RedisURI.create("redis://host3")); -StatefulRedisMasterReplicaConnection connection = MasterReplica +StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica .connect(redisClient, StringCodec.UTF8, nodes); -connection.setReadFrom(ReadFrom.MASTER_PREFERRED); +connection.setReadFrom(ReadFrom.PRIMARY_PREFERRED); System.out.println("Connected to Redis"); @@ -138,10 +138,10 @@ Sentinel-managed nodes in multiple ways: Redis Sentinel commands 2. Using Redis Sentinel to [connect to a - master](#redis-discovery-using-redis-sentinel) + primary](#redis-discovery-using-redis-sentinel) -3. Using Redis Sentinel to connect to master nodes and replicas through - the {master-replica-api-link}. +3. Using Redis Sentinel to connect to primary nodes and replicas through + the `PrimaryReplica` API. In both cases, you need to supply a `RedisURI` since the Redis Sentinel integration supports multiple Sentinel hosts to provide high @@ -154,7 +154,7 @@ asynchronous connections and no connection pooling. Lettuce exposes an API to interact with Redis Sentinel nodes directly. This is useful for performing administrative tasks using Lettuce. You -can monitor new master nodes, query master addresses, replicas and much +can monitor new primary nodes, query primary addresses, replicas and much more. A connection to a Redis Sentinel node is established by `RedisClient.connectSentinel()`. Use a [Publish/Subscribe connection](user-guide/pubsub.md) to subscribe to Sentinel events. @@ -163,17 +163,17 @@ connection](user-guide/pubsub.md) to subscribe to Sentinel events. One or more Redis Sentinels can monitor Redis instances . These Redis instances are usually operated together with a replica of the Redis -instance. Once the master goes down, the replica is promoted to a -master. Once a master instance is not reachable anymore, the failover +instance. Once the primary goes down, the replica is promoted to a +primary. Once a primary instance is not reachable anymore, the failover process is started by the Redis Sentinels. Usually, the client connection is terminated. The disconnect can result in any of the following options: -1. The master comes back: The connection is restored to the Redis +1. The primary comes back: The connection is restored to the Redis instance -2. A replica is promoted to a master: Lettuce performs an address - lookup using the `masterId`. As soon as the Redis Sentinel provides +2. A replica is promoted to a primary: Lettuce performs an address + lookup using the `primaryId`. As soon as the Redis Sentinel provides an address the connection is restored to the new Redis instance Read more at @@ -186,11 +186,11 @@ RedisClient client = new RedisClient(redisUri); RedisSentinelAsyncConnection connection = client.connectSentinelAsync(); -Map map = connection.master("mymaster").get(); +Map map = connection.primary("myprimary").get(); ``` ``` java -RedisURI redisUri = RedisURI.Builder.sentinel("sentinelhost1", "mymaster").withSentinel("sentinelhost2").build(); +RedisURI redisUri = RedisURI.Builder.sentinelPrimary("sentinelhost1", "myprimary").withSentinel("sentinelhost2").build(); RedisClient client = RedisClient.create(redisUri); RedisConnection connection = client.connect(); @@ -198,7 +198,7 @@ RedisConnection connection = client.connect(); !!! NOTE Every time you connect to a Redis instance using Redis Sentinel, the - Redis master is looked up using a new connection to a Redis Sentinel. + Redis primary is looked up using a new connection to a Redis Sentinel. This can be time-consuming, especially when multiple Redis Sentinels are used and one or more of them are not reachable. @@ -245,7 +245,7 @@ users of the cluster connection might be affected. ### Command routing The [concept of Redis Cluster](https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/) -bases on sharding. Every master node within the cluster handles one or +bases on sharding. Every primary node within the cluster handles one or more slots. Slots are the [unit of sharding](https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/#redis-cluster-data-sharding) and calculated from the commands' key using `CRC16 MOD 16384`. Hash @@ -277,7 +277,7 @@ Following commands are supported for cross-slot command execution: - `DEL`: Delete the `KEY`s. Returns the number of keys that were removed. -- `EXISTS`: Count the number of `KEY`s that exist across the master +- `EXISTS`: Count the number of `KEY`s that exist across the primary nodes being responsible for the particular key. - `MGET`: Get the values of all given `KEY`s. Returns the values in the @@ -297,16 +297,16 @@ Following commands are executed on multiple cluster nodes operations: - `CLIENT SETNAME`: Set the client name on all known cluster node connections. Returns always `OK`. -- `KEYS`: Return/Stream all keys that are stored on all masters. +- `KEYS`: Return/Stream all keys that are stored on all primaries. -- `DBSIZE`: Return the number of keys that are stored on all masters. +- `DBSIZE`: Return the number of keys that are stored on all primaries. -- `FLUSHALL`: Flush all data on the cluster masters. Returns always +- `FLUSHALL`: Flush all data on the cluster primaries. Returns always `OK`. -- `FLUSHDB`: Flush all data on the cluster masters. Returns always `OK`. +- `FLUSHDB`: Flush all data on the cluster primaries. Returns always `OK`. -- `RANDOMKEY`: Return a random key from a random master. +- `RANDOMKEY`: Return a random key from a random primary. - `SCAN`: Scan the keyspace across the whole cluster according to `ReadFrom` settings. @@ -333,12 +333,12 @@ Cross-slot command execution is available on the following APIs: ### Execution of commands on one or multiple cluster nodes Sometimes commands have to be executed on multiple cluster nodes. The -advanced cluster API allows to select a set of nodes (e.g. all masters, +advanced cluster API allows to select a set of nodes (e.g. all primaries, all replicas) and trigger a command on this set. ``` java RedisAdvancedClusterAsyncCommands async = clusterClient.connect().async(); -AsyncNodeSelection replicas = connection.slaves(); +AsyncNodeSelection replicas = connection.replicas(); AsyncExecutions> executions = replicas.commands().keys("*"); executions.forEach(result -> result.thenAccept(keys -> System.out.println(keys))); @@ -354,7 +354,7 @@ selection updates its node set upon a [cluster topology view refresh](#refreshing-the-cluster-topology-view). Node selections can be constructed by the following presets: -- masters +- primaries - replicas (operate on connections with activated `READONLY` mode) @@ -376,7 +376,7 @@ feedback from the users. So feel free to contribute. ### Refreshing the cluster topology view The Redis Cluster configuration may change at runtime. New nodes can be -added, the master for a specific slot can change. Lettuce handles +added, the primary for a specific slot can change. Lettuce handles `MOVED` and `ASK` redirects transparently but in case too many commands run into redirects, you should refresh the cluster topology view. The topology is bound to a `RedisClusterClient` instance. All cluster @@ -516,22 +516,22 @@ The ReadFrom setting describes how Lettuce routes read operations to replica nodes. By default, Lettuce routes its read operations in multi-node connections -to the master node. Reading from the master returns the most recent +to the primary node. Reading from the primary returns the most recent version of the data because write operations are issued to the single -master node. Reading from masters guarantees strong consistency. +primary node. Reading from primaries guarantees strong consistency. You can reduce latency or improve read throughput by distributing reads to replica members for applications that do not require fully up-to-date data. -Be careful if using other ReadFrom settings than `MASTER`. Settings -other than `MASTER` may return stale data because the replication is +Be careful if using other ReadFrom settings than `PRIMARY`. Settings +other than `PRIMARY` may return stale data because the replication is asynchronous. Data in the replicas may not hold the most recent data. ### Redis Cluster Redis Cluster is a multi-node operated Redis setup that uses one or more -master nodes and allows to setup replica nodes. Redis Cluster +primary nodes and allows to setup replica nodes. Redis Cluster connections allow to set a `ReadFrom` setting on connection level. This setting applies for all read operations on this connection. @@ -549,37 +549,37 @@ connection.close(); client.shutdown(); ``` -### Master/Replica connections ("Master/Slave") +### Primary/Replica connections (legacy master/slave) -Redis nodes can be operated in a Master/Replica setup to achieve -availability and performance. Master/Replica setups can be run either +Redis nodes can be operated in a Primary/Replica setup to achieve +availability and performance. Primary/Replica setups can be run either Standalone or managed using Redis Sentinel. Lettuce allows to use -replica nodes for read operations by using the `MasterReplica` API that -supports both Master/Replica setups: +replica nodes for read operations by using the `PrimaryReplica` API that +supports both Primary/Replica setups: -1. Redis Standalone Master/Replica (no failover) +1. Redis Standalone Primary/Replica (no failover) -2. Redis Sentinel Master/Replica (Sentinel-managed failover) +2. Redis Sentinel Primary/Replica (Sentinel-managed failover) The resulting connection uses in any case the primary connection-point to dispatch non-read operations. #### Redis Sentinel -Master/Replica with Redis Sentinel is very similar to regular Redis -Sentinel operations. When the master fails over, a replica is promoted -by Redis Sentinel to the new master and the client obtains the new +Primary/Replica with Redis Sentinel is very similar to regular Redis +Sentinel operations. When the primary fails over, a replica is promoted +by Redis Sentinel to the new primary and the client obtains the new topology from Redis Sentinel. -Connections to Master/Replica require one or more Redis Sentinel -connection points and a master name. The primary connection point is the -Sentinel monitored master node. +Connections to Primary/Replica require one or more Redis Sentinel +connection points and a primary name. The primary connection point is the +Sentinel monitored primary node. ``` java -RedisURI sentinelUri = RedisURI.Builder.sentinel("sentinel-host", 26379, "master-name").build(); +RedisURI sentinelUri = RedisURI.Builder.sentinelPrimary("sentinel-host", 26379, "primary-name").build(); RedisClient client = RedisClient.create(); -StatefulRedisMasterReplicaConnection connection = MasterReplica.connect( +StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect( client, StringCodec.UTF8 sentinelUri); @@ -594,23 +594,23 @@ client.shutdown(); #### Redis Standalone -Master/Replica with Redis Standalone is very similar to regular Redis -Standalone operations. A Redis Standalone Master/Replica setup is static +Primary/Replica with Redis Standalone is very similar to regular Redis +Standalone operations. A Redis Standalone Primary/Replica setup is static and provides no built-in failover. Replicas are read from the Redis -master node’s `INFO` command. +primary node’s `INFO` command. -Connecting to Redis Standalone Master/Replica nodes requires connections -to use the Redis master for the `RedisURI`. The node used within the +Connecting to Redis Standalone Primary/Replica nodes requires connections +to use the Redis primary for the `RedisURI`. The node used within the `RedisURI` is the primary connection point. ``` java -RedisURI masterUri = RedisURI.Builder.redis("master-host", 6379).build(); +RedisURI primaryUri = RedisURI.Builder.redis("primary-host", 6379).build(); RedisClient client = RedisClient.create(); -StatefulRedisMasterReplicaConnection connection = MasterReplica.connect( +StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect( client, StringCodec.UTF8, - masterUri); + primaryUri); connection.setReadFrom(ReadFrom.REPLICA); @@ -620,42 +620,42 @@ connection.close(); client.shutdown(); ``` -### Use Cases for non-master reads +### Use Cases for non-primary reads -The following use cases are common for using non-master read settings +The following use cases are common for using non-primary read settings and encourage eventual consistency: - Providing local reads for geographically distributed applications. If you have Redis and application servers in multiple data centers, you may consider having a geographically distributed cluster. Using the `LOWEST_LATENCY` setting allows the client to read from the - lowest-latency members, rather than always reading from the master + lowest-latency members, rather than always reading from the primary node. -- Maintaining availability during a failover. Use `MASTER_PREFERRED` if - you want an application to read from the master by default, but to - allow stale reads from replicas when the master node is unavailable. - `MASTER_PREFERRED` allows a "read-only mode" for your application +- Maintaining availability during a failover. Use `PRIMARY_PREFERRED` if + you want an application to read from the primary by default, but to + allow stale reads from replicas when the primary node is unavailable. + `PRIMARY_PREFERRED` allows a "read-only mode" for your application during a failover. - Increase read throughput by allowing stale reads If you want to increase your read throughput by adding additional replica nodes to your cluster Use `REPLICA` to read explicitly from replicas and reduce - read load on the master node. Using replica reads can highly lead to + read load on the primary node. Using replica reads can highly lead to stale reads. ### Read from settings -All `ReadFrom` settings except `MASTER` may return stale data because +All `ReadFrom` settings except `PRIMARY` may return stale data because replicas replication is asynchronous and requires some delay. You need to ensure that your application can tolerate stale data. | Setting | Description | |---------------------|--------------------------------------------------------------------------------| -| `MASTER` | Default mode. Read from the current master node. | -| `MASTER_PREFERRED` | Read from the master, but if it is unavailable, read from replica nodes. | +| `PRIMARY` | Default mode. Read from the current primary node. | +| `PRIMARY_PREFERRED` | Read from the primary, but if it is unavailable, read from replica nodes. | | `REPLICA` | Read from replica nodes. | -| `REPLICA_PREFERRED` | Read from the replica nodes, but if none is unavailable, read from the master. | +| `REPLICA_PREFERRED` | Read from the replica nodes, but if none is unavailable, read from the primary. | | `LOWEST_LATENCY` | Read from any node of the cluster with the lowest latency. | | `ANY` | Read from any node of the cluster. | | `ANY_REPLICA` | Read from any replica of the cluster. | @@ -667,4 +667,3 @@ to ensure that your application can tolerate stale data. Custom read settings can be implemented by extending the `io.lettuce.core.ReadFrom` class. - diff --git a/docs/new-features.md b/docs/new-features.md index 0eec2f8230..b2acc23b3e 100644 --- a/docs/new-features.md +++ b/docs/new-features.md @@ -142,7 +142,7 @@ - Add support for [Redis Streams](https://redis.io/topics/streams-intro). -- Asynchronous `connect()` for Master/Replica connections. +- Asynchronous `connect()` for Primary/Replica connections. - [Asynchronous Connection Pooling](advanced-usage.md#asynchronous-connection-pooling) through `AsyncConnectionPoolSupport` and `AsyncPool`. @@ -166,7 +166,7 @@ - Reactive `ScanStream` to iterate over the keyspace using `SCAN` commands. -- Transactions using Master/Replica connections are bound to the master +- Transactions using Primary/Replica connections are bound to the primary node. ## What’s new in Lettuce 5.0 @@ -196,4 +196,3 @@ - HTML and PDF reference documentation along with a new project website: . - diff --git a/docs/redis-command-interfaces.md b/docs/redis-command-interfaces.md index 6a644bdc85..3f0f48f3cc 100644 --- a/docs/redis-command-interfaces.md +++ b/docs/redis-command-interfaces.md @@ -155,7 +155,7 @@ public interface MixedCommands extends Commands { to determine a command intent (whether a command is a read-only one). Commands are resolved case-sensitive. Use lower-case command names in `@Command` to resolve to an unknown command to e.g. enforce - master-routing. + primary-routing. ### CamelCase in method names @@ -581,4 +581,3 @@ Errors are transported through `RedisFuture`. Synchronous commands don’t receive any result/exception signal except if the batch is flushed through a synchronous method call. Synchronous flushing throws `BatchException` containing the failed commands. - diff --git a/docs/user-guide/async-api.md b/docs/user-guide/async-api.md index c11c350d44..aa4537a617 100644 --- a/docs/user-guide/async-api.md +++ b/docs/user-guide/async-api.md @@ -458,14 +458,14 @@ couple of `…​Either()` methods are available on a `CompletionStage`, see the [Java 8 API docs](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html) for the full reference. The either-or pattern consumes the value from the first future that is completed. A good example might be two services -returning the same data, for instance, a Master-Replica scenario, but +returning the same data, for instance, a Primary-Replica scenario, but you want to return the data as fast as possible: ``` java -RedisStringAsyncCommands master = masterClient.connect().async(); +RedisStringAsyncCommands primary = primaryClient.connect().async(); RedisStringAsyncCommands replica = replicaClient.connect().async(); -RedisFuture future = master.get("key"); +RedisFuture future = primary.get("key"); future.acceptEither(replica.get("key"), new Consumer() { @Override public void accept(String value) { @@ -568,4 +568,4 @@ Runnable listener = new Runnable() { }; set.thenRun(listener); -``` \ No newline at end of file +``` diff --git a/docs/user-guide/pubsub.md b/docs/user-guide/pubsub.md index 96186f4103..f8c0e43d24 100644 --- a/docs/user-guide/pubsub.md +++ b/docs/user-guide/pubsub.md @@ -99,7 +99,7 @@ connection.addListener(new RedisClusterPubSubListener() { ... }) connection.setNodeMessagePropagation(true); RedisPubSubCommands sync = connection.sync(); -sync.masters().commands().subscribe("__keyspace@0__:*"); +sync.primaries().commands().subscribe("__keyspace@0__:*"); ``` There are two things to pay special attention to: @@ -107,12 +107,12 @@ There are two things to pay special attention to: 1. Replication: Keys replicated to replica nodes, especially considering expiry, generate keyspace events on all nodes holding the key. If a key expires and it is replicated, it will expire on - the master and all replicas. Each Redis server will emit keyspace - events. Subscribing to non-master nodes, therefore, will let your + the primary and all replicas. Each Redis server will emit keyspace + events. Subscribing to non-primary nodes, therefore, will let your application see multiple events of the same type for the same key because of Redis distributed nature. 2. Topology Changes: Subscriptions are issued either by using the NodeSelection API or by calling `subscribe(…)` on the individual cluster node connections. Subscription registrations are not - propagated to new nodes that are added on a topology change. \ No newline at end of file + propagated to new nodes that are added on a topology change. diff --git a/src/main/java/io/lettuce/core/ReadFrom.java b/src/main/java/io/lettuce/core/ReadFrom.java index d4300ccefa..eaf99e3602 100644 --- a/src/main/java/io/lettuce/core/ReadFrom.java +++ b/src/main/java/io/lettuce/core/ReadFrom.java @@ -39,12 +39,18 @@ public abstract class ReadFrom { /** * Setting to read from the upstream only. + * + * @deprecated since 7.3, use {@link #PRIMARY}. */ + @Deprecated public static final ReadFrom MASTER = new ReadFromImpl.ReadFromUpstream(); /** - * Setting to read preferred from the upstream and fall back to a replica if the master is not available. + * Setting to read preferred from the upstream and fall back to a replica if the primary is not available. + * + * @deprecated since 7.3, use {@link #PRIMARY_PREFERRED}. */ + @Deprecated public static final ReadFrom MASTER_PREFERRED = new ReadFromImpl.ReadFromUpstreamPreferred(); /** @@ -61,6 +67,20 @@ public abstract class ReadFrom { */ public static final ReadFrom UPSTREAM_PREFERRED = new ReadFromImpl.ReadFromUpstreamPreferred(); + /** + * Setting to read from the upstream only. + * + * @since 7.3 + */ + public static final ReadFrom PRIMARY = UPSTREAM; + + /** + * Setting to read preferred from the upstream and fall back to a replica if the upstream is not available. + * + * @since 7.3 + */ + public static final ReadFrom PRIMARY_PREFERRED = UPSTREAM_PREFERRED; + /** * Setting to read preferred from replica and fall back to upstream if no replica is available. * @@ -214,19 +234,27 @@ public static ReadFrom valueOf(String name) { } } - if (name.equalsIgnoreCase("master")) { + if (name.equalsIgnoreCase("upstream")) { return UPSTREAM; } - if (name.equalsIgnoreCase("masterPreferred")) { + if (name.equalsIgnoreCase("upstreamPreferred")) { return UPSTREAM_PREFERRED; } - if (name.equalsIgnoreCase("upstream")) { + if (name.equalsIgnoreCase("primary")) { + return PRIMARY; + } + + if (name.equalsIgnoreCase("primaryPreferred")) { + return PRIMARY_PREFERRED; + } + + if (name.equalsIgnoreCase("master")) { return UPSTREAM; } - if (name.equalsIgnoreCase("upstreamPreferred")) { + if (name.equalsIgnoreCase("masterPreferred")) { return UPSTREAM_PREFERRED; } diff --git a/src/main/java/io/lettuce/core/RedisURI.java b/src/main/java/io/lettuce/core/RedisURI.java index d5c6f09e38..e64dd693f9 100644 --- a/src/main/java/io/lettuce/core/RedisURI.java +++ b/src/main/java/io/lettuce/core/RedisURI.java @@ -60,8 +60,8 @@ *

* {@code RedisURI.Builder.redis("localhost", 6379).withPassword("password").withDatabase(1).build(); } *

- * See {@link io.lettuce.core.RedisURI.Builder#redis(String)} and {@link io.lettuce.core.RedisURI.Builder#sentinel(String)} for - * more options. + * See {@link io.lettuce.core.RedisURI.Builder#redis(String)} and + * {@link io.lettuce.core.RedisURI.Builder#sentinelPrimary(String, String)} for more options. *
  • Construct your own instance: *

    * {@code new RedisURI("localhost", 6379, Duration.ofSeconds(60));} @@ -98,7 +98,7 @@ * redis-sentinel{@code ://}[[username{@code :}]password@]host1 [{@code :} * port1][, host2 [{@code :}port2]][, hostN [{@code :}portN]][{@code /} * database][{@code ?} [timeout=timeout[d|h|m|s|ms|us|ns]] [ - * &sentinelMasterId=sentinelMasterId] [&database=database] [&clientName=clientName] + * &sentinelPrimaryId=sentinelPrimaryId] [&database=database] [&clientName=clientName] * [&libraryName=libraryName] [&libraryVersion=libraryVersion] [&verifyPeer=NONE|CA|FULL]] * * @@ -184,8 +184,17 @@ public class RedisURI implements Serializable, ConnectionPoint { public static final String PARAMETER_NAME_DATABASE_ALT = "db"; + /** + * @deprecated since 7.3, use {@link #PARAMETER_NAME_SENTINEL_PRIMARY_ID}. + */ + @Deprecated public static final String PARAMETER_NAME_SENTINEL_MASTER_ID = "sentinelMasterId"; + /** + * @since 7.3 + */ + public static final String PARAMETER_NAME_SENTINEL_PRIMARY_ID = "sentinelPrimaryId"; + public static final String PARAMETER_NAME_CLIENT_NAME = "clientName"; public static final String PARAMETER_NAME_LIBRARY_NAME = "libraryName"; @@ -380,19 +389,43 @@ public void setHost(String host) { } /** - * Returns the Sentinel Master Id. + * Returns the Sentinel primary id. * - * @return the Sentinel Master Id. + * @return the Sentinel primary id. + * @since 7.3 */ + public String getSentinelPrimaryId() { + return sentinelMasterId; + } + + /** + * Sets the Sentinel primary id. + * + * @param sentinelPrimaryId the Sentinel primary id. + * @since 7.3 + */ + public void setSentinelPrimaryId(String sentinelPrimaryId) { + this.sentinelMasterId = sentinelPrimaryId; + } + + /** + * Returns the Sentinel master id. + * + * @return the Sentinel master id. + * @deprecated since 7.3, use {@link #getSentinelPrimaryId()}. + */ + @Deprecated public String getSentinelMasterId() { return sentinelMasterId; } /** - * Sets the Sentinel Master Id. + * Sets the Sentinel master id. * - * @param sentinelMasterId the Sentinel Master Id. + * @param sentinelMasterId the Sentinel master id. + * @deprecated since 7.3, use {@link #setSentinelPrimaryId(String)}. */ + @Deprecated public void setSentinelMasterId(String sentinelMasterId) { this.sentinelMasterId = sentinelMasterId; } @@ -520,7 +553,7 @@ public void setAuthentication(String username, CharSequence password) { * provider no explicit {@link RedisCredentialsProvider} was configured. * * @return the {@link RedisCredentialsProvider} to use to authenticate Redis connections - * @since 6.2 + * @since 7.3 */ public RedisCredentialsProvider getCredentialsProvider() { return this.credentialsProvider; @@ -531,7 +564,7 @@ public RedisCredentialsProvider getCredentialsProvider() { * username/password. * * @param credentialsProvider the credentials provider to use when authenticating a Redis connection. - * @since 6.2 + * @since 7.3 */ public void setCredentialsProvider(RedisCredentialsProvider credentialsProvider) { @@ -897,6 +930,10 @@ private static RedisURI buildRedisUriFromUri(URI uri) { parseVerifyPeer(builder, queryParam); } + if (forStartWith.startsWith(PARAMETER_NAME_SENTINEL_PRIMARY_ID.toLowerCase() + "=")) { + parseSentinelPrimaryId(builder, queryParam); + } + if (forStartWith.startsWith(PARAMETER_NAME_SENTINEL_MASTER_ID.toLowerCase() + "=")) { parseSentinelMasterId(builder, queryParam); } @@ -904,7 +941,7 @@ private static RedisURI buildRedisUriFromUri(URI uri) { } if (isSentinel(uri.getScheme())) { - LettuceAssert.notEmpty(builder.sentinelMasterId, "URI must contain the sentinelMasterId"); + LettuceAssert.notEmpty(builder.sentinelMasterId, "URI must contain the sentinelPrimaryId"); } return builder.build(); @@ -995,7 +1032,7 @@ private String getQueryString() { } if (sentinelMasterId != null) { - queryPairs.add(PARAMETER_NAME_SENTINEL_MASTER_ID + "=" + urlEncode(sentinelMasterId)); + queryPairs.add(PARAMETER_NAME_SENTINEL_PRIMARY_ID + "=" + urlEncode(sentinelMasterId)); } if (timeout.getSeconds() != DEFAULT_TIMEOUT) { @@ -1190,11 +1227,15 @@ private static void parseVerifyPeer(Builder builder, String queryParam) { } } + private static void parseSentinelPrimaryId(Builder builder, String queryParam) { + parseSentinelMasterId(builder, queryParam); + } + private static void parseSentinelMasterId(Builder builder, String queryParam) { String masterIdString = getValuePart(queryParam); if (isNotEmpty(masterIdString)) { - builder.withSentinelMasterId(masterIdString); + builder.withSentinelPrimaryId(masterIdString); } } @@ -1295,7 +1336,7 @@ private static RedisURI.Builder configureSentinel(URI uri) { LettuceAssert.notNull(builder, "Invalid URI, cannot get host part"); if (isNotEmpty(masterId)) { - builder.withSentinelMasterId(masterId); + builder.withSentinelPrimaryId(masterId); } if (uri.getScheme().equals(URI_SCHEME_REDIS_SENTINEL_SECURE)) { @@ -1416,13 +1457,59 @@ public static Builder sentinel(String host, int port) { return builder.withSentinel(host, port); } + /** + * Set Sentinel host and primary id. Creates a new builder. + * + * @param host the host name + * @param primaryId sentinel primary id + * @return new builder with Sentinel host/port. + * @since 7.3 + */ + public static Builder sentinelPrimary(String host, String primaryId) { + return sentinelPrimary(host, DEFAULT_SENTINEL_PORT, primaryId); + } + + /** + * Set Sentinel host, port and primary id. Creates a new builder. + * + * @param host the host name + * @param port the port + * @param primaryId sentinel primary id + * @return new builder with Sentinel host/port. + * @since 7.3 + */ + public static Builder sentinelPrimary(String host, int port, String primaryId) { + return sentinelPrimary(host, port, primaryId, null); + } + + /** + * Set Sentinel host, port, primary id and Sentinel authentication. Creates a new builder. + * + * @param host the host name + * @param port the port + * @param primaryId sentinel primary id + * @param password the Sentinel password (supported since Redis 5.0.1) + * @return new builder with Sentinel host/port. + * @since 7.3 + */ + public static Builder sentinelPrimary(String host, int port, String primaryId, CharSequence password) { + + LettuceAssert.notEmpty(host, "Host must not be empty"); + LettuceAssert.isTrue(isValidPort(port), () -> String.format("Port out of range: %s", port)); + + return password == null ? RedisURI.builder().withSentinelPrimaryId(primaryId).withSentinel(host, port) + : RedisURI.builder().withSentinelPrimaryId(primaryId).withSentinel(host, port, password); + } + /** * Set Sentinel host and master id. Creates a new builder. * * @param host the host name * @param masterId sentinel master id * @return new builder with Sentinel host/port. + * @deprecated since 7.3, use {@link #sentinelPrimary(String, String)}. */ + @Deprecated public static Builder sentinel(String host, String masterId) { return sentinel(host, DEFAULT_SENTINEL_PORT, masterId); } @@ -1434,7 +1521,9 @@ public static Builder sentinel(String host, String masterId) { * @param port the port * @param masterId sentinel master id * @return new builder with Sentinel host/port. + * @deprecated since 7.3, use {@link #sentinelPrimary(String, int, String)}. */ + @Deprecated public static Builder sentinel(String host, int port, String masterId) { return sentinel(host, port, masterId, null); } @@ -1447,7 +1536,9 @@ public static Builder sentinel(String host, int port, String masterId) { * @param masterId sentinel master id * @param password the Sentinel password (supported since Redis 5.0.1) * @return new builder with Sentinel host/port. + * @deprecated since 7.3, use {@link #sentinelPrimary(String, int, String, CharSequence)}. */ + @Deprecated public static Builder sentinel(String host, int port, String masterId, CharSequence password) { LettuceAssert.notEmpty(host, "Host must not be empty"); @@ -1762,7 +1853,7 @@ public Builder withAuthentication(String username, char[] password) { * Configures authentication. * * @param credentialsProvider the credentials provider to use - * @since 6.2 + * @since 7.3 */ public Builder withAuthentication(RedisCredentialsProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; @@ -1815,19 +1906,32 @@ public Builder withTimeout(Duration timeout) { } /** - * Configures a sentinel master Id. + * Configures a sentinel primary id. * - * @param sentinelMasterId sentinel master id, must not be empty or {@code null} + * @param sentinelPrimaryId sentinel primary id, must not be empty or {@code null} * @return the builder + * @since 7.3 */ - public Builder withSentinelMasterId(String sentinelMasterId) { + public Builder withSentinelPrimaryId(String sentinelPrimaryId) { - LettuceAssert.notEmpty(sentinelMasterId, "Sentinel master id must not empty"); + LettuceAssert.notEmpty(sentinelPrimaryId, "Sentinel primary id must not be empty"); - this.sentinelMasterId = sentinelMasterId; + this.sentinelMasterId = sentinelPrimaryId; return this; } + /** + * Configures a sentinel master id. + * + * @param sentinelMasterId sentinel master id, must not be empty or {@code null} + * @return the builder + * @deprecated since 7.3, use {@link #withSentinelPrimaryId(String)}. + */ + @Deprecated + public Builder withSentinelMasterId(String sentinelMasterId) { + return withSentinelPrimaryId(sentinelMasterId); + } + /** * Builds a new {@link RedisURI}. * diff --git a/src/main/java/io/lettuce/core/cluster/PartitionAccessor.java b/src/main/java/io/lettuce/core/cluster/PartitionAccessor.java index 488309cde9..cb7698e359 100644 --- a/src/main/java/io/lettuce/core/cluster/PartitionAccessor.java +++ b/src/main/java/io/lettuce/core/cluster/PartitionAccessor.java @@ -27,7 +27,7 @@ List getUpstream() { List getReadCandidates(RedisClusterNode upstream) { return get(redisClusterNode -> redisClusterNode.getNodeId().equals(upstream.getNodeId()) || (redisClusterNode.is(RedisClusterNode.NodeFlag.REPLICA) - && upstream.getNodeId().equals(redisClusterNode.getSlaveOf()))); + && upstream.getNodeId().equals(redisClusterNode.getReplicaOf()))); } List get(Predicate test) { diff --git a/src/main/java/io/lettuce/core/cluster/PooledClusterConnectionProvider.java b/src/main/java/io/lettuce/core/cluster/PooledClusterConnectionProvider.java index e1f2bf56dd..edeb647762 100644 --- a/src/main/java/io/lettuce/core/cluster/PooledClusterConnectionProvider.java +++ b/src/main/java/io/lettuce/core/cluster/PooledClusterConnectionProvider.java @@ -428,7 +428,7 @@ private static boolean isReadCandidate(RedisClusterNode upstream, RedisClusterNo } // consider only replicas contain data from replication - if (upstream.getNodeId().equals(partition.getSlaveOf()) && partition.getReplOffset() != 0) { + if (upstream.getNodeId().equals(partition.getReplicaOf()) && partition.getReplOffset() != 0) { return true; } diff --git a/src/main/java/io/lettuce/core/cluster/api/async/RedisAdvancedClusterAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/RedisAdvancedClusterAsyncCommands.java index f89ba6b706..83de680180 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/RedisAdvancedClusterAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/RedisAdvancedClusterAsyncCommands.java @@ -84,7 +84,7 @@ public interface RedisAdvancedClusterAsyncCommands extends RedisClusterAsy * Select all upstream nodes. * * @return API with asynchronous executed commands on a selection of upstream cluster nodes. - * @deprecated since 6.0 in favor of {@link #upstream()}. + * @deprecated since 6.0 in favor of {@link #upstream()} (use {@link #primaries()} for primary terminology). */ default AsyncNodeSelection masters() { return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.UPSTREAM)); @@ -100,6 +100,16 @@ default AsyncNodeSelection upstream() { return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.UPSTREAM)); } + /** + * Select all primary nodes. + * + * @return API with asynchronous executed commands on a selection of primary cluster nodes. + * @since 7.3 + */ + default AsyncNodeSelection primaries() { + return upstream(); + } + /** * Select all replicas. * diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/RedisAdvancedClusterCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/RedisAdvancedClusterCommands.java index 28ecaf2986..a3f3fb1ca7 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/RedisAdvancedClusterCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/RedisAdvancedClusterCommands.java @@ -79,7 +79,7 @@ public interface RedisAdvancedClusterCommands extends RedisClusterCommands * Select all upstream nodes. * * @return API with synchronous executed commands on a selection of upstream cluster nodes. - * @deprecated since 6.0 in favor of {@link #upstream()}. + * @deprecated since 6.0 in favor of {@link #upstream()} (use {@link #primaries()} for primary terminology). */ @Deprecated default NodeSelection masters() { @@ -95,6 +95,16 @@ default NodeSelection upstream() { return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.UPSTREAM)); } + /** + * Select all primary nodes. + * + * @return API with synchronous executed commands on a selection of primary cluster nodes. + * @since 7.3 + */ + default NodeSelection primaries() { + return upstream(); + } + /** * Select all replicas. * diff --git a/src/main/java/io/lettuce/core/cluster/models/partitions/ClusterPartitionParser.java b/src/main/java/io/lettuce/core/cluster/models/partitions/ClusterPartitionParser.java index af12099f52..bd85a70e83 100644 --- a/src/main/java/io/lettuce/core/cluster/models/partitions/ClusterPartitionParser.java +++ b/src/main/java/io/lettuce/core/cluster/models/partitions/ClusterPartitionParser.java @@ -115,7 +115,7 @@ private static void associateMasterWithReplicas(RedisClusterNode master, List *

  • Newly added or removed nodes to/from the Redis Cluster
  • *
  • Changes in {@link RedisClusterNode#getSlots()} responsibility
  • - *
  • Changes to the {@link RedisClusterNode#getSlaveOf() replication source} (the master of a replica)
  • + *
  • Changes to the {@link RedisClusterNode#getReplicaOf() replication source} (the primary of a replica)
  • *
  • Changes to the {@link RedisClusterNode#getUri()} () connection point}
  • * * diff --git a/src/main/java/io/lettuce/core/cluster/models/partitions/RedisClusterNode.java b/src/main/java/io/lettuce/core/cluster/models/partitions/RedisClusterNode.java index c17006f731..8f14042441 100644 --- a/src/main/java/io/lettuce/core/cluster/models/partitions/RedisClusterNode.java +++ b/src/main/java/io/lettuce/core/cluster/models/partitions/RedisClusterNode.java @@ -37,9 +37,10 @@ /** * Representation of a Redis Cluster node. A {@link RedisClusterNode} is identified by its {@code nodeId}. *

    - * A {@link RedisClusterNode} can be a {@link #getRole() responsible master} or replica. Masters can be responsible for zero to - * {@link io.lettuce.core.cluster.SlotHash#SLOT_COUNT 16384} slots. Each replica refers to exactly one {@link #getSlaveOf() - * master}. Nodes can have different {@link io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag flags} assigned. + * A {@link RedisClusterNode} can be a {@link #getRole() responsible primary} or replica. Primaries can be responsible for zero + * to {@link io.lettuce.core.cluster.SlotHash#SLOT_COUNT 16384} slots. Each replica refers to exactly one + * {@link #getReplicaOf()} primary upstream. Nodes can have different + * {@link io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag flags} assigned. *

    * This class is mutable and not thread-safe if mutated by multiple threads concurrently. * @@ -206,6 +207,29 @@ public void setConnected(boolean connected) { this.connected = connected; } + /** + * @return the replication source, can be {@code null} + * @since 7.3 + */ + public String getReplicaOf() { + return slaveOf; + } + + /** + * Sets the replication source. + * + * @param replicaOf the replication source, can be {@code null} + * @since 7.3 + */ + public void setReplicaOf(String replicaOf) { + this.slaveOf = replicaOf; + } + + /** + * @return the replication source, can be {@code null} + * @deprecated since 7.3, use {@link #getReplicaOf()}. + */ + @Deprecated public String getSlaveOf() { return slaveOf; } @@ -214,7 +238,9 @@ public String getSlaveOf() { * Sets the replication source. * * @param slaveOf the replication source, can be {@code null} + * @deprecated since 7.3, use {@link #setReplicaOf(String)}. */ + @Deprecated public void setSlaveOf(String slaveOf) { this.slaveOf = slaveOf; } @@ -407,8 +433,9 @@ public void setFlags(Set flags) { */ public boolean is(NodeFlag nodeFlag) { - if (nodeFlag == NodeFlag.MASTER || nodeFlag == NodeFlag.UPSTREAM) { - return getFlags().contains(NodeFlag.MASTER) || getFlags().contains(NodeFlag.UPSTREAM); + if (nodeFlag == NodeFlag.MASTER || nodeFlag == NodeFlag.UPSTREAM || nodeFlag == NodeFlag.PRIMARY) { + return getFlags().contains(NodeFlag.MASTER) || getFlags().contains(NodeFlag.UPSTREAM) + || getFlags().contains(NodeFlag.PRIMARY); } if (nodeFlag == NodeFlag.SLAVE || nodeFlag == NodeFlag.REPLICA) { @@ -481,7 +508,7 @@ public String toString() { sb.append(" [uri=").append(uri); sb.append(", nodeId='").append(nodeId).append('\''); sb.append(", connected=").append(connected); - sb.append(", slaveOf='").append(slaveOf).append('\''); + sb.append(", replicaOf='").append(slaveOf).append('\''); sb.append(", pingSentTimestamp=").append(pingSentTimestamp); sb.append(", pongReceivedTimestamp=").append(pongReceivedTimestamp); sb.append(", configEpoch=").append(configEpoch); @@ -509,6 +536,11 @@ public enum NodeFlag { REPLICA, // + /** + * Synonym for {@link #UPSTREAM}. + */ + PRIMARY, // + /** * Synonym for {@link #UPSTREAM}. */ diff --git a/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotRange.java b/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotRange.java index 74e0dad436..56334c03cc 100644 --- a/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotRange.java +++ b/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotRange.java @@ -12,7 +12,7 @@ import io.lettuce.core.internal.LettuceAssert; /** - * Represents a range of slots together with its master and replicas. + * Represents a range of slots together with its primary and replicas. * * @author Mark Paluch * @since 3.0 @@ -36,7 +36,7 @@ public ClusterSlotRange() { * * @param from from slot * @param to to slot - * @param upstream master for the slots, may be {@code null} + * @param upstream primary for the slots, may be {@code null} * @param replicaNodes list of replicas must not be {@code null} but may be empty */ public ClusterSlotRange(int from, int to, RedisClusterNode upstream, List replicaNodes) { @@ -55,7 +55,7 @@ private RedisClusterNode toRedisClusterNode(HostAndPort hostAndPort, String slav int port = hostAndPort.hasPort() ? hostAndPort.getPort() : RedisURI.DEFAULT_REDIS_PORT; RedisClusterNode redisClusterNode = new RedisClusterNode(); redisClusterNode.setUri(RedisURI.create(hostAndPort.getHostText(), port)); - redisClusterNode.setSlaveOf(slaveOf); + redisClusterNode.setReplicaOf(slaveOf); redisClusterNode.setFlags(flags); return redisClusterNode; } @@ -81,10 +81,26 @@ public RedisClusterNode getUpstream() { return upstream; } + /** + * @return the primary for the slots, may be {@code null} + * @since 7.3 + */ + public RedisClusterNode getPrimary() { + return upstream; + } + public void setUpstream(RedisClusterNode upstream) { this.upstream = upstream; } + /** + * @param primary the primary for the slots, may be {@code null} + * @since 7.3 + */ + public void setPrimary(RedisClusterNode primary) { + this.upstream = primary; + } + @Deprecated public List getSlaveNodes() { return replicaNodes; @@ -117,7 +133,7 @@ public String toString() { sb.append(getClass().getSimpleName()); sb.append(" [from=").append(from); sb.append(", to=").append(to); - sb.append(", masterNode=").append(upstream); + sb.append(", primaryNode=").append(upstream); sb.append(", replicaNodes=").append(replicaNodes); sb.append(']'); return sb.toString(); diff --git a/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotsParser.java b/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotsParser.java index 6583476f56..bff2ee56e1 100644 --- a/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotsParser.java +++ b/src/main/java/io/lettuce/core/cluster/models/slots/ClusterSlotsParser.java @@ -87,7 +87,7 @@ private static ClusterSlotRange parseRange(List range, Map extends RedisPubSubAsyncC * Select all upstream nodes. * * @return API with asynchronous executed commands on a selection of upstream cluster nodes. - * @deprecated since 6.0 in favor of {@link #upstream()}. + * @deprecated since 6.0 in favor of {@link #upstream()} (use {@link #primaries()} for primary terminology). */ @Deprecated default PubSubAsyncNodeSelection masters() { @@ -42,6 +42,16 @@ default PubSubAsyncNodeSelection upstream() { return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.UPSTREAM)); } + /** + * Select all primary nodes. + * + * @return API with asynchronous executed commands on a selection of primary cluster nodes. + * @since 7.3 + */ + default PubSubAsyncNodeSelection primaries() { + return upstream(); + } + /** * Select all replicas. * diff --git a/src/main/java/io/lettuce/core/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java b/src/main/java/io/lettuce/core/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java index a8f6a21201..4a675428d1 100644 --- a/src/main/java/io/lettuce/core/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java +++ b/src/main/java/io/lettuce/core/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java @@ -28,7 +28,7 @@ public interface RedisClusterPubSubReactiveCommands extends RedisPubSubRea * Select all upstream nodes. * * @return API with reactive executed commands on a selection of upstream cluster nodes. - * @deprecated since 6.0 in favor of {@link #upstream()}. + * @deprecated since 6.0 in favor of {@link #upstream()} (use {@link #primaries()} for primary terminology). */ @Deprecated default PubSubReactiveNodeSelection masters() { @@ -44,6 +44,16 @@ default PubSubReactiveNodeSelection upstream() { return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.UPSTREAM)); } + /** + * Select all primary nodes. + * + * @return API with asynchronous executed commands on a selection of primary cluster nodes. + * @since 7.3 + */ + default PubSubReactiveNodeSelection primaries() { + return upstream(); + } + /** * Select all replicas. * diff --git a/src/main/java/io/lettuce/core/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java b/src/main/java/io/lettuce/core/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java index 4674c524fb..1125c8bc6f 100644 --- a/src/main/java/io/lettuce/core/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java +++ b/src/main/java/io/lettuce/core/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java @@ -26,7 +26,7 @@ public interface RedisClusterPubSubCommands extends RedisPubSubCommands masters() { @@ -43,6 +43,16 @@ default PubSubNodeSelection upstream() { return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.UPSTREAM)); } + /** + * Select all primary nodes. + * + * @return API with asynchronous executed commands on a selection of primary cluster nodes. + * @since 7.3 + */ + default PubSubNodeSelection primaries() { + return upstream(); + } + /** * Select all replicas. * diff --git a/src/main/java/io/lettuce/core/masterreplica/AutodiscoveryConnector.java b/src/main/java/io/lettuce/core/masterreplica/AutodiscoveryConnector.java index cb17ec886a..9a0dfc9d85 100644 --- a/src/main/java/io/lettuce/core/masterreplica/AutodiscoveryConnector.java +++ b/src/main/java/io/lettuce/core/masterreplica/AutodiscoveryConnector.java @@ -145,7 +145,7 @@ private Mono> initializeConnection(Re private static RedisNodeDescription lookupMaster(List nodes) { Optional first = findFirst(nodes, n -> n.getRole().isUpstream()); - return first.orElseThrow(() -> new IllegalStateException("Cannot lookup master from " + nodes)); + return first.orElseThrow(() -> new IllegalStateException("Cannot lookup primary from " + nodes)); } private static RedisNodeDescription getConnectedNode(RedisURI redisURI, List nodes) { diff --git a/src/main/java/io/lettuce/core/masterreplica/MasterReplica.java b/src/main/java/io/lettuce/core/masterreplica/MasterReplica.java index ae7a81147d..41468a4921 100644 --- a/src/main/java/io/lettuce/core/masterreplica/MasterReplica.java +++ b/src/main/java/io/lettuce/core/masterreplica/MasterReplica.java @@ -17,10 +17,10 @@ import io.netty.util.internal.logging.InternalLoggerFactory; /** - * Master-Replica connection API. + * Primary-Replica connection API. *

    - * This API allows connections to Redis Master/Replica setups which run either in a static Master/Replica setup or are managed - * by Redis Sentinel. Master-Replica connections can discover topologies and select a source for read operations using + * This API allows connections to Redis Primary/Replica setups which run either in a static Primary/Replica setup or are managed + * by Redis Sentinel. Primary-Replica connections can discover topologies and select a source for read operations using * {@link io.lettuce.core.ReadFrom}. *

    *

    @@ -29,7 +29,7 @@ * *

      * RedisClient client = RedisClient.create();
    - * StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client,
    + * StatefulRedisPrimaryReplicaConnection<String, String> connection = PrimaryReplica.connect(client,
      *         RedisURI.create("redis://localhost"), StringCodec.UTF8);
      * // ...
      *
    @@ -40,50 +40,52 @@
      * 

    *

    Topology Discovery

    *

    - * Master-Replica topologies are either static or semi-static. Redis Standalone instances with attached replicas provide no + * Primary-Replica topologies are either static or semi-static. Redis Standalone instances with attached replicas provide no * failover/HA mechanism. Redis Sentinel managed instances are controlled by Redis Sentinel and allow failover (which include - * master promotion). The {@link MasterReplica} API supports both mechanisms. The topology is provided by a + * primary promotion). The {@link MasterReplica} API supports both mechanisms. The topology is provided by a * {@link TopologyProvider}: * *

      *
    • {@link ReplicaTopologyProvider}: Dynamic topology lookup using the {@code INFO REPLICATION} output. Replicas are listed - * as {@code replicaN=...} entries. The initial connection can either point to a master or a replica and the topology provider - * will discover nodes. The connection needs to be re-established outside of lettuce in a case of Master/Replica failover or + * as {@code replicaN=...} entries. The initial connection can either point to a primary or a replica and the topology provider + * will discover nodes. The connection needs to be re-established outside of lettuce in a case of Primary/Replica failover or * topology changes.
    • *
    • {@link StaticMasterReplicaTopologyProvider}: Topology is defined by the list of {@link RedisURI URIs} and the - * {@code ROLE} output. MasterReplica uses only the supplied nodes and won't discover additional nodes in the setup. The - * connection needs to be re-established outside of lettuce in a case of Master/Replica failover or topology changes.
    • + * {@code ROLE} output. This API uses only the supplied nodes and won't discover additional nodes in the setup. The connection + * needs to be re-established outside of lettuce in a case of Primary/Replica failover or topology changes. *
    • {@link SentinelTopologyProvider}: Dynamic topology lookup using the Redis Sentinel API. In particular, - * {@code SENTINEL MASTER} and {@code SENTINEL SLAVES} output. Master/Replica failover is handled by lettuce.
    • + * {@code SENTINEL MASTER} and {@code SENTINEL SLAVES} output. Primary/Replica failover is handled by lettuce. *
    * *

    Topology Updates

    *
      - *
    • Standalone Master/Replica: Performs a one-time topology lookup which remains static afterward
    • + *
    • Standalone Primary/Replica: Performs a one-time topology lookup which remains static afterward
    • *
    • Redis Sentinel: Subscribes to all Sentinels and listens for Pub/Sub messages to trigger topology refreshing
    • *
    * - *

    Connection Fault-Tolerance

    Connecting to Master/Replica bears the possibility that individual nodes are not + *

    Connection Fault-Tolerance

    Connecting to Primary/Replica bears the possibility that individual nodes are not * reachable. {@link MasterReplica} can still connect to a partially-available set of nodes. * *
      - *
    • Redis Sentinel: At least one Sentinel must be reachable, the masterId must be registered and at least one host must be - * available (master or replica). Allows for runtime-recovery based on Sentinel Events.
    • + *
    • Redis Sentinel: At least one Sentinel must be reachable, the primaryId must be registered and at least one host must be + * available (primary or replica). Allows for runtime-recovery based on Sentinel Events.
    • *
    • Static Setup (auto-discovery): The initial endpoint must be reachable. No recovery/reconfiguration during runtime.
    • *
    • Static Setup (provided hosts): All endpoints must be reachable. No recovery/reconfiguration during runtime.
    • *
    * * @author Mark Paluch * @since 5.2 + * @deprecated since 7.3, use {@link io.lettuce.core.primaryreplica.PrimaryReplica}. */ +@Deprecated public class MasterReplica { /** - * Open a new connection to a Redis Master-Replica server/servers using the supplied {@link RedisURI} and the supplied + * Open a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and the supplied * {@link RedisCodec codec} to encode/decode keys. *

    - * This {@link MasterReplica} performs auto-discovery of nodes using either Redis Sentinel or Master/Replica. A - * {@link RedisURI} can point to either a master or a replica host. + * This {@link MasterReplica} performs auto-discovery of nodes using either Redis Sentinel or Primary/Replica. A + * {@link RedisURI} can point to either a primary or a replica host. *

    * * @param redisClient the Redis client. @@ -99,11 +101,11 @@ public static StatefulRedisMasterReplicaConnection connect(RedisCli } /** - * Open asynchronously a new connection to a Redis Master-Replica server/servers using the supplied {@link RedisURI} and the - * supplied {@link RedisCodec codec} to encode/decode keys. + * Open asynchronously a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and + * the supplied {@link RedisCodec codec} to encode/decode keys. *

    - * This {@link MasterReplica} performs auto-discovery of nodes using either Redis Sentinel or Master/Replica. A - * {@link RedisURI} can point to either a master or a replica host. + * This {@link MasterReplica} performs auto-discovery of nodes using either Redis Sentinel or Primary/Replica. A + * {@link RedisURI} can point to either a primary or a replica host. *

    * * @param redisClient the Redis client. @@ -134,11 +136,11 @@ private static CompletableFuture - * This {@link MasterReplica} performs auto-discovery of nodes if the URI is a Redis Sentinel URI. Master/Replica URIs will - * be treated as static topology and no additional hosts are discovered in such case. Redis Standalone Master/Replica will + * This {@link MasterReplica} performs auto-discovery of nodes if the URI is a Redis Sentinel URI. Primary/Replica URIs will + * be treated as static topology and no additional hosts are discovered in such case. Redis Standalone Primary/Replica will * discover the roles of the supplied {@link RedisURI URIs} and issue commands to the appropriate node. *

    *

    @@ -161,11 +163,11 @@ public static StatefulRedisMasterReplicaConnection connect(RedisCli } /** - * Open asynchronously a new connection to a Redis Master-Replica server/servers using the supplied {@link RedisURI} and the - * supplied {@link RedisCodec codec} to encode/decode keys. + * Open asynchronously a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and + * the supplied {@link RedisCodec codec} to encode/decode keys. *

    - * This {@link MasterReplica} performs auto-discovery of nodes if the URI is a Redis Sentinel URI. Master/Replica URIs will - * be treated as static topology and no additional hosts are discovered in such case. Redis Standalone Master/Replica will + * This {@link MasterReplica} performs auto-discovery of nodes if the URI is a Redis Sentinel URI. Primary/Replica URIs will + * be treated as static topology and no additional hosts are discovered in such case. Redis Standalone Primary/Replica will * discover the roles of the supplied {@link RedisURI URIs} and issue commands to the appropriate node. *

    *

    diff --git a/src/main/java/io/lettuce/core/masterreplica/ReplicaTopologyProvider.java b/src/main/java/io/lettuce/core/masterreplica/ReplicaTopologyProvider.java index c93ce8a138..b555d91e2b 100644 --- a/src/main/java/io/lettuce/core/masterreplica/ReplicaTopologyProvider.java +++ b/src/main/java/io/lettuce/core/masterreplica/ReplicaTopologyProvider.java @@ -182,7 +182,7 @@ private RedisNodeDescription getMasterFromInfo(String info) { boolean foundPort = masterPortMatcher.find(); if (!foundHost || !foundPort) { - throw new IllegalStateException("Cannot resolve master from info " + info); + throw new IllegalStateException("Cannot resolve primary from info " + info); } String host = masterHostMatcher.group(1); diff --git a/src/main/java/io/lettuce/core/masterreplica/SentinelTopologyProvider.java b/src/main/java/io/lettuce/core/masterreplica/SentinelTopologyProvider.java index e00d340080..13960d220d 100644 --- a/src/main/java/io/lettuce/core/masterreplica/SentinelTopologyProvider.java +++ b/src/main/java/io/lettuce/core/masterreplica/SentinelTopologyProvider.java @@ -62,7 +62,7 @@ public SentinelTopologyProvider(String masterId, RedisClient redisClient, RedisU @Override public List getNodes() { - logger.debug("lookup topology for masterId {}", masterId); + logger.debug("lookup topology for primaryId {}", masterId); try { return getNodesAsync().get(timeout.toMillis(), TimeUnit.MILLISECONDS); @@ -74,7 +74,7 @@ public List getNodes() { @Override public CompletableFuture> getNodesAsync() { - logger.debug("lookup topology for masterId {}", masterId); + logger.debug("lookup topology for primaryId {}", masterId); Mono> connect = Mono .fromFuture(redisClient.connectSentinelAsync(StringCodec.UTF8, sentinelUri)); diff --git a/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnection.java b/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnection.java index ce5a9edbd0..5260a42aa5 100644 --- a/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnection.java +++ b/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnection.java @@ -1,7 +1,7 @@ package io.lettuce.core.masterreplica; import io.lettuce.core.ReadFrom; -import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.primaryreplica.StatefulRedisPrimaryReplicaConnection; /** * Redis Master-Replica connection. The connection allows replica reads by setting {@link ReadFrom}. @@ -10,22 +10,28 @@ * @param Value type. * @author Mark Paluch * @since 4.1 + * @deprecated since 7.3, use {@link io.lettuce.core.primaryreplica.StatefulRedisPrimaryReplicaConnection}. */ -public interface StatefulRedisMasterReplicaConnection extends StatefulRedisConnection { +@Deprecated +public interface StatefulRedisMasterReplicaConnection extends StatefulRedisPrimaryReplicaConnection { /** * Set from which nodes data is read. The setting is used as default for read operations on this connection. See the * documentation for {@link ReadFrom} for more information. * * @param readFrom the read from setting, must not be {@code null} + * @deprecated since 7.3, use {@link StatefulRedisPrimaryReplicaConnection#setReadFrom(ReadFrom)}. */ + @Deprecated void setReadFrom(ReadFrom readFrom); /** * Gets the {@link ReadFrom} setting for this connection. Defaults to {@link ReadFrom#UPSTREAM} if not set. * * @return the read from setting + * @deprecated since 7.3, use {@link StatefulRedisPrimaryReplicaConnection#getReadFrom()}. */ + @Deprecated ReadFrom getReadFrom(); } diff --git a/src/main/java/io/lettuce/core/masterreplica/package-info.java b/src/main/java/io/lettuce/core/masterreplica/package-info.java index a4cf1cbea0..3721dd6217 100644 --- a/src/main/java/io/lettuce/core/masterreplica/package-info.java +++ b/src/main/java/io/lettuce/core/masterreplica/package-info.java @@ -1,6 +1,6 @@ /** - * Client support for Redis Master/Replica setups. {@link io.lettuce.core.masterreplica.MasterReplica} supports self-managed, - * Redis Sentinel-managed, AWS ElastiCache and Azure Redis managed Master/Replica setups. + * Client support for Redis Primary/Replica setups. {@link io.lettuce.core.primaryreplica.PrimaryReplica} supports self-managed, + * Redis Sentinel-managed, AWS ElastiCache and Azure Redis managed Primary/Replica setups. * * Connections can be obtained by providing the {@link io.lettuce.core.RedisClient}, a {@link io.lettuce.core.RedisURI} and a * {@link io.lettuce.core.codec.RedisCodec}. @@ -8,7 +8,7 @@ *

      *
      * RedisClient client = RedisClient.create();
    - * StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(client,
    + * StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect(client,
      *         RedisURI.create("redis://localhost"), StringCodec.UTF8);
      * // ...
      *
    diff --git a/src/main/java/io/lettuce/core/models/role/RedisInstance.java b/src/main/java/io/lettuce/core/models/role/RedisInstance.java
    index 79c993bfca..0906d09c48 100644
    --- a/src/main/java/io/lettuce/core/models/role/RedisInstance.java
    +++ b/src/main/java/io/lettuce/core/models/role/RedisInstance.java
    @@ -19,6 +19,7 @@ public interface RedisInstance {
          */
         enum Role {
     
    +        @Deprecated
             MASTER {
     
                 @Override
    @@ -31,6 +32,11 @@ public boolean isUpstream() {
                     return true;
                 }
     
    +            @Override
    +            public boolean isPrimary() {
    +                return true;
    +            }
    +
             },
     
             @Deprecated
    @@ -55,6 +61,30 @@ public boolean isUpstream() {
                     return true;
                 }
     
    +            @Override
    +            public boolean isPrimary() {
    +                return true;
    +            }
    +
    +        },
    +
    +        PRIMARY {
    +
    +            @Override
    +            public boolean isMaster() {
    +                return true;
    +            }
    +
    +            @Override
    +            public boolean isUpstream() {
    +                return true;
    +            }
    +
    +            @Override
    +            public boolean isPrimary() {
    +                return true;
    +            }
    +
             },
     
             REPLICA {
    @@ -71,11 +101,21 @@ public boolean isReplica() {
             /**
              * @return {@code true} if the role indicates that the role is a replication source.
              * @since 6.0
    +         * @deprecated since 7.3, use {@link #isPrimary()} or {@link #isUpstream()}.
              */
    +        @Deprecated
             public boolean isMaster() {
                 return false;
             }
     
    +        /**
    +         * @return {@code true} if the role indicates that the role is a primary replication source.
    +         * @since 7.3
    +         */
    +        public boolean isPrimary() {
    +            return false;
    +        }
    +
             /**
              * @return {@code true} if the role indicates that the role is a replication source.
              * @since 6.1
    diff --git a/src/main/java/io/lettuce/core/models/role/RedisMasterInstance.java b/src/main/java/io/lettuce/core/models/role/RedisMasterInstance.java
    index 1ed7098732..7f231dec0c 100644
    --- a/src/main/java/io/lettuce/core/models/role/RedisMasterInstance.java
    +++ b/src/main/java/io/lettuce/core/models/role/RedisMasterInstance.java
    @@ -3,12 +3,14 @@
     import java.util.List;
     
     /**
    - * Represents a upstream (master) instance.
    + * Represents an upstream (primary) instance.
      *
      * @author Mark Paluch
      * @since 3.0
    + * @deprecated since 7.3, use {@link RedisPrimaryInstance}.
      */
     @SuppressWarnings("serial")
    +@Deprecated
     public class RedisMasterInstance extends RedisUpstreamInstance {
     
         public RedisMasterInstance() {
    diff --git a/src/main/java/io/lettuce/core/models/role/RedisPrimaryInstance.java b/src/main/java/io/lettuce/core/models/role/RedisPrimaryInstance.java
    new file mode 100644
    index 0000000000..9ed8b65dd5
    --- /dev/null
    +++ b/src/main/java/io/lettuce/core/models/role/RedisPrimaryInstance.java
    @@ -0,0 +1,35 @@
    +package io.lettuce.core.models.role;
    +
    +import java.util.List;
    +
    +/**
    + * Represents an upstream (primary) instance.
    + *
    + * @author yeong0jae
    + * @since 7.3
    + */
    +@SuppressWarnings("serial")
    +public class RedisPrimaryInstance extends RedisUpstreamInstance {
    +
    +    public RedisPrimaryInstance() {
    +    }
    +
    +    /**
    +     * Constructs a {@link RedisPrimaryInstance}
    +     *
    +     * @param replicationOffset the replication offset
    +     * @param replicas list of replicas, must not be {@code null} but may be empty
    +     */
    +    public RedisPrimaryInstance(long replicationOffset, List replicas) {
    +        super(replicationOffset, replicas);
    +    }
    +
    +    /**
    +     * @return always {@link io.lettuce.core.models.role.RedisInstance.Role#PRIMARY}
    +     */
    +    @Override
    +    public Role getRole() {
    +        return Role.PRIMARY;
    +    }
    +
    +}
    diff --git a/src/main/java/io/lettuce/core/models/role/RedisReplicaInstance.java b/src/main/java/io/lettuce/core/models/role/RedisReplicaInstance.java
    index 19df1da8f4..f095edd5cd 100644
    --- a/src/main/java/io/lettuce/core/models/role/RedisReplicaInstance.java
    +++ b/src/main/java/io/lettuce/core/models/role/RedisReplicaInstance.java
    @@ -23,7 +23,7 @@ public RedisReplicaInstance() {
         /**
          * Constructs a {@link RedisReplicaInstance}
          *
    -     * @param upstream master for the replication, must not be {@code null}
    +     * @param upstream primary for the replication, must not be {@code null}
          * @param state replica state, must not be {@code null}
          */
         RedisReplicaInstance(ReplicationPartner upstream, State state) {
    @@ -87,17 +87,17 @@ public enum State {
              */
             HANDSHAKE,
             /**
    -         * the instance needs to connect to its master.
    +         * the instance needs to connect to its primary.
              */
             CONNECT,
     
             /**
    -         * the replica-master connection is in progress.
    +         * the replica-primary connection is in progress.
              */
             CONNECTING,
     
             /**
    -         * the master and replica are trying to perform the synchronization.
    +         * the primary and replica are trying to perform the synchronization.
              */
             SYNC,
     
    @@ -111,7 +111,7 @@ public enum State {
         public String toString() {
             final StringBuilder sb = new StringBuilder();
             sb.append(getClass().getSimpleName());
    -        sb.append(" [master=").append(upstream);
    +        sb.append(" [primary=").append(upstream);
             sb.append(", state=").append(state);
             sb.append(']');
             return sb.toString();
    diff --git a/src/main/java/io/lettuce/core/models/role/RedisSentinelInstance.java b/src/main/java/io/lettuce/core/models/role/RedisSentinelInstance.java
    index 5af48d440a..df189829d1 100644
    --- a/src/main/java/io/lettuce/core/models/role/RedisSentinelInstance.java
    +++ b/src/main/java/io/lettuce/core/models/role/RedisSentinelInstance.java
    @@ -23,7 +23,7 @@ public RedisSentinelInstance() {
         /**
          * Constructs a {@link RedisSentinelInstance}
          *
    -     * @param monitoredMasters list of monitored masters, must not be {@code null} but may be empty
    +     * @param monitoredMasters list of monitored primaries, must not be {@code null} but may be empty
          */
         public RedisSentinelInstance(List monitoredMasters) {
             LettuceAssert.notNull(monitoredMasters, "List of monitoredMasters must not be null");
    @@ -41,7 +41,7 @@ public Role getRole() {
     
         /**
          *
    -     * @return List of monitored master names.
    +     * @return List of monitored primary names.
          */
         public List getMonitoredMasters() {
             return monitoredMasters;
    diff --git a/src/main/java/io/lettuce/core/models/role/RedisSlaveInstance.java b/src/main/java/io/lettuce/core/models/role/RedisSlaveInstance.java
    index ee8a6b80ea..ec1069742b 100644
    --- a/src/main/java/io/lettuce/core/models/role/RedisSlaveInstance.java
    +++ b/src/main/java/io/lettuce/core/models/role/RedisSlaveInstance.java
    @@ -21,7 +21,7 @@ public RedisSlaveInstance() {
         /**
          * Constructs a {@link RedisSlaveInstance}
          *
    -     * @param master master for the replication, must not be {@code null}
    +     * @param master primary for the replication, must not be {@code null}
          * @param state replica state, must not be {@code null}
          */
         RedisSlaveInstance(ReplicationPartner master, State state) {
    @@ -38,14 +38,14 @@ public Role getRole() {
     
         /**
          *
    -     * @return the replication master.
    +     * @return the replication primary.
          */
         public ReplicationPartner getMaster() {
             return getUpstream();
         }
     
         public void setMaster(ReplicationPartner master) {
    -        LettuceAssert.notNull(master, "Master must not be null");
    +        LettuceAssert.notNull(master, "Primary must not be null");
             setUpstream(master);
         }
     
    diff --git a/src/main/java/io/lettuce/core/primaryreplica/PrimaryReplica.java b/src/main/java/io/lettuce/core/primaryreplica/PrimaryReplica.java
    new file mode 100644
    index 0000000000..091cee5633
    --- /dev/null
    +++ b/src/main/java/io/lettuce/core/primaryreplica/PrimaryReplica.java
    @@ -0,0 +1,108 @@
    +package io.lettuce.core.primaryreplica;
    +
    +import java.util.concurrent.CompletableFuture;
    +
    +import io.lettuce.core.RedisClient;
    +import io.lettuce.core.RedisURI;
    +import io.lettuce.core.codec.RedisCodec;
    +import io.lettuce.core.masterreplica.MasterReplica;
    +
    +/**
    + * Primary-Replica connection API.
    + * 

    + * This API allows connections to Redis Primary/Replica setups which run either in a static Primary/Replica setup or are managed + * by Redis Sentinel. Primary-Replica connections can discover topologies and select a source for read operations using + * {@link io.lettuce.core.ReadFrom}. + *

    + * + * @author yeong0jae + * @since 7.3 + */ +@SuppressWarnings("deprecation") +public class PrimaryReplica { + + /** + * Open a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and the supplied + * {@link RedisCodec codec} to encode/decode keys. + *

    + * This {@link PrimaryReplica} performs auto-discovery of nodes using either Redis Sentinel or Primary/Replica. A + * {@link RedisURI} can point to either a primary or a replica host. + *

    + * + * @param redisClient the Redis client. + * @param codec Use this codec to encode/decode keys and values, must not be {@code null}. + * @param redisURI the Redis server to connect to, must not be {@code null}. + * @param Key type. + * @param Value type. + * @return a new connection. + */ + public static StatefulRedisPrimaryReplicaConnection connect(RedisClient redisClient, RedisCodec codec, + RedisURI redisURI) { + return MasterReplica.connect(redisClient, codec, redisURI); + } + + /** + * Open asynchronously a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and + * the supplied {@link RedisCodec codec} to encode/decode keys. + *

    + * This {@link PrimaryReplica} performs auto-discovery of nodes using either Redis Sentinel or Primary/Replica. A + * {@link RedisURI} can point to either a primary or a replica host. + *

    + * + * @param redisClient the Redis client. + * @param codec Use this codec to encode/decode keys and values, must not be {@code null}. + * @param redisURI the Redis server to connect to, must not be {@code null}. + * @param Key type. + * @param Value type. + * @return {@link CompletableFuture} that is notified once the connect is finished. + */ + public static CompletableFuture> connectAsync(RedisClient redisClient, + RedisCodec codec, RedisURI redisURI) { + return MasterReplica.connectAsync(redisClient, codec, redisURI) + .thenApply(connection -> (StatefulRedisPrimaryReplicaConnection) connection); + } + + /** + * Open a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and the supplied + * {@link RedisCodec codec} to encode/decode keys. + *

    + * This {@link PrimaryReplica} performs auto-discovery of nodes if the URI is a Redis Sentinel URI. Primary/Replica URIs + * will be treated as static topology and no additional hosts are discovered in such case. Redis Standalone Primary/Replica + * will discover the roles of the supplied {@link RedisURI URIs} and issue commands to the appropriate node. + *

    + * + * @param redisClient the Redis client. + * @param codec Use this codec to encode/decode keys and values, must not be {@code null}. + * @param redisURIs the Redis server(s) to connect to, must not be {@code null}. + * @param Key type. + * @param Value type. + * @return a new connection. + */ + public static StatefulRedisPrimaryReplicaConnection connect(RedisClient redisClient, RedisCodec codec, + Iterable redisURIs) { + return MasterReplica.connect(redisClient, codec, redisURIs); + } + + /** + * Open asynchronously a new connection to a Redis Primary-Replica server/servers using the supplied {@link RedisURI} and + * the supplied {@link RedisCodec codec} to encode/decode keys. + *

    + * This {@link PrimaryReplica} performs auto-discovery of nodes if the URI is a Redis Sentinel URI. Primary/Replica URIs + * will be treated as static topology and no additional hosts are discovered in such case. Redis Standalone Primary/Replica + * will discover the roles of the supplied {@link RedisURI URIs} and issue commands to the appropriate node. + *

    + * + * @param redisClient the Redis client. + * @param codec Use this codec to encode/decode keys and values, must not be {@code null}. + * @param redisURIs the Redis server(s) to connect to, must not be {@code null}. + * @param Key type. + * @param Value type. + * @return {@link CompletableFuture} that is notified once the connect is finished. + */ + public static CompletableFuture> connectAsync(RedisClient redisClient, + RedisCodec codec, Iterable redisURIs) { + return MasterReplica.connectAsync(redisClient, codec, redisURIs) + .thenApply(connection -> (StatefulRedisPrimaryReplicaConnection) connection); + } + +} diff --git a/src/main/java/io/lettuce/core/primaryreplica/StatefulRedisPrimaryReplicaConnection.java b/src/main/java/io/lettuce/core/primaryreplica/StatefulRedisPrimaryReplicaConnection.java new file mode 100644 index 0000000000..ecae832610 --- /dev/null +++ b/src/main/java/io/lettuce/core/primaryreplica/StatefulRedisPrimaryReplicaConnection.java @@ -0,0 +1,31 @@ +package io.lettuce.core.primaryreplica; + +import io.lettuce.core.ReadFrom; +import io.lettuce.core.api.StatefulRedisConnection; + +/** + * Redis Primary-Replica connection. The connection allows replica reads by setting {@link ReadFrom}. + * + * @param Key type. + * @param Value type. + * @author yeong0jae + * @since 7.3 + */ +public interface StatefulRedisPrimaryReplicaConnection extends StatefulRedisConnection { + + /** + * Set from which nodes data is read. The setting is used as default for read operations on this connection. See the + * documentation for {@link ReadFrom} for more information. + * + * @param readFrom the read from setting, must not be {@code null} + */ + void setReadFrom(ReadFrom readFrom); + + /** + * Gets the {@link ReadFrom} setting for this connection. Defaults to {@link ReadFrom#PRIMARY} if not set. + * + * @return the read from setting + */ + ReadFrom getReadFrom(); + +} diff --git a/src/main/java/io/lettuce/core/sentinel/api/async/RedisSentinelAsyncCommands.java b/src/main/java/io/lettuce/core/sentinel/api/async/RedisSentinelAsyncCommands.java index 503306341b..f9f9b86d43 100644 --- a/src/main/java/io/lettuce/core/sentinel/api/async/RedisSentinelAsyncCommands.java +++ b/src/main/java/io/lettuce/core/sentinel/api/async/RedisSentinelAsyncCommands.java @@ -43,40 +43,78 @@ public interface RedisSentinelAsyncCommands { /** - * Return the ip and port number of the master with that name. + * Return the ip and port number of the primary with that name. * * @param key the key. * @return SocketAddress. + * @since 7.3 */ + default RedisFuture getPrimaryAddrByName(K key) { + return getMasterAddrByName(key); + } + + /** + * Return the ip and port number of the primary with that name. + * + * @param key the key. + * @return SocketAddress. + * @deprecated since 7.3, use {@link #getPrimaryAddrByName(Object)}. + */ + @Deprecated RedisFuture getMasterAddrByName(K key); /** - * Enumerates all the monitored masters and their states. + * Enumerates all the monitored primaries and their states. + * + * @return Map<K, V>>. + * @since 7.3 + */ + default RedisFuture>> primaries() { + return masters(); + } + + /** + * Enumerates all the monitored primaries and their states. * * @return Map<K, V>>. + * @deprecated since 7.3, use {@link #primaries()}. */ + @Deprecated RedisFuture>> masters(); /** - * Show the state and info of the specified master. + * Show the state and info of the specified primary. + * + * @param key the key. + * @return Map<K, V>. + * @since 7.3 + */ + default RedisFuture> primary(K key) { + return master(key); + } + + /** + * Show the state and info of the specified primary. * * @param key the key. * @return Map<K, V>. + * @deprecated since 7.3, use {@link #primary(Object)}. */ + @Deprecated RedisFuture> master(K key); /** - * Provides a list of replicas for the master with the specified name. + * Provides a list of replicas for the primary with the specified name. * * @param key the key. * @return List<Map<K, V>>. - * @deprecated since 6.2, use #replicas(Object) instead. + * @deprecated since 7.3, use #replicas(Object) instead. */ @Deprecated RedisFuture>> slaves(K key); /** - * This command will reset all the masters with matching name. + * This command will reset all the primaries with matching name. * * @param key the key. * @return Long. @@ -84,24 +122,24 @@ public interface RedisSentinelAsyncCommands { RedisFuture reset(K key); /** - * Provides a list of replicas for the master with the specified name. + * Provides a list of replicas for the primary with the specified name. * * @param key the key. * @return List<Map<K, V>>. - * @since 6.2 + * @since 7.3 */ RedisFuture>> replicas(K key); /** * Perform a failover. * - * @param key the master id. + * @param key the primary id. * @return String. */ RedisFuture failover(K key); /** - * This command tells the Sentinel to start monitoring a new master with the specified name, ip, port, and quorum. + * This command tells the Sentinel to start monitoring a new primary with the specified name, ip, port, and quorum. * * @param key the key. * @param ip the IP address. @@ -122,7 +160,7 @@ public interface RedisSentinelAsyncCommands { RedisFuture set(K key, String option, V value); /** - * remove the specified master. + * remove the specified primary. * * @param key the key. * @return String. diff --git a/src/main/java/io/lettuce/core/sentinel/api/reactive/RedisSentinelReactiveCommands.java b/src/main/java/io/lettuce/core/sentinel/api/reactive/RedisSentinelReactiveCommands.java index 18b01b4fad..74f398148b 100644 --- a/src/main/java/io/lettuce/core/sentinel/api/reactive/RedisSentinelReactiveCommands.java +++ b/src/main/java/io/lettuce/core/sentinel/api/reactive/RedisSentinelReactiveCommands.java @@ -43,40 +43,78 @@ public interface RedisSentinelReactiveCommands { /** - * Return the ip and port number of the master with that name. + * Return the ip and port number of the primary with that name. * * @param key the key. * @return SocketAddress. + * @since 7.3 */ + default Mono getPrimaryAddrByName(K key) { + return getMasterAddrByName(key); + } + + /** + * Return the ip and port number of the primary with that name. + * + * @param key the key. + * @return SocketAddress. + * @deprecated since 7.3, use {@link #getPrimaryAddrByName(Object)}. + */ + @Deprecated Mono getMasterAddrByName(K key); /** - * Enumerates all the monitored masters and their states. + * Enumerates all the monitored primaries and their states. + * + * @return Map<K, V>>. + * @since 7.3 + */ + default Flux> primaries() { + return masters(); + } + + /** + * Enumerates all the monitored primaries and their states. * * @return Map<K, V>>. + * @deprecated since 7.3, use {@link #primaries()}. */ + @Deprecated Flux> masters(); /** - * Show the state and info of the specified master. + * Show the state and info of the specified primary. + * + * @param key the key. + * @return Map<K, V>. + * @since 7.3 + */ + default Mono> primary(K key) { + return master(key); + } + + /** + * Show the state and info of the specified primary. * * @param key the key. * @return Map<K, V>. + * @deprecated since 7.3, use {@link #primary(Object)}. */ + @Deprecated Mono> master(K key); /** - * Provides a list of replicas for the master with the specified name. + * Provides a list of replicas for the primary with the specified name. * * @param key the key. * @return Map<K, V>. - * @deprecated since 6.2, use #replicas(Object) instead. + * @deprecated since 7.3, use #replicas(Object) instead. */ @Deprecated Flux> slaves(K key); /** - * This command will reset all the masters with matching name. + * This command will reset all the primaries with matching name. * * @param key the key. * @return Long. @@ -84,24 +122,24 @@ public interface RedisSentinelReactiveCommands { Mono reset(K key); /** - * Provides a list of replicas for the master with the specified name. + * Provides a list of replicas for the primary with the specified name. * * @param key the key. * @return Map<K, V>. - * @since 6.2 + * @since 7.3 */ Flux> replicas(K key); /** * Perform a failover. * - * @param key the master id. + * @param key the primary id. * @return String. */ Mono failover(K key); /** - * This command tells the Sentinel to start monitoring a new master with the specified name, ip, port, and quorum. + * This command tells the Sentinel to start monitoring a new primary with the specified name, ip, port, and quorum. * * @param key the key. * @param ip the IP address. @@ -122,7 +160,7 @@ public interface RedisSentinelReactiveCommands { Mono set(K key, String option, V value); /** - * remove the specified master. + * remove the specified primary. * * @param key the key. * @return String. diff --git a/src/main/java/io/lettuce/core/sentinel/api/sync/RedisSentinelCommands.java b/src/main/java/io/lettuce/core/sentinel/api/sync/RedisSentinelCommands.java index bef0820423..b24617fb06 100644 --- a/src/main/java/io/lettuce/core/sentinel/api/sync/RedisSentinelCommands.java +++ b/src/main/java/io/lettuce/core/sentinel/api/sync/RedisSentinelCommands.java @@ -42,40 +42,78 @@ public interface RedisSentinelCommands { /** - * Return the ip and port number of the master with that name. + * Return the ip and port number of the primary with that name. * * @param key the key. * @return SocketAddress. + * @since 7.3 */ + default SocketAddress getPrimaryAddrByName(K key) { + return getMasterAddrByName(key); + } + + /** + * Return the ip and port number of the primary with that name. + * + * @param key the key. + * @return SocketAddress. + * @deprecated since 7.3, use {@link #getPrimaryAddrByName(Object)}. + */ + @Deprecated SocketAddress getMasterAddrByName(K key); /** - * Enumerates all the monitored masters and their states. + * Enumerates all the monitored primaries and their states. + * + * @return Map<K, V>>. + * @since 7.3 + */ + default List> primaries() { + return masters(); + } + + /** + * Enumerates all the monitored primaries and their states. * * @return Map<K, V>>. + * @deprecated since 7.3, use {@link #primaries()}. */ + @Deprecated List> masters(); /** - * Show the state and info of the specified master. + * Show the state and info of the specified primary. + * + * @param key the key. + * @return Map<K, V>. + * @since 7.3 + */ + default Map primary(K key) { + return master(key); + } + + /** + * Show the state and info of the specified primary. * * @param key the key. * @return Map<K, V>. + * @deprecated since 7.3, use {@link #primary(Object)}. */ + @Deprecated Map master(K key); /** - * Provides a list of replicas for the master with the specified name. + * Provides a list of replicas for the primary with the specified name. * * @param key the key. * @return List<Map<K, V>>. - * @deprecated since 6.2, use #replicas(Object) instead. + * @deprecated since 7.3, use #replicas(Object) instead. */ @Deprecated List> slaves(K key); /** - * This command will reset all the masters with matching name. + * This command will reset all the primaries with matching name. * * @param key the key. * @return Long. @@ -83,24 +121,24 @@ public interface RedisSentinelCommands { Long reset(K key); /** - * Provides a list of replicas for the master with the specified name. + * Provides a list of replicas for the primary with the specified name. * * @param key the key. * @return List<Map<K, V>>. - * @since 6.2 + * @since 7.3 */ List> replicas(K key); /** * Perform a failover. * - * @param key the master id. + * @param key the primary id. * @return String. */ String failover(K key); /** - * This command tells the Sentinel to start monitoring a new master with the specified name, ip, port, and quorum. + * This command tells the Sentinel to start monitoring a new primary with the specified name, ip, port, and quorum. * * @param key the key. * @param ip the IP address. @@ -121,7 +159,7 @@ public interface RedisSentinelCommands { String set(K key, String option, V value); /** - * remove the specified master. + * remove the specified primary. * * @param key the key. * @return String. diff --git a/src/main/resources/META-INF/native-image/io.lettuce/lettuce-core/proxy-config.json b/src/main/resources/META-INF/native-image/io.lettuce/lettuce-core/proxy-config.json index 8d6f4cfd49..f4156790a2 100644 --- a/src/main/resources/META-INF/native-image/io.lettuce/lettuce-core/proxy-config.json +++ b/src/main/resources/META-INF/native-image/io.lettuce/lettuce-core/proxy-config.json @@ -44,6 +44,10 @@ "io.lettuce.core.support.ConnectionWrapping$HasTargetConnection", "io.lettuce.core.masterreplica.StatefulRedisMasterReplicaConnection" ], + [ + "io.lettuce.core.support.ConnectionWrapping$HasTargetConnection", + "io.lettuce.core.primaryreplica.StatefulRedisPrimaryReplicaConnection" + ], [ "io.lettuce.core.support.ConnectionWrapping$HasTargetConnection", "io.lettuce.core.api.StatefulRedisConnection" diff --git a/src/test/java/io/lettuce/core/RedisURIUnitTests.java b/src/test/java/io/lettuce/core/RedisURIUnitTests.java index e47e38fad6..68dc0accd7 100644 --- a/src/test/java/io/lettuce/core/RedisURIUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisURIUnitTests.java @@ -149,12 +149,13 @@ void sentinelUriTest() { RedisURI redisURI = RedisURI.create("redis-sentinel://auth@h1:222,h2,h3:1234/5?sentinelMasterId=masterId"); assertThat(redisURI.getSentinelMasterId()).isEqualTo("masterId"); + assertThat(redisURI.getSentinelPrimaryId()).isEqualTo("masterId"); assertThat(redisURI.getSentinels().get(0).getPort()).isEqualTo(222); assertThat(redisURI.getSentinels().get(1).getPort()).isEqualTo(RedisURI.DEFAULT_SENTINEL_PORT); assertThat(redisURI.getSentinels().get(2).getPort()).isEqualTo(1234); assertThat(redisURI.getDatabase()).isEqualTo(5); - assertThat(redisURI).hasToString("redis-sentinel://****@h1:222,h2,h3:1234/5?sentinelMasterId=masterId"); + assertThat(redisURI).hasToString("redis-sentinel://****@h1:222,h2,h3:1234/5?sentinelPrimaryId=masterId"); } @Test @@ -163,7 +164,7 @@ void sentinelSecureUriTest() { RedisURI redisURI = RedisURI.create("rediss-sentinel://auth@h1:222,h2,h3:1234/5?sentinelMasterId=masterId"); assertThat(redisURI.isSsl()).isTrue(); - assertThat(redisURI).hasToString("rediss-sentinel://****@h1:222,h2,h3:1234/5?sentinelMasterId=masterId"); + assertThat(redisURI).hasToString("rediss-sentinel://****@h1:222,h2,h3:1234/5?sentinelPrimaryId=masterId"); } @Test diff --git a/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java b/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java index 32303bdfaa..be05ab1700 100644 --- a/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java +++ b/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java @@ -3,34 +3,15 @@ import java.util.Arrays; import java.util.List; -import io.lettuce.core.ReadFrom; -import io.lettuce.core.RedisClient; -import io.lettuce.core.RedisURI; -import io.lettuce.core.codec.StringCodec; -import io.lettuce.core.masterreplica.MasterReplica; -import io.lettuce.core.masterreplica.StatefulRedisMasterReplicaConnection; - /** * @author Mark Paluch + * @deprecated since 7.3, use {@link ConnectToPrimaryReplicaUsingElastiCacheCluster}. */ +@Deprecated public class ConnectToMasterSlaveUsingElastiCacheCluster { public static void main(String[] args) { - - // Syntax: redis://[password@]host[:port][/databaseNumber] - RedisClient redisClient = RedisClient.create(); - - List nodes = Arrays.asList(RedisURI.create("redis://host1"), RedisURI.create("redis://host2"), - RedisURI.create("redis://host3")); - - StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(redisClient, StringCodec.UTF8, - nodes); - connection.setReadFrom(ReadFrom.UPSTREAM_PREFERRED); - - System.out.println("Connected to Redis"); - - connection.close(); - redisClient.shutdown(); + ConnectToPrimaryReplicaUsingElastiCacheCluster.main(args); } } diff --git a/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingRedisSentinel.java b/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingRedisSentinel.java index d08200e224..cf75e84236 100644 --- a/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingRedisSentinel.java +++ b/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingRedisSentinel.java @@ -1,29 +1,14 @@ package io.lettuce.examples; -import io.lettuce.core.ReadFrom; -import io.lettuce.core.RedisClient; -import io.lettuce.core.RedisURI; -import io.lettuce.core.codec.StringCodec; -import io.lettuce.core.masterreplica.MasterReplica; -import io.lettuce.core.masterreplica.StatefulRedisMasterReplicaConnection; - /** * @author Mark Paluch + * @deprecated since 7.3, use {@link ConnectToPrimaryReplicaUsingRedisSentinel}. */ +@Deprecated public class ConnectToMasterSlaveUsingRedisSentinel { public static void main(String[] args) { - // Syntax: redis-sentinel://[password@]host[:port][,host2[:port2]][/databaseNumber]#sentinelMasterId - RedisClient redisClient = RedisClient.create(); - - StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(redisClient, StringCodec.UTF8, - RedisURI.create("redis-sentinel://localhost:26379,localhost:26380/0#mymaster")); - connection.setReadFrom(ReadFrom.UPSTREAM_PREFERRED); - - System.out.println("Connected to Redis"); - - connection.close(); - redisClient.shutdown(); + ConnectToPrimaryReplicaUsingRedisSentinel.main(args); } } diff --git a/src/test/java/io/lettuce/examples/ConnectToPrimaryReplicaUsingElastiCacheCluster.java b/src/test/java/io/lettuce/examples/ConnectToPrimaryReplicaUsingElastiCacheCluster.java new file mode 100644 index 0000000000..a9ae59807c --- /dev/null +++ b/src/test/java/io/lettuce/examples/ConnectToPrimaryReplicaUsingElastiCacheCluster.java @@ -0,0 +1,37 @@ +package io.lettuce.examples; + +import java.util.Arrays; +import java.util.List; + +import io.lettuce.core.ReadFrom; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.primaryreplica.PrimaryReplica; +import io.lettuce.core.primaryreplica.StatefulRedisPrimaryReplicaConnection; + +/** + * @author yeong0jae + * @since 7.3 + */ +public class ConnectToPrimaryReplicaUsingElastiCacheCluster { + + public static void main(String[] args) { + + // Syntax: redis://[password@]host[:port][/databaseNumber] + RedisClient redisClient = RedisClient.create(); + + List nodes = Arrays.asList(RedisURI.create("redis://host1"), RedisURI.create("redis://host2"), + RedisURI.create("redis://host3")); + + StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect(redisClient, StringCodec.UTF8, + nodes); + connection.setReadFrom(ReadFrom.PRIMARY_PREFERRED); + + System.out.println("Connected to Redis"); + + connection.close(); + redisClient.shutdown(); + } + +} diff --git a/src/test/java/io/lettuce/examples/ConnectToPrimaryReplicaUsingRedisSentinel.java b/src/test/java/io/lettuce/examples/ConnectToPrimaryReplicaUsingRedisSentinel.java new file mode 100644 index 0000000000..d833bb969d --- /dev/null +++ b/src/test/java/io/lettuce/examples/ConnectToPrimaryReplicaUsingRedisSentinel.java @@ -0,0 +1,30 @@ +package io.lettuce.examples; + +import io.lettuce.core.ReadFrom; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.primaryreplica.PrimaryReplica; +import io.lettuce.core.primaryreplica.StatefulRedisPrimaryReplicaConnection; + +/** + * @author yeong0jae + * @since 7.3 + */ +public class ConnectToPrimaryReplicaUsingRedisSentinel { + + public static void main(String[] args) { + // Syntax: redis-sentinel://[password@]host[:port][,host2[:port2]][/databaseNumber]#sentinelPrimaryId + RedisClient redisClient = RedisClient.create(); + + StatefulRedisPrimaryReplicaConnection connection = PrimaryReplica.connect(redisClient, StringCodec.UTF8, + RedisURI.create("redis-sentinel://localhost:26379,localhost:26380/0#myprimary")); + connection.setReadFrom(ReadFrom.PRIMARY_PREFERRED); + + System.out.println("Connected to Redis"); + + connection.close(); + redisClient.shutdown(); + } + +} diff --git a/src/test/java/io/lettuce/examples/ConnectToRedisUsingRedisSentinel.java b/src/test/java/io/lettuce/examples/ConnectToRedisUsingRedisSentinel.java index 24a032e925..5a93295f39 100644 --- a/src/test/java/io/lettuce/examples/ConnectToRedisUsingRedisSentinel.java +++ b/src/test/java/io/lettuce/examples/ConnectToRedisUsingRedisSentinel.java @@ -10,8 +10,8 @@ public class ConnectToRedisUsingRedisSentinel { public static void main(String[] args) { - // Syntax: redis-sentinel://[password@]host[:port][,host2[:port2]][/databaseNumber]#sentinelMasterId - RedisClient redisClient = RedisClient.create("redis-sentinel://localhost:26379,localhost:26380/0#mymaster"); + // Syntax: redis-sentinel://[password@]host[:port][,host2[:port2]][/databaseNumber]#sentinelPrimaryId + RedisClient redisClient = RedisClient.create("redis-sentinel://localhost:26379,localhost:26380/0#myprimary"); StatefulRedisConnection connection = redisClient.connect(); diff --git a/src/test/resources/spring-test.xml b/src/test/resources/spring-test.xml index 9e2f82bf67..ba33c821ed 100644 --- a/src/test/resources/spring-test.xml +++ b/src/test/resources/spring-test.xml @@ -8,8 +8,8 @@ - - - + + +