Skip to content

Commit 0101cf6

Browse files
authored
Introduce configuration options in the cluster API (#137)
This PR introduces `valkeyClusterOption` and a new API to allow users to set all options before connecting synchronously or asynchronously to a cluster. Example: valkeyClusterOptions options = { .initial_nodes = "127.0.0.1:7000"; }; valkeyClusterContext *cc = valkeyClusterConnectWithOptions(&options) Some API functions are removed/replaced and some are changed, see migration-guide.md for information on API changes. The new option struct enables users to set the initial nodes, callbacks, timeouts, options, TLS- and event-adapters instead of using a wide range of `valkeyClusterSetOptionXxx` functions on a `valkeyClusterContext`. There are still options that are allowed to be configured during runtime like `valkeyClusterSetOptionTimeout`, but most other options currently requires a reconnect. The async cluster API will no longer require that users calls the blocking cluster API using `valkeyClusterConnect2(acc->cc)`. We now provide a new option `VALKEY_OPT_BLOCKING_INITIAL_UPDATE` to enable a blocking slotmap update after an initial connect using the `valkeyClusterAsyncConnectWithOptions` API. With this change there is a symmetry between the cluster API and the standalone API, which already provides a `valkeyOptions` struct to allow users to configure options. Signed-off-by: Björn Svensson <[email protected]>
1 parent 67491af commit 0101cf6

40 files changed

+932
-1094
lines changed

.github/wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Autoloading
1717
backend
1818
backends
1919
behaviour
20+
bitwise
2021
boolean
2122
bugfix
2223
CAS

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ IF(ENABLE_TLS)
161161
ENDIF()
162162
FIND_PACKAGE(OpenSSL REQUIRED)
163163
SET(valkey_tls_sources
164-
src/cluster_tls.c
165164
src/tls.c)
166165
ADD_LIBRARY(valkey_tls ${valkey_tls_sources})
167166
ADD_LIBRARY(valkey::valkey_tls ALIAS valkey_tls)

Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ INCLUDE_DIR = include/valkey
1515
TEST_SRCS = $(TEST_DIR)/client_test.c $(TEST_DIR)/ut_parse_cmd.c $(TEST_DIR)/ut_slotmap_update.c
1616
TEST_BINS = $(patsubst $(TEST_DIR)/%.c,$(TEST_DIR)/%,$(TEST_SRCS))
1717

18-
SOURCES = $(filter-out $(wildcard $(SRC_DIR)/*tls.c) $(SRC_DIR)/rdma.c, $(wildcard $(SRC_DIR)/*.c))
19-
HEADERS = $(filter-out $(wildcard $(INCLUDE_DIR)/*tls.h) $(INCLUDE_DIR)/rdma.h, $(wildcard $(INCLUDE_DIR)/*.h))
18+
SOURCES = $(filter-out $(SRC_DIR)/tls.c $(SRC_DIR)/rdma.c, $(wildcard $(SRC_DIR)/*.c))
19+
HEADERS = $(filter-out $(INCLUDE_DIR)/tls.h $(INCLUDE_DIR)/rdma.h, $(wildcard $(INCLUDE_DIR)/*.h))
2020

2121
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SOURCES))
2222

@@ -95,7 +95,7 @@ TLS_DYLIB_MAKE_CMD=$(CC) $(OPTIMIZATION) $(PLATFORM_FLAGS) -shared -Wl,-soname,$
9595
USE_TLS?=0
9696

9797
ifeq ($(USE_TLS),1)
98-
TLS_SOURCES = $(wildcard $(SRC_DIR)/*tls.c)
98+
TLS_SOURCES = $(SRC_DIR)/tls.c
9999
TLS_OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(TLS_SOURCES))
100100

101101
# This is required for test.c only
@@ -293,7 +293,6 @@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) $(TLS_INSTALL)
293293
install-tls: $(TLS_DYLIBNAME) $(TLS_STLIBNAME) $(TLS_PKGCONFNAME)
294294
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
295295
$(INSTALL) $(INCLUDE_DIR)/tls.h $(INSTALL_INCLUDE_PATH)
296-
$(INSTALL) $(INCLUDE_DIR)/cluster_tls.h $(INSTALL_INCLUDE_PATH)
297296
$(INSTALL) $(TLS_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(TLS_DYLIB_MINOR_NAME)
298297
ln -sf $(TLS_DYLIB_MINOR_NAME) $(INSTALL_LIBRARY_PATH)/$(TLS_ROOT_DYLIB_NAME)
299298
ln -sf $(TLS_DYLIB_MINOR_NAME) $(INSTALL_LIBRARY_PATH)/$(TLS_DYLIB_MAJOR_NAME)

docs/cluster.md

Lines changed: 155 additions & 70 deletions
Large diffs are not rendered by default.

docs/migration-guide.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,20 @@ The type `sds` is removed from the public API.
2727

2828
## Migrating from `hiredis-cluster` 0.14.0
2929

30+
* The cluster client initiation procedure is changed and `valkeyClusterOptions`
31+
should be used to specify options when creating a context.
32+
See documentation for configuration examples when using the
33+
[Synchronous API](cluster.md#synchronous-api) or the
34+
[Asynchronous API](cluster.md#asynchronous-api).
35+
The [examples](../examples/) directory also contains some common client
36+
initiation examples that might be helpful.
37+
* The default command to update the internal slot map is changed to `CLUSTER SLOTS`.
38+
`CLUSTER NODES` can be re-enabled through options using `VALKEY_OPT_USE_CLUSTER_NODES`.
39+
3040
### Renamed API functions
3141

3242
* `ctx_get_by_node` is renamed to `valkeyClusterGetValkeyContext`.
3343
* `actx_get_by_node` is renamed to `valkeyClusterGetValkeyAsyncContext`.
34-
* `redisClusterAsyncSetConnectCallbackNC` is renamed to `valkeyClusterAsyncSetConnectCallback`.
3544

3645
### Renamed API defines
3746

@@ -41,14 +50,32 @@ The type `sds` is removed from the public API.
4150

4251
### Removed API functions
4352

44-
* `redisClusterSetMaxRedirect` removed and replaced with `valkeyClusterSetOptionMaxRetry`.
45-
* `redisClusterSetOptionAddNode` removed and replaced with `valkeyClusterSetOptionAddNodes`.
46-
(Note the "s" in the end of the function name.)
53+
* `redisClusterConnect2` removed, use `valkeyClusterConnectWithOptions`.
54+
* `redisClusterContextInit` removed, use `valkeyClusterConnectWithOptions`.
55+
* `redisClusterSetConnectCallback` removed, use `valkeyClusterOptions.connect_callback`.
56+
* `redisClusterSetEventCallback` removed, use `valkeyClusterOptions.event_callback`.
57+
* `redisClusterSetMaxRedirect` removed, use `valkeyClusterOptions.max_retry`.
58+
* `redisClusterSetOptionAddNode` removed, use `valkeyClusterOptions.initial_nodes`.
59+
* `redisClusterSetOptionAddNodes` removed, use `valkeyClusterOptions.initial_nodes`.
4760
* `redisClusterSetOptionConnectBlock` removed since it was deprecated.
4861
* `redisClusterSetOptionConnectNonBlock` removed since it was deprecated.
62+
* `redisClusterSetOptionConnectTimeout` removed, use `valkeyClusterOptions.connect_timeout`.
63+
* `redisClusterSetOptionMaxRetry` removed, use `valkeyClusterOptions.max_retry`.
64+
* `redisClusterSetOptionParseSlaves` removed, use `valkeyClusterOptions.flags` and `VALKEY_OPT_USE_REPLICAS`.
65+
* `redisClusterSetOptionPassword` removed, use `valkeyClusterOptions.password`.
66+
* `redisClusterSetOptionRouteUseSlots` removed, the use of `CLUSTER SLOTS` is enabled by default.
67+
* `redisClusterSetOptionUsername` removed, use `valkeyClusterOptions.username`.
68+
* `redisClusterAsyncSetConnectCallback` removed, but `valkeyClusterOptions.async_connect_callback` can be used which accepts a non-const callback function prototype.
69+
* `redisClusterAsyncSetConnectCallbackNC` removed, use `valkeyClusterOptions.async_connect_callback`.
70+
* `redisClusterAsyncSetDisconnectCallback` removed, use `valkeyClusterOptions.async_disconnect_callback`.
4971
* `parse_cluster_nodes` removed from API, for internal use only.
5072
* `parse_cluster_slots` removed from API, for internal use only.
51-
* `redisClusterAsyncSetConnectCallback` is removed, but can be replaced with `valkeyClusterAsyncSetConnectCallback` which accepts the non-const callback function prototype.
73+
74+
### Removed API defines
75+
76+
* `HIRCLUSTER_FLAG_NULL` removed.
77+
* `HIRCLUSTER_FLAG_ADD_SLAVE` removed, flag can be replaced with an option, see `VALKEY_OPT_USE_REPLICAS`.
78+
* `HIRCLUSTER_FLAG_ROUTE_USE_SLOTS` removed, the use of `CLUSTER SLOTS` is enabled by default.
5279

5380
### Removed support for splitting multi-key commands per slot
5481

docs/standalone.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ There are also several flags you can specify when using the `valkeyOptions` help
7272
7373
| Flag | Description |
7474
| --- | --- |
75-
| VALKEY\_OPT\_NONBLOCK | Tells libvalkey to make a non-blocking connection. |
76-
| VALKEY\_OPT\_REUSEADDR | Tells libvalkey to set the [SO_REUSEADDR](https://man7.org/linux/man-pages/man7/socket.7.html) socket option |
77-
| VALKEY\_OPT\_PREFER\_IPV4<br>VALKEY\_OPT\_PREFER_IPV6<br>VALKEY\_OPT\_PREFER\_IP\_UNSPEC | Informs libvalkey to either prefer IPv4 or IPv6 when invoking [getaddrinfo](https://man7.org/linux/man-pages/man3/gai_strerror.3.html). `VALKEY_OPT_PREFER_IP_UNSPEC` will cause libvalkey to specify `AF_UNSPEC` in the getaddrinfo call, which means both IPv4 and IPv6 addresses will be searched simultaneously.<br>Libvalkey prefers IPv4 by default. |
78-
| VALKEY\_OPT\_NO\_PUSH\_AUTOFREE | Tells libvalkey to not install the default RESP3 PUSH handler (which just intercepts and frees the replies). This is useful in situations where you want to process these messages in-band. |
79-
| VALKEY\_OPT\_NOAUTOFREEREPLIES | **ASYNC**: tells libvalkey not to automatically invoke `freeReplyObject` after executing the reply callback. |
80-
| VALKEY\_OPT\_NOAUTOFREE | **ASYNC**: Tells libvalkey not to automatically free the `valkeyAsyncContext` on connection/communication failure, but only if the user makes an explicit call to `valkeyAsyncDisconnect` or `valkeyAsyncFree` |
75+
| `VALKEY_OPT_NONBLOCK` | Tells libvalkey to make a non-blocking connection. |
76+
| `VALKEY_OPT_REUSEADDR` | Tells libvalkey to set the [SO_REUSEADDR](https://man7.org/linux/man-pages/man7/socket.7.html) socket option |
77+
| `VALKEY_OPT_PREFER_IPV4`<br>`VALKEY_OPT_PREFER_IPV6`<br>`VALKEY_OPT_PREFER_IP_UNSPEC` | Informs libvalkey to either prefer IPv4 or IPv6 when invoking [getaddrinfo](https://man7.org/linux/man-pages/man3/gai_strerror.3.html). `VALKEY_OPT_PREFER_IP_UNSPEC` will cause libvalkey to specify `AF_UNSPEC` in the getaddrinfo call, which means both IPv4 and IPv6 addresses will be searched simultaneously.<br>Libvalkey prefers IPv4 by default. |
78+
| `VALKEY_OPT_NO_PUSH_AUTOFREE` | Tells libvalkey to not install the default RESP3 PUSH handler (which just intercepts and frees the replies). This is useful in situations where you want to process these messages in-band. |
79+
| `VALKEY_OPT_NOAUTOFREEREPLIES` | **ASYNC**: tells libvalkey not to automatically invoke `freeReplyObject` after executing the reply callback. |
80+
| `VALKEY_OPT_NOAUTOFREE` | **ASYNC**: Tells libvalkey not to automatically free the `valkeyAsyncContext` on connection/communication failure, but only if the user makes an explicit call to `valkeyAsyncDisconnect` or `valkeyAsyncFree` |
8181
8282
### Executing commands
8383
@@ -298,7 +298,7 @@ Libvalkey also has an asynchronous API which supports a great many different eve
298298
Libvalkey provides an `valkeyAsyncContext` to manage asynchronous connections which works similarly to the synchronous context.
299299

300300
```c
301-
valkeyAsyncContext *ac = valkeyAsyncConnect("loalhost", 6379);
301+
valkeyAsyncContext *ac = valkeyAsyncConnect("localhost", 6379);
302302
if (ac == NULL) {
303303
fprintf(stderr, "Error: Out of memory trying to allocate valkeyAsyncContext\n");
304304
exit(1);

examples/cluster-async-tls.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <valkey/cluster.h>
2-
#include <valkey/cluster_tls.h>
2+
#include <valkey/tls.h>
33

44
#include <valkey/adapters/libevent.h>
55

@@ -66,23 +66,22 @@ int main(int argc, char **argv) {
6666
exit(1);
6767
}
6868

69-
valkeyClusterAsyncContext *acc = valkeyClusterAsyncContextInit();
70-
assert(acc);
71-
valkeyClusterAsyncSetConnectCallback(acc, connectCallback);
72-
valkeyClusterAsyncSetDisconnectCallback(acc, disconnectCallback);
73-
valkeyClusterSetOptionAddNodes(acc->cc, CLUSTER_NODE_TLS);
74-
valkeyClusterSetOptionRouteUseSlots(acc->cc);
75-
valkeyClusterSetOptionParseSlaves(acc->cc);
76-
valkeyClusterSetOptionEnableTLS(acc->cc, tls);
77-
78-
if (valkeyClusterConnect2(acc->cc) != VALKEY_OK) {
79-
printf("Error: %s\n", acc->cc->errstr);
69+
struct event_base *base = event_base_new();
70+
71+
valkeyClusterOptions options = {0};
72+
options.initial_nodes = CLUSTER_NODE_TLS;
73+
options.async_connect_callback = connectCallback;
74+
options.async_disconnect_callback = disconnectCallback;
75+
options.tls = tls;
76+
options.tls_init_fn = &valkeyInitiateTLSWithContext;
77+
valkeyClusterOptionsUseLibevent(&options, base);
78+
79+
valkeyClusterAsyncContext *acc = valkeyClusterAsyncConnectWithOptions(&options);
80+
if (acc == NULL || acc->err != 0) {
81+
printf("Error: %s\n", acc ? acc->errstr : "OOM");
8082
exit(-1);
8183
}
8284

83-
struct event_base *base = event_base_new();
84-
valkeyClusterLibeventAttach(acc, base);
85-
8685
int status;
8786
status = valkeyClusterAsyncCommand(acc, setCallback, (char *)"THE_ID",
8887
"SET %s %s", "key", "value");

examples/cluster-async.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,53 +49,55 @@ void disconnectCallback(const valkeyAsyncContext *ac, int status) {
4949
int main(int argc, char **argv) {
5050
(void)argc;
5151
(void)argv;
52+
struct event_base *base = event_base_new();
53+
54+
valkeyClusterOptions options = {0};
55+
options.initial_nodes = "127.0.0.1:7000";
56+
options.async_connect_callback = connectCallback;
57+
options.async_disconnect_callback = disconnectCallback;
58+
valkeyClusterOptionsUseLibevent(&options, base);
59+
5260
printf("Connecting...\n");
53-
valkeyClusterAsyncContext *cc =
54-
valkeyClusterAsyncConnect("127.0.0.1:7000", VALKEYCLUSTER_FLAG_NULL);
55-
if (!cc) {
61+
valkeyClusterAsyncContext *acc = valkeyClusterAsyncConnectWithOptions(&options);
62+
if (!acc) {
5663
printf("Error: Allocation failure\n");
5764
exit(-1);
58-
} else if (cc->err) {
59-
printf("Error: %s\n", cc->errstr);
65+
} else if (acc->err) {
66+
printf("Error: %s\n", acc->errstr);
6067
// handle error
6168
exit(-1);
6269
}
6370

64-
struct event_base *base = event_base_new();
65-
valkeyClusterLibeventAttach(cc, base);
66-
valkeyClusterAsyncSetConnectCallback(cc, connectCallback);
67-
valkeyClusterAsyncSetDisconnectCallback(cc, disconnectCallback);
68-
6971
int status;
70-
status = valkeyClusterAsyncCommand(cc, setCallback, (char *)"THE_ID",
72+
status = valkeyClusterAsyncCommand(acc, setCallback, (char *)"THE_ID",
7173
"SET %s %s", "key", "value");
7274
if (status != VALKEY_OK) {
73-
printf("error: err=%d errstr=%s\n", cc->err, cc->errstr);
75+
printf("error: err=%d errstr=%s\n", acc->err, acc->errstr);
7476
}
7577

76-
status = valkeyClusterAsyncCommand(cc, getCallback, (char *)"THE_ID",
78+
status = valkeyClusterAsyncCommand(acc, getCallback, (char *)"THE_ID",
7779
"GET %s", "key");
7880
if (status != VALKEY_OK) {
79-
printf("error: err=%d errstr=%s\n", cc->err, cc->errstr);
81+
printf("error: err=%d errstr=%s\n", acc->err, acc->errstr);
8082
}
8183

82-
status = valkeyClusterAsyncCommand(cc, setCallback, (char *)"THE_ID",
84+
status = valkeyClusterAsyncCommand(acc, setCallback, (char *)"THE_ID",
8385
"SET %s %s", "key2", "value2");
8486
if (status != VALKEY_OK) {
85-
printf("error: err=%d errstr=%s\n", cc->err, cc->errstr);
87+
printf("error: err=%d errstr=%s\n", acc->err, acc->errstr);
8688
}
8789

88-
status = valkeyClusterAsyncCommand(cc, getCallback, (char *)"THE_ID",
90+
status = valkeyClusterAsyncCommand(acc, getCallback, (char *)"THE_ID",
8991
"GET %s", "key2");
9092
if (status != VALKEY_OK) {
91-
printf("error: err=%d errstr=%s\n", cc->err, cc->errstr);
93+
printf("error: err=%d errstr=%s\n", acc->err, acc->errstr);
9294
}
9395

9496
printf("Dispatch..\n");
9597
event_base_dispatch(base);
9698

9799
printf("Done..\n");
98-
valkeyClusterAsyncFree(cc);
100+
valkeyClusterAsyncFree(acc);
99101
event_base_free(base);
100102
return 0;
101103
}

examples/cluster-clientside-caching-async.c

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,8 @@ void disconnectCallback(const valkeyAsyncContext *ac, int status) {
126126
/* Helper to modify keys using a separate client. */
127127
void modifyKey(const char *key, const char *value) {
128128
printf("Modify key: '%s'\n", key);
129-
valkeyClusterContext *cc = valkeyClusterContextInit();
130-
int status = valkeyClusterSetOptionAddNodes(cc, CLUSTER_NODE);
131-
assert(status == VALKEY_OK);
132-
status = valkeyClusterConnect2(cc);
133-
assert(status == VALKEY_OK);
129+
valkeyClusterContext *cc = valkeyClusterConnect(CLUSTER_NODE);
130+
assert(cc);
134131

135132
valkeyReply *reply = valkeyClusterCommand(cc, "SET %s %s", key, value);
136133
assert(reply != NULL);
@@ -142,24 +139,22 @@ void modifyKey(const char *key, const char *value) {
142139
int main(int argc, char **argv) {
143140
(void)argc;
144141
(void)argv;
145-
valkeyClusterAsyncContext *acc = valkeyClusterAsyncContextInit();
142+
struct event_base *base = event_base_new();
143+
144+
valkeyClusterOptions options = {0};
145+
options.initial_nodes = CLUSTER_NODE;
146+
options.async_connect_callback = connectCallback;
147+
options.async_disconnect_callback = disconnectCallback;
148+
valkeyClusterOptionsUseLibevent(&options, base);
149+
150+
valkeyClusterAsyncContext *acc = valkeyClusterAsyncContextInit(&options);
146151
assert(acc);
147152

148153
int status;
149-
status = valkeyClusterAsyncSetConnectCallback(acc, connectCallback);
150-
assert(status == VALKEY_OK);
151-
status = valkeyClusterAsyncSetDisconnectCallback(acc, disconnectCallback);
152-
assert(status == VALKEY_OK);
153-
status = valkeyClusterSetEventCallback(acc->cc, eventCallback, acc);
154-
assert(status == VALKEY_OK);
155-
status = valkeyClusterSetOptionAddNodes(acc->cc, CLUSTER_NODE);
156-
assert(status == VALKEY_OK);
157-
158-
struct event_base *base = event_base_new();
159-
status = valkeyClusterLibeventAttach(acc, base);
154+
status = valkeyClusterAsyncSetEventCallback(acc, eventCallback, acc);
160155
assert(status == VALKEY_OK);
161156

162-
status = valkeyClusterAsyncConnect2(acc);
157+
status = valkeyClusterAsyncConnect(acc);
163158
assert(status == VALKEY_OK);
164159

165160
event_base_dispatch(base);

examples/cluster-simple.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ int main(int argc, char **argv) {
88
UNUSED(argv);
99
struct timeval timeout = {1, 500000}; // 1.5s
1010

11-
valkeyClusterContext *cc = valkeyClusterContextInit();
12-
valkeyClusterSetOptionAddNodes(cc, "127.0.0.1:7000");
13-
valkeyClusterSetOptionConnectTimeout(cc, timeout);
14-
valkeyClusterSetOptionRouteUseSlots(cc);
15-
valkeyClusterConnect2(cc);
11+
valkeyClusterOptions options = {0};
12+
options.initial_nodes = "127.0.0.1:7000";
13+
options.connect_timeout = &timeout;
14+
15+
valkeyClusterContext *cc = valkeyClusterConnectWithOptions(&options);
1616
if (!cc) {
1717
printf("Error: Allocation failure\n");
1818
exit(-1);

0 commit comments

Comments
 (0)