Skip to content

Commit 0820e84

Browse files
feature: support standalone seamless ha
Signed-off-by: bodong.ybd <[email protected]>
1 parent 764569d commit 0820e84

12 files changed

+541
-25
lines changed

Makefile

+46-1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,29 @@ replicaof localhost 6388
145145
extended-redis-compatibility yes
146146
endef
147147

148+
define VALKEY12_CONF
149+
daemonize yes
150+
protected-mode no
151+
port 6391
152+
pidfile /tmp/valkey12.pid
153+
logfile /tmp/valkey12.log
154+
save ""
155+
appendonly no
156+
extended-redis-compatibility yes
157+
endef
158+
159+
define VALKEY13_CONF
160+
daemonize yes
161+
protected-mode no
162+
port 6392
163+
pidfile /tmp/valkey13.pid
164+
logfile /tmp/valkey13.log
165+
save ""
166+
appendonly no
167+
replicaof localhost 6391
168+
extended-redis-compatibility yes
169+
endef
170+
148171
# SENTINELS
149172
define VALKEY_SENTINEL1
150173
port 26379
@@ -409,6 +432,8 @@ export VALKEY8_CONF
409432
export VALKEY9_CONF
410433
export VALKEY10_CONF
411434
export VALKEY11_CONF
435+
export VALKEY12_CONF
436+
export VALKEY13_CONF
412437
export VALKEY_SENTINEL1
413438
export VALKEY_SENTINEL2
414439
export VALKEY_SENTINEL3
@@ -445,6 +470,8 @@ start: stunnel cleanup compile-module
445470
echo "$$VALKEY9_CONF" | valkey-server -
446471
echo "$$VALKEY10_CONF" | valkey-server -
447472
echo "$$VALKEY11_CONF" | valkey-server -
473+
echo "$$VALKEY12_CONF" | valkey-server -
474+
echo "$$VALKEY13_CONF" | valkey-server -
448475
echo "$$VALKEY_SENTINEL1" > /tmp/sentinel1.conf && valkey-server /tmp/sentinel1.conf --sentinel
449476
@sleep 0.5
450477
echo "$$VALKEY_SENTINEL2" > /tmp/sentinel2.conf && valkey-server /tmp/sentinel2.conf --sentinel
@@ -465,6 +492,7 @@ start: stunnel cleanup compile-module
465492
echo "$$VALKEY_STABLE_CLUSTER_NODE3_CONF" | valkey-server -
466493
echo "$$VALKEY_UDS" | valkey-server -
467494
echo "$$VALKEY_UNAVAILABLE_CONF" | valkey-server -
495+
@sleep 0.5
468496
valkey-cli -a cluster --cluster create 127.0.0.1:7479 127.0.0.1:7480 127.0.0.1:7481 --cluster-yes
469497
cleanup:
470498
- rm -vf /tmp/valkey_cluster_node*.conf 2>/dev/null
@@ -487,6 +515,8 @@ stop:
487515
kill `cat /tmp/valkey9.pid`
488516
kill `cat /tmp/valkey10.pid`
489517
kill `cat /tmp/valkey11.pid`
518+
kill `cat /tmp/valkey12.pid`
519+
kill `cat /tmp/valkey13.pid`
490520
kill `cat /tmp/sentinel1.pid`
491521
kill `cat /tmp/sentinel2.pid`
492522
kill `cat /tmp/sentinel3.pid`
@@ -517,7 +547,22 @@ stop:
517547
rm -f /tmp/valkey_stable_cluster_node2.conf
518548
rm -f /tmp/valkey_stable_cluster_node3.conf
519549

