From f306ab48bb063215e5dfb51183bfb565387ec364 Mon Sep 17 00:00:00 2001 From: SreedharReddyKallu <39802874+SreedharReddyKallu@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:03:02 +0000 Subject: [PATCH 1/7] Implement failOver with TakeOver option --- .../io/lettuce/core/AbstractRedisAsyncCommands.java | 5 +++++ .../java/io/lettuce/core/RedisCommandBuilder.java | 12 ++++++++++++ .../cluster/api/async/RedisClusterAsyncCommands.java | 11 +++++++++++ .../io/lettuce/core/protocol/CommandKeyword.java | 2 +- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index 6763c469c0..ddaa28ea3f 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -410,6 +410,11 @@ public RedisFuture clusterFailover(boolean force) { return dispatch(commandBuilder.clusterFailover(force)); } + @Override + public RedisFuture clusterFailover(boolean force,boolean takeOver) { + return dispatch(commandBuilder.clusterFailover(force,takeOver)); + } + @Override public RedisFuture clusterFlushslots() { return dispatch(commandBuilder.clusterFlushslots()); diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java index 0e9109edcf..90553b6cae 100644 --- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java @@ -587,6 +587,18 @@ Command clusterFailover(boolean force) { return createCommand(CLUSTER, new StatusOutput<>(codec), args); } + Command clusterFailover(boolean force,boolean takeOver) { + + CommandArgs args = new CommandArgs<>(codec).add(FAILOVER); + if (force) { + args.add(FORCE); + } + else if(takeOver) { + args.add(TAKEOVER); + } + return createCommand(CLUSTER, new StatusOutput<>(codec), args); + } + Command clusterFlushslots() { CommandArgs args = new CommandArgs<>(codec).add(FLUSHSLOTS); diff --git a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java index 63d8d9801d..76ac45360c 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java @@ -140,9 +140,20 @@ public interface RedisClusterAsyncCommands extends BaseRedisAsyncCommands< * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply + * @deprecated use {@link #clusterFailover(boolean,boolean)} instead. */ + @Deprecated RedisFuture clusterFailover(boolean force); + /** + * Failover a cluster node. Turns the currently connected node into a master and the master into its replica. + * + * @param force do not coordinate with master if {@code true} + * @param takeOver do not coordinate with the rest of the cluster if {@code true} + * @return String simple-string-reply + */ + RedisFuture clusterFailover(boolean force,boolean takeOver); + /** * Delete all the slots associated with the specified node. The number of deleted slots is returned. * diff --git a/src/main/java/io/lettuce/core/protocol/CommandKeyword.java b/src/main/java/io/lettuce/core/protocol/CommandKeyword.java index e2249001b2..f8a33fb38e 100644 --- a/src/main/java/io/lettuce/core/protocol/CommandKeyword.java +++ b/src/main/java/io/lettuce/core/protocol/CommandKeyword.java @@ -41,7 +41,7 @@ public enum CommandKeyword implements ProtocolKeyword { RESETSTAT, RESTART, RETRYCOUNT, REWRITE, RIGHT, SAVECONFIG, SDSLEN, SETNAME, SETSLOT, SHARDS, SLOTS, STABLE, - MIGRATING, IMPORTING, SAVE, SKIPME, SLAVES, STREAM, STORE, SUM, SEGFAULT, SETUSER, TRACKING, TYPE, UNBLOCK, USERS, USAGE, WEIGHTS, WHOAMI, + MIGRATING, IMPORTING, SAVE, SKIPME, SLAVES, STREAM, STORE, SUM, SEGFAULT, SETUSER, TAKEOVER, TRACKING, TYPE, UNBLOCK, USERS, USAGE, WEIGHTS, WHOAMI, WITHSCORES, WITHVALUES, XOR, XX, YES; From 450464ca66a6e880ce180c6c057ac8d82a1faa3b Mon Sep 17 00:00:00 2001 From: SreedharReddyKallu <39802874+SreedharReddyKallu@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:28:32 +0000 Subject: [PATCH 2/7] Implement FAILOVER with TAKEOVER option --- .../io/lettuce/core/AbstractRedisReactiveCommands.java | 5 +++++ .../api/reactive/RedisClusterReactiveCommands.java | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 9252193b57..32617b67c8 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -432,6 +432,11 @@ public Mono clusterFailover(boolean force) { return createMono(() -> commandBuilder.clusterFailover(force)); } + @Override + public Mono clusterFailover(boolean force, boolean takeOver) { + return createMono(() -> commandBuilder.clusterFailover(force, takeOver)); + } + @Override public Mono clusterFlushslots() { return createMono(commandBuilder::clusterFlushslots); diff --git a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java index e3151458bc..82183a5297 100644 --- a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java @@ -141,9 +141,19 @@ public interface RedisClusterReactiveCommands extends BaseRedisReactiveCom * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply + * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ Mono clusterFailover(boolean force); + /** + * Failover a cluster node. Turns the currently connected node into a master and the master into its replica. + * + * @param force do not coordinate with master if {@code true} + * @param takeOver do not coordinate with the rest of the cluster if {@code true} + * @return String simple-string-reply + */ + Mono clusterFailover(boolean force, boolean takeOver); + /** * Delete all the slots associated with the specified node. The number of deleted slots is returned. * From e0aa6911538580c962ed4cd8770d8c8b023e95f0 Mon Sep 17 00:00:00 2001 From: Sreedhar Reddy Kallu Date: Wed, 15 Mar 2023 10:15:52 +0530 Subject: [PATCH 3/7] Implement takeOver --- .../core/AbstractRedisAsyncCommands.java | 4 +-- .../io/lettuce/core/RedisCommandBuilder.java | 5 ++-- .../api/async/RedisClusterAsyncCommands.java | 3 ++- .../RedisClusterReactiveCommands.java | 1 + .../api/sync/RedisClusterCommands.java | 10 +++++++ .../RedisClusterStressScenariosTest.java | 26 +++++++++++++++++++ 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index ddaa28ea3f..4a05773d7d 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -411,8 +411,8 @@ public RedisFuture clusterFailover(boolean force) { } @Override - public RedisFuture clusterFailover(boolean force,boolean takeOver) { - return dispatch(commandBuilder.clusterFailover(force,takeOver)); + public RedisFuture clusterFailover(boolean force, boolean takeOver) { + return dispatch(commandBuilder.clusterFailover(force, takeOver)); } @Override diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java index 90553b6cae..e3935fe825 100644 --- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java @@ -587,13 +587,12 @@ Command clusterFailover(boolean force) { return createCommand(CLUSTER, new StatusOutput<>(codec), args); } - Command clusterFailover(boolean force,boolean takeOver) { + Command clusterFailover(boolean force, boolean takeOver) { CommandArgs args = new CommandArgs<>(codec).add(FAILOVER); if (force) { args.add(FORCE); - } - else if(takeOver) { + } else if (takeOver) { args.add(TAKEOVER); } return createCommand(CLUSTER, new StatusOutput<>(codec), args); diff --git a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java index 76ac45360c..e8b09f2aa3 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java @@ -150,9 +150,10 @@ public interface RedisClusterAsyncCommands extends BaseRedisAsyncCommands< * * @param force do not coordinate with master if {@code true} * @param takeOver do not coordinate with the rest of the cluster if {@code true} + * force will take precedence over takeOver if both are set. * @return String simple-string-reply */ - RedisFuture clusterFailover(boolean force,boolean takeOver); + RedisFuture clusterFailover(boolean force, boolean takeOver); /** * Delete all the slots associated with the specified node. The number of deleted slots is returned. diff --git a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java index 82183a5297..edd013f0dd 100644 --- a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java @@ -143,6 +143,7 @@ public interface RedisClusterReactiveCommands extends BaseRedisReactiveCom * @return String simple-string-reply * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ + @Deprecated Mono clusterFailover(boolean force); /** diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java index 38872bfc1a..a05cff0550 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java @@ -138,9 +138,19 @@ public interface RedisClusterCommands extends BaseRedisCommands, Red * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply + * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ + @Deprecated String clusterFailover(boolean force); + /** + * Failover a cluster node. Turns the currently connected node into a master and the master into its replica. + * + * @param force do not coordinate with master if {@code true} + * @return String simple-string-reply + */ + String clusterFailover(boolean force, boolean takeOver); + /** * Delete all the slots associated with the specified node. The number of deleted slots is returned. * diff --git a/src/test/java/io/lettuce/core/cluster/RedisClusterStressScenariosTest.java b/src/test/java/io/lettuce/core/cluster/RedisClusterStressScenariosTest.java index a95c8ab7d3..05e8d90367 100644 --- a/src/test/java/io/lettuce/core/cluster/RedisClusterStressScenariosTest.java +++ b/src/test/java/io/lettuce/core/cluster/RedisClusterStressScenariosTest.java @@ -131,6 +131,32 @@ public void testClusterFailover() { assertThat(redis5Node.is(RedisClusterNode.NodeFlag.REPLICA)).isTrue(); assertThat(redis6Node.is(RedisClusterNode.NodeFlag.UPSTREAM)).isTrue(); + } + @Test + public void testClusterFailoverWithTakeOver() { + + log.info("Cluster node 5 is master"); + log.info("Cluster nodes seen from node 5:\n" + redissync5.clusterNodes()); + log.info("Cluster nodes seen from node 6:\n" + redissync6.clusterNodes()); + + Wait.untilTrue(() -> getOwnPartition(redissync5).is(RedisClusterNode.NodeFlag.UPSTREAM)).waitOrTimeout(); + Wait.untilTrue(() -> getOwnPartition(redissync6).is(RedisClusterNode.NodeFlag.REPLICA)).waitOrTimeout(); + + String failover = redissync6.clusterFailover(false, true); + assertThat(failover).isEqualTo("OK"); + + Wait.untilTrue(() -> getOwnPartition(redissync6).is(RedisClusterNode.NodeFlag.UPSTREAM)).waitOrTimeout(); + Wait.untilTrue(() -> getOwnPartition(redissync5).is(RedisClusterNode.NodeFlag.REPLICA)).waitOrTimeout(); + + log.info("Cluster nodes seen from node 5 after clusterFailover:\n" + redissync5.clusterNodes()); + log.info("Cluster nodes seen from node 6 after clusterFailover:\n" + redissync6.clusterNodes()); + + RedisClusterNode redis5Node = getOwnPartition(redissync5); + RedisClusterNode redis6Node = getOwnPartition(redissync6); + + assertThat(redis5Node.is(RedisClusterNode.NodeFlag.REPLICA)).isTrue(); + assertThat(redis6Node.is(RedisClusterNode.NodeFlag.UPSTREAM)).isTrue(); + } @Test From 9dece560b7f55e67e0235b22e66f035e58d907a7 Mon Sep 17 00:00:00 2001 From: Sreedhar Reddy Kallu Date: Wed, 15 Mar 2023 10:28:46 +0530 Subject: [PATCH 4/7] Implement takeOver --- .../core/cluster/api/async/RedisClusterAsyncCommands.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java index e8b09f2aa3..b167712569 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java @@ -140,9 +140,9 @@ public interface RedisClusterAsyncCommands extends BaseRedisAsyncCommands< * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply - * @deprecated use {@link #clusterFailover(boolean,boolean)} instead. + * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ - @Deprecated + @Deprecated RedisFuture clusterFailover(boolean force); /** From 80ee239c19fe3906d4b911a05f5490bbe790368c Mon Sep 17 00:00:00 2001 From: Sreedhar Reddy Kallu Date: Thu, 23 Mar 2023 16:07:05 +0530 Subject: [PATCH 5/7] Implement takeOver --- .../core/cluster/api/async/RedisClusterAsyncCommands.java | 2 -- .../core/cluster/api/reactive/RedisClusterReactiveCommands.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java index b167712569..cb58f5260c 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java @@ -140,9 +140,7 @@ public interface RedisClusterAsyncCommands extends BaseRedisAsyncCommands< * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply - * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ - @Deprecated RedisFuture clusterFailover(boolean force); /** diff --git a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java index edd013f0dd..eee5bea6f1 100644 --- a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java @@ -141,9 +141,7 @@ public interface RedisClusterReactiveCommands extends BaseRedisReactiveCom * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply - * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ - @Deprecated Mono clusterFailover(boolean force); /** From 572648ff38f29c742fa43f3d9619bc5cbdf15eb8 Mon Sep 17 00:00:00 2001 From: Sreedhar Reddy Kallu Date: Thu, 23 Mar 2023 16:09:05 +0530 Subject: [PATCH 6/7] Implement takeOver --- .../io/lettuce/core/cluster/api/sync/RedisClusterCommands.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java index a05cff0550..f764a82e8b 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java @@ -138,9 +138,7 @@ public interface RedisClusterCommands extends BaseRedisCommands, Red * * @param force do not coordinate with master if {@code true} * @return String simple-string-reply - * @deprecated use {@link #clusterFailover(boolean, boolean)} instead. */ - @Deprecated String clusterFailover(boolean force); /** From 395d30835fd39aad22aee5546941686f9f1f8281 Mon Sep 17 00:00:00 2001 From: Sreedhar Reddy Kallu Date: Thu, 23 Mar 2023 16:10:43 +0530 Subject: [PATCH 7/7] Implement takeOver --- .../io/lettuce/core/cluster/api/sync/RedisClusterCommands.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java index f764a82e8b..2a8ca0587a 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java @@ -145,6 +145,8 @@ public interface RedisClusterCommands extends BaseRedisCommands, Red * Failover a cluster node. Turns the currently connected node into a master and the master into its replica. * * @param force do not coordinate with master if {@code true} + * @param takeOver do not coordinate with the rest of the cluster if {@code true} + * force will take precedence over takeOver if both are set. * @return String simple-string-reply */ String clusterFailover(boolean force, boolean takeOver);