OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
strategy.h
1 #pragma once
2 
3 #include <ozo/type_traits.h>
4 #include <ozo/asio.h>
5 #include <ozo/deadline.h>
6 #include <ozo/connection.h>
7 
8 #include <tuple>
9 
10 
23 #ifdef OZO_DOCUMENTATION
24 namespace ozo {
117 template <typename T>
118 constexpr auto FailoverStrategy = std::false_type;
119 
129 template <typename T>
130 constexpr auto FailoverTry = std::false_type;
131 }
132 #endif
133 
134 namespace ozo::failover {
135 
136 namespace hana = boost::hana;
137 
146 template <
147  typename ConnectionProvider,
148  typename TimeConstraint,
149  typename ...Args>
151  static_assert(ozo::TimeConstraint<TimeConstraint>, "TimeConstraint should models ozo::TimeConstraint");
152  static_assert(ozo::ConnectionProvider<ConnectionProvider>, "ConnectionProvider should models ozo::ConnectionProvider");
153 
154  std::decay_t<ConnectionProvider> provider;
155  TimeConstraint time_constraint;
156  hana::tuple<std::decay_t<Args>...> args;
157 
165  basic_context(ConnectionProvider p, TimeConstraint t, Args ...args)
166  : provider(std::forward<ConnectionProvider>(p)),
167  time_constraint(t),
168  args(std::forward<Args>(args)...) {}
169 };
170 
171 template <typename FailoverStrategy, typename Operation>
172 struct get_first_try_impl {
173  template <typename Allocator, typename ...Args>
174  static auto apply(const Operation& op, const FailoverStrategy& s, const Allocator& alloc, Args&& ...args) {
175  return s.get_first_try(op, alloc, std::forward<Args>(args)...);
176  }
177 };
178 
212 template <typename FailoverStrategy, typename Operation, typename Allocator, typename ...Args>
213 inline auto get_first_try(const Operation& op, const FailoverStrategy& strategy, const Allocator& alloc, Args&& ...args) {
214  return get_first_try_impl<FailoverStrategy, Operation>::apply(op, strategy, alloc, std::forward<Args>(args)...);
215 }
216 
217 template <typename Try>
218 struct get_try_context_impl {
219  static decltype(auto) apply(const Try& a_try) {
220  return a_try.get_context();
221  }
222 };
223 
251 template <typename FailoverTry>
252 inline auto get_try_context(const FailoverTry& a_try) {
253  auto res = detail::apply<get_try_context_impl>(ozo::unwrap(a_try));
254  static_assert(HanaSequence<decltype(res)>,
255  "get_try_context_impl::apply() should provide HanaSequence");
256  return res;
257 }
258 
259 template <typename Try>
260 struct get_next_try_impl {
261  template <typename Conn>
262  static auto apply(Try& a_try, error_code ec, Conn&& conn) {
263  return a_try.get_next_try(ec, conn);
264  }
265 };
266 
305 template <typename Try, typename Connection>
306 inline auto get_next_try(Try& a_try, const error_code& ec, Connection& conn) {
307  return detail::apply<get_next_try_impl>(ozo::unwrap(a_try), ec, conn);
308 }
309 
310 template <typename Try>
311 struct initiate_next_try_impl {
312  template <typename Connection, typename Initiator>
313  static auto apply(Try& a_try, const error_code& ec, Connection& conn, Initiator init) {
314  if (auto next = get_next_try(a_try, ec, conn); !ozo::is_null(next)) {
315  init(std::move(next));
316  }
317  }
318 };
319 
360 template <typename Try, typename Connection, typename Initiator>
361 inline auto initiate_next_try(Try& a_try, const error_code& ec, Connection& conn, Initiator&& init) {
362  return detail::apply<initiate_next_try_impl>(ozo::unwrap(a_try), ec, conn, std::forward<Initiator>(init));
363 }
364 
365 namespace detail {
366 
367 template <template<typename...> typename Template, typename Allocator, typename ...Ts>
368 static auto allocate_shared(const Allocator& alloc, Ts&& ...vs) {
369  using type = decltype(Template{std::forward<Ts>(vs)...});
370  return std::allocate_shared<type>(alloc, std::forward<Ts>(vs)...);
371 }
372 
373 template <typename Try, typename Operation, typename Handler>
374 inline void initiate_operation(const Operation&, Try&&, Handler&&);
375 
376 template <typename Operation, typename Try, typename Handler>
377 struct continuation {
378  Operation op_;
379  Try try_;
380  Handler handler_;
381 
382  continuation(const Operation& op, Try a_try, Handler handler)
383  : op_(op), try_(std::move(a_try)), handler_(std::move(handler)) {}
384 
385  template <typename Connection>
386  void operator() (error_code ec, Connection&& conn) {
387  static_assert(ozo::Connection<Connection>, "conn should model Connection concept");
388  if (ec) {
389  bool initiated = false;
390 
391  initiate_next_try(try_, ec, conn, [&] (auto next_try) {
392  initiate_operation(op_, std::move(next_try), std::move(handler_));
393  initiated = true;
394  });
395 
396  if (initiated) {
397  return;
398  }
399  }
400  handler_(std::move(ec), std::forward<Connection>(conn));
401  }
402 
403  using executor_type = decltype(asio::get_associated_executor(handler_));
404 
405  executor_type get_executor() const {
406  return asio::get_associated_executor(handler_);
407  }
408 
409  using allocator_type = decltype(asio::get_associated_allocator(handler_));
410 
411  allocator_type get_allocator() const {
412  return asio::get_associated_allocator(handler_);
413  }
414 };
415 
416 template <typename Try, typename Operation, typename Handler>
417 inline void initiate_operation(const Operation& op, Try&& a_try, Handler&& handler) {
418  hana::unpack(get_try_context(a_try), [&](auto&& ...args) {
420  continuation{op, std::forward<Try>(a_try), std::forward<Handler>(handler)},
421  std::forward<decltype(args)>(args)...
422  );
423  });
424 }
425 
426 template <typename FailoverStrategy, typename Operation>
427 struct operation_initiator {
428  FailoverStrategy strategy_;
429  Operation op_;
430 
431  constexpr operation_initiator(FailoverStrategy strategy, const Operation& op)
432  : strategy_(std::move(strategy)), op_(op) {}
433 
434  template <typename Handler, typename ...Args>
435  void operator() (Handler&& handler, Args&& ...args) const {
436  auto first_try = get_first_try(op_, strategy_, asio::get_associated_allocator(handler), std::forward<Args>(args)...);
437  initiate_operation(op_, std::move(first_try), std::forward<Handler>(handler));
438  }
439 };
440 
441 } // namespace detail
442 
443 struct construct_initiator_impl {
444  template <typename FailoverStrategy, typename Op>
445  constexpr static auto apply(FailoverStrategy&& strategy, const Op& op) {
446  return detail::operation_initiator(std::forward<FailoverStrategy>(strategy), op);
447  }
448 };
449 } // namespace ozo::failover
ozo::unwrap
constexpr decltype(auto) unwrap(T &&v) noexcept(noexcept(unwrap_impl< std::decay_t< T >>::apply(std::forward< T >(v))))
Unwraps argument underlying value or forwards the argument.
Definition: unwrap.h:57
ozo::error_code
boost::system::error_code error_code
Error code representation of the library.
Definition: error.h:38
ozo::failover::basic_context
Basic operation context.
Definition: strategy.h:150
ozo::FailoverStrategy
constexpr auto FailoverStrategy
FailoverStrategy concept.
Definition: strategy.h:118
ozo::get_executor
auto get_executor(const Connection &conn) noexcept
Get the executor associated with the object.
Definition: connection.h:130
ozo::failover::basic_context::args
hana::tuple< std::decay_t< Args >... > args
Other arguments of an operation except CompletionToken.
Definition: strategy.h:156
ConnectionProvider
Connection provider concept
ozo::failover::basic_context::provider
std::decay_t< ConnectionProvider > provider
connection provider for an operation, typically deduced from operation's 1st argument.
Definition: strategy.h:151
ozo::failover::get_first_try
auto get_first_try(const Operation &op, const FailoverStrategy &strategy, const Allocator &alloc, Args &&...args)
Get the first try object for an operation.
Definition: strategy.h:213
ozo::get_operation_initiator
constexpr auto get_operation_initiator(const Operation &op)
Get asynchronous operation initiator.
Definition: asio.h:166
ozo::failover::basic_context::basic_context
basic_context(ConnectionProvider p, TimeConstraint t, Args ...args)
Definition: strategy.h:165
ozo::failover::initiate_next_try
auto initiate_next_try(Try &a_try, const error_code &ec, Connection &conn, Initiator &&init)
Initiates the next try of an operation execution.
Definition: strategy.h:361
ozo::failover::basic_context::time_constraint
TimeConstraint time_constraint
#TimeConstraint for an operation, typically deduced from operation's 2nd argument.
Definition: strategy.h:155
ozo::failover::get_try_context
auto get_try_context(const FailoverTry &a_try)
Get operation context for the try.
Definition: strategy.h:252
Handler
Handler concept.
ozo::is_null
constexpr decltype(auto) is_null(const T &v) noexcept(noexcept(is_null_impl< T >::apply(v)))
Indicates if value is in null state.
Definition: nullable.h:85
ozo::failover::get_next_try
auto get_next_try(Try &a_try, const error_code &ec, Connection &conn)
Get the next try object.
Definition: strategy.h:306
Connection
Database connection concept.
ozo::FailoverTry
constexpr auto FailoverTry
FailoverTry concept.
Definition: strategy.h:130