520-
test: | start mvn-test stop
550+
show-log:
551+
echo "====== valkey1.log =======" && cat /tmp/valkey1.log
552+
echo "====== valkey2.log =======" && cat /tmp/valkey2.log
553+
echo "====== valkey3.log =======" && cat /tmp/valkey3.log
554+
echo "====== valkey4.log =======" && cat /tmp/valkey4.log
555+
echo "====== valkey5.log =======" && cat /tmp/valkey5.log
556+
echo "====== valkey6.log =======" && cat /tmp/valkey6.log
557+
echo "====== valkey7.log =======" && cat /tmp/valkey7.log
558+
echo "====== valkey8.log =======" && cat /tmp/valkey8.log
559+
echo "====== valkey9.log =======" && cat /tmp/valkey9.log
560+
echo "====== valkey10.log =======" && cat /tmp/valkey10.log
561+
echo "====== valkey11.log =======" && cat /tmp/valkey11.log
562+
echo "====== valkey12.log =======" && cat /tmp/valkey12.log
563+
echo "====== valkey13.log =======" && cat /tmp/valkey13.log
564+
565+
test: | start show-log mvn-test stop
521566

522567
mvn-test:
523568
mvn -Dtest=${SKIP_SSL}${TEST} clean compile test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.jackey;
2+
3+
public class ClientCapaConfig {
4+
private final boolean disabled;
5+
private final boolean redirect;
6+
7+
public static final ClientCapaConfig DEFAULT = new ClientCapaConfig();
8+
public static final ClientCapaConfig DISABLED = new ClientCapaConfig(true, false);
9+
10+
public ClientCapaConfig() {
11+
this(false, true);
12+
}
13+
14+
public ClientCapaConfig(boolean disabled, boolean redirect) {
15+
this.disabled = disabled;
16+
this.redirect = redirect;
17+
}
18+
19+
public final boolean isDisabled() {
20+
return disabled;
21+
}
22+
23+
public boolean isRedirect() {
24+
return redirect;
25+
}
26+
27+
public static ClientCapaConfig withRedirect() {
28+
return new ClientCapaConfig(false, true);
29+
}
30+
}

src/main/java/io/jackey/Connection.java

+15
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ final HostAndPort getHostAndPort() {
8484
return ((DefaultJedisSocketFactory) socketFactory).getHostAndPort();
8585
}
8686

87+
public final ConnectionPool getMemberOf() {
88+
return memberOf;
89+
}
90+
8791
public int getSoTimeout() {
8892
return soTimeout;
8993
}
@@ -414,6 +418,7 @@ private void initializeFromClientConfig(final JedisClientConfig config) {
414418
fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETNAME).add(clientName));
415419
}
416420

421+
// CLIENT SETINFO LIB-NAME & LIB-VER
417422
ClientSetInfoConfig setInfoConfig = config.getClientSetInfoConfig();
418423
if (setInfoConfig == null) setInfoConfig = ClientSetInfoConfig.DEFAULT;
419424

@@ -435,6 +440,16 @@ private void initializeFromClientConfig(final JedisClientConfig config) {
435440
}
436441
}
437442

443+
// CLIENT CAPA REDIRECT
444+
ClientCapaConfig capaConfig = config.getClientCapaConfig();
445+
if (capaConfig == null) capaConfig = ClientCapaConfig.DEFAULT;
446+
if (!capaConfig.isDisabled()) {
447+
if (capaConfig.isRedirect()) {
448+
fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.CAPA)
449+
.add(ClientAttributeOption.REDIRECT.getRaw()));
450+
}
451+
}
452+
438453
for (CommandArguments arg : fireAndForgetMsg) {
439454
sendCommand(arg);
440455
}

