Skip to content

Commit 61f9a29

Browse files
committed
Makes connection_base a private base.
1 parent dc9b333 commit 61f9a29

File tree

5 files changed

+178
-100
lines changed

5 files changed

+178
-100
lines changed

include/aedis/connection.hpp

+103-7
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace aedis {
3131
*/
3232
template <class AsyncReadWriteStream = boost::asio::ip::tcp::socket>
3333
class connection :
34-
public connection_base<
34+
private connection_base<
3535
typename AsyncReadWriteStream::executor_type,
3636
connection<AsyncReadWriteStream>> {
3737
public:
@@ -40,6 +40,10 @@ class connection :
4040

4141
/// Type of the next layer
4242
using next_layer_type = AsyncReadWriteStream;
43+
using base_type = connection_base<executor_type, connection<AsyncReadWriteStream>>;
44+
45+
/// List of operations that can be canceled.
46+
using operation = typename base_type::operation;
4347

4448
/** @brief Connection configuration parameters.
4549
*/
@@ -67,6 +71,9 @@ class connection :
6771
: connection(ioc.get_executor())
6872
{ }
6973

74+
/// Returns the associated executor.
75+
auto get_executor() {return stream_.get_executor();}
76+
7077
/// Resets the underlying stream.
7178
void reset_stream()
7279
{
@@ -174,28 +181,117 @@ class connection :
174181
return base_type::async_run(ep, req, adapter, ts, std::move(token));
175182
}
176183

184+
/** @brief Executes a command on the Redis server asynchronously.
185+
*
186+
* This function will send a request to the Redis server and
187+
* complete when the response arrives. If the request contains
188+
* only commands that don't expect a response, the completion
189+
* occurs after it has been written to the underlying stream.
190+
* Multiple concurrent calls to this function will be
191+
* automatically queued by the implementation.
192+
*
193+
* @param req Request object.
194+
* @param adapter Response adapter.
195+
* @param token Asio completion token.
196+
*
197+
* For an example see echo_server.cpp. The completion token must
198+
* have the following signature
199+
*
200+
* @code
201+
* void f(boost::system::error_code, std::size_t);
202+
* @endcode
203+
*
204+
* Where the second parameter is the size of the response in
205+
* bytes.
206+
*/
207+
template <
208+
class Adapter = detail::response_traits<void>::adapter_type,
209+
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
210+
auto async_exec(
211+
resp3::request const& req,
212+
Adapter adapter = adapt(),
213+
CompletionToken token = CompletionToken{})
214+
{
215+
return base_type::async_exec(req, adapter, std::move(token));
216+
}
217+
218+
/** @brief Receives server side pushes asynchronously.
219+
*
220+
* Users that expect server pushes should call this function in a
221+
* loop. If a push arrives and there is no reader, the connection
222+
* will hang and eventually timeout.
223+
*
224+
* @param adapter The response adapter.
225+
* @param token The Asio completion token.
226+
*
227+
* For an example see subscriber.cpp. The completion token must
228+
* have the following signature
229+
*
230+
* @code
231+
* void f(boost::system::error_code, std::size_t);
232+
* @endcode
233+
*
234+
* Where the second parameter is the size of the push in
235+
* bytes.
236+
*/
237+
template <
238+
class Adapter = detail::response_traits<void>::adapter_type,
239+
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
240+
auto async_receive_push(
241+
Adapter adapter = adapt(),
242+
CompletionToken token = CompletionToken{})
243+
{
244+
return base_type::async_receive_push(adapter, std::move(token));
245+
}
246+
247+
/** @brief Cancel operations.
248+
*
249+
* @li `operation::exec`: Cancels operations started with
250+
* `async_exec`. Has precedence over
251+
* `request::config::close_on_connection_lost`
252+
* @li operation::run: Cancels the `async_run` operation. Notice
253+
* that the preferred way to close a connection is to send a
254+
* [QUIT](https://redis.io/commands/quit/) command to the server.
255+
* An unresponsive Redis server will also cause the idle-checks to
256+
* timeout and lead to `connection::async_run` completing with
257+
* `error::idle_timeout`. Calling `cancel(operation::run)`
258+
* directly should be seen as the last option.
259+
* @li operation::receive_push: Cancels any ongoing callto
260+
* `async_receive_push`.
261+
*
262+
* @param op: The operation to be cancelled.
263+
* @returns The number of operations that have been canceled.
264+
*/
265+
auto cancel(operation op) -> std::size_t
266+
{ return base_type::cancel(op); }
267+
177268
private:
178-
using base_type = connection_base<executor_type, connection<AsyncReadWriteStream>>;
179269
using this_type = connection<next_layer_type>;
180270

181271
template <class, class> friend class connection_base;
182272
template <class, class> friend struct detail::exec_read_op;
183273
template <class, class> friend struct detail::exec_op;
184274
template <class, class> friend struct detail::receive_push_op;
185-
template <class> friend struct detail::ping_op;
186275
template <class> friend struct detail::check_idle_op;
187276
template <class> friend struct detail::reader_op;
188277
template <class> friend struct detail::writer_op;
189-
template <class> friend struct detail::connect_with_timeout_op;
278+
template <class, class> friend struct detail::connect_with_timeout_op;
190279
template <class> friend struct detail::run_op;
280+
template <class> friend struct aedis::detail::ping_op;
191281

192-
template <class CompletionToken>
193-
auto async_connect(timeouts ts, CompletionToken&& token)
282+
template <class Timer, class CompletionToken>
283+
auto
284+
async_connect(
285+
boost::asio::ip::tcp::resolver::results_type const& endpoints,
286+
timeouts ts,
287+
Timer& timer,
288+
CompletionToken&& token)
194289
{
195290
return boost::asio::async_compose
196291
< CompletionToken
197292
, void(boost::system::error_code)
198-
>(detail::connect_with_timeout_op<this_type>{this, ts}, token, stream_);
293+
>(detail::connect_with_timeout_op<this_type, Timer>{this, &endpoints, ts, &timer},
294+
token, stream_);
199295
}
200296

201297
void close() { stream_.close(); }

include/aedis/connection_base.hpp

+7-77
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727

2828
namespace aedis {
2929

30-
/** @brief Base class for high level Redis asynchronous connections.
31-
* @ingroup any
30+
/** Base class for high level Redis asynchronous connections.
3231
*
3332
* This class is not meant to be instantiated directly but as base
3433
* class in the CRTP.
@@ -40,8 +39,8 @@ namespace aedis {
4039
template <class Executor, class Derived>
4140
class connection_base {
4241
public:
43-
/// Executor type.
4442
using executor_type = Executor;
43+
using this_type = connection_base<Executor, Derived>;
4544

4645
/** @brief List of async operations exposed by this class.
4746
*
@@ -57,10 +56,6 @@ class connection_base {
5756
receive_push,
5857
};
5958

60-
/** @brief Constructor
61-
*
62-
* @param ex The executor.
63-
*/
6459
explicit connection_base(executor_type ex)
6560
: resv_{ex}
6661
, ping_timer_{ex}
@@ -75,27 +70,8 @@ class connection_base {
7570
read_timer_.expires_at(std::chrono::steady_clock::time_point::max());
7671
}
7772

78-
/// Returns the executor.
7973
auto get_executor() {return resv_.get_executor();}
8074

81-
/** @brief Cancel operations.
82-
*
83-
* @li `operation::exec`: Cancels operations started with
84-
* `async_exec`. Has precedence over
85-
* `request::config::close_on_connection_lost`
86-
* @li operation::run: Cancels the `async_run` operation. Notice
87-
* that the preferred way to close a connection is to send a
88-
* [QUIT](https://redis.io/commands/quit/) command to the server.
89-
* An unresponsive Redis server will also cause the idle-checks to
90-
* timeout and lead to `connection::async_run` completing with
91-
* `error::idle_timeout`. Calling `cancel(operation::run)`
92-
* directly should be seen as the last option.
93-
* @li operation::receive_push: Cancels any ongoing callto
94-
* `async_receive_push`.
95-
*
96-
* @param op: The operation to be cancelled.
97-
* @returns The number of operations that have been canceled.
98-
*/
9975
auto cancel(operation op) -> std::size_t
10076
{
10177
switch (op) {
@@ -142,29 +118,6 @@ class connection_base {
142118
}
143119
}
144120

145-
/** @brief Executes a command on the Redis server asynchronously.
146-
*
147-
* This function will send a request to the Redis server and
148-
* complete when the response arrives. If the request contains
149-
* only commands that don't expect a response, the completion
150-
* occurs after it has been written to the underlying stream.
151-
* Multiple concurrent calls to this function will be
152-
* automatically queued by the implementation.
153-
*
154-
* @param req Request object.
155-
* @param adapter Response adapter.
156-
* @param token Asio completion token.
157-
*
158-
* For an example see echo_server.cpp. The completion token must
159-
* have the following signature
160-
*
161-
* @code
162-
* void f(boost::system::error_code, std::size_t);
163-
* @endcode
164-
*
165-
* Where the second parameter is the size of the response in
166-
* bytes.
167-
*/
168121
template <
169122
class Adapter = detail::response_traits<void>::adapter_type,
170123
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
@@ -181,25 +134,6 @@ class connection_base {
181134
>(detail::exec_op<Derived, Adapter>{&derived(), &req, adapter}, token, resv_);
182135
}
183136

184-
/** @brief Receives server side pushes asynchronously.
185-
*
186-
* Users that expect server pushes should call this function in a
187-
* loop. If a push arrives and there is no reader, the connection
188-
* will hang and eventually timeout.
189-
*
190-
* @param adapter The response adapter.
191-
* @param token The Asio completion token.
192-
*
193-
* For an example see subscriber.cpp. The completion token must
194-
* have the following signature
195-
*
196-
* @code
197-
* void f(boost::system::error_code, std::size_t);
198-
* @endcode
199-
*
200-
* Where the second parameter is the size of the push in
201-
* bytes.
202-
*/
203137
template <
204138
class Adapter = detail::response_traits<void>::adapter_type,
205139
class CompletionToken = boost::asio::default_completion_token_t<executor_type>>
@@ -214,7 +148,6 @@ class connection_base {
214148
>(detail::receive_push_op<Derived, decltype(f)>{&derived(), f}, token, resv_);
215149
}
216150

217-
protected:
218151
template <class Timeouts, class CompletionToken>
219152
auto
220153
async_run(endpoint ep, Timeouts ts, CompletionToken token)
@@ -307,7 +240,7 @@ class connection_base {
307240
return boost::asio::async_compose
308241
< CompletionToken
309242
, void(boost::system::error_code)
310-
>(detail::resolve_with_timeout_op<Derived>{&derived(), d},
243+
>(detail::resolve_with_timeout_op<this_type>{this, d},
311244
token, resv_);
312245
}
313246

@@ -337,7 +270,7 @@ class connection_base {
337270
return boost::asio::async_compose
338271
< CompletionToken
339272
, void(boost::system::error_code)
340-
>(detail::start_op<Derived, Timeouts>{&derived(), ts}, token, resv_);
273+
>(detail::start_op<this_type, Timeouts>{this, ts}, token, resv_);
341274
}
342275

343276
template <class CompletionToken>
@@ -428,13 +361,7 @@ class connection_base {
428361

429362
// IO objects
430363
resolver_type resv_;
431-
protected:
432364
timer_type ping_timer_;
433-
endpoint ep_;
434-
// The result of async_resolve.
435-
boost::asio::ip::tcp::resolver::results_type endpoints_;
436-
437-
private:
438365
timer_type check_idle_timer_;
439366
timer_type writer_timer_;
440367
timer_type read_timer_;
@@ -450,6 +377,9 @@ class connection_base {
450377

451378
resp3::request req_;
452379
std::vector<resp3::node<std::string>> response_;
380+
endpoint ep_;
381+
// The result of async_resolve.
382+
boost::asio::ip::tcp::resolver::results_type endpoints_;
453383
};
454384

455385
} // aedis

include/aedis/detail/connection_ops.hpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030

3131
namespace aedis::detail {
3232

33-
template <class Conn>
33+
template <class Conn, class Timer>
3434
struct connect_with_timeout_op {
3535
Conn* conn = nullptr;
36+
boost::asio::ip::tcp::resolver::results_type const* endpoints = nullptr;
3637
typename Conn::timeouts ts;
38+
Timer* timer = nullptr;
3739
boost::asio::coroutine coro{};
3840

3941
template <class Self>
@@ -43,10 +45,10 @@ struct connect_with_timeout_op {
4345
{
4446
reenter (coro)
4547
{
46-
conn->ping_timer_.expires_after(ts.connect_timeout);
48+
timer->expires_after(ts.connect_timeout);
4749
yield
4850
detail::async_connect(
49-
conn->next_layer(), conn->ping_timer_, conn->endpoints_, std::move(self));
51+
conn->next_layer(), *timer, *endpoints, std::move(self));
5052
self.complete(ec);
5153
}
5254
}
@@ -425,7 +427,7 @@ struct run_op {
425427
}
426428

427429
yield
428-
conn->derived().async_connect(ts, std::move(self));
430+
conn->derived().async_connect(conn->endpoints_, ts, conn->ping_timer_, std::move(self));
429431
if (ec) {
430432
conn->cancel(Conn::operation::run);
431433
self.complete(ec);

0 commit comments

Comments
 (0)