Skip to content

Commit 5a47981

Browse files
committed
Introduce RDMA transport (experimental)
Valkey Over RDMA[1] has been supported as experimental feature since Valkey 8.0. Support RDMA transport for the client side. RDMA is not a builtin feature, supported as module only, so we have to run test.sh with more argument @VALKEY_RDMA_MODULE and @VALKEY_RDMA_ADDR. An example to run test.sh: VALKEY_RDMA_MODULE=/path/to/valkey-rdma.so VALKEY_RDMA_ADDR=192.168.122.1 TEST_RDMA=1 ./test.sh ... Testing against RDMA connection (192.168.122.1:56379): valkey-io#138 Is able to deliver commands: PASSED valkey-io#139 Is a able to send commands verbatim: PASSED valkey-io#140 %s String interpolation works: PASSED valkey-io#141 %b String interpolation works: PASSED valkey-io#142 Binary reply length is correct: PASSED valkey-io#143 Can parse nil replies: PASSED valkey-io#144 Can parse integer replies: PASSED valkey-io#145 Can parse multi bulk replies: PASSED valkey-io#146 Can handle nested multi bulk replies: PASSED valkey-io#147 Send command by passing argc/argv: PASSED valkey-io#148 Can pass NULL to valkeyGetReply: PASSED valkey-io#149 RESP3 PUSH messages are handled out of band by default: PASSED valkey-io#150 We can set a custom RESP3 PUSH handler: PASSED valkey-io#151 We properly handle a NIL invalidation payload: PASSED valkey-io#152 With no handler, PUSH replies come in-band: PASSED valkey-io#153 With no PUSH handler, no replies are lost: PASSED valkey-io#154 We set a default RESP3 handler for valkeyContext: PASSED valkey-io#155 We don't set a default RESP3 push handler for valkeyAsyncContext: PASSED valkey-io#156 Our VALKEY_OPT_NO_PUSH_AUTOFREE flag works: PASSED valkey-io#157 We can use valkeyOptions to set a custom PUSH handler for valkeyContext: PASSED valkey-io#158 We can use valkeyOptions to set a custom PUSH handler for valkeyAsyncContext: PASSED valkey-io#159 We can use valkeyOptions to set privdata: PASSED valkey-io#160 Our privdata destructor fires when we free the context: PASSED valkey-io#161 Successfully completes a command when the timeout is not exceeded: PASSED valkey-io#162 Does not return a reply when the command times out: SKIPPED valkey-io#163 Reconnect properly reconnects after a timeout: PASSED valkey-io#164 Reconnect properly uses owned parameters: PASSED valkey-io#165 Returns I/O error when the connection is lost: PASSED valkey-io#166 Returns I/O error on socket timeout: PASSED valkey-io#167 Set error when an invalid timeout usec value is used during connect: PASSED valkey-io#168 Set error when an invalid timeout sec value is used during connect: PASSED valkey-io#169 Append format command: PASSED valkey-io#170 Throughput: (1000x PING: 0.010s) (1000x LRANGE with 500 elements: 0.060s) (1000x INCRBY: 0.012s) (10000x PING (pipelined): 0.066s) (10000x LRANGE with 500 elements (pipelined): 0.523s) (10000x INCRBY (pipelined): 0.024s) ... Thanks to Michael Grunder for lots of review suggestions! Link[1]: valkey-io/valkey#477 Signed-off-by: zhenwei pi <[email protected]>
1 parent b526998 commit 5a47981

File tree

9 files changed

+1206
-10
lines changed

9 files changed

+1206
-10
lines changed

Makefile

Lines changed: 64 additions & 7 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
1616
TEST_BINS = $(patsubst $(TEST_DIR)/%.c,$(TEST_DIR)/%,$(TEST_SRCS))
1717

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

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

@@ -25,6 +25,7 @@ PKGCONFNAME=$(LIB_DIR)/valkey.pc
2525

2626
PKGCONF_TEMPLATE = valkey.pc.in
2727
SSL_PKGCONF_TEMPLATE = valkey_ssl.pc.in
28+
RDMA_PKGCONF_TEMPLATE = valkey_rdma.pc.in
2829

2930
LIBVALKEY_HEADER=$(INCLUDE_DIR)/valkey.h
3031
LIBVALKEY_VERSION=$(shell awk '/LIBVALKEY_(MAJOR|MINOR|PATCH|SONAME)/{print $$3}' $(LIBVALKEY_HEADER))
@@ -111,6 +112,38 @@ else
111112
endif
112113
##################### SSL variables end #####################
113114

