Skip to content

Commit 746fb62

Browse files
authored
Merge pull request #235 from boostorg/develop
Develop to master
2 parents 8df535f + ac4e6e2 commit 746fb62

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1749
-1788
lines changed

README.md

+72-62
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,39 @@ Boost.Redis is a high-level [Redis](https://redis.io/) client library built on t
44
[Boost.Asio](https://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
55
that implements the Redis protocol
66
[RESP3](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md).
7-
The requirements for using Boost.Redis are:
7+
The requirements for using Boost.Redis are
88

9-
* Boost. The library is included in Boost distributions starting with 1.84.
9+
* Boost 1.84 or higher.
1010
* C++17 or higher.
1111
* Redis 6 or higher (must support RESP3).
12-
* Gcc (11, 12), Clang (11, 13, 14) and Visual Studio (16 2019, 17 2022).
12+
* GCC (11, 12), Clang (11, 13, 14) and Visual Studio (16 2019, 17 2022).
1313
* Have basic-level knowledge about [Redis](https://redis.io/docs/)
1414
and [Boost.Asio](https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio/overview.html).
1515

16-
The latest release can be downloaded on
17-
https://github.com/boostorg/redis/releases. The library headers can be
18-
found in the `include` subdirectory and a compilation of the source
16+
To use the library it is necessary to include
1917

2018
```cpp
2119
#include <boost/redis/src.hpp>
2220
```
2321

24-
is required. The simplest way to do it is to included this header in
25-
no more than one source file in your applications. To build the
26-
examples and tests cmake is supported, for example
22+
in no more than one source file in your applications. To build the
23+
examples and tests with cmake run
2724

2825
```cpp
2926
# Linux
30-
$ BOOST_ROOT=/opt/boost_1_84_0 cmake --preset g++-11
27+
$ BOOST_ROOT=/opt/boost_1_84_0 cmake -S <source-dir> -B <binary-dir>
3128

3229
# Windows
3330
$ cmake -G "Visual Studio 17 2022" -A x64 -B bin64 -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
3431
```
3532

33+
For more details see https://github.com/boostorg/cmake.
34+
3635
<a name="connection"></a>
3736
## Connection
3837

39-
Let us start with a simple application that uses a short-lived
40-
connection to send a [ping](https://redis.io/commands/ping/) command
41-
to Redis
38+
The code below uses a short-lived connection to
39+
[ping](https://redis.io/commands/ping/) the Redis server
4240

4341
```cpp
4442
auto co_main(config const& cfg) -> net::awaitable<void>
@@ -50,11 +48,11 @@ auto co_main(config const& cfg) -> net::awaitable<void>
5048
request req;
5149
req.push("PING", "Hello world");
5250

53-
// Response where the PONG response will be stored.
51+
// Response object.
5452
response<std::string> resp;
5553

5654
// Executes the request.
57-
co_await conn->async_exec(req, resp, net::deferred);
55+
co_await conn->async_exec(req, resp);
5856
conn->cancel();
5957

6058
std::cout << "PING: " << std::get<0>(resp).value() << std::endl;
@@ -98,7 +96,7 @@ receiver(std::shared_ptr<connection> conn) -> net::awaitable<void>
9896
while (conn->will_reconnect()) {
9997
10098
// Reconnect to channels.
101-
co_await conn->async_exec(req, ignore, net::deferred);
99+
co_await conn->async_exec(req, ignore);
102100
103101
// Loop reading Redis pushes.
104102
for (;;) {
@@ -145,21 +143,18 @@ req.push_range("SUBSCRIBE", std::cbegin(list), std::cend(list));
145143
req.push_range("HSET", "key", map);
146144
```
147145
148-
Sending a request to Redis is performed with `boost::redis::connection::async_exec` as already stated.
149-
150-
### Config flags
151-
152-
The `boost::redis::request::config` object inside the request dictates how the
153-
`boost::redis::connection` should handle the request in some important situations. The
154-
reader is advised to read it carefully.
146+
Sending a request to Redis is performed with `boost::redis::connection::async_exec` as already stated. The
147+
`boost::redis::request::config` object inside the request dictates how
148+
the `boost::redis::connection` the request is handled in some
149+
situations. The reader is advised to read it carefully.
155150
156151
<a name="responses"></a>
157152
## Responses
158153
159-
Boost.Redis uses the following strategy to support Redis responses
154+
Boost.Redis uses the following strategy to deal with Redis responses
160155
161-
* `boost::redis::request` is used for requests whose number of commands are not dynamic.
162-
* **Dynamic**: Otherwise use `boost::redis::generic_response`.
156+
* `boost::redis::request` used for requests whose number of commands are not dynamic.
157+
* `boost::redis::generic_response` used when the size is dynamic.
163158
164159
For example, the request below has three commands
165160
@@ -170,8 +165,8 @@ req.push("INCR", "key");
170165
req.push("QUIT");
171166
```
172167

173-
and its response also has three comamnds and can be read in the
174-
following response object
168+
and therefore its response will also contain three elements which can
169+
be read in the following reponse object
175170

176171
```cpp
177172
response<std::string, int, std::string>
@@ -186,7 +181,7 @@ To ignore responses to individual commands in the request use the tag
186181

187182
```cpp
188183
// Ignore the second and last responses.
189-
response<std::string, boost::redis::ignore_t, std::string, boost::redis::ignore_t>
184+
response<std::string, ignore_t, std::string, ignore_t>
190185
```
191186

192187
The following table provides the resp3-types returned by some Redis
@@ -230,7 +225,7 @@ req.push("QUIT");
230225

231226
```
232227

233-
can be read in the tuple below
228+
can be read in the response object below
234229

235230
```cpp
236231
response<
@@ -243,17 +238,18 @@ response<
243238
> resp;
244239
```
245240

246-
Where both are passed to `async_exec` as showed elsewhere
241+
Then, to execute the request and read the response use `async_exec` as
242+
shown below
247243

248244
```cpp
249-
co_await conn->async_exec(req, resp, net::deferred);
245+
co_await conn->async_exec(req, resp);
250246
```
251247
252248
If the intention is to ignore responses altogether use `ignore`
253249
254250
```cpp
255251
// Ignores the response
256-
co_await conn->async_exec(req, ignore, net::deferred);
252+
co_await conn->async_exec(req, ignore);
257253
```
258254

259255
Responses that contain nested aggregates or heterogeneous data
@@ -279,27 +275,23 @@ req.push("SUBSCRIBE", "channel");
279275
req.push("QUIT");
280276
```
281277

282-
must be read in this tuple `response<std::string, std::string>`,
283-
that has static size two.
278+
must be read in the response object `response<std::string, std::string>`.
284279

285280
### Null
286281

287-
It is not uncommon for apps to access keys that do not exist or
288-
that have already expired in the Redis server, to deal with these
289-
cases Boost.Redis provides support for `std::optional`. To use it,
290-
wrap your type around `std::optional` like this
282+
It is not uncommon for apps to access keys that do not exist or that
283+
have already expired in the Redis server, to deal with these usecases
284+
wrap the type with an `std::optional` as shown below
291285

292286
```cpp
293287
response<
294288
std::optional<A>,
295289
std::optional<B>,
296290
...
297291
> resp;
298-
299-
co_await conn->async_exec(req, resp, net::deferred);
300292
```
301293

302-
Everything else stays pretty much the same.
294+
Everything else stays the same.
303295

304296
### Transactions
305297

@@ -321,22 +313,18 @@ use the following response type
321313
```cpp
322314
using boost::redis::ignore;
323315

324-
using exec_resp_type =
316+
317+
response<
318+
ignore_t, // multi
319+
ignore_t, // QUEUED
320+
ignore_t, // QUEUED
321+
ignore_t, // QUEUED
325322
response<
326323
std::optional<std::string>, // get
327324
std::optional<std::vector<std::string>>, // lrange
328325
std::optional<std::map<std::string, std::string>> // hgetall
329-
>;
330-
331-
response<
332-
boost::redis::ignore_t, // multi
333-
boost::redis::ignore_t, // get
334-
boost::redis::ignore_t, // lrange
335-
boost::redis::ignore_t, // hgetall
336-
exec_resp_type, // exec
326+
> // exec
337327
> resp;
338-
339-
co_await conn->async_exec(req, resp, net::deferred);
340328
```
341329

342330
For a complete example see cpp20_containers.cpp.
@@ -350,7 +338,7 @@ commands won't fit in the model presented above, some examples are
350338

351339
* Commands (like `set`) whose responses don't have a fixed
352340
RESP3 type. Expecting an `int` and receiving a blob-string
353-
will result in error.
341+
results in an error.
354342
* RESP3 aggregates that contain nested aggregates can't be read in STL containers.
355343
* Transactions with a dynamic number of commands can't be read in a `response`.
356344

@@ -384,7 +372,7 @@ using other types
384372
```cpp
385373
// Receives any RESP3 simple or aggregate data type.
386374
boost::redis::generic_response resp;
387-
co_await conn->async_exec(req, resp, net::deferred);
375+
co_await conn->async_exec(req, resp);
388376
```
389377

390378
For example, suppose we want to retrieve a hash data structure
@@ -411,7 +399,7 @@ the following customization points
411399
void boost_redis_to_bulk(std::string& to, mystruct const& obj);
412400

413401
// Deserialize
414-
void boost_redis_from_bulk(mystruct& obj, char const* p, std::size_t size, boost::system::error_code& ec)
402+
void boost_redis_from_bulk(mystruct& u, node_view const& node, boost::system::error_code&)
415403
```
416404
417405
These functions are accessed over ADL and therefore they must be
@@ -447,7 +435,7 @@ main motivations for choosing an echo server are
447435
448436
* Simple to implement and does not require expertise level in most languages.
449437
* I/O bound: Echo servers have very low CPU consumption in general
450-
and therefore are excelent to measure how a program handles concurrent requests.
438+
and therefore are excellent to measure how a program handles concurrent requests.
451439
* It simulates very well a typical backend in regard to concurrency.
452440
453441
I also imposed some constraints on the implementations
@@ -510,7 +498,7 @@ in the graph, the reasons are
510498
I don't know for sure why it is so slow, I suppose it has
511499
something to do with its lack of automatic
512500
[pipelining](https://redis.io/docs/manual/pipelining/) support.
513-
In fact, the more TCP connections I lauch the worse its
501+
In fact, the more TCP connections I launch the worse its
514502
performance gets.
515503
516504
* Libuv: I left it out because it would require me writing to much
@@ -676,6 +664,28 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
676664

677665
## Changelog
678666

667+
### Boost 1.88
668+
669+
* (Issue [233](https://github.com/boostorg/redis/issues/233))
670+
To deal with keys that might not exits in the Redis server, the
671+
library supports `std::optional`, for example
672+
`response<std::optional<std::vector<std::string>>>`. In some cases
673+
however, such as the [MGET](https://redis.io/docs/latest/commands/mget/) command,
674+
each element in the vector might be non exiting, now it is possible
675+
to specify a response as `response<std::optional<std::vector<std::optional<std::string>>>>`.
676+
677+
* (Issue [225](https://github.com/boostorg/redis/issues/225))
678+
Use `deferred` as the connection default completion token.
679+
680+
* (Issue [128](https://github.com/boostorg/redis/issues/128))
681+
Adds a new `async_exec` overload that allows passing response
682+
adapters. This makes it possible to receive Redis responses directly
683+
in custom data structures thereby avoiding uncessary data copying.
684+
Thanks to Ruben Perez (@anarthal) for implementing this feature.
685+
686+
* There are also other multiple small improvements in this release,
687+
users can refer to the git history for more details.
688+
679689
### Boost 1.87
680690

681691
* (Issue [205](https://github.com/boostorg/redis/issues/205))
@@ -721,11 +731,11 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
721731
makes it simpler to use the `requirepass` configuration in Redis.
722732

723733
* (Issue [189](https://github.com/boostorg/redis/issues/189)).
724-
Fixes narrowing convertion by using `std::size_t` instead of
734+
Fixes narrowing conversion by using `std::size_t` instead of
725735
`std::uint64_t` for the sizes of bulks and aggregates. The code
726736
relies now on `std::from_chars` returning an error if a value
727737
greater than 32 is received on platforms on which the size
728-
of`std::size_t` is 32.
738+
of `std::size_t` is 32.
729739

730740

731741
### Boost 1.84 (First release in Boost)
@@ -797,7 +807,7 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
797807
would wait for a response to arrive before sending the next one. Now requests
798808
are continuously coalesced and written to the socket. `request::coalesce`
799809
became unnecessary and was removed. I could measure significative performance
800-
gains with theses changes.
810+
gains with these changes.
801811

802812
* Improves serialization examples using Boost.Describe to serialize to JSON and protobuf. See
803813
cpp20_json.cpp and cpp20_protobuf.cpp for more details.
@@ -1004,7 +1014,7 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
10041014
* Fixes a bug in the `connection::async_run(host, port)` overload
10051015
that was causing crashes on reconnection.
10061016

1007-
* Fixes the executor usage in the connection class. Before theses
1017+
* Fixes the executor usage in the connection class. Before these
10081018
changes it was imposing `any_io_executor` on users.
10091019

10101020
* `connection::async_receiver_event` is not cancelled anymore when

example/cpp20_chat_room.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
#include <boost/redis/connection.hpp>
8-
#include <boost/asio/deferred.hpp>
98
#include <boost/asio/signal_set.hpp>
109
#include <boost/asio/co_spawn.hpp>
1110
#include <boost/asio/detached.hpp>
@@ -18,13 +17,12 @@
1817
#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
1918

2019
namespace asio = boost::asio;
21-
using stream_descriptor = asio::deferred_t::as_default_on_t<asio::posix::stream_descriptor>;
22-
using signal_set = asio::deferred_t::as_default_on_t<asio::signal_set>;
20+
using asio::posix::stream_descriptor;
21+
using asio::signal_set;
2322
using boost::asio::async_read_until;
2423
using boost::asio::awaitable;
2524
using boost::asio::co_spawn;
2625
using boost::asio::consign;
27-
using boost::asio::deferred;
2826
using boost::asio::detached;
2927
using boost::asio::dynamic_buffer;
3028
using boost::asio::redirect_error;
@@ -52,7 +50,7 @@ receiver(std::shared_ptr<connection> conn) -> awaitable<void>
5250
while (conn->will_reconnect()) {
5351

5452
// Subscribe to channels.
55-
co_await conn->async_exec(req, ignore, deferred);
53+
co_await conn->async_exec(req, ignore);
5654

5755
// Loop reading Redis push messages.
5856
for (error_code ec;;) {
@@ -76,7 +74,7 @@ auto publisher(std::shared_ptr<stream_descriptor> in, std::shared_ptr<connection
7674
auto n = co_await async_read_until(*in, dynamic_buffer(msg, 1024), "\n");
7775
request req;
7876
req.push("PUBLISH", "channel", msg);
79-
co_await conn->async_exec(req, ignore, deferred);
77+
co_await conn->async_exec(req, ignore);
8078
msg.erase(0, n);
8179
}
8280
}

0 commit comments

Comments
 (0)