src/main/java/io/jackey/DefaultJedisClientConfig.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ public final class DefaultJedisClientConfig implements JedisClientConfig {
2525
private final HostAndPortMapper hostAndPortMapper;
2626

2727
private final ClientSetInfoConfig clientSetInfoConfig;
28+
private final ClientCapaConfig clientCapaConfig;
2829

2930
private DefaultJedisClientConfig(RedisProtocol protocol, int connectionTimeoutMillis, int soTimeoutMillis,
3031
int blockingSocketTimeoutMillis, Supplier<RedisCredentials> credentialsProvider, int database,
3132
String clientName, boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
3233
HostnameVerifier hostnameVerifier, HostAndPortMapper hostAndPortMapper,
33-
ClientSetInfoConfig clientSetInfoConfig) {
34+
ClientSetInfoConfig clientSetInfoConfig, ClientCapaConfig clientCapaConfig) {
3435
this.redisProtocol = protocol;
3536
this.connectionTimeoutMillis = connectionTimeoutMillis;
3637
this.socketTimeoutMillis = soTimeoutMillis;
@@ -44,6 +45,7 @@ private DefaultJedisClientConfig(RedisProtocol protocol, int connectionTimeoutMi
4445
this.hostnameVerifier = hostnameVerifier;
4546
this.hostAndPortMapper = hostAndPortMapper;
4647
this.clientSetInfoConfig = clientSetInfoConfig;
48+
this.clientCapaConfig = clientCapaConfig;
4749
}
4850

4951
@Override
@@ -122,6 +124,11 @@ public ClientSetInfoConfig getClientSetInfoConfig() {
122124
return clientSetInfoConfig;
123125
}
124126

127+
@Override
128+
public ClientCapaConfig getClientCapaConfig() {
129+
return clientCapaConfig;
130+
}
131+
125132
public static Builder builder() {
126133
return new Builder();
127134
}
@@ -148,6 +155,7 @@ public static class Builder {
148155
private HostAndPortMapper hostAndPortMapper = null;
149156

150157
private ClientSetInfoConfig clientSetInfoConfig = ClientSetInfoConfig.DEFAULT;
158+
private ClientCapaConfig clientCapaConfig = ClientCapaConfig.DEFAULT;
151159

152160
private Builder() {
153161
}
@@ -160,7 +168,7 @@ public DefaultJedisClientConfig build() {
160168

161169
return new DefaultJedisClientConfig(redisProtocol, connectionTimeoutMillis, socketTimeoutMillis,
162170
blockingSocketTimeoutMillis, credentialsProvider, database, clientName, ssl,
163-
sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper, clientSetInfoConfig);
171+
sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper, clientSetInfoConfig, clientCapaConfig);
164172
}
165173

166174
/**
@@ -255,6 +263,11 @@ public Builder clientSetInfoConfig(ClientSetInfoConfig setInfoConfig) {
255263
this.clientSetInfoConfig = setInfoConfig;
256264
return this;
257265
}
266+
267+
public Builder clientCapaConfig(ClientCapaConfig capaConfig) {
268+
this.clientCapaConfig = capaConfig;
269+
return this;
270+
}
258271
}
259272

260273
public static DefaultJedisClientConfig create(int connectionTimeoutMillis, int soTimeoutMillis,
@@ -264,7 +277,7 @@ public static DefaultJedisClientConfig create(int connectionTimeoutMillis, int s
264277
return new DefaultJedisClientConfig(null,
265278
connectionTimeoutMillis, soTimeoutMillis, blockingSocketTimeoutMillis,
266279
new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(user, password)), database,
267-
clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper, null);
280+
clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper, null, null);
268281
}
269282

270283
public static DefaultJedisClientConfig copyConfig(JedisClientConfig copy) {
@@ -273,6 +286,6 @@ public static DefaultJedisClientConfig copyConfig(JedisClientConfig copy) {
273286
copy.getBlockingSocketTimeoutMillis(), copy.getCredentialsProvider(),
274287
copy.getDatabase(), copy.getClientName(), copy.isSsl(), copy.getSslSocketFactory(),
275288
copy.getSslParameters(), copy.getHostnameVerifier(), copy.getHostAndPortMapper(),
276-
copy.getClientSetInfoConfig());
289+
copy.getClientSetInfoConfig(), copy.getClientCapaConfig());
277290
}
278291
}

src/main/java/io/jackey/JedisClientConfig.java

+4
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,8 @@ default HostAndPortMapper getHostAndPortMapper() {
8787
default ClientSetInfoConfig getClientSetInfoConfig() {
8888
return ClientSetInfoConfig.DEFAULT;
8989
}
90+
91+
default ClientCapaConfig getClientCapaConfig() {
92+
return ClientCapaConfig.DEFAULT;
93+
}
9094
}

src/main/java/io/jackey/Protocol.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public final class Protocol {
6565
private static final String NOAUTH_PREFIX = "NOAUTH";
6666
private static final String WRONGPASS_PREFIX = "WRONGPASS";
6767
private static final String NOPERM_PREFIX = "NOPERM";
68+
private static final String REDIRECT_PREFIX = "REDIRECT ";
6869

6970
private Protocol() {
7071
throw new InstantiationError("Must not instantiate this class");
@@ -100,6 +101,9 @@ private static void processError(final RedisInputStream is) {
100101
// throw new JedisAskDataException(message, new HostAndPort(askInfo[1],
101102
// Integer.parseInt(askInfo[2])), Integer.parseInt(askInfo[0]));
102103
throw new JedisAskDataException(message, HostAndPort.from(askInfo[1]), Integer.parseInt(askInfo[0]));
104+
} else if (message.startsWith(REDIRECT_PREFIX)) {
105+
String host = parseTargetHost(message);
106+
throw new JedisRedirectionException(message, HostAndPort.from(host), -1); // slot -1 means standalone
103107
} else if (message.startsWith(CLUSTERDOWN_PREFIX)) {
104108
throw new JedisClusterException(message);
105109
} else if (message.startsWith(BUSY_PREFIX)) {
@@ -140,6 +144,11 @@ private static String[] parseTargetHostAndSlot(String clusterRedirectResponse) {
140144
return response;
141145
}
142146

147+
private static String parseTargetHost(String clusterRedirectResponse) {
148+
String[] messageInfo = clusterRedirectResponse.split(" ");
149+
return messageInfo[1];
150+
}
151+
143152
private static Object process(final RedisInputStream is) {
144153
final byte b = is.readByte();
145154
//System.out.println((char) b);
@@ -309,7 +318,7 @@ public static enum Keyword implements Rawable {
309318
DELETE, LIBRARYNAME, WITHCODE, DESCRIPTION, GETKEYS, GETKEYSANDFLAGS, DOCS, FILTERBY, DUMP,
310319
MODULE, ACLCAT, PATTERN, DOCTOR, LATEST, HISTORY, USAGE, SAMPLES, PURGE, STATS, LOADEX, CONFIG, ARGS, RANK,
311320
NOW, VERSION, ADDR, SKIPME, USER, LADDR,
312-
CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES, MAXAGE;
321+
CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES, MAXAGE, CAPA;
313322

314323
private final byte[] raw;
315324

src/main/java/io/jackey/UnifiedJedis.java

+26
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,32 @@ protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Dura
251251
new ClusterCommandObjects(), protocol);
252252
}
253253

254+
/**
255+
* Constructs a {@code UnifiedJedis} instance with the given parameters.
256+
*
257+
* @param provider the connection provider for redirect handling
258+
* @param maxAttempts the maximum number of attempts to execute a command before giving up
259+
* @param maxTotalRetriesDuration the maximum total duration to retry commands before giving up
260+
*/
261+
public UnifiedJedis(RedirectConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration) {
262+
this(new RedirectCommandExecutor(provider, maxAttempts, maxTotalRetriesDuration), provider);
263+
}
264+
265+
/**
266+
* A constructor with an additional parameter for customizing the Redis communication protocol.
267+
*
268+
* @param provider the connection provider for redirect handling
269+
* @param maxAttempts the maximum number of attempts to execute a command before giving up
270+
* @param maxTotalRetriesDuration the maximum total duration to retry commands before giving up
271+
* @param protocol the Redis protocol implementation to use
272+
*/
273+
protected UnifiedJedis(RedirectConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration,
274+
RedisProtocol protocol) {
275+
this(new RedirectCommandExecutor(provider, maxAttempts, maxTotalRetriesDuration), provider, new CommandObjects(),
276+
protocol);
277+
}
278+
279+
254280
/**
255281
* @deprecated Sharding/Sharded feature will be removed in next major release.
256282
*/

src/main/java/io/jackey/args/ClientAttributeOption.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import io.jackey.util.SafeEncoder;
44

55
/**
6-
* CLIENT SETINFO command attr option
6+
* CLIENT command attr option
77
* since redis 7.2
88
*/
99
public enum ClientAttributeOption implements Rawable {
1010
LIB_NAME("LIB-NAME"),
11-
LIB_VER("LIB-VER");
11+
LIB_VER("LIB-VER"),
12+
REDIRECT("REDIRECT");
1213

1314
private final byte[] raw;
1415

0 commit comments

Comments
 (0)