115+
#################### RDMA variables start ####################
116+
RDMA_LIBNAME=libvalkey_rdma
117+
RDMA_PKGCONFNAME=$(LIB_DIR)/valkey_rdma.pc
118+
RDMA_INSTALLNAME=install-rdma
119+
RDMA_DYLIB_MINOR_NAME=$(RDMA_LIBNAME).$(DYLIBSUFFIX).$(LIBVALKEY_SONAME)
120+
RDMA_DYLIB_MAJOR_NAME=$(RDMA_LIBNAME).$(DYLIBSUFFIX).$(LIBVALKEY_MAJOR)
121+
RDMA_ROOT_DYLIB_NAME=$(RDMA_LIBNAME).$(DYLIBSUFFIX)
122+
RDMA_DYLIBNAME=$(LIB_DIR)/$(RDMA_LIBNAME).$(DYLIBSUFFIX)
123+
RDMA_STLIBNAME=$(LIB_DIR)/$(RDMA_LIBNAME).$(STLIBSUFFIX)
124+
RDMA_DYLIB_MAKE_CMD=$(CC) $(OPTIMIZATION) $(PLATFORM_FLAGS) -shared -Wl,-soname,$(RDMA_DYLIB_MINOR_NAME)
125+
126+
USE_RDMA?=0
127+
128+
ifeq ($(USE_RDMA),1)
129+
RDMA_SOURCES = $(wildcard $(SRC_DIR)/*rdma*.c)
130+
RDMA_OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(RDMA_SOURCES))
131+
132+
RDMA_LDFLAGS+=-lrdmacm -libverbs
133+
# This is required for test.c only
134+
CFLAGS+=-DVALKEY_TEST_RDMA
135+
RDMA_STLIB=$(RDMA_STLIBNAME)
136+
RDMA_DYLIB=$(RDMA_DYLIBNAME)
137+
RDMA_PKGCONF=$(RDMA_PKGCONFNAME)
138+
RDMA_INSTALL=$(RDMA_INSTALLNAME)
139+
else
140+
RDMA_STLIB=
141+
RDMA_DYLIB=
142+
RDMA_PKGCONF=
143+
RDMA_INSTALL=
144+
endif
145+
##################### RDMA variables end #####################
146+
114147
# Platform-specific overrides
115148
uname_S := $(shell uname -s 2>/dev/null || echo not)
116149

@@ -174,30 +207,36 @@ $(SSL_DYLIBNAME): $(SSL_OBJS)
174207
$(SSL_STLIBNAME): $(SSL_OBJS)
175208
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJS)
176209

210+
$(RDMA_DYLIBNAME): $(RDMA_OBJS)
211+
$(RDMA_DYLIB_MAKE_CMD) $(DYLIB_PLUGIN) -o $(RDMA_DYLIBNAME) $(RDMA_OBJS) $(REAL_LDFLAGS) $(LDFLAGS) $(RDMA_LDFLAGS)
212+
213+
$(RDMA_STLIBNAME): $(RDMA_OBJS)
214+
$(STLIB_MAKE_CMD) $(RDMA_STLIBNAME) $(RDMA_OBJS)
215+
177216
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
178217
$(CC) -std=c99 -pedantic $(REAL_CFLAGS) -I$(INCLUDE_DIR) -MMD -MP -c $< -o $@
179218

180219
$(OBJ_DIR)/%.o: $(TEST_DIR)/%.c | $(OBJ_DIR)
181220
$(CC) -std=c99 -pedantic $(REAL_CFLAGS) -I$(INCLUDE_DIR) -MMD -MP -c $< -o $@
182221

183222
$(TEST_DIR)/%: $(OBJ_DIR)/%.o $(STLIBNAME)
184-
$(CC) -o $@ $< $(STLIBNAME) $(SSL_STLIB) $(LDFLAGS) $(TEST_LDFLAGS)
223+
$(CC) -o $@ $< $(RDMA_STLIB) $(STLIBNAME) $(SSL_STLIB) $(LDFLAGS) $(TEST_LDFLAGS)
185224

186225
$(OBJ_DIR):
187226
mkdir -p $(OBJ_DIR)
188227

189228
$(LIB_DIR):
190229
mkdir -p $(LIB_DIR)
191230

192-
dynamic: $(DYLIBNAME) $(SSL_DYLIB)
231+
dynamic: $(DYLIBNAME) $(SSL_DYLIB) $(RDMA_DYLIB)
193232

194-
static: $(STLIBNAME) $(SSL_STLIB)
233+
static: $(STLIBNAME) $(SSL_STLIB) $(RDMA_STLIB)
195234

196-
pkgconfig: $(PKGCONFNAME) $(SSL_PKGCONF)
235+
pkgconfig: $(PKGCONFNAME) $(SSL_PKGCONF) $(RDMA_PKGCONF)
197236

198237
-include $(OBJS:.o=.d)
199238

200-
TEST_LDFLAGS = $(SSL_LDFLAGS)
239+
TEST_LDFLAGS = $(SSL_LDFLAGS) $(RDMA_LDFLAGS)
201240
ifeq ($(USE_SSL),1)
202241
TEST_LDFLAGS += -pthread
203242
endif
@@ -232,6 +271,14 @@ $(SSL_PKGCONFNAME): $(SSL_PKGCONF_TEMPLATE)
232271
-e 's|@PROJECT_VERSION@|$(LIBVALKEY_SONAME)|g' \
233272
$< > $@
234273

274+
$(RDMA_PKGCONFNAME): $(RDMA_PKGCONF_TEMPLATE)
275+
@echo "Generating $@ for pkgconfig..."
276+
sed \
277+
-e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|g' \
278+
-e 's|@CMAKE_INSTALL_LIBDIR@|$(INSTALL_LIBRARY_PATH)|g' \
279+
-e 's|@PROJECT_VERSION@|$(LIBVALKEY_SONAME)|g' \
280+
$< > $@
281+
235282
install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) $(SSL_INSTALL)
236283
mkdir -p $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
237284
$(INSTALL) $(HEADERS) $(INSTALL_INCLUDE_PATH)
@@ -253,6 +300,16 @@ install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
253300
mkdir -p $(INSTALL_PKGCONF_PATH)
254301
$(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
255302

303+
install-rdma: $(RDMA_DYLIBNAME) $(RDMA_STLIBNAME) $(RDMA_PKGCONFNAME)
304+
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
305+
$(INSTALL) $(INCLUDE_DIR)/valkey_rdma.h $(INSTALL_INCLUDE_PATH)
306+
$(INSTALL) $(RDMA_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(RDMA_DYLIB_MINOR_NAME)
307+
ln -sf $(RDMA_DYLIB_MINOR_NAME) $(INSTALL_LIBRARY_PATH)/$(RDMA_ROOT_DYLIB_NAME)
308+
ln -sf $(RDMA_DYLIB_MINOR_NAME) $(INSTALL_LIBRARY_PATH)/$(RDMA_DYLIB_MAJOR_NAME)
309+
$(INSTALL) $(RDMA_STLIBNAME) $(INSTALL_LIBRARY_PATH)
310+
mkdir -p $(INSTALL_PKGCONF_PATH)
311+
$(INSTALL) $(RDMA_PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
312+
256313
32bit:
257314
@echo ""
258315
@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"

include/valkey/valkey.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ enum valkeyConnectionType {
148148
VALKEY_CONN_TCP,
149149
VALKEY_CONN_UNIX,
150150
VALKEY_CONN_USERFD,
151+
VALKEY_CONN_RDMA, /* experimental, may be removed in any version */
151152

152153
VALKEY_CONN_MAX
153154
};

