Skip to content

Commit d29a057

Browse files
committed
Uses composition instead of inheritance in the connection class.
1 parent 82430af commit d29a057

File tree

3 files changed

+171
-124
lines changed

3 files changed

+171
-124
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.14)
22

3-
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
3+
#set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
44

55
project(
66
boost_redis

include/boost/redis/connection.hpp

Lines changed: 167 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#ifndef BOOST_REDIS_CONNECTION_HPP
88
#define BOOST_REDIS_CONNECTION_HPP
99

10-
#include <boost/redis/connection_base.hpp>
10+
#include <boost/redis/detail/connection_base.hpp>
1111
#include <boost/redis/logger.hpp>
1212
#include <boost/redis/config.hpp>
1313
#include <boost/asio/io_context.hpp>
@@ -34,7 +34,7 @@ struct reconnection_op {
3434
BOOST_ASIO_CORO_REENTER (coro_) for (;;)
3535
{
3636
BOOST_ASIO_CORO_YIELD
37-
conn_->async_run_one(conn_->cfg_, logger_, std::move(self));
37+
conn_->impl_.async_run(conn_->cfg_, logger_, std::move(self));
3838
conn_->cancel(operation::receive);
3939
logger_.on_connection_lost(ec);
4040
if (!conn_->will_reconnect() || is_cancelled(self)) {
@@ -68,14 +68,15 @@ struct reconnection_op {
6868
*
6969
*/
7070
template <class Executor>
71-
class basic_connection : public connection_base<Executor> {
71+
class basic_connection {
7272
public:
73-
using base_type = connection_base<Executor>;
74-
using this_type = basic_connection<Executor>;
75-
7673
/// Executor type.
7774
using executor_type = Executor;
7875

76+
/// Returns the underlying executor.
77+
executor_type get_executor() noexcept
78+
{ return impl_.get_executor(); }
79+
7980
/// Rebinds the socket type to another executor.
8081
template <class Executor1>
8182
struct rebind_executor
@@ -87,7 +88,7 @@ class basic_connection : public connection_base<Executor> {
8788
/// Contructs from an executor.
8889
explicit
8990
basic_connection(executor_type ex, asio::ssl::context::method method = asio::ssl::context::tls_client)
90-
: base_type{ex, method}
91+
: impl_{ex, method}
9192
, timer_{ex}
9293
{ }
9394

@@ -97,12 +98,28 @@ class basic_connection : public connection_base<Executor> {
9798
: basic_connection(ioc.get_executor(), method)
9899
{ }
99100

100-
/** @brief High-level connection to Redis.
101+
/** @brief Starts underlying connection operations.
102+
*
103+
* This member function provides the following functionality
104+
*
105+
* 1. Resolve the address passed on `boost::redis::config::addr`.
106+
* 2. Connect to one of the results obtained in the resolve operation.
107+
* 3. Send a [HELLO](https://redis.io/commands/hello/) command where each of its parameters are read from `cfg`.
108+
* 4. Start a health-check operation where ping commands are sent
109+
* at intervals specified in
110+
* `boost::redis::config::health_check_interval`. The message passed to
111+
* `PING` will be `boost::redis::config::health_check_id`. Passing a
112+
* timeout with value zero will disable health-checks. If the Redis
113+
* server does not respond to a health-check within two times the value
114+
* specified here, it will be considered unresponsive and the connection
115+
* will be closed and a new connection will be stablished.
116+
* 5. Starts read and write operations with the Redis
117+
* server. More specifically it will trigger the write of all
118+
* requests i.e. calls to `async_exec` that happened prior to this
119+
* call.
101120
*
102-
* This connection class adds reconnection functionality to
103-
* `boost::redis::connection_base::async_run_one`. When a
104-
* connection is lost for any reason, a new one is stablished
105-
* automatically. To disable reconnection call
121+
* When a connection is lost for any reason, a new one is
122+
* stablished automatically. To disable reconnection call
106123
* `boost::redis::connection::cancel(operation::reconnection)`.
107124
*
108125
* @param cfg Configuration paramters.
@@ -115,11 +132,6 @@ class basic_connection : public connection_base<Executor> {
115132
* void f(system::error_code);
116133
* @endcode
117134
*
118-
* @remarks
119-
*
120-
* * This function will complete only if reconnection was disabled
121-
* and the connection is lost.
122-
*
123135
* For example on how to call this function refer to
124136
* cpp20_intro.cpp or any other example.
125137
*/
@@ -132,6 +144,8 @@ class basic_connection : public connection_base<Executor> {
132144
Logger l = Logger{},
133145
CompletionToken token = CompletionToken{})
134146
{
147+
using this_type = basic_connection<executor_type>;
148+
135149
cfg_ = cfg;
136150
l.set_prefix(cfg_.log_prefix);
137151
return asio::async_compose
@@ -140,6 +154,77 @@ class basic_connection : public connection_base<Executor> {
140154
>(detail::reconnection_op<this_type, Logger>{this, l}, token, timer_);
141155
}
142156

157+
/** @brief Receives server side pushes asynchronously.
158+
*
159+
* When pushes arrive and there is no `async_receive` operation in
160+
* progress, pushed data, requests, and responses will be paused
161+
* until `async_receive` is called again. Apps will usually want
162+
* to call `async_receive` in a loop.
163+
*
164+
* To cancel an ongoing receive operation apps should call
165+
* `connection::cancel(operation::receive)`.
166+
*
167+
* @param response Response object.
168+
* @param token Completion token.
169+
*
170+
* For an example see cpp20_subscriber.cpp. The completion token must
171+
* have the following signature
172+
*
173+
* @code
174+
* void f(system::error_code, std::size_t);
175+
* @endcode
176+
*
177+
* Where the second parameter is the size of the push received in
178+
* bytes.
179+
*/
180+
template <
181+
class Response = ignore_t,
182+
class CompletionToken = asio::default_completion_token_t<executor_type>
183+
>
184+
auto
185+
async_receive(
186+
Response& response,
187+
CompletionToken token = CompletionToken{})
188+
{
189+
return impl_.async_receive(response, token);
190+
}
191+
192+
/** @brief Executes commands on the Redis server asynchronously.
193+
*
194+
* This function sends a request to the Redis server and waits for
195+
* the responses to each individual command in the request. If the
196+
* request contains only commands that don't expect a response,
197+
* the completion occurs after it has been written to the
198+
* underlying stream. Multiple concurrent calls to this function
199+
* will be automatically queued by the implementation.
200+
*
201+
* @param req Request.
202+
* @param resp Response.
203+
* @param token Completion token.
204+
*
205+
* For an example see cpp20_echo_server.cpp. The completion token must
206+
* have the following signature
207+
*
208+
* @code
209+
* void f(system::error_code, std::size_t);
210+
* @endcode
211+
*
212+
* Where the second parameter is the size of the response received
213+
* in bytes.
214+
*/
215+
template <
216+
class Response = ignore_t,
217+
class CompletionToken = asio::default_completion_token_t<executor_type>
218+
>
219+
auto
220+
async_exec(
221+
request const& req,
222+
Response& resp = ignore,
223+
CompletionToken token = CompletionToken{})
224+
{
225+
return impl_.async_exec(req, resp, token);
226+
}
227+
143228
/** @brief Cancel operations.
144229
*
145230
* @li `operation::exec`: Cancels operations started with
@@ -152,7 +237,7 @@ class basic_connection : public connection_base<Executor> {
152237
* @param op: The operation to be cancelled.
153238
* @returns The number of operations that have been canceled.
154239
*/
155-
void cancel(operation op = operation::all) override
240+
void cancel(operation op = operation::all)
156241
{
157242
switch (op) {
158243
case operation::reconnection:
@@ -163,16 +248,51 @@ class basic_connection : public connection_base<Executor> {
163248
default: /* ignore */;
164249
}
165250

166-
base_type::cancel(op);
251+
impl_.cancel(op);
167252
}
168253

169254
/// Returns true if the connection was canceled.
170255
bool will_reconnect() const noexcept
171256
{ return cfg_.reconnect_wait_interval != std::chrono::seconds::zero();}
172257

173-
private:
174-
config cfg_;
258+
/** @brief Reserve memory on the read and write internal buffers.
259+
*
260+
* This function will call `std::string::reserve` on the
261+
* underlying buffers.
262+
*
263+
* @param read The new capacity of the read buffer.
264+
* @param write The new capacity of the write buffer.
265+
*/
266+
void reserve(std::size_t read, std::size_t write)
267+
{
268+
impl_.reserve(read, write);
269+
}
270+
271+
/// Sets the maximum size of the read buffer.
272+
void set_max_buffer_read_size(std::size_t max_read_size) noexcept
273+
{ impl_.set_max_buffer_read_size(max_read_size); }
175274

275+
/// Returns the ssl context.
276+
auto const& get_ssl_context() const noexcept
277+
{ return impl_.get_ssl_context();}
278+
279+
/// Returns the ssl context.
280+
auto& get_ssl_context() noexcept
281+
{ return impl_.get_ssl_context();}
282+
283+
/// Resets the underlying stream.
284+
void reset_stream()
285+
{ impl_.reset_stream(); }
286+
287+
/// Returns a reference to the next layer.
288+
auto& next_layer() noexcept
289+
{ return impl_.next_layer(); }
290+
291+
/// Returns a const reference to the next layer.
292+
auto const& next_layer() const noexcept
293+
{ return impl_.next_layer(); }
294+
295+
private:
176296
using timer_type =
177297
asio::basic_waitable_timer<
178298
std::chrono::steady_clock,
@@ -181,11 +301,19 @@ class basic_connection : public connection_base<Executor> {
181301

182302
template <class, class> friend struct detail::reconnection_op;
183303

304+
config cfg_;
305+
detail::connection_base<executor_type> impl_;
184306
timer_type timer_;
185307
};
186308

187-
/** \brief A connection that uses the asio::any_io_executor.
309+
/** \brief A basic_connection that type erases the executor.
188310
* \ingroup high-level-api
311+
*
312+
* This connection type uses the asio::any_io_executor and
313+
* asio::any_completion_token to reduce compilation times.
314+
*
315+
* For documentaiton of each member function see
316+
* `boost::redis::basic_connection`.
189317
*/
190318
class connection {
191319
public:
@@ -198,8 +326,11 @@ class connection {
198326
/// Contructs from a context.
199327
explicit connection(asio::io_context& ioc, asio::ssl::context::method method = asio::ssl::context::tls_client);
200328

201-
executor_type get_executor() noexcept { return impl_.get_executor(); }
329+
/// Returns the underlying executor.
330+
executor_type get_executor() noexcept
331+
{ return impl_.get_executor(); }
202332

333+
/// Calls `boost::redis::basic_connection::async_run`.
203334
template <class CompletionToken>
204335
auto async_run(config const& cfg, logger l, CompletionToken token)
205336
{
@@ -211,31 +342,38 @@ class connection {
211342
}, token, this, &cfg, l);
212343
}
213344

345+
/// Calls `boost::redis::basic_connection::async_receive`.
214346
template <class Response, class CompletionToken>
215347
auto async_receive(Response& response, CompletionToken token)
216348
{
217349
return impl_.async_receive(response, std::move(token));
218350
}
219351

352+
/// Calls `boost::redis::basic_connection::async_exec`.
220353
template <class Response, class CompletionToken>
221354
auto async_exec(request const& req, Response& resp, CompletionToken token)
222355
{
223356
return impl_.async_exec(req, resp, std::move(token));
224357
}
225358

359+
/// Calls `boost::redis::basic_connection::cancel`.
226360
void cancel(operation op = operation::all);
227361

228-
/// Returns true if the connection was canceled.
362+
/// Calls `boost::redis::basic_connection::will_reconnect`.
229363
bool will_reconnect() const noexcept
230364
{ return impl_.will_reconnect();}
231365

232-
/// Returns a reference to the next layer.
233-
auto& next_layer() noexcept { return impl_.next_layer(); }
366+
/// Calls `boost::redis::basic_connection::next_layer`.
367+
auto& next_layer() noexcept
368+
{ return impl_.next_layer(); }
234369

235-
/// Returns a const reference to the next layer.
236-
auto const& next_layer() const noexcept { return impl_.next_layer(); }
370+
/// Calls `boost::redis::basic_connection::next_layer`.
371+
auto const& next_layer() const noexcept
372+
{ return impl_.next_layer(); }
237373

238-
void reset_stream() { impl_.reset_stream();}
374+
/// Calls `boost::redis::basic_connection::reset_stream`.
375+
void reset_stream()
376+
{ impl_.reset_stream();}
239377

240378
private:
241379
void

0 commit comments

Comments
 (0)