1
1
# boost_redis
2
2
3
- Boost.Redis is a [ Redis] ( https://redis.io/ ) client library built on top of
3
+ Boost.Redis is a high-level [ Redis] ( https://redis.io/ ) client library built on top of
4
4
[ Boost.Asio] ( https://www.boost.org/doc/libs/release/doc/html/boost_asio.html )
5
5
that implements Redis plain text protocol
6
6
[ RESP3] ( https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md ) .
7
7
It can multiplex any number of client
8
8
requests, responses, and server pushes onto a single active socket
9
- connection to the Redis server. The library hides low-level code away
10
- from the user, which, in the majority of the cases will be concerned
11
- with only three library entities
12
-
13
- * ` boost::redis::connection ` : A full-duplex connection to the Redis
14
- server with high-level functions to execute Redis commands, receive
15
- server pushes and automatic command [ pipelines] ( https://redis.io/docs/manual/pipelining/ ) .
16
- * ` boost::redis::request ` : A container of Redis commands that supports
17
- STL containers and user defined data types.
18
- * ` boost::redis::response ` : Container of Redis responses.
19
-
20
- In the next sections we will cover all these points in detail with
21
- examples. The requirements for using Boost.Redis are
9
+ connection to the Redis server. The requirements for using Boost.Redis are
22
10
23
11
* Boost 1.81 or greater.
24
12
* C++17 minimum.
25
13
* Redis 6 or higher (must support RESP3).
26
14
* Gcc (10, 11, 12), Clang (11, 13, 14) and Visual Studio (16 2019, 17 2022).
27
- * Have basic-level knowledge about Redis and understand Asio and its asynchronous model.
15
+ * Have basic-level knowledge about [ Redis] ( https://redis.io/docs/ )
16
+ and [ Boost.Asio] ( https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio/overview.html ) .
28
17
29
- To install Boost.Redis download the latest release on
30
- https://github.com/boostorg/redis/releases . Boost.Redis is a header only
31
- library, so you can starting using it right away by adding the
32
- ` include ` subdirectory to your project and including
18
+ The latest release can be downloaded on
19
+ https://github.com/boostorg/redis/releases . The library headers can be
20
+ found in the ` include ` subdirectory and a compilation of the source
33
21
34
22
``` cpp
35
23
#include < boost/redis/src.hpp>
36
24
```
37
25
38
- in no more than one source file in your applications. To build the
26
+ is required. The simplest way to do it is to included this header in
27
+ no more than one source file in your applications. To build the
39
28
examples and tests cmake is supported, for example
40
29
41
30
``` cpp
@@ -45,21 +34,10 @@ $ BOOST_ROOT=/opt/boost_1_81_0 cmake --preset g++-11
45
34
# Windows
46
35
$ cmake -G " Visual Studio 17 2022" -A x64 -B bin64 -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
47
36
```
37
+
48
38
<a name =" connection " ></a >
49
39
## Connection
50
40
51
- Readers that are not familiar with Redis are advised to learn more about
52
- it on https://redis.io/docs/ before we start, in essence
53
-
54
- > Redis is an open source (BSD licensed), in-memory data structure
55
- > store used as a database, cache, message broker, and streaming
56
- > engine. Redis provides data structures such as strings, hashes,
57
- > lists, sets, sorted sets with range queries, bitmaps, hyperloglogs,
58
- > geospatial indexes, and streams. Redis has built-in replication, Lua
59
- > scripting, LRU eviction, transactions, and different levels of
60
- > on-disk persistence, and provides high availability via Redis
61
- > Sentinel and automatic partitioning with Redis Cluster.
62
-
63
41
Let us start with a simple application that uses a short-lived
64
42
connection to send a [ ping] ( https://redis.io/commands/ping/ ) command
65
43
to Redis
@@ -78,7 +56,7 @@ auto co_main(config const& cfg) -> net::awaitable<void>
78
56
response< std::string > resp;
79
57
80
58
// Executes the request.
81
- co_await conn->async_exec(req, resp);
59
+ co_await conn->async_exec(req, resp, net::deferred );
82
60
conn->cancel();
83
61
84
62
std::cout << "PING: " << std::get<0>(resp).value() << std::endl;
@@ -87,12 +65,12 @@ auto co_main(config const& cfg) -> net::awaitable<void>
87
65
88
66
The roles played by the `async_run` and `async_exec` functions are
89
67
90
- * `connection:: async_exec`: Execute the commands contained in the
68
+ * `async_exec`: Execute the commands contained in the
91
69
request and store the individual responses in the `resp` object. Can
92
70
be called from multiple places in your code concurrently.
93
- * `connection:: async_run`: Resolve, connect, ssl-handshake,
94
- resp3-handshake, health-checks reconnection and coordinate low-level
95
- read and write operations. .
71
+ * `async_run`: Resolve, connect, ssl-handshake,
72
+ resp3-handshake, health-checks, reconnection and coordinate low-level
73
+ read and write operations (among other things) .
96
74
97
75
### Server pushes
98
76
@@ -114,22 +92,22 @@ receiver(std::shared_ptr<connection> conn) -> net::awaitable<void>
114
92
request req;
115
93
req.push("SUBSCRIBE", "channel");
116
94
117
- while (!conn->is_cancelled()) {
95
+ // Loop while reconnection is enabled
96
+ while (conn->will_reconnect()) {
118
97
119
98
// Reconnect to channels.
120
- co_await conn->async_exec(req);
99
+ co_await conn->async_exec(req, ignore, net::deferred );
121
100
122
- // Loop reading Redis pushs messages .
101
+ // Loop reading Redis pushes .
123
102
for (generic_response resp;;) {
124
103
error_code ec;
125
104
co_await conn->async_receive(resp, net::redirect_error(net::use_awaitable, ec));
126
105
if (ec)
127
106
break; // Connection lost, break so we can reconnect to channels.
128
- std::cout
129
- << resp.value().at(1).value
130
- << " " << resp.value().at(2).value
131
- << " " << resp.value().at(3).value
132
- << std::endl;
107
+
108
+ // Use the response resp in some way and then clear it.
109
+ ...
110
+
133
111
resp.value().clear();
134
112
}
135
113
}
@@ -167,22 +145,21 @@ req.push_range("HSET", "key", map);
167
145
168
146
Sending a request to Redis is performed with `boost::redis::connection::async_exec` as already stated.
169
147
170
- <a name="responses"></a>
171
-
172
148
### Config flags
173
149
174
150
The `boost::redis::request::config` object inside the request dictates how the
175
151
`boost::redis::connection` should handle the request in some important situations. The
176
152
reader is advised to read it carefully.
177
153
154
+ <a name="responses"></a>
178
155
## Responses
179
156
180
157
Boost.Redis uses the following strategy to support Redis responses
181
158
182
- * **Static**: For `boost::redis::request` whose sizes are known at compile time use the `response` type .
159
+ * `boost::redis::request` is used for requests whose number of commands are not dynamic .
183
160
* **Dynamic**: Otherwise use `boost::redis::generic_response`.
184
161
185
- For example, below is a request with a compile time size
162
+ For example, the request below has three commands
186
163
187
164
```cpp
188
165
request req;
@@ -191,18 +168,19 @@ req.push("INCR", "key");
191
168
req.push("QUIT");
192
169
```
193
170
194
- To read the response to this request users can use the following tuple
171
+ and its response also has three comamnds and can be read in the
172
+ following response object
195
173
196
174
``` cpp
197
175
response<std::string, int , std::string>
198
176
```
199
177
200
- The pattern might have become apparent to the reader: the tuple must
178
+ The response behaves as a tuple and must
201
179
have as many elements as the request has commands (exceptions below).
202
180
It is also necessary that each tuple element is capable of storing the
203
181
response to the command it refers to, otherwise an error will occur.
204
182
To ignore responses to individual commands in the request use the tag
205
- ` boost::redis::ignore_t `
183
+ ` boost::redis::ignore_t ` , for example
206
184
207
185
``` cpp
208
186
// Ignore the second and last responses.
@@ -266,18 +244,14 @@ response<
266
244
Where both are passed to ` async_exec ` as showed elsewhere
267
245
268
246
``` cpp
269
- co_await conn->async_exec (req, resp);
247
+ co_await conn->async_exec (req, resp, net::deferred );
270
248
```
271
249
272
- If the intention is to ignore the response to all commands altogether
273
- use `ignore`
250
+ If the intention is to ignore responses altogether use `ignore`
274
251
275
252
```cpp
276
253
// Ignores the response
277
- co_await conn->async_exec(req, ignore);
278
-
279
- // The default response argument will also ignore responses.
280
- co_await conn->async_exec(req);
254
+ co_await conn->async_exec(req, ignore, net::deferred);
281
255
```
282
256
283
257
Responses that contain nested aggregates or heterogeneous data
@@ -294,7 +268,7 @@ Commands that have no response like
294
268
* ` "PSUBSCRIBE" `
295
269
* ` "UNSUBSCRIBE" `
296
270
297
- must be ** NOT** be included in the response tuple. For example, the request below
271
+ must ** NOT** be included in the response tuple. For example, the request below
298
272
299
273
``` cpp
300
274
request req;
@@ -304,7 +278,7 @@ req.push("QUIT");
304
278
```
305
279
306
280
must be read in this tuple ` response<std::string, std::string> ` ,
307
- that has size two.
281
+ that has static size two.
308
282
309
283
### Null
310
284
@@ -320,17 +294,17 @@ response<
320
294
...
321
295
> resp;
322
296
323
- co_await conn->async_exec (req, resp);
297
+ co_await conn->async_exec (req, resp, net::deferred );
324
298
```
325
299
326
300
Everything else stays pretty much the same.
327
301
328
302
### Transactions
329
303
330
- To read responses to transactions we must first observe that Redis will
331
- queue the transaction commands and send their individual responses as elements
332
- of an array, the array is itself the response to the `EXEC` command.
333
- For example, to read the response to this request
304
+ To read responses to transactions we must first observe that Redis
305
+ will queue the transaction commands and send their individual
306
+ responses as elements of an array, the array is itself the response to
307
+ the `EXEC` command. For example, to read the response to this request
334
308
335
309
```cpp
336
310
req.push("MULTI");
@@ -360,7 +334,7 @@ response<
360
334
exec_resp_type, // exec
361
335
> resp;
362
336
363
- co_await conn->async_exec (req, resp);
337
+ co_await conn->async_exec (req, resp, net::deferred );
364
338
```
365
339
366
340
For a complete example see cpp20_containers.cpp.
@@ -373,8 +347,8 @@ There are cases where responses to Redis
373
347
commands won't fit in the model presented above, some examples are
374
348
375
349
* Commands (like `set`) whose responses don't have a fixed
376
- RESP3 type. Expecting an `int` and receiving a blob-string
377
- will result in error.
350
+ RESP3 type. Expecting an `int` and receiving a blob-string
351
+ will result in error.
378
352
* RESP3 aggregates that contain nested aggregates can't be read in STL containers.
379
353
* Transactions with a dynamic number of commands can't be read in a `response`.
380
354
@@ -408,7 +382,7 @@ using other types
408
382
``` cpp
409
383
// Receives any RESP3 simple or aggregate data type.
410
384
boost::redis::generic_response resp;
411
- co_await conn->async_exec (req, resp);
385
+ co_await conn->async_exec (req, resp, net::deferred );
412
386
```
413
387
414
388
For example, suppose we want to retrieve a hash data structure
@@ -460,9 +434,8 @@ The examples below show how to use the features discussed so far
460
434
* cpp17_intro.cpp: Uses callbacks and requires C++17.
461
435
* cpp17_intro_sync.cpp: Runs ` async_run ` in a separate thread and performs synchronous calls to ` async_exec ` .
462
436
463
- To avoid repetition code that is common to some examples has been
464
- grouped in common.hpp. The main function used in some async examples
465
- has been factored out in the main.cpp file.
437
+ The main function used in some async examples has been factored out in
438
+ the main.cpp file.
466
439
467
440
## Echo server benchmark
468
441
@@ -701,7 +674,7 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
701
674
702
675
## Changelog
703
676
704
- ### master (incorporates changes to conform the boost review and more)
677
+ ### develop (incorporates changes to conform the boost review and more)
705
678
706
679
* Adds Redis stream example.
707
680
0 commit comments