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