include/valkey/valkey_rdma.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
/*
3+
* Copyright (c) 2021-2024 zhenwei pi <[email protected]>
4+
*
5+
* Valkey Over RDMA has been supported as experimental feature since Valkey-8.0.
6+
* It's also supported as an experimental feature by libvalkey,
7+
* It may be removed or changed in any version.
8+
*
9+
* All rights reserved.
10+
*
11+
* Redistribution and use in source and binary forms, with or without
12+
* modification, are permitted provided that the following conditions are met:
13+
*
14+
* * Redistributions of source code must retain the above copyright notice,
15+
* this list of conditions and the following disclaimer.
16+
* * Redistributions in binary form must reproduce the above copyright
17+
* notice, this list of conditions and the following disclaimer in the
18+
* documentation and/or other materials provided with the distribution.
19+
* * Neither the name of the copyright holder nor the names of its
20+
* contributors may be used to endorse or promote products derived
21+
* from this software without specific prior written permission.
22+
*
23+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33+
* POSSIBILITY OF SUCH DAMAGE.
34+
*/
35+
36+
#ifndef VALKEY_RDMA_H
37+
#define VALKEY_RDMA_H
38+
39+
#ifdef __cplusplus
40+
extern "C" {
41+
#endif
42+
43+
/**
44+
* Helper macros to initialize options for RDMA.
45+
* It's ok to reuse TCP options.
46+
*/
47+
#define VALKEY_OPTIONS_SET_RDMA(opts, ip_, port_) do { \
48+
(opts)->type = VALKEY_CONN_RDMA; \
49+
(opts)->endpoint.tcp.ip = ip_; \
50+
(opts)->endpoint.tcp.port = port_; \
51+
} while(0)
52+
53+
54+
int valkeyInitiateRdma(void);
55+
56+
#ifdef __cplusplus
57+
}
58+
#endif
59+
60+
#endif /* VALKEY_RDMA_H */

0 commit comments

Comments
 (0)