mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Improves documentations of the connection class.
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,15 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## master
|
||||
## v1.0.0
|
||||
|
||||
* Adds experimental cmake support for windows users.
|
||||
|
||||
* Adds new class `sync` that wraps a `connection` and offers a
|
||||
thread-safe synchronous API. All free functions from the `sync.hpp`
|
||||
are now member functions of the `sync` class.
|
||||
* Adds new class `aedis::sync` that wraps an `aedis::connection` in
|
||||
a thread-safe and synchronous API. All free functions from the
|
||||
`sync.hpp` are now member functions of `aedis::sync`.
|
||||
|
||||
* Split `connection::async_receive_event` in two functions, one to
|
||||
receive events and another for server side pushes.
|
||||
* Split `aedis::connection::async_receive_event` in two functions, one
|
||||
to receive events and another for server side pushes, see
|
||||
`aedis::connection::async_receive_push`.
|
||||
|
||||
* Removes collision between `aedis::adapter::adapt` and
|
||||
`aedis::adapt`.
|
||||
|
||||
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(
|
||||
Aedis
|
||||
VERSION 0.3.0
|
||||
VERSION 1.0.0
|
||||
DESCRIPTION "An async redis client designed for performance and scalability"
|
||||
HOMEPAGE_URL "https://mzimbres.github.io/aedis"
|
||||
LANGUAGES CXX
|
||||
|
||||
@@ -14,3 +14,7 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
|
||||
|
||||
* See the official github-pages for documentation: https://mzimbres.github.io/aedis
|
||||
|
||||
### Installation
|
||||
|
||||
See https://mzimbres.github.io/aedis/#using-aedis
|
||||
|
||||
|
||||
@@ -85,9 +85,3 @@ The code used in the benchmarks can be found at
|
||||
## Running the benchmarks
|
||||
|
||||
Run one of the echo-server programs in one terminal and the [echo-server-client](https://github.com/mzimbres/aedis/blob/42880e788bec6020dd018194075a211ad9f339e8/benchmarks/cpp/asio/echo_server_client.cpp) in another.
|
||||
|
||||
## Contributing
|
||||
|
||||
If your spot any performance improvement in any of the example or
|
||||
would like to include other clients, please open a PR and I will
|
||||
gladly merge it.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([Aedis], [0.3.0], [mzimbres@gmail.com])
|
||||
AC_INIT([Aedis], [1.0.0], [mzimbres@gmail.com])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR(include/aedis.hpp)
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
Aedis is a high-level [Redis](https://redis.io/) client library
|
||||
built on top of
|
||||
[Asio](https://www.boost.org/doc/libs/release/doc/html/boost_asio.html),
|
||||
some of its distinctive features are
|
||||
[Asio](https://www.boost.org/doc/libs/release/doc/html/boost_asio.html).
|
||||
Some of its distinctive features are
|
||||
|
||||
\li Support for the latest version of the Redis communication protocol [RESP3](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md).
|
||||
\li First class support for STL containers and C++ built-in types.
|
||||
@@ -31,11 +31,11 @@
|
||||
\li Healthy checks, back pressure and low latency.
|
||||
\li Hides most of the low level asynchronous operations away from the user.
|
||||
|
||||
Let us start with an overview of asynchronous code.
|
||||
Let us have a look a some code snippets
|
||||
|
||||
@subsection Async
|
||||
|
||||
The code below sends a ping command to Redis (see intro.cpp)
|
||||
The code below sends a ping command to Redis and quits (see intro.cpp)
|
||||
|
||||
@code
|
||||
int main()
|
||||
@@ -56,9 +56,9 @@
|
||||
}
|
||||
@endcode
|
||||
|
||||
The connection class maintains a healthy connection with
|
||||
Redis over which users can execute their commands, without any
|
||||
need of queuing. For example, to execute more than one command
|
||||
The connection class maintains a healthy connection with Redis
|
||||
over which users can execute their commands, without any need of
|
||||
queuing. For example, to execute more than one request
|
||||
|
||||
@code
|
||||
int main()
|
||||
@@ -78,7 +78,7 @@
|
||||
}
|
||||
@endcode
|
||||
|
||||
The `async_exec` functions above can be called from different
|
||||
The `connection::async_exec` functions above can be called from different
|
||||
places in the code without knowing about each other, see for
|
||||
example echo_server.cpp. Server-side pushes are supported on the
|
||||
same connection where commands are executed, a typical subscriber
|
||||
@@ -88,55 +88,42 @@
|
||||
@code
|
||||
net::awaitable<void> reader(std::shared_ptr<connection> db)
|
||||
{
|
||||
request req;
|
||||
req.push("SUBSCRIBE", "channel");
|
||||
|
||||
for (std::vector<node_type> resp;;) {
|
||||
auto ev = co_await db->async_receive_event(aedis::adapt(resp));
|
||||
|
||||
switch (ev) {
|
||||
case connection::event::push:
|
||||
// Use resp and clear it.
|
||||
resp.clear();
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
co_await db->async_receive_event(adapt(resp));
|
||||
// Use resp and clear it.
|
||||
resp.clear();
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
|
||||
@subsection Sync
|
||||
|
||||
The `connection` class is async-only, many users however need to
|
||||
interact with it synchronously, this is also supported by Aedis as long
|
||||
as this interaction occurs across threads, for example (see
|
||||
intro_sync.cpp)
|
||||
The `connection` class offers only an asynchronous API.
|
||||
Synchronous communications with redis is provided by the `aedis::sync`
|
||||
wrapper class. (see intro_sync.cpp)
|
||||
|
||||
@code
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
net::io_context ioc{1};
|
||||
connection conn{ioc};
|
||||
|
||||
std::thread thread{[&]() {
|
||||
conn.async_run(net::detached);
|
||||
ioc.run();
|
||||
}};
|
||||
|
||||
request req;
|
||||
req.push("PING");
|
||||
req.push("QUIT");
|
||||
|
||||
std::tuple<std::string, aedis::ignore> resp;
|
||||
exec(conn, req, adapt(resp));
|
||||
thread.join();
|
||||
|
||||
std::cout << "Response: " << std::get<0>(resp) << std::endl;
|
||||
} catch (std::exception const& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
net::io_context ioc{1};
|
||||
auto work = net::make_work_guard(ioc);
|
||||
std::thread t1{[&]() { ioc.run(); }};
|
||||
|
||||
sync<connection> conn{work.get_executor()};
|
||||
std::thread t2{[&]() { boost::system::error_code ec; conn.run(ec); }};
|
||||
|
||||
request req;
|
||||
req.push("PING");
|
||||
req.push("QUIT");
|
||||
|
||||
std::tuple<std::string, aedis::ignore> resp;
|
||||
conn.exec(req, adapt(resp));
|
||||
std::cout << "Response: " << std::get<0>(resp) << std::endl;
|
||||
|
||||
work.reset();
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
@endcode
|
||||
|
||||
@@ -151,23 +138,27 @@
|
||||
For a simple installation run
|
||||
|
||||
```
|
||||
# Clone the repository and checkout the lastest release tag.
|
||||
$ git clone --branch v0.3.0 https://github.com/mzimbres/aedis.git
|
||||
$ git clone --branch v1.0.0 https://github.com/mzimbres/aedis.git
|
||||
$ cd aedis
|
||||
|
||||
# Build an example
|
||||
# Option 1: Direct compilation.
|
||||
$ g++ -std=c++17 -pthread examples/intro.cpp -I./include -I/path/boost_1_79_0/include/
|
||||
|
||||
# Option 2: Use cmake.
|
||||
$ BOOST_ROOT=/opt/boost_1_79_0/ cmake -DCMAKE_CXX_FLAGS=-std=c++20 .
|
||||
```
|
||||
|
||||
@note CMake support is still experimental.
|
||||
|
||||
For a proper full installation on the system run
|
||||
|
||||
```
|
||||
# Download and unpack the latest release
|
||||
$ wget https://github.com/mzimbres/aedis/releases/download/v0.3.0/aedis-0.3.0.tar.gz
|
||||
$ tar -xzvf aedis-0.3.0.tar.gz
|
||||
$ wget https://github.com/mzimbres/aedis/releases/download/v1.0.0/aedis-1.0.0.tar.gz
|
||||
$ tar -xzvf aedis-1.0.0.tar.gz
|
||||
|
||||
# Configure, build and install
|
||||
$ CXXFLAGS="-std=c++17" ./configure --prefix=/opt/aedis-0.3.0 --with-boost=/opt/boost_1_78_0
|
||||
$ CXXFLAGS="-std=c++17" ./configure --prefix=/opt/aedis-1.0.0 --with-boost=/opt/boost_1_78_0
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
@@ -177,12 +168,6 @@
|
||||
$ make
|
||||
```
|
||||
|
||||
There is also experimental support cmake, for example
|
||||
|
||||
@code
|
||||
$ BOOST_ROOT=/opt/boost_1_79_0/ cmake -DCMAKE_CXX_FLAGS=-std=c++20 .
|
||||
@endcode
|
||||
|
||||
@subsubsection using_aedis Using Aedis
|
||||
|
||||
When writing you own applications include the following header
|
||||
@@ -380,7 +365,7 @@
|
||||
|
||||
To read the response to transactions we have to observe that Redis
|
||||
queues the commands as they arrive and sends the responses back to
|
||||
the user in a single array, in the response to the @c exec command.
|
||||
the user as an array, in the response to the @c exec command.
|
||||
For example, to read the response to the this request
|
||||
|
||||
@code
|
||||
@@ -397,7 +382,7 @@
|
||||
using aedis::ignore;
|
||||
using boost::optional;
|
||||
|
||||
using tresp_type =
|
||||
using exec_resp_type =
|
||||
std::tuple<
|
||||
optional<std::string>, // get
|
||||
optional<std::vector<std::string>>, // lrange
|
||||
@@ -409,7 +394,7 @@
|
||||
ignore, // get
|
||||
ignore, // lrange
|
||||
ignore, // hgetall
|
||||
tresp_type, // exec
|
||||
exec_resp_type, // exec
|
||||
> resp;
|
||||
|
||||
co_await db->async_exec(req, adapt(resp));
|
||||
@@ -443,7 +428,7 @@
|
||||
There are cases where responses to Redis
|
||||
commands won't fit in the model presented above, some examples are
|
||||
|
||||
@li Commands (like \c set) whose response don't have a fixed
|
||||
@li Commands (like \c set) whose responses don't have a fixed
|
||||
RESP3 type. Expecting an \c int and receiving a blob-string
|
||||
will result in error.
|
||||
@li RESP3 aggregates that contain nested aggregates can't be read in STL containers.
|
||||
@@ -487,14 +472,14 @@
|
||||
@endcode
|
||||
|
||||
For example, suppose we want to retrieve a hash data structure
|
||||
from Redis with \c hgetall, some of the options are
|
||||
from Redis with `HGETALL`, some of the options are
|
||||
|
||||
@li \c std::vector<node<std::string>: Works always.
|
||||
@li \c std::vector<std::string>: Efficient and flat, all elements as string.
|
||||
@li \c std::map<std::string, std::string>: Efficient if you need the data as a \c std::map
|
||||
@li \c std::map<U, V>: Efficient if you are storing serialized data. Avoids temporaries and requires \c from_bulk for \c U and \c V.
|
||||
|
||||
In addition to the above users can also use unordered versions of the containers. The same reasoning also applies to sets e.g. \c smembers.
|
||||
In addition to the above users can also use unordered versions of the containers. The same reasoning also applies to sets e.g. `SMEMBERS`.
|
||||
|
||||
\section examples Examples
|
||||
|
||||
@@ -503,8 +488,8 @@
|
||||
@li intro.cpp: Basic steps with Aedis.
|
||||
@li intro_sync.cpp: Synchronous version of intro.cpp.
|
||||
@li containers.cpp: Shows how to send and receive stl containers.
|
||||
@li serialization.cpp: Shows the \c request support to serialization of user types.
|
||||
@li subscriber.cpp: Shows how to subscribe to a channel and how to reconnect when connection is lost.
|
||||
@li serialization.cpp: Shows how to serialize your own types.
|
||||
@li subscriber.cpp: Shows how to use pubsub.
|
||||
@li subscriber_sync.cpp: Synchronous version of subscriber.cpp.
|
||||
@li echo_server.cpp: A simple TCP echo server that uses coroutines.
|
||||
@li chat_room.cpp: A simple chat room that uses coroutines.
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace aedis {
|
||||
|
||||
/** @brief Tag used tp ignore responses.
|
||||
/** @brief Tag used to ignore responses.
|
||||
* @ingroup any
|
||||
*
|
||||
* For example
|
||||
|
||||
@@ -26,13 +26,20 @@
|
||||
|
||||
namespace aedis {
|
||||
|
||||
/** @brief A high level Redis asynchronous connection to Redis.
|
||||
/** @brief A high level connection to Redis.
|
||||
* @ingroup any
|
||||
*
|
||||
* This class keeps a healthy connection to the Redis instance where
|
||||
* commands can be sent at any time. For more details, please see the
|
||||
* documentation of each individual function.
|
||||
*
|
||||
* @remarks This class exposes only asynchronous member functions,
|
||||
* synchronous communications with the Redis server is provided by
|
||||
* the sync class.
|
||||
*
|
||||
* @tparam AsyncReadWriteStream A stream that supports
|
||||
* `async_read_some` and `async_write_some`.
|
||||
*
|
||||
*/
|
||||
template <class AsyncReadWriteStream = boost::asio::ip::tcp::socket>
|
||||
class connection {
|
||||
@@ -43,20 +50,13 @@ public:
|
||||
/// Type of the next layer
|
||||
using next_layer_type = AsyncReadWriteStream;
|
||||
|
||||
using default_completion_token_type = boost::asio::default_completion_token_t<executor_type>;
|
||||
using push_channel_type = boost::asio::experimental::channel<executor_type, void(boost::system::error_code, std::size_t)>;
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
using clock_traits_type = boost::asio::wait_traits<clock_type>;
|
||||
using timer_type = boost::asio::basic_waitable_timer<clock_type, clock_traits_type, executor_type>;
|
||||
using resolver_type = boost::asio::ip::basic_resolver<boost::asio::ip::tcp, executor_type>;
|
||||
|
||||
/** @brief Connection configuration parameters.
|
||||
*/
|
||||
struct config {
|
||||
/// The Redis server address.
|
||||
/// Redis server address.
|
||||
std::string host = "127.0.0.1";
|
||||
|
||||
/// The Redis server port.
|
||||
/// Redis server port.
|
||||
std::string port = "6379";
|
||||
|
||||
/// Username if authentication is required.
|
||||
@@ -71,30 +71,30 @@ public:
|
||||
/// Timeout of the connect operation.
|
||||
std::chrono::milliseconds connect_timeout = std::chrono::seconds{10};
|
||||
|
||||
/// Time interval ping operations.
|
||||
/// Time interval of ping operations.
|
||||
std::chrono::milliseconds ping_interval = std::chrono::seconds{1};
|
||||
|
||||
/// Time waited before trying a reconnection (see enable reconnect).
|
||||
/// Time waited before trying a reconnection (see config::enable_reconnect).
|
||||
std::chrono::milliseconds reconnect_interval = std::chrono::seconds{1};
|
||||
|
||||
/// The maximum size allowed on read operations.
|
||||
/// The maximum size of read operations.
|
||||
std::size_t max_read_size = (std::numeric_limits<std::size_t>::max)();
|
||||
|
||||
/// Whether to coalesce requests (see [pipelines](https://redis.io/topics/pipelining)).
|
||||
bool coalesce_requests = true;
|
||||
|
||||
/// Enable events
|
||||
/// Enable internal events, see connection::async_receive_event.
|
||||
bool enable_events = false;
|
||||
|
||||
/// Enable automatic reconnection (see also reconnect_interval).
|
||||
/// Enable automatic reconnection (see also config::reconnect_interval).
|
||||
bool enable_reconnect = false;
|
||||
};
|
||||
|
||||
/// Events communicated through \c async_receive_event.
|
||||
/// Events that are communicated by `connection::async_receive_event`.
|
||||
enum class event {
|
||||
/// The address has been successfully resolved.
|
||||
/// Resolve operation was successful.
|
||||
resolve,
|
||||
/// Connected to the Redis server.
|
||||
/// Connect operation was successful.
|
||||
connect,
|
||||
/// Success sending AUTH and HELLO.
|
||||
hello,
|
||||
@@ -102,24 +102,23 @@ public:
|
||||
invalid
|
||||
};
|
||||
|
||||
using event_channel_type = boost::asio::experimental::channel<executor_type, void(boost::system::error_code, event)>;
|
||||
|
||||
/** @brief Async operations that can be cancelled.
|
||||
/** @brief Async operations exposed by this class.
|
||||
*
|
||||
* See the \c cancel member function for more information.
|
||||
* The operations listed below can be cancelled with the `cancel`
|
||||
* member function.
|
||||
*/
|
||||
enum class operation {
|
||||
/// Operations started with \c async_exec.
|
||||
/// `connection::async_exec` operations.
|
||||
exec,
|
||||
/// Operation started with \c async_run.
|
||||
/// `connection::async_run` operations.
|
||||
run,
|
||||
/// Operation started with async_receive_event.
|
||||
/// `connection::async_receive_event` operations.
|
||||
receive_event,
|
||||
/// Operation started with async_receive_push.
|
||||
/// `connection::async_receive_push` operations.
|
||||
receive_push,
|
||||
};
|
||||
|
||||
/** \brief Construct a connection from an executor.
|
||||
/** \brief Contructor
|
||||
*
|
||||
* \param ex The executor.
|
||||
* \param cfg Configuration parameters.
|
||||
@@ -139,7 +138,7 @@ public:
|
||||
read_timer_.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
}
|
||||
|
||||
/** \brief Construct a connection from an io_context.
|
||||
/** \brief Constructor
|
||||
*
|
||||
* \param ioc The executor.
|
||||
* \param cfg Configuration parameters.
|
||||
@@ -153,15 +152,18 @@ public:
|
||||
|
||||
/** @brief Cancel operations.
|
||||
*
|
||||
* @li operation::exec: Cancels all operations started with \c async_exec.
|
||||
* @li operation::run: Cancels @c async_run. The prefered way to
|
||||
* close a connection is to set config::enable_reconnect to
|
||||
* false and send a \c quit command. Otherwise an unresponsive Redis server
|
||||
* will cause the idle-checks to kick in and lead to \c
|
||||
* async_run returning with idle_timeout. Calling \c
|
||||
* cancel(operation::run) directly should be seen as the last
|
||||
* option.
|
||||
* @li operation::receive_event: Cancels @c async_receive_event.
|
||||
* @li `operation::exec`: Cancels operations started with `async_exec`.
|
||||
*
|
||||
* @li operation::run: Cancels `async_run`. Notice that the
|
||||
* preferred way to close a connection is to ensure
|
||||
* `config::enable_reconnect` is set to `false` and send `QUIT`
|
||||
* to the server. An unresponsive Redis server will also cause
|
||||
* the idle-checks to kick in and lead to
|
||||
* `connection::async_run` completing with
|
||||
* `error::idle_timeout`. Calling `cancel(operation::run)`
|
||||
* directly should be seen as the last option.
|
||||
*
|
||||
* @li operation::receive_event: Cancels `connection::async_receive_event`.
|
||||
*
|
||||
* @param op: The operation to be cancelled.
|
||||
* @returns The number of operations that have been canceled.
|
||||
@@ -190,11 +192,11 @@ public:
|
||||
writer_timer_.cancel();
|
||||
ping_timer_.cancel();
|
||||
|
||||
// Cancel own pings if there are any waiting.
|
||||
auto point = std::stable_partition(std::begin(reqs_), std::end(reqs_), [](auto const& ptr) {
|
||||
return !ptr->req->close_on_run_completion;
|
||||
});
|
||||
|
||||
// Cancel own pings if there are any waiting.
|
||||
std::for_each(point, std::end(reqs_), [](auto const& ptr) {
|
||||
ptr->stop = true;
|
||||
ptr->timer.cancel();
|
||||
@@ -225,6 +227,8 @@ public:
|
||||
config const& get_config() const noexcept { return cfg_;}
|
||||
|
||||
/** @name Asynchronous functions
|
||||
*
|
||||
* Each of these operations a individually cancellable.
|
||||
**/
|
||||
|
||||
/// @{
|
||||
@@ -232,25 +236,28 @@ public:
|
||||
*
|
||||
* This function performs the following steps
|
||||
*
|
||||
* \li Resolves the Redis host as of \c async_resolve with the
|
||||
* timeout passed in connection::config::resolve_timeout.
|
||||
* @li Resolves the Redis host as of `async_resolve` with the
|
||||
* timeout passed in `config::resolve_timeout`.
|
||||
*
|
||||
* \li Connects to one of the endpoints returned by the resolve
|
||||
* operation with the timeout passed in connection::config::connect_timeout.
|
||||
* @li Connects to one of the endpoints returned by the resolve
|
||||
* operation with the timeout passed in `config::connect_timeout`.
|
||||
*
|
||||
* \li Starts the idle check operation with the timeout of twice
|
||||
* the value of connection::config::ping_interval. If no data is
|
||||
* received during that time interval \c async_run completes with
|
||||
* error::idle_timeout.
|
||||
* @li Starts healthy checks with a timeout twice
|
||||
* the value of `config::ping_interval`. If no data is
|
||||
* received during that time interval `connection::async_run` completes with
|
||||
* `error::idle_timeout`.
|
||||
*
|
||||
* \li Starts the healthy check operation that sends command::ping
|
||||
* to Redis with a frequency equal to
|
||||
* connection::config::ping_interval.
|
||||
* @li Starts the healthy check operation that sends `PING`s to
|
||||
* Redis with a frequency equal to `config::ping_interval`.
|
||||
*
|
||||
* \li Starts reading from the socket and delivering events to the
|
||||
* request started with \c async_exec and \c async_receive_event.
|
||||
* @li Starts reading from the socket and executes all requests
|
||||
* that have been started prior to this function call.
|
||||
*
|
||||
* For an example see echo_server.cpp.
|
||||
* @remark When a timeout occur and config::enable_reconnect is
|
||||
* set, this function will automatically try a reconnection
|
||||
* without returning control to the user.
|
||||
*
|
||||
* For an example see echo_server.cpp.
|
||||
*
|
||||
* \param token Completion token.
|
||||
*
|
||||
@@ -259,10 +266,8 @@ public:
|
||||
* @code
|
||||
* void f(boost::system::error_code);
|
||||
* @endcode
|
||||
*
|
||||
* \return This function returns only when there is an error.
|
||||
*/
|
||||
template <class CompletionToken = default_completion_token_type>
|
||||
template <class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
|
||||
auto async_run(CompletionToken token = CompletionToken{})
|
||||
{
|
||||
return boost::asio::async_compose
|
||||
@@ -273,7 +278,7 @@ public:
|
||||
|
||||
/** @brief Connects and executes a request asynchronously.
|
||||
*
|
||||
* Combines \c async_run and the other \c async_exec overload in a
|
||||
* Combines the other `async_run` overload with `async_exec` in a
|
||||
* single function. This function is useful for users that want to
|
||||
* send a single request to the server and close it.
|
||||
*
|
||||
@@ -281,7 +286,8 @@ public:
|
||||
* \param adapter Response adapter.
|
||||
* \param token Asio completion token.
|
||||
*
|
||||
* For an example see intro.cpp. The completion token must have the following signature
|
||||
* For an example see intro.cpp. The completion token must have
|
||||
* the following signature
|
||||
*
|
||||
* @code
|
||||
* void f(boost::system::error_code, std::size_t);
|
||||
@@ -291,7 +297,7 @@ public:
|
||||
*/
|
||||
template <
|
||||
class Adapter = detail::response_traits<void>::adapter_type,
|
||||
class CompletionToken = default_completion_token_type>
|
||||
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
|
||||
auto async_run(
|
||||
resp3::request const& req,
|
||||
Adapter adapter = adapt(),
|
||||
@@ -305,6 +311,9 @@ public:
|
||||
}
|
||||
|
||||
/** @brief Executes a command on the redis server asynchronously.
|
||||
*
|
||||
* There is no need to synchronize multiple calls to this
|
||||
* function as it keeps an internal queue.
|
||||
*
|
||||
* \param req Request object.
|
||||
* \param adapter Response adapter.
|
||||
@@ -322,7 +331,7 @@ public:
|
||||
*/
|
||||
template <
|
||||
class Adapter = detail::response_traits<void>::adapter_type,
|
||||
class CompletionToken = default_completion_token_type>
|
||||
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
|
||||
auto async_exec(
|
||||
resp3::request const& req,
|
||||
Adapter adapter = adapt(),
|
||||
@@ -336,11 +345,11 @@ public:
|
||||
>(detail::exec_op<connection, Adapter>{this, &req, adapter}, token, resv_);
|
||||
}
|
||||
|
||||
/** @brief Receives unsolicited events asynchronously.
|
||||
/** @brief Receives server side pushes asynchronously.
|
||||
*
|
||||
* Users that expect unsolicited events should call this function
|
||||
* in a loop. If an unsolicited events comes in and there is no
|
||||
* reader, the connection will hang and eventually timeout.
|
||||
* Users that expect server pushes have to call this function in a
|
||||
* loop. If an unsolicited event comes in and there is no reader,
|
||||
* the connection will hang and eventually timeout.
|
||||
*
|
||||
* \param adapter The response adapter.
|
||||
* \param token The Asio completion token.
|
||||
@@ -351,10 +360,13 @@ public:
|
||||
* @code
|
||||
* void f(boost::system::error_code, std::size_t);
|
||||
* @endcode
|
||||
*
|
||||
* Where the second parameter is the size of the push in
|
||||
* bytes.
|
||||
*/
|
||||
template <
|
||||
class Adapter = detail::response_traits<void>::adapter_type,
|
||||
class CompletionToken = default_completion_token_type>
|
||||
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
|
||||
auto async_receive_push(
|
||||
Adapter adapter = adapt(),
|
||||
CompletionToken token = CompletionToken{})
|
||||
@@ -374,7 +386,7 @@ public:
|
||||
|
||||
/** @brief Receives internal events.
|
||||
*
|
||||
* See enum \c events for a list of events.
|
||||
* See enum \c events for the list of events.
|
||||
*
|
||||
* \param token The Asio completion token.
|
||||
*
|
||||
@@ -384,7 +396,7 @@ public:
|
||||
* void f(boost::system::error_code, event);
|
||||
* @endcode
|
||||
*/
|
||||
template <class CompletionToken = default_completion_token_type>
|
||||
template <class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
|
||||
auto async_receive_event(CompletionToken token = CompletionToken{})
|
||||
{
|
||||
return event_channel_.async_receive(token);
|
||||
@@ -392,6 +404,14 @@ public:
|
||||
/// @}
|
||||
|
||||
private:
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
using clock_traits_type = boost::asio::wait_traits<clock_type>;
|
||||
using timer_type = boost::asio::basic_waitable_timer<clock_type, clock_traits_type, executor_type>;
|
||||
using resolver_type = boost::asio::ip::basic_resolver<boost::asio::ip::tcp, executor_type>;
|
||||
using push_channel_type = boost::asio::experimental::channel<executor_type, void(boost::system::error_code, std::size_t)>;
|
||||
using time_point_type = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
using event_channel_type = boost::asio::experimental::channel<executor_type, void(boost::system::error_code, event)>;
|
||||
|
||||
struct req_info {
|
||||
req_info(executor_type ex) : timer{ex} {}
|
||||
timer_type timer;
|
||||
@@ -401,7 +421,6 @@ private:
|
||||
bool written = false;
|
||||
};
|
||||
|
||||
using time_point_type = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
using reqs_type = std::deque<std::shared_ptr<req_info>>;
|
||||
|
||||
template <class T, class U> friend struct detail::receive_push_op;
|
||||
@@ -419,7 +438,7 @@ private:
|
||||
template <class T> friend struct detail::start_op;
|
||||
template <class T> friend struct detail::send_receive_op;
|
||||
|
||||
template <class CompletionToken = default_completion_token_type>
|
||||
template <class CompletionToken>
|
||||
auto async_run_one(CompletionToken token = CompletionToken{})
|
||||
{
|
||||
return boost::asio::async_compose
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
|
||||
/** @brief Executes a request synchronously.
|
||||
*
|
||||
* The functions calls `connections::async_receive_exec` and waits
|
||||
* The functions calls `connection::async_exec` and waits
|
||||
* for its completion.
|
||||
*
|
||||
* @param req The request.
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
|
||||
/** @brief Executes a command synchronously
|
||||
*
|
||||
* The functions calls `connections::async_exec` and waits for its
|
||||
* The functions calls `connection::async_exec` and waits for its
|
||||
* completion.
|
||||
*
|
||||
* @param req The request.
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
|
||||
/** @brief Receives server pushes synchronusly.
|
||||
*
|
||||
* The functions calls `connections::async_receive_push` and
|
||||
* The functions calls `connection::async_receive_push` and
|
||||
* waits for its completion.
|
||||
*
|
||||
* @param adapter The response adapter.
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
|
||||
/** @brief Receives server pushes synchronusly.
|
||||
*
|
||||
* The functions calls `connections::async_receive_push` and
|
||||
* The functions calls `connection::async_receive_push` and
|
||||
* waits for its completion.
|
||||
*
|
||||
* @param adapter The response adapter.
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
|
||||
/** @brief Receives events synchronously.
|
||||
*
|
||||
* The functions calls `connections::async_receive_event` and
|
||||
* The functions calls `connection::async_receive_event` and
|
||||
* waits for its completion.
|
||||
*
|
||||
* @param ec Error code in case of error.
|
||||
@@ -174,7 +174,7 @@ public:
|
||||
|
||||
/** @brief Receives events synchronously
|
||||
*
|
||||
* The functions calls `connections::async_receive_event` and
|
||||
* The functions calls `connection::async_receive_event` and
|
||||
* waits for its completion.
|
||||
*
|
||||
* @throws std::system_error in case of error.
|
||||
@@ -191,7 +191,7 @@ public:
|
||||
|
||||
/** @brief Calls \c async_run from the underlying connection.
|
||||
*
|
||||
* The functions calls `connections::async_run` and waits for its
|
||||
* The functions calls `connection::async_run` and waits for its
|
||||
* completion.
|
||||
*
|
||||
* @param ec Error code.
|
||||
@@ -217,7 +217,7 @@ public:
|
||||
|
||||
/** @brief Calls \c async_run from the underlying connection.
|
||||
*
|
||||
* The functions calls `connections::async_run` and waits for its
|
||||
* The functions calls `connection::async_run` and waits for its
|
||||
* completion.
|
||||
*
|
||||
* @throws std::system_error.
|
||||
|
||||
Reference in New Issue
Block a user