]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
11fdf7f2 TL |
3 | |
4 | /* | |
5 | * Ceph - scalable distributed file system | |
6 | * | |
7 | * Copyright (C) 2018 Red Hat, Inc. | |
8 | * | |
9 | * This is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License version 2.1, as published by the Free Software | |
12 | * Foundation. See file COPYING. | |
13 | * | |
14 | */ | |
15 | ||
16 | #pragma once | |
17 | ||
18 | #include "include/rados/librados_fwd.hpp" | |
19 | #include <memory> | |
20 | #include "common/ceph_mutex.h" | |
9f95a23c TL |
21 | #include "common/async/completion.h" |
22 | #include "common/async/yield_context.h" | |
11fdf7f2 TL |
23 | #include "services/svc_rados.h" |
24 | #include "rgw_aio.h" | |
25 | ||
26 | namespace rgw { | |
27 | ||
9f95a23c | 28 | class Throttle { |
11fdf7f2 TL |
29 | protected: |
30 | const uint64_t window; | |
31 | uint64_t pending_size = 0; | |
32 | ||
9f95a23c TL |
33 | AioResultList pending; |
34 | AioResultList completed; | |
35 | ||
11fdf7f2 TL |
36 | bool is_available() const { return pending_size <= window; } |
37 | bool has_completion() const { return !completed.empty(); } | |
38 | bool is_drained() const { return pending.empty(); } | |
39 | ||
11fdf7f2 TL |
40 | enum class Wait { None, Available, Completion, Drained }; |
41 | Wait waiter = Wait::None; | |
42 | ||
43 | bool waiter_ready() const; | |
44 | ||
11fdf7f2 | 45 | public: |
9f95a23c | 46 | Throttle(uint64_t window) : window(window) {} |
11fdf7f2 | 47 | |
9f95a23c | 48 | ~Throttle() { |
11fdf7f2 TL |
49 | // must drain before destructing |
50 | ceph_assert(pending.empty()); | |
51 | ceph_assert(completed.empty()); | |
52 | } | |
9f95a23c TL |
53 | }; |
54 | ||
55 | // a throttle for aio operations. all public functions must be called from | |
56 | // the same thread | |
57 | class BlockingAioThrottle final : public Aio, private Throttle { | |
58 | ceph::mutex mutex = ceph::make_mutex("AioThrottle"); | |
59 | ceph::condition_variable cond; | |
60 | ||
61 | struct Pending : AioResultEntry { | |
62 | BlockingAioThrottle *parent = nullptr; | |
63 | uint64_t cost = 0; | |
64 | librados::AioCompletion *completion = nullptr; | |
65 | }; | |
66 | public: | |
67 | BlockingAioThrottle(uint64_t window) : Throttle(window) {} | |
68 | ||
69 | AioResultList get(const RGWSI_RADOS::Obj& obj, OpFunc&& f, | |
70 | uint64_t cost, uint64_t id) override final; | |
71 | ||
72 | void put(AioResult& r) override final; | |
73 | ||
74 | AioResultList poll() override final; | |
75 | ||
76 | AioResultList wait() override final; | |
11fdf7f2 | 77 | |
9f95a23c TL |
78 | AioResultList drain() override final; |
79 | }; | |
80 | ||
81 | #ifdef HAVE_BOOST_CONTEXT | |
82 | // a throttle that yields the coroutine instead of blocking. all public | |
83 | // functions must be called within the coroutine strand | |
84 | class YieldingAioThrottle final : public Aio, private Throttle { | |
85 | boost::asio::io_context& context; | |
86 | spawn::yield_context yield; | |
87 | struct Handler; | |
88 | ||
89 | // completion callback associated with the waiter | |
90 | using Completion = ceph::async::Completion<void(boost::system::error_code)>; | |
91 | std::unique_ptr<Completion> completion; | |
11fdf7f2 | 92 | |
9f95a23c TL |
93 | template <typename CompletionToken> |
94 | auto async_wait(CompletionToken&& token); | |
11fdf7f2 | 95 | |
9f95a23c TL |
96 | struct Pending : AioResultEntry { uint64_t cost = 0; }; |
97 | ||
98 | public: | |
99 | YieldingAioThrottle(uint64_t window, boost::asio::io_context& context, | |
100 | spawn::yield_context yield) | |
101 | : Throttle(window), context(context), yield(yield) | |
102 | {} | |
11fdf7f2 | 103 | |
9f95a23c TL |
104 | AioResultList get(const RGWSI_RADOS::Obj& obj, OpFunc&& f, |
105 | uint64_t cost, uint64_t id) override final; | |
11fdf7f2 | 106 | |
9f95a23c TL |
107 | void put(AioResult& r) override final; |
108 | ||
109 | AioResultList poll() override final; | |
110 | ||
111 | AioResultList wait() override final; | |
112 | ||
113 | AioResultList drain() override final; | |
11fdf7f2 | 114 | }; |
9f95a23c TL |
115 | #endif // HAVE_BOOST_CONTEXT |
116 | ||
117 | // return a smart pointer to Aio | |
118 | inline auto make_throttle(uint64_t window_size, optional_yield y) | |
119 | { | |
120 | #ifdef HAVE_BOOST_CONTEXT | |
121 | std::unique_ptr<Aio> aio; | |
122 | if (y) { | |
123 | aio = std::make_unique<YieldingAioThrottle>(window_size, | |
124 | y.get_io_context(), | |
125 | y.get_yield_context()); | |
126 | } else { | |
127 | aio = std::make_unique<BlockingAioThrottle>(window_size); | |
128 | } | |
129 | return aio; | |
130 | #else | |
131 | return std::make_optional<BlockingAioThrottle>(window_size); | |
132 | #endif | |
133 | } | |
11fdf7f2 TL |
134 | |
135 | } // namespace rgw |