14
14
#include < boost/redis/detail/health_checker.hpp>
15
15
#include < boost/redis/detail/helper.hpp>
16
16
#include < boost/redis/detail/multiplexer.hpp>
17
+ #include < boost/redis/detail/reader_fsm.hpp>
17
18
#include < boost/redis/detail/redis_stream.hpp>
18
19
#include < boost/redis/detail/resp3_handshaker.hpp>
19
20
#include < boost/redis/error.hpp>
@@ -206,85 +207,57 @@ struct writer_op {
206
207
};
207
208
208
209
template <class Conn , class Logger >
209
- struct reader_op {
210
- using dyn_buffer_type = asio::dynamic_string_buffer<
211
- char ,
212
- std::char_traits<char >,
213
- std::allocator<char >>;
214
-
210
+ class reader_op {
211
+ private:
215
212
// TODO: Move this to config so the user can fine tune?
216
213
static constexpr std::size_t buffer_growth_hint = 4096 ;
217
214
218
215
Conn* conn_;
219
216
Logger logger_;
220
- std::pair<tribool, std::size_t > res_{std::make_pair (std::nullopt, 0 )};
221
- asio::coroutine coro{};
217
+ detail::reader_fsm fsm_;
218
+
219
+ public:
220
+ reader_op (Conn& conn, Logger logger) noexcept
221
+ : conn_{&conn}
222
+ , logger_{logger}
223
+ , fsm_{conn.mpx_ }
224
+ { }
222
225
223
226
template <class Self >
224
227
void operator ()(Self& self, system::error_code ec = {}, std::size_t n = 0 )
225
228
{
226
- BOOST_ASIO_CORO_REENTER (coro) for (;;)
227
- {
228
- // Appends some data to the buffer if necessary.
229
- BOOST_ASIO_CORO_YIELD
230
- async_append_some (
231
- conn_->stream_ ,
232
- dyn_buffer_type{conn_->mpx_ .get_read_buffer (), conn_->cfg_ .max_read_size },
233
- conn_->mpx_ .get_parser ().get_suggested_buffer_growth (buffer_growth_hint),
234
- std::move (self));
235
-
236
- logger_.on_read (ec, n);
237
-
238
- // The connection is not viable after an error.
239
- if (ec) {
240
- logger_.trace (" reader_op (1)" , ec);
241
- conn_->cancel (operation::run);
242
- self.complete (ec);
243
- return ;
244
- }
245
-
246
- // The connection might have been canceled while this op was
247
- // suspended or after queueing so we have to check.
248
- if (!conn_->is_open ()) {
249
- logger_.trace (" reader_op (2): connection is closed." );
250
- self.complete (ec);
251
- return ;
252
- }
253
-
254
- while (!conn_->mpx_ .get_read_buffer ().empty ()) {
255
- res_ = conn_->mpx_ .consume_next (ec);
256
-
257
- if (ec) {
258
- logger_.trace (" reader_op (3)" , ec);
259
- conn_->cancel (operation::run);
260
- self.complete (ec);
229
+ using dyn_buffer_type = asio::dynamic_string_buffer<
230
+ char ,
231
+ std::char_traits<char >,
232
+ std::allocator<char >>;
233
+
234
+ for (;;) {
235
+ auto act = fsm_.resume (n, ec, self.get_cancellation_state ().cancelled ());
236
+
237
+ logger_.on_fsm_resume (act);
238
+
239
+ switch (act.type_ ) {
240
+ case reader_fsm::action::type::setup_cancellation:
241
+ self.reset_cancellation_state (asio::enable_terminal_cancellation ());
242
+ continue ;
243
+ case reader_fsm::action::type::needs_more:
244
+ case reader_fsm::action::type::append_some:
245
+ async_append_some (
246
+ conn_->stream_ ,
247
+ dyn_buffer_type{conn_->mpx_ .get_read_buffer (), conn_->cfg_ .max_read_size },
248
+ conn_->mpx_ .get_parser ().get_suggested_buffer_growth (buffer_growth_hint),
249
+ std::move (self));
261
250
return ;
262
- }
263
-
264
- if (!res_.first .has_value ()) {
265
- // More data is needed.
266
- break ;
267
- }
268
-
269
- if (res_.first .value ()) {
270
- if (!conn_->receive_channel_ .try_send (ec, res_.second )) {
271
- BOOST_ASIO_CORO_YIELD
272
- conn_->receive_channel_ .async_send (ec, res_.second , std::move (self));
273
- }
274
-
275
- if (ec) {
276
- logger_.trace (" reader_op (4)" , ec);
277
- conn_->cancel (operation::run);
278
- self.complete (ec);
279
- return ;
280
- }
281
-
282
- if (!conn_->is_open ()) {
283
- logger_.trace (" reader_op (5): connection is closed." );
284
- self.complete (asio::error::operation_aborted);
251
+ case reader_fsm::action::type::notify_push_receiver:
252
+ if (conn_->receive_channel_ .try_send (ec, act.push_size_ )) {
253
+ continue ;
254
+ } else {
255
+ conn_->receive_channel_ .async_send (ec, act.push_size_ , std::move (self));
285
256
return ;
286
257
}
287
- }
258
+ return ;
259
+ case reader_fsm::action::type::cancel_run: conn_->cancel (operation::run); continue ;
260
+ case reader_fsm::action::type::done: self.complete (act.ec_ ); return ;
288
261
}
289
262
}
290
263
}
@@ -340,20 +313,20 @@ class run_op {
340
313
// causing an authentication problem.
341
314
BOOST_ASIO_CORO_YIELD
342
315
asio::experimental::make_parallel_group (
343
- [this ](auto token) {
344
- return conn_->handshaker_ .async_hello (*conn_, logger_ , token);
316
+ [this , logger = logger_ ](auto token) {
317
+ return conn_->handshaker_ .async_hello (*conn_, logger , token);
345
318
},
346
- [this ](auto token) {
347
- return conn_->health_checker_ .async_ping (*conn_, logger_ , token);
319
+ [this , logger = logger_ ](auto token) {
320
+ return conn_->health_checker_ .async_ping (*conn_, logger , token);
348
321
},
349
- [this ](auto token) {
350
- return conn_->health_checker_ .async_check_timeout (*conn_, logger_ , token);
322
+ [this , logger = logger_ ](auto token) {
323
+ return conn_->health_checker_ .async_check_timeout (*conn_, logger , token);
351
324
},
352
- [this ](auto token) {
353
- return conn_->reader (logger_ , token);
325
+ [this , logger = logger_ ](auto token) {
326
+ return conn_->reader (logger , token);
354
327
},
355
- [this ](auto token) {
356
- return conn_->writer (logger_ , token);
328
+ [this , logger = logger_ ](auto token) {
329
+ return conn_->writer (logger , token);
357
330
})
358
331
.async_wait (asio::experimental::wait_for_one_error (), std::move (self));
359
332
@@ -730,7 +703,7 @@ class basic_connection {
730
703
mpx_.cancel_on_conn_lost ();
731
704
}
732
705
733
- template <class , class > friend struct detail ::reader_op;
706
+ template <class , class > friend class detail ::reader_op;
734
707
template <class , class > friend struct detail ::writer_op;
735
708
template <class > friend struct detail ::exec_op;
736
709
template <class , class > friend class detail ::run_op;
@@ -739,7 +712,7 @@ class basic_connection {
739
712
auto reader (Logger l, CompletionToken&& token)
740
713
{
741
714
return asio::async_compose<CompletionToken, void (system::error_code)>(
742
- detail::reader_op<this_type, Logger>{this , l},
715
+ detail::reader_op<this_type, Logger>{* this , l},
743
716
std::forward<CompletionToken>(token),
744
717
writer_timer_);
745
718
}
0 commit comments