]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/librados_test_stub/TestRadosClient.h" | |
5 | #include "test/librados_test_stub/TestIoCtxImpl.h" | |
6 | #include "librados/AioCompletionImpl.h" | |
11fdf7f2 | 7 | #include "include/ceph_assert.h" |
7c673cae FG |
8 | #include "common/ceph_json.h" |
9 | #include "common/Finisher.h" | |
10 | #include <boost/bind.hpp> | |
11 | #include <boost/thread.hpp> | |
12 | #include <errno.h> | |
13 | ||
31f18b77 | 14 | #include <atomic> |
11fdf7f2 | 15 | #include <sstream> |
31f18b77 | 16 | |
7c673cae FG |
17 | static int get_concurrency() { |
18 | int concurrency = 0; | |
19 | char *env = getenv("LIBRADOS_CONCURRENCY"); | |
20 | if (env != NULL) { | |
21 | concurrency = atoi(env); | |
22 | } | |
23 | if (concurrency == 0) { | |
24 | concurrency = boost::thread::thread::hardware_concurrency(); | |
25 | } | |
26 | if (concurrency == 0) { | |
27 | concurrency = 1; | |
28 | } | |
29 | return concurrency; | |
30 | } | |
31 | ||
32 | namespace librados { | |
33 | ||
34 | static void finish_aio_completion(AioCompletionImpl *c, int r) { | |
9f95a23c | 35 | c->lock.lock(); |
7c673cae FG |
36 | c->complete = true; |
37 | c->rval = r; | |
9f95a23c | 38 | c->lock.unlock(); |
7c673cae FG |
39 | |
40 | rados_callback_t cb_complete = c->callback_complete; | |
41 | void *cb_complete_arg = c->callback_complete_arg; | |
42 | if (cb_complete) { | |
43 | cb_complete(c, cb_complete_arg); | |
44 | } | |
45 | ||
46 | rados_callback_t cb_safe = c->callback_safe; | |
47 | void *cb_safe_arg = c->callback_safe_arg; | |
48 | if (cb_safe) { | |
49 | cb_safe(c, cb_safe_arg); | |
50 | } | |
51 | ||
9f95a23c | 52 | c->lock.lock(); |
7c673cae FG |
53 | c->callback_complete = NULL; |
54 | c->callback_safe = NULL; | |
9f95a23c | 55 | c->cond.notify_all(); |
7c673cae FG |
56 | c->put_unlock(); |
57 | } | |
58 | ||
59 | class AioFunctionContext : public Context { | |
60 | public: | |
61 | AioFunctionContext(const TestRadosClient::AioFunction &callback, | |
62 | Finisher *finisher, AioCompletionImpl *c) | |
63 | : m_callback(callback), m_finisher(finisher), m_comp(c) | |
64 | { | |
65 | if (m_comp != NULL) { | |
66 | m_comp->get(); | |
67 | } | |
68 | } | |
69 | ||
70 | void finish(int r) override { | |
71 | int ret = m_callback(); | |
72 | if (m_comp != NULL) { | |
73 | if (m_finisher != NULL) { | |
9f95a23c | 74 | m_finisher->queue(new LambdaContext(boost::bind( |
7c673cae FG |
75 | &finish_aio_completion, m_comp, ret))); |
76 | } else { | |
77 | finish_aio_completion(m_comp, ret); | |
78 | } | |
79 | } | |
80 | } | |
81 | private: | |
82 | TestRadosClient::AioFunction m_callback; | |
83 | Finisher *m_finisher; | |
84 | AioCompletionImpl *m_comp; | |
85 | }; | |
86 | ||
87 | TestRadosClient::TestRadosClient(CephContext *cct, | |
88 | TestWatchNotify *watch_notify) | |
89 | : m_cct(cct->get()), m_watch_notify(watch_notify), | |
90 | m_aio_finisher(new Finisher(m_cct)) | |
91 | { | |
92 | get(); | |
93 | ||
94 | // simulate multiple OSDs | |
95 | int concurrency = get_concurrency(); | |
96 | for (int i = 0; i < concurrency; ++i) { | |
97 | m_finishers.push_back(new Finisher(m_cct)); | |
98 | m_finishers.back()->start(); | |
99 | } | |
100 | ||
101 | // replicate AIO callback processing | |
102 | m_aio_finisher->start(); | |
103 | } | |
104 | ||
105 | TestRadosClient::~TestRadosClient() { | |
106 | flush_aio_operations(); | |
107 | ||
108 | for (size_t i = 0; i < m_finishers.size(); ++i) { | |
109 | m_finishers[i]->stop(); | |
110 | delete m_finishers[i]; | |
111 | } | |
112 | m_aio_finisher->stop(); | |
113 | delete m_aio_finisher; | |
114 | ||
115 | m_cct->put(); | |
116 | m_cct = NULL; | |
117 | } | |
118 | ||
119 | void TestRadosClient::get() { | |
31f18b77 | 120 | m_refcount++; |
7c673cae FG |
121 | } |
122 | ||
123 | void TestRadosClient::put() { | |
31f18b77 | 124 | if (--m_refcount == 0) { |
7c673cae FG |
125 | shutdown(); |
126 | delete this; | |
127 | } | |
128 | } | |
129 | ||
130 | CephContext *TestRadosClient::cct() { | |
131 | return m_cct; | |
132 | } | |
133 | ||
134 | int TestRadosClient::connect() { | |
135 | return 0; | |
136 | } | |
137 | ||
138 | void TestRadosClient::shutdown() { | |
139 | } | |
140 | ||
141 | int TestRadosClient::wait_for_latest_osdmap() { | |
142 | return 0; | |
143 | } | |
144 | ||
145 | int TestRadosClient::mon_command(const std::vector<std::string>& cmd, | |
146 | const bufferlist &inbl, | |
147 | bufferlist *outbl, std::string *outs) { | |
148 | for (std::vector<std::string>::const_iterator it = cmd.begin(); | |
149 | it != cmd.end(); ++it) { | |
150 | JSONParser parser; | |
151 | if (!parser.parse(it->c_str(), it->length())) { | |
152 | return -EINVAL; | |
153 | } | |
154 | ||
155 | JSONObjIter j_it = parser.find("prefix"); | |
156 | if (j_it.end()) { | |
157 | return -EINVAL; | |
158 | } | |
159 | ||
160 | if ((*j_it)->get_data() == "osd tier add") { | |
161 | return 0; | |
162 | } else if ((*j_it)->get_data() == "osd tier cache-mode") { | |
163 | return 0; | |
164 | } else if ((*j_it)->get_data() == "osd tier set-overlay") { | |
165 | return 0; | |
166 | } else if ((*j_it)->get_data() == "osd tier remove-overlay") { | |
167 | return 0; | |
168 | } else if ((*j_it)->get_data() == "osd tier remove") { | |
169 | return 0; | |
11fdf7f2 TL |
170 | } else if ((*j_it)->get_data() == "config-key rm") { |
171 | return 0; | |
f6b5b4d7 TL |
172 | } else if ((*j_it)->get_data() == "config set") { |
173 | return 0; | |
11fdf7f2 TL |
174 | } else if ((*j_it)->get_data() == "df") { |
175 | std::stringstream str; | |
176 | str << R"({"pools": [)"; | |
177 | ||
178 | std::list<std::pair<int64_t, std::string>> pools; | |
179 | pool_list(pools); | |
180 | for (auto& pool : pools) { | |
181 | if (pools.begin()->first != pool.first) { | |
182 | str << ","; | |
183 | } | |
184 | str << R"({"name": ")" << pool.second << R"(", "stats": )" | |
185 | << R"({"percent_used": 1.0, "bytes_used": 0, "max_avail": 0}})"; | |
186 | } | |
187 | ||
188 | str << "]}"; | |
189 | outbl->append(str.str()); | |
190 | return 0; | |
7c673cae FG |
191 | } |
192 | } | |
193 | return -ENOSYS; | |
194 | } | |
195 | ||
196 | void TestRadosClient::add_aio_operation(const std::string& oid, | |
197 | bool queue_callback, | |
198 | const AioFunction &aio_function, | |
199 | AioCompletionImpl *c) { | |
200 | AioFunctionContext *ctx = new AioFunctionContext( | |
201 | aio_function, queue_callback ? m_aio_finisher : NULL, c); | |
202 | get_finisher(oid)->queue(ctx); | |
203 | } | |
204 | ||
205 | struct WaitForFlush { | |
206 | int flushed() { | |
31f18b77 | 207 | if (--count == 0) { |
9f95a23c | 208 | aio_finisher->queue(new LambdaContext(boost::bind( |
7c673cae FG |
209 | &finish_aio_completion, c, 0))); |
210 | delete this; | |
211 | } | |
212 | return 0; | |
213 | } | |
214 | ||
31f18b77 | 215 | std::atomic<int64_t> count = { 0 }; |
7c673cae FG |
216 | Finisher *aio_finisher; |
217 | AioCompletionImpl *c; | |
218 | }; | |
219 | ||
220 | void TestRadosClient::flush_aio_operations() { | |
221 | AioCompletionImpl *comp = new AioCompletionImpl(); | |
222 | flush_aio_operations(comp); | |
9f95a23c | 223 | comp->wait_for_complete(); |
7c673cae FG |
224 | comp->put(); |
225 | } | |
226 | ||
227 | void TestRadosClient::flush_aio_operations(AioCompletionImpl *c) { | |
228 | c->get(); | |
229 | ||
230 | WaitForFlush *wait_for_flush = new WaitForFlush(); | |
31f18b77 | 231 | wait_for_flush->count = m_finishers.size(); |
7c673cae FG |
232 | wait_for_flush->aio_finisher = m_aio_finisher; |
233 | wait_for_flush->c = c; | |
234 | ||
235 | for (size_t i = 0; i < m_finishers.size(); ++i) { | |
236 | AioFunctionContext *ctx = new AioFunctionContext( | |
237 | boost::bind(&WaitForFlush::flushed, wait_for_flush), | |
238 | nullptr, nullptr); | |
239 | m_finishers[i]->queue(ctx); | |
240 | } | |
241 | } | |
242 | ||
243 | int TestRadosClient::aio_watch_flush(AioCompletionImpl *c) { | |
244 | c->get(); | |
9f95a23c | 245 | Context *ctx = new LambdaContext(boost::bind( |
7c673cae FG |
246 | &TestRadosClient::finish_aio_completion, this, c, _1)); |
247 | get_watch_notify()->aio_flush(this, ctx); | |
248 | return 0; | |
249 | } | |
250 | ||
251 | void TestRadosClient::finish_aio_completion(AioCompletionImpl *c, int r) { | |
252 | librados::finish_aio_completion(c, r); | |
253 | } | |
254 | ||
255 | Finisher *TestRadosClient::get_finisher(const std::string &oid) { | |
256 | std::size_t h = m_hash(oid); | |
257 | return m_finishers[h % m_finishers.size()]; | |
258 | } | |
259 | ||
260 | } // namespace librados |