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/TestIoCtxImpl.h"
5 #include "test/librados_test_stub/TestClassHandler.h"
6 #include "test/librados_test_stub/TestRadosClient.h"
7 #include "test/librados_test_stub/TestWatchNotify.h"
8 #include "librados/AioCompletionImpl.h"
9 #include "include/ceph_assert.h"
10 #include "common/Finisher.h"
11 #include "common/valgrind.h"
12 #include "objclass/objclass.h"
13 #include <boost/bind.hpp>
14 #include <errno.h>
15
16 namespace librados {
17
18 TestIoCtxImpl::TestIoCtxImpl() : m_client(NULL) {
19 get();
20 }
21
22 TestIoCtxImpl::TestIoCtxImpl(TestRadosClient *client, int64_t pool_id,
23 const std::string& pool_name)
24 : m_client(client), m_pool_id(pool_id), m_pool_name(pool_name),
25 m_snap_seq(CEPH_NOSNAP)
26 {
27 m_client->get();
28 get();
29 }
30
31 TestIoCtxImpl::TestIoCtxImpl(const TestIoCtxImpl& rhs)
32 : m_client(rhs.m_client),
33 m_pool_id(rhs.m_pool_id),
34 m_pool_name(rhs.m_pool_name),
35 m_namespace_name(rhs.m_namespace_name),
36 m_snap_seq(rhs.m_snap_seq)
37 {
38 m_client->get();
39 get();
40 }
41
(1) Event exn_spec_violation: |
An exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate(). |
Also see events: |
[fun_call_w_exception] |
42 TestIoCtxImpl::~TestIoCtxImpl() {
(2) Event fun_call_w_exception: |
Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details] |
Also see events: |
[exn_spec_violation] |
43 ceph_assert(m_pending_ops == 0);
44 }
45
46 void TestObjectOperationImpl::get() {
47 m_refcount++;
48 }
49
50 void TestObjectOperationImpl::put() {
51 if (--m_refcount == 0) {
52 ANNOTATE_HAPPENS_AFTER(&m_refcount);
53 ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(&m_refcount);
54 delete this;
55 } else {
56 ANNOTATE_HAPPENS_BEFORE(&m_refcount);
57 }
58 }
59
60 void TestIoCtxImpl::get() {
61 m_refcount++;
62 }
63
64 void TestIoCtxImpl::put() {
65 if (--m_refcount == 0) {
66 m_client->put();
67 delete this;
68 }
69 }
70
71 uint64_t TestIoCtxImpl::get_instance_id() const {
72 return m_client->get_instance_id();
73 }
74
75 int64_t TestIoCtxImpl::get_id() {
76 return m_pool_id;
77 }
78
79 uint64_t TestIoCtxImpl::get_last_version() {
80 return 0;
81 }
82
83 std::string TestIoCtxImpl::get_pool_name() {
84 return m_pool_name;
85 }
86
87 int TestIoCtxImpl::aio_flush() {
88 m_client->flush_aio_operations();
89 return 0;
90 }
91
92 void TestIoCtxImpl::aio_flush_async(AioCompletionImpl *c) {
93 m_client->flush_aio_operations(c);
94 }
95
96 void TestIoCtxImpl::aio_notify(const std::string& oid, AioCompletionImpl *c,
97 bufferlist& bl, uint64_t timeout_ms,
98 bufferlist *pbl) {
99 m_pending_ops++;
100 c->get();
101 C_AioNotify *ctx = new C_AioNotify(this, c);
102 m_client->get_watch_notify()->aio_notify(m_client, m_pool_id, get_namespace(),
103 oid, bl, timeout_ms, pbl, ctx);
104 }
105
106 int TestIoCtxImpl::aio_operate(const std::string& oid, TestObjectOperationImpl &ops,
107 AioCompletionImpl *c, SnapContext *snap_context,
108 int flags) {
109 // TODO flags for now
110 ops.get();
111 m_pending_ops++;
112 m_client->add_aio_operation(oid, true, boost::bind(
113 &TestIoCtxImpl::execute_aio_operations, this, oid, &ops,
114 reinterpret_cast<bufferlist*>(0),
115 snap_context != NULL ? *snap_context : m_snapc), c);
116 return 0;
117 }
118
119 int TestIoCtxImpl::aio_operate_read(const std::string& oid,
120 TestObjectOperationImpl &ops,
121 AioCompletionImpl *c, int flags,
122 bufferlist *pbl) {
123 // TODO ignoring flags for now
124 ops.get();
125 m_pending_ops++;
126 m_client->add_aio_operation(oid, true, boost::bind(
127 &TestIoCtxImpl::execute_aio_operations, this, oid, &ops, pbl, m_snapc), c);
128 return 0;
129 }
130
131 int TestIoCtxImpl::aio_watch(const std::string& o, AioCompletionImpl *c,
132 uint64_t *handle, librados::WatchCtx2 *watch_ctx) {
133 m_pending_ops++;
134 c->get();
135 C_AioNotify *ctx = new C_AioNotify(this, c);
136 if (m_client->is_blacklisted()) {
137 m_client->get_aio_finisher()->queue(ctx, -EBLACKLISTED);
138 } else {
139 m_client->get_watch_notify()->aio_watch(m_client, m_pool_id,
140 get_namespace(), o,
141 get_instance_id(), handle, nullptr,
142 watch_ctx, ctx);
143 }
144 return 0;
145 }
146
147 int TestIoCtxImpl::aio_unwatch(uint64_t handle, AioCompletionImpl *c) {
148 m_pending_ops++;
149 c->get();
150 C_AioNotify *ctx = new C_AioNotify(this, c);
151 if (m_client->is_blacklisted()) {
152 m_client->get_aio_finisher()->queue(ctx, -EBLACKLISTED);
153 } else {
154 m_client->get_watch_notify()->aio_unwatch(m_client, handle, ctx);
155 }
156 return 0;
157 }
158
159 int TestIoCtxImpl::exec(const std::string& oid, TestClassHandler *handler,
160 const char *cls, const char *method,
161 bufferlist& inbl, bufferlist* outbl,
162 const SnapContext &snapc) {
163 if (m_client->is_blacklisted()) {
164 return -EBLACKLISTED;
165 }
166
167 cls_method_cxx_call_t call = handler->get_method(cls, method);
168 if (call == NULL) {
169 return -ENOSYS;
170 }
171
172 return (*call)(reinterpret_cast<cls_method_context_t>(
173 handler->get_method_context(this, oid, snapc).get()), &inbl, outbl);
174 }
175
176 int TestIoCtxImpl::list_watchers(const std::string& o,
177 std::list<obj_watch_t> *out_watchers) {
178 if (m_client->is_blacklisted()) {
179 return -EBLACKLISTED;
180 }
181
182 return m_client->get_watch_notify()->list_watchers(m_pool_id, get_namespace(),
183 o, out_watchers);
184 }
185
186 int TestIoCtxImpl::notify(const std::string& o, bufferlist& bl,
187 uint64_t timeout_ms, bufferlist *pbl) {
188 if (m_client->is_blacklisted()) {
189 return -EBLACKLISTED;
190 }
191
192 return m_client->get_watch_notify()->notify(m_client, m_pool_id,
193 get_namespace(), o, bl,
194 timeout_ms, pbl);
195 }
196
197 void TestIoCtxImpl::notify_ack(const std::string& o, uint64_t notify_id,
198 uint64_t handle, bufferlist& bl) {
199 m_client->get_watch_notify()->notify_ack(m_client, m_pool_id, get_namespace(),
200 o, notify_id, handle,
201 m_client->get_instance_id(), bl);
202 }
203
204 int TestIoCtxImpl::operate(const std::string& oid, TestObjectOperationImpl &ops) {
205 AioCompletionImpl *comp = new AioCompletionImpl();
206
207 ops.get();
208 m_pending_ops++;
209 m_client->add_aio_operation(oid, false, boost::bind(
210 &TestIoCtxImpl::execute_aio_operations, this, oid, &ops,
211 reinterpret_cast<bufferlist*>(0), m_snapc), comp);
212
213 comp->wait_for_safe();
214 int ret = comp->get_return_value();
215 comp->put();
216 return ret;
217 }
218
219 int TestIoCtxImpl::operate_read(const std::string& oid, TestObjectOperationImpl &ops,
220 bufferlist *pbl) {
221 AioCompletionImpl *comp = new AioCompletionImpl();
222
223 ops.get();
224 m_pending_ops++;
225 m_client->add_aio_operation(oid, false, boost::bind(
226 &TestIoCtxImpl::execute_aio_operations, this, oid, &ops, pbl,
227 m_snapc), comp);
228
229 comp->wait_for_complete();
230 int ret = comp->get_return_value();
231 comp->put();
232 return ret;
233 }
234
235 void TestIoCtxImpl::aio_selfmanaged_snap_create(uint64_t *snapid,
236 AioCompletionImpl *c) {
237 m_client->add_aio_operation(
238 "", true,
239 boost::bind(&TestIoCtxImpl::selfmanaged_snap_create, this, snapid), c);
240 }
241
242 void TestIoCtxImpl::aio_selfmanaged_snap_remove(uint64_t snapid,
243 AioCompletionImpl *c) {
244 m_client->add_aio_operation(
245 "", true,
246 boost::bind(&TestIoCtxImpl::selfmanaged_snap_remove, this, snapid), c);
247 }
248
249 int TestIoCtxImpl::selfmanaged_snap_set_write_ctx(snap_t seq,
250 std::vector<snap_t>& snaps) {
251 std::vector<snapid_t> snap_ids(snaps.begin(), snaps.end());
252 m_snapc = SnapContext(seq, snap_ids);
253 return 0;
254 }
255
256 int TestIoCtxImpl::set_alloc_hint(const std::string& oid,
257 uint64_t expected_object_size,
258 uint64_t expected_write_size,
259 const SnapContext &snapc) {
260 return 0;
261 }
262
263 void TestIoCtxImpl::set_snap_read(snap_t seq) {
264 if (seq == 0) {
265 seq = CEPH_NOSNAP;
266 }
267 m_snap_seq = seq;
268 }
269
270 int TestIoCtxImpl::tmap_update(const std::string& oid, bufferlist& cmdbl) {
271 if (m_client->is_blacklisted()) {
272 return -EBLACKLISTED;
273 }
274
275 // TODO: protect against concurrent tmap updates
276 bufferlist tmap_header;
277 std::map<string,bufferlist> tmap;
278 uint64_t size = 0;
279 int r = stat(oid, &size, NULL);
280 if (r == -ENOENT) {
281 r = create(oid, false, m_snapc);
282 }
283 if (r < 0) {
284 return r;
285 }
286
287 if (size > 0) {
288 bufferlist inbl;
289 r = read(oid, size, 0, &inbl);
290 if (r < 0) {
291 return r;
292 }
293 auto iter = inbl.cbegin();
294 decode(tmap_header, iter);
295 decode(tmap, iter);
296 }
297
298 __u8 c;
299 std::string key;
300 bufferlist value;
301 auto iter = cmdbl.cbegin();
302 decode(c, iter);
303 decode(key, iter);
304
305 switch (c) {
306 case CEPH_OSD_TMAP_SET:
307 decode(value, iter);
308 tmap[key] = value;
309 break;
310 case CEPH_OSD_TMAP_RM:
311 r = tmap.erase(key);
312 if (r == 0) {
313 return -ENOENT;
314 }
315 break;
316 default:
317 return -EINVAL;
318 }
319
320 bufferlist out;
321 encode(tmap_header, out);
322 encode(tmap, out);
323 r = write_full(oid, out, m_snapc);
324 return r;
325 }
326
327 int TestIoCtxImpl::unwatch(uint64_t handle) {
328 if (m_client->is_blacklisted()) {
329 return -EBLACKLISTED;
330 }
331
332 return m_client->get_watch_notify()->unwatch(m_client, handle);
333 }
334
335 int TestIoCtxImpl::watch(const std::string& o, uint64_t *handle,
336 librados::WatchCtx *ctx, librados::WatchCtx2 *ctx2) {
337 if (m_client->is_blacklisted()) {
338 return -EBLACKLISTED;
339 }
340
341 return m_client->get_watch_notify()->watch(m_client, m_pool_id,
342 get_namespace(), o,
343 get_instance_id(), handle, ctx,
344 ctx2);
345 }
346
347 int TestIoCtxImpl::execute_operation(const std::string& oid,
348 const Operation &operation) {
349 if (m_client->is_blacklisted()) {
350 return -EBLACKLISTED;
351 }
352
353 TestRadosClient::Transaction transaction(m_client, get_namespace(), oid);
354 return operation(this, oid);
355 }
356
357 int TestIoCtxImpl::execute_aio_operations(const std::string& oid,
358 TestObjectOperationImpl *ops,
359 bufferlist *pbl,
360 const SnapContext &snapc) {
361 int ret = 0;
362 if (m_client->is_blacklisted()) {
363 ret = -EBLACKLISTED;
364 } else {
365 TestRadosClient::Transaction transaction(m_client, get_namespace(), oid);
366 for (ObjectOperations::iterator it = ops->ops.begin();
367 it != ops->ops.end(); ++it) {
368 ret = (*it)(this, oid, pbl, snapc);
369 if (ret < 0) {
370 break;
371 }
372 }
373 }
374 m_pending_ops--;
375 ops->put();
376 return ret;
377 }
378
379 void TestIoCtxImpl::handle_aio_notify_complete(AioCompletionImpl *c, int r) {
380 m_pending_ops--;
381
382 m_client->finish_aio_completion(c, r);
383 }
384
385 } // namespace librados
386