Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librados_test_stub / LibradosTestStub.cc
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/LibradosTestStub.h"
5 #include "include/rados/librados.hpp"
6 #include "include/stringify.h"
7 #include "common/ceph_argparse.h"
8 #include "common/common_init.h"
9 #include "common/config.h"
10 #include "common/debug.h"
11 #include "common/snap_types.h"
12 #include "librados/AioCompletionImpl.h"
13 #include "test/librados_test_stub/TestClassHandler.h"
14 #include "test/librados_test_stub/TestIoCtxImpl.h"
15 #include "test/librados_test_stub/TestRadosClient.h"
16 #include "test/librados_test_stub/TestMemCluster.h"
17 #include "test/librados_test_stub/TestMemRadosClient.h"
18 #include "objclass/objclass.h"
19 #include "osd/osd_types.h"
20 #include <arpa/inet.h>
21 #include <boost/bind.hpp>
22 #include <boost/shared_ptr.hpp>
23 #include <deque>
24 #include <list>
25 #include <vector>
26 #include "include/assert.h"
27 #include "include/compat.h"
28
29 #define dout_context g_ceph_context
30 #define dout_subsys ceph_subsys_rados
31
32 namespace librados {
33
34 MockTestMemIoCtxImpl &get_mock_io_ctx(IoCtx &ioctx) {
35   MockTestMemIoCtxImpl **mock =
36     reinterpret_cast<MockTestMemIoCtxImpl **>(&ioctx);
37   return **mock;
38 }
39
40 } // namespace librados
41
42 namespace librados_test_stub {
43
44 TestClusterRef &cluster() {
45   static TestClusterRef s_cluster;
46   return s_cluster;
47 }
48
49 void set_cluster(TestClusterRef cluster_ref) {
50   cluster() = cluster_ref;
51 }
52
53 TestClusterRef get_cluster() {
54   auto &cluster_ref = cluster();
55   if (cluster_ref.get() == nullptr) {
56     cluster_ref.reset(new librados::TestMemCluster());
57   }
58   return cluster_ref;
59 }
60
61 } // namespace librados_test_stub
62
63 namespace {
64
65 librados::TestClassHandler *get_class_handler() {
66   static boost::shared_ptr<librados::TestClassHandler> s_class_handler;
67   if (!s_class_handler) {
68     s_class_handler.reset(new librados::TestClassHandler());
69     s_class_handler->open_all_classes();
70   }
71   return s_class_handler.get();
72 }
73
74 void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen) {
75   if (outbuf) {
76     if (outbl.length() > 0) {
77       *outbuf = (char *)malloc(outbl.length());
78       memcpy(*outbuf, outbl.c_str(), outbl.length());
79     } else {
80       *outbuf = NULL;
81     }
82   }
83   if (outbuflen) {
84     *outbuflen = outbl.length();
85   }
86 }
87
88 void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen) {
89   if (outbuf) {
90     if (outbl.length() > 0) {
91       *outbuf = (char *)malloc(outbl.length());
92       memcpy(*outbuf, outbl.c_str(), outbl.length());
93     } else {
94       *outbuf = NULL;
95     }
96   }
97   if (outbuflen) {
98     *outbuflen = outbl.length();
99   }
100 }
101
102 librados::TestRadosClient *create_rados_client() {
103   CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
104   CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0);
105   cct->_conf->parse_env();
106   cct->_conf->apply_changes(nullptr);
107
108   auto rados_client =
109     librados_test_stub::get_cluster()->create_rados_client(cct);
110   cct->put();
111   return rados_client;
112 }
113
114 } // anonymous namespace
115
116 extern "C" int rados_aio_create_completion(void *cb_arg,
117                                            rados_callback_t cb_complete,
118                                            rados_callback_t cb_safe,
119                                            rados_completion_t *pc)
120 {
121   librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
122   if (cb_complete) {
123     c->set_complete_callback(cb_arg, cb_complete);
124   }
125   if (cb_safe) {
126     c->set_safe_callback(cb_arg, cb_safe);
127   }
128   *pc = c;
129   return 0;
130 }
131
132 extern "C" int rados_aio_get_return_value(rados_completion_t c) {
133   return reinterpret_cast<librados::AioCompletionImpl*>(c)->get_return_value();
134 }
135
136 extern "C" rados_config_t rados_cct(rados_t cluster)
137 {
138   librados::TestRadosClient *client =
139     reinterpret_cast<librados::TestRadosClient*>(cluster);
140   return reinterpret_cast<rados_config_t>(client->cct());
141 }
142
143 extern "C" int rados_conf_set(rados_t cluster, const char *option,
144                               const char *value) {
145   librados::TestRadosClient *impl =
146     reinterpret_cast<librados::TestRadosClient*>(cluster);
147   CephContext *cct = impl->cct();
148   return cct->_conf->set_val(option, value);
149 }
150
151 extern "C" int rados_conf_parse_env(rados_t cluster, const char *var) {
152   librados::TestRadosClient *client =
153     reinterpret_cast<librados::TestRadosClient*>(cluster);
154   md_config_t *conf = client->cct()->_conf;
155   std::vector<const char*> args;
156   env_to_vec(args, var);
157   int ret = conf->parse_argv(args);
158   if (ret == 0) {
159     conf->apply_changes(NULL);
160   }
161   return ret;
162 }
163
164 extern "C" int rados_conf_read_file(rados_t cluster, const char *path) {
165   librados::TestRadosClient *client =
166     reinterpret_cast<librados::TestRadosClient*>(cluster);
167   md_config_t *conf = client->cct()->_conf;
168   int ret = conf->parse_config_files(path, NULL, 0);
169   if (ret == 0) {
170     conf->parse_env();
171     conf->apply_changes(NULL);
172     conf->complain_about_parse_errors(client->cct());
173   } else if (ret == -ENOENT) {
174     // ignore missing client config
175     return 0;
176   }
177   return ret;
178 }
179
180 extern "C" int rados_connect(rados_t cluster) {
181   librados::TestRadosClient *client =
182     reinterpret_cast<librados::TestRadosClient*>(cluster);
183   return client->connect();
184 }
185
186 extern "C" int rados_create(rados_t *cluster, const char * const id) {
187   *cluster = create_rados_client();
188   return 0;
189 }
190
191 extern "C" rados_config_t rados_ioctx_cct(rados_ioctx_t ioctx)
192 {
193   librados::TestIoCtxImpl *ctx =
194     reinterpret_cast<librados::TestIoCtxImpl*>(ioctx);
195   return reinterpret_cast<rados_config_t>(ctx->get_rados_client()->cct());
196 }
197
198 extern "C" int rados_ioctx_create(rados_t cluster, const char *pool_name,
199                                   rados_ioctx_t *ioctx) {
200   librados::TestRadosClient *client =
201     reinterpret_cast<librados::TestRadosClient*>(cluster);
202
203   int64_t pool_id = client->pool_lookup(pool_name);
204   if (pool_id < 0) {
205     return static_cast<int>(pool_id);
206   }
207
208   *ioctx = reinterpret_cast<rados_ioctx_t>(
209       client->create_ioctx(pool_id, pool_name));
210   return 0;
211 }
212
213 extern "C" int rados_ioctx_create2(rados_t cluster, int64_t pool_id,
214                                    rados_ioctx_t *ioctx)
215 {
216   librados::TestRadosClient *client =
217     reinterpret_cast<librados::TestRadosClient*>(cluster);
218
219   std::list<std::pair<int64_t, std::string> > pools;
220   int r = client->pool_list(pools);
221   if (r < 0) {
222     return r;
223   }
224
225   for (std::list<std::pair<int64_t, std::string> >::iterator it =
226        pools.begin(); it != pools.end(); ++it) {
227     if (it->first == pool_id) {
228       *ioctx = reinterpret_cast<rados_ioctx_t>(
229         client->create_ioctx(pool_id, it->second));
230       return 0;
231     }
232   }
233   return -ENOENT;
234 }
235
236 extern "C" void rados_ioctx_destroy(rados_ioctx_t io) {
237   librados::TestIoCtxImpl *ctx =
238     reinterpret_cast<librados::TestIoCtxImpl*>(io);
239   ctx->put();
240 }
241
242 extern "C" rados_t rados_ioctx_get_cluster(rados_ioctx_t io) {
243   librados::TestIoCtxImpl *ctx =
244     reinterpret_cast<librados::TestIoCtxImpl*>(io);
245   return reinterpret_cast<rados_t>(ctx->get_rados_client());
246 }
247
248 extern "C" int rados_mon_command(rados_t cluster, const char **cmd,
249                                  size_t cmdlen, const char *inbuf,
250                                  size_t inbuflen, char **outbuf,
251                                  size_t *outbuflen, char **outs,
252                                  size_t *outslen) {
253   librados::TestRadosClient *client =
254     reinterpret_cast<librados::TestRadosClient*>(cluster);
255
256   vector<string> cmdvec;
257   for (size_t i = 0; i < cmdlen; i++) {
258     cmdvec.push_back(cmd[i]);
259   }
260
261   bufferlist inbl;
262   inbl.append(inbuf, inbuflen);
263
264   bufferlist outbl;
265   string outstring;
266   int ret = client->mon_command(cmdvec, inbl, &outbl, &outstring);
267
268   do_out_buffer(outbl, outbuf, outbuflen);
269   do_out_buffer(outstring, outs, outslen);
270   return ret;
271 }
272
273 extern "C" int rados_nobjects_list_open(rados_ioctx_t io,
274                                         rados_list_ctx_t *ctx) {
275   librados::TestIoCtxImpl *io_ctx =
276     reinterpret_cast<librados::TestIoCtxImpl*>(io);
277   librados::TestRadosClient *client = io_ctx->get_rados_client();
278
279   std::list<librados::TestRadosClient::Object> *list =
280     new std::list<librados::TestRadosClient::Object>();
281   
282   client->object_list(io_ctx->get_id(), list);
283   list->push_front(librados::TestRadosClient::Object());
284   *ctx = reinterpret_cast<rados_list_ctx_t>(list);
285   return 0;
286 }
287
288 extern "C" int rados_nobjects_list_next(rados_list_ctx_t ctx,
289                                         const char **entry,
290                                         const char **key,
291                                         const char **nspace) {
292   std::list<librados::TestRadosClient::Object> *list =
293     reinterpret_cast<std::list<librados::TestRadosClient::Object> *>(ctx);
294   if (!list->empty()) {
295     list->pop_front();
296   }
297   if (list->empty()) {
298     return -ENOENT;
299   }
300
301   librados::TestRadosClient::Object &obj = list->front();
302   if (entry != NULL) {
303     *entry = obj.oid.c_str();
304   }
305   if (key != NULL) {
306     *key = obj.locator.c_str();
307   }
308   if (nspace != NULL) {
309     *nspace = obj.nspace.c_str();
310   }
311   return 0;
312 }
313
314 extern "C" void rados_nobjects_list_close(rados_list_ctx_t ctx) {
315   std::list<librados::TestRadosClient::Object> *list =
316     reinterpret_cast<std::list<librados::TestRadosClient::Object> *>(ctx);
317   delete list;
318 }
319
320 extern "C" int rados_pool_create(rados_t cluster, const char *pool_name) {
321   librados::TestRadosClient *client =
322     reinterpret_cast<librados::TestRadosClient*>(cluster);
323   return client->pool_create(pool_name);
324 }
325
326 extern "C" int rados_pool_delete(rados_t cluster, const char *pool_name) {
327   librados::TestRadosClient *client =
328     reinterpret_cast<librados::TestRadosClient*>(cluster);
329   return client->pool_delete(pool_name);
330 }
331
332 extern "C" void rados_shutdown(rados_t cluster) {
333   librados::TestRadosClient *client =
334     reinterpret_cast<librados::TestRadosClient*>(cluster);
335   client->put();
336 }
337
338 extern "C" int rados_wait_for_latest_osdmap(rados_t cluster) {
339   librados::TestRadosClient *client =
340     reinterpret_cast<librados::TestRadosClient*>(cluster);
341   return client->wait_for_latest_osdmap();
342 }
343
344 namespace librados {
345
346 void AioCompletion::release() {
347   AioCompletionImpl *c = reinterpret_cast<AioCompletionImpl *>(pc);
348   c->release();
349   delete this;
350 }
351
352 IoCtx::IoCtx() : io_ctx_impl(NULL) {
353 }
354
355 IoCtx::~IoCtx() {
356   close();
357 }
358
359 IoCtx::IoCtx(const IoCtx& rhs) {
360   io_ctx_impl = rhs.io_ctx_impl;
361   if (io_ctx_impl) {
362     TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
363     ctx->get();
364   }
365 }
366
367 IoCtx& IoCtx::operator=(const IoCtx& rhs) {
368   if (io_ctx_impl) {
369     TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
370     ctx->put();
371   }
372
373   io_ctx_impl = rhs.io_ctx_impl;
374   if (io_ctx_impl) {
375     TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
376     ctx->get();
377   }
378   return *this;
379 }
380
381 int IoCtx::aio_flush() {
382   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
383   ctx->aio_flush();
384   return 0;
385 }
386
387 int IoCtx::aio_flush_async(AioCompletion *c) {
388   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
389   ctx->aio_flush_async(c->pc);
390   return 0;
391 }
392
393 int IoCtx::aio_notify(const std::string& oid, AioCompletion *c, bufferlist& bl,
394                       uint64_t timeout_ms, bufferlist *pbl) {
395   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
396   ctx->aio_notify(oid, c->pc, bl, timeout_ms, pbl);
397   return 0;
398 }
399
400 int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
401                        ObjectReadOperation *op, bufferlist *pbl) {
402   return aio_operate(oid, c, op, 0, pbl);
403 }
404
405 int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
406                        ObjectReadOperation *op, int flags,
407                        bufferlist *pbl) {
408   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
409   TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
410   return ctx->aio_operate_read(oid, *ops, c->pc, flags, pbl);
411 }
412
413 int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
414                        ObjectReadOperation *op, int flags,
415                        bufferlist *pbl, const blkin_trace_info *trace_info) {
416   return aio_operate(oid, c, op, flags, pbl);
417 }
418
419 int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
420                        ObjectWriteOperation *op) {
421   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
422   TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
423   return ctx->aio_operate(oid, *ops, c->pc, NULL, 0);
424 }
425
426 int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
427                        ObjectWriteOperation *op, snap_t seq,
428                        std::vector<snap_t>& snaps) {
429   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
430   TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
431
432   std::vector<snapid_t> snv;
433   snv.resize(snaps.size());
434   for (size_t i = 0; i < snaps.size(); ++i)
435     snv[i] = snaps[i];
436   SnapContext snapc(seq, snv);
437
438   return ctx->aio_operate(oid, *ops, c->pc, &snapc, 0);
439 }
440
441 int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
442                        ObjectWriteOperation *op, snap_t seq,
443                        std::vector<snap_t>& snaps,
444                        const blkin_trace_info *trace_info) {
445   return aio_operate(oid, c, op, seq, snaps);
446 }
447
448 int IoCtx::aio_remove(const std::string& oid, AioCompletion *c) {
449   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
450   return ctx->aio_remove(oid, c->pc);
451 }
452
453 int IoCtx::aio_watch(const std::string& o, AioCompletion *c, uint64_t *handle,
454                      librados::WatchCtx2 *watch_ctx) {
455   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
456   return ctx->aio_watch(o, c->pc, handle, watch_ctx);
457 }
458
459 int IoCtx::aio_unwatch(uint64_t handle, AioCompletion *c) {
460   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
461   return ctx->aio_unwatch(handle, c->pc);
462 }
463
464 config_t IoCtx::cct() {
465   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
466   return reinterpret_cast<config_t>(ctx->get_rados_client()->cct());
467 }
468
469 void IoCtx::close() {
470   if (io_ctx_impl) {
471     TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
472     ctx->put();
473   }
474   io_ctx_impl = NULL;
475 }
476
477 int IoCtx::create(const std::string& oid, bool exclusive) {
478   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
479   return ctx->execute_operation(
480     oid, boost::bind(&TestIoCtxImpl::create, _1, _2, exclusive));
481 }
482
483 void IoCtx::dup(const IoCtx& rhs) {
484   close();
485   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(rhs.io_ctx_impl);
486   io_ctx_impl = reinterpret_cast<IoCtxImpl*>(ctx->clone());
487 }
488
489 int IoCtx::exec(const std::string& oid, const char *cls, const char *method,
490                 bufferlist& inbl, bufferlist& outbl) {
491   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
492   return ctx->execute_operation(
493     oid, boost::bind(&TestIoCtxImpl::exec, _1, _2, get_class_handler(), cls,
494                      method, inbl, &outbl, ctx->get_snap_context()));
495 }
496
497 void IoCtx::from_rados_ioctx_t(rados_ioctx_t p, IoCtx &io) {
498   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(p);
499   ctx->get();
500
501   io.close();
502   io.io_ctx_impl = reinterpret_cast<IoCtxImpl*>(ctx);
503 }
504
505 uint64_t IoCtx::get_instance_id() const {
506   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
507   return ctx->get_instance_id();
508 }
509
510 int64_t IoCtx::get_id() {
511   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
512   return ctx->get_id();
513 }
514
515 uint64_t IoCtx::get_last_version() {
516   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
517   return ctx->get_last_version();
518 }
519
520 std::string IoCtx::get_pool_name() {
521   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
522   return ctx->get_pool_name();
523 }
524
525 int IoCtx::list_snaps(const std::string& o, snap_set_t *out_snaps) {
526   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
527   return ctx->execute_operation(
528     o, boost::bind(&TestIoCtxImpl::list_snaps, _1, _2, out_snaps));
529 }
530
531 int IoCtx::list_watchers(const std::string& o,
532                          std::list<obj_watch_t> *out_watchers) {
533   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
534   return ctx->execute_operation(
535     o, boost::bind(&TestIoCtxImpl::list_watchers, _1, _2, out_watchers));
536 }
537
538 int IoCtx::notify(const std::string& o, uint64_t ver, bufferlist& bl) {
539   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
540   return ctx->notify(o, bl, 0, NULL);
541 }
542
543 int IoCtx::notify2(const std::string& o, bufferlist& bl,
544                    uint64_t timeout_ms, bufferlist *pbl) {
545   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
546   return ctx->notify(o, bl, timeout_ms, pbl);
547 }
548
549 void IoCtx::notify_ack(const std::string& o, uint64_t notify_id,
550                        uint64_t handle, bufferlist& bl) {
551   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
552   ctx->notify_ack(o, notify_id, handle, bl);
553 }
554
555 int IoCtx::omap_get_vals(const std::string& oid,
556                          const std::string& start_after,
557                          uint64_t max_return,
558                          std::map<std::string, bufferlist> *out_vals) {
559   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
560   return ctx->execute_operation(
561     oid, boost::bind(&TestIoCtxImpl::omap_get_vals, _1, _2, start_after, "",
562                      max_return, out_vals));
563 }
564
565 int IoCtx::operate(const std::string& oid, ObjectWriteOperation *op) {
566   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
567   TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
568   return ctx->operate(oid, *ops);
569 }
570
571 int IoCtx::operate(const std::string& oid, ObjectReadOperation *op,
572                    bufferlist *pbl) {
573   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
574   TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
575   return ctx->operate_read(oid, *ops, pbl);
576 }
577
578 int IoCtx::read(const std::string& oid, bufferlist& bl, size_t len,
579                 uint64_t off) {
580   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
581   return ctx->execute_operation(
582     oid, boost::bind(&TestIoCtxImpl::read, _1, _2, len, off, &bl));
583 }
584
585 int IoCtx::remove(const std::string& oid) {
586   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
587   return ctx->execute_operation(
588     oid, boost::bind(&TestIoCtxImpl::remove, _1, _2, ctx->get_snap_context()));
589 }
590
591 int IoCtx::selfmanaged_snap_create(uint64_t *snapid) {
592   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
593   return ctx->selfmanaged_snap_create(snapid);
594 }
595
596 void IoCtx::aio_selfmanaged_snap_create(uint64_t *snapid, AioCompletion* c) {
597   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
598   return ctx->aio_selfmanaged_snap_create(snapid, c->pc);
599 }
600
601 int IoCtx::selfmanaged_snap_remove(uint64_t snapid) {
602   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
603   return ctx->selfmanaged_snap_remove(snapid);
604 }
605
606 void IoCtx::aio_selfmanaged_snap_remove(uint64_t snapid, AioCompletion* c) {
607   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
608   ctx->aio_selfmanaged_snap_remove(snapid, c->pc);
609 }
610
611 int IoCtx::selfmanaged_snap_rollback(const std::string& oid,
612                                      uint64_t snapid) {
613   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
614   return ctx->selfmanaged_snap_rollback(oid, snapid);
615 }
616
617 int IoCtx::selfmanaged_snap_set_write_ctx(snap_t seq,
618                                           std::vector<snap_t>& snaps) {
619   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
620   return ctx->selfmanaged_snap_set_write_ctx(seq, snaps);
621 }
622
623 void IoCtx::snap_set_read(snap_t seq) {
624   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
625   ctx->set_snap_read(seq);
626 }
627
628 int IoCtx::stat(const std::string& oid, uint64_t *psize, time_t *pmtime) {
629   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
630   return ctx->execute_operation(
631     oid, boost::bind(&TestIoCtxImpl::stat, _1, _2, psize, pmtime));
632 }
633
634 int IoCtx::tmap_update(const std::string& oid, bufferlist& cmdbl) {
635   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
636   return ctx->execute_operation(
637     oid, boost::bind(&TestIoCtxImpl::tmap_update, _1, _2, cmdbl));
638 }
639
640 int IoCtx::trunc(const std::string& oid, uint64_t off) {
641   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
642   return ctx->execute_operation(
643     oid, boost::bind(&TestIoCtxImpl::truncate, _1, _2, off,
644                      ctx->get_snap_context()));
645 }
646
647 int IoCtx::unwatch2(uint64_t handle) {
648   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
649   return ctx->unwatch(handle);
650 }
651
652 int IoCtx::unwatch(const std::string& o, uint64_t handle) {
653   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
654   return ctx->unwatch(handle);
655 }
656
657 int IoCtx::watch(const std::string& o, uint64_t ver, uint64_t *handle,
658                  librados::WatchCtx *wctx) {
659   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
660   return ctx->watch(o, handle, wctx, NULL);
661 }
662
663 int IoCtx::watch2(const std::string& o, uint64_t *handle,
664                   librados::WatchCtx2 *wctx) {
665   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
666   return ctx->watch(o, handle, NULL, wctx);
667 }
668
669 int IoCtx::write(const std::string& oid, bufferlist& bl, size_t len,
670                  uint64_t off) {
671   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
672   return ctx->execute_operation(
673     oid, boost::bind(&TestIoCtxImpl::write, _1, _2, bl, len, off,
674                      ctx->get_snap_context()));
675 }
676
677 int IoCtx::write_full(const std::string& oid, bufferlist& bl) {
678   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
679   return ctx->execute_operation(
680     oid, boost::bind(&TestIoCtxImpl::write_full, _1, _2, bl,
681                      ctx->get_snap_context()));
682 }
683
684 int IoCtx::writesame(const std::string& oid, bufferlist& bl, size_t len,
685                      uint64_t off) {
686   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
687   return ctx->execute_operation(
688     oid, boost::bind(&TestIoCtxImpl::writesame, _1, _2, bl, len, off,
689                      ctx->get_snap_context()));
690 }
691
692 int IoCtx::cmpext(const std::string& oid, uint64_t off, bufferlist& cmp_bl) {
693   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
694   return ctx->execute_operation(
695     oid, boost::bind(&TestIoCtxImpl::cmpext, _1, _2, off, cmp_bl));
696 }
697
698 int IoCtx::application_enable(const std::string& app_name, bool force) {
699   return 0;
700 }
701
702 int IoCtx::application_enable_async(const std::string& app_name,
703                                     bool force, PoolAsyncCompletion *c) {
704   return -EOPNOTSUPP;
705 }
706
707 int IoCtx::application_list(std::set<std::string> *app_names) {
708   return -EOPNOTSUPP;
709 }
710
711 int IoCtx::application_metadata_get(const std::string& app_name,
712                                     const std::string &key,
713                                     std::string *value) {
714   return -EOPNOTSUPP;
715 }
716
717 int IoCtx::application_metadata_set(const std::string& app_name,
718                                     const std::string &key,
719                                     const std::string& value) {
720   return -EOPNOTSUPP;
721 }
722
723 int IoCtx::application_metadata_remove(const std::string& app_name,
724                                        const std::string &key) {
725   return -EOPNOTSUPP;
726 }
727
728 int IoCtx::application_metadata_list(const std::string& app_name,
729                                      std::map<std::string, std::string> *values) {
730   return -EOPNOTSUPP;
731 }
732
733 static int save_operation_result(int result, int *pval) {
734   if (pval != NULL) {
735     *pval = result;
736   }
737   return result;
738 }
739
740 ObjectOperation::ObjectOperation() {
741   TestObjectOperationImpl *o = new TestObjectOperationImpl();
742   o->get();
743   impl = reinterpret_cast<ObjectOperationImpl*>(o);
744 }
745
746 ObjectOperation::~ObjectOperation() {
747   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
748   if (o) {
749     o->put();
750     o = NULL;
751   }
752 }
753
754 void ObjectOperation::assert_exists() {
755   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
756   o->ops.push_back(boost::bind(&TestIoCtxImpl::assert_exists, _1, _2));
757 }
758
759 void ObjectOperation::exec(const char *cls, const char *method,
760                            bufferlist& inbl) {
761   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
762   o->ops.push_back(boost::bind(&TestIoCtxImpl::exec, _1, _2,
763                                get_class_handler(), cls, method, inbl, _3, _4));
764 }
765
766 void ObjectOperation::set_op_flags2(int flags) {
767 }
768
769 size_t ObjectOperation::size() {
770   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
771   return o->ops.size();
772 }
773
774 void ObjectOperation::cmpext(uint64_t off, bufferlist& cmp_bl, int *prval) {
775   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
776   ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::cmpext, _1, _2, off, cmp_bl);
777   if (prval != NULL) {
778     op = boost::bind(save_operation_result,
779                      boost::bind(op, _1, _2, _3, _4), prval);
780   }
781   o->ops.push_back(op);
782 }
783
784 void ObjectReadOperation::list_snaps(snap_set_t *out_snaps, int *prval) {
785   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
786
787   ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::list_snaps, _1, _2,
788                                            out_snaps);
789   if (prval != NULL) {
790     op = boost::bind(save_operation_result,
791                      boost::bind(op, _1, _2, _3, _4), prval);
792   }
793   o->ops.push_back(op);
794 }
795
796 void ObjectReadOperation::list_watchers(std::list<obj_watch_t> *out_watchers,
797                                         int *prval) {
798   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
799
800   ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::list_watchers, _1,
801                                            _2, out_watchers);
802   if (prval != NULL) {
803     op = boost::bind(save_operation_result,
804                      boost::bind(op, _1, _2, _3, _4), prval);
805   }
806   o->ops.push_back(op);
807 }
808
809 void ObjectReadOperation::read(size_t off, uint64_t len, bufferlist *pbl,
810                                int *prval) {
811   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
812
813   ObjectOperationTestImpl op;
814   if (pbl != NULL) {
815     op = boost::bind(&TestIoCtxImpl::read, _1, _2, len, off, pbl);
816   } else {
817     op = boost::bind(&TestIoCtxImpl::read, _1, _2, len, off, _3);
818   }
819
820   if (prval != NULL) {
821     op = boost::bind(save_operation_result,
822                      boost::bind(op, _1, _2, _3, _4), prval);
823   }
824   o->ops.push_back(op);
825 }
826
827 void ObjectReadOperation::sparse_read(uint64_t off, uint64_t len,
828                                       std::map<uint64_t,uint64_t> *m,
829                                       bufferlist *pbl, int *prval) {
830   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
831
832   ObjectOperationTestImpl op;
833   if (pbl != NULL) {
834     op = boost::bind(&TestIoCtxImpl::sparse_read, _1, _2, off, len, m, pbl);
835   } else {
836     op = boost::bind(&TestIoCtxImpl::sparse_read, _1, _2, off, len, m, _3);
837   }
838
839   if (prval != NULL) {
840     op = boost::bind(save_operation_result,
841                      boost::bind(op, _1, _2, _3, _4), prval);
842   }
843   o->ops.push_back(op);
844 }
845
846 void ObjectReadOperation::stat(uint64_t *psize, time_t *pmtime, int *prval) {
847   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
848
849   ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::stat, _1, _2,
850                                            psize, pmtime);
851
852   if (prval != NULL) {
853     op = boost::bind(save_operation_result,
854                      boost::bind(op, _1, _2, _3, _4), prval);
855   }
856   o->ops.push_back(op);
857 }
858
859 void ObjectWriteOperation::append(const bufferlist &bl) {
860   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
861   o->ops.push_back(boost::bind(&TestIoCtxImpl::append, _1, _2, bl, _4));
862 }
863
864 void ObjectWriteOperation::create(bool exclusive) {
865   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
866   o->ops.push_back(boost::bind(&TestIoCtxImpl::create, _1, _2, exclusive));
867 }
868
869 void ObjectWriteOperation::omap_set(const std::map<std::string, bufferlist> &map) {
870   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
871   o->ops.push_back(boost::bind(&TestIoCtxImpl::omap_set, _1, _2, boost::ref(map)));
872 }
873
874 void ObjectWriteOperation::remove() {
875   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
876   o->ops.push_back(boost::bind(&TestIoCtxImpl::remove, _1, _2, _4));
877 }
878
879 void ObjectWriteOperation::selfmanaged_snap_rollback(uint64_t snapid) {
880   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
881   o->ops.push_back(boost::bind(&TestIoCtxImpl::selfmanaged_snap_rollback,
882                                _1, _2, snapid));
883 }
884
885 void ObjectWriteOperation::set_alloc_hint(uint64_t expected_object_size,
886                                           uint64_t expected_write_size) {
887   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
888   o->ops.push_back(boost::bind(&TestIoCtxImpl::set_alloc_hint, _1, _2,
889                                expected_object_size, expected_write_size));
890 }
891
892
893 void ObjectWriteOperation::tmap_update(const bufferlist& cmdbl) {
894   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
895   o->ops.push_back(boost::bind(&TestIoCtxImpl::tmap_update, _1, _2,
896                                cmdbl));
897 }
898
899 void ObjectWriteOperation::truncate(uint64_t off) {
900   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
901   o->ops.push_back(boost::bind(&TestIoCtxImpl::truncate, _1, _2, off, _4));
902 }
903
904 void ObjectWriteOperation::write(uint64_t off, const bufferlist& bl) {
905   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
906   o->ops.push_back(boost::bind(&TestIoCtxImpl::write, _1, _2, bl, bl.length(),
907                                off, _4));
908 }
909
910 void ObjectWriteOperation::write_full(const bufferlist& bl) {
911   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
912   o->ops.push_back(boost::bind(&TestIoCtxImpl::write_full, _1, _2, bl, _4));
913 }
914
915 void ObjectWriteOperation::writesame(uint64_t off, uint64_t len, const bufferlist& bl) {
916   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
917   o->ops.push_back(boost::bind(&TestIoCtxImpl::writesame, _1, _2, bl, len,
918                                off, _4));
919 }
920
921 void ObjectWriteOperation::zero(uint64_t off, uint64_t len) {
922   TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
923   o->ops.push_back(boost::bind(&TestIoCtxImpl::zero, _1, _2, off, len));
924 }
925
926 Rados::Rados() : client(NULL) {
927 }
928
929 Rados::Rados(IoCtx& ioctx) {
930   TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(ioctx.io_ctx_impl);
931   TestRadosClient *impl = ctx->get_rados_client();
932   impl->get();
933
934   client = reinterpret_cast<RadosClient*>(impl);
935   assert(client != NULL);
936 }
937
938 Rados::~Rados() {
939   shutdown();
940 }
941
942 AioCompletion *Rados::aio_create_completion(void *cb_arg,
943                                             callback_t cb_complete,
944                                             callback_t cb_safe) {
945   AioCompletionImpl *c;
946   int r = rados_aio_create_completion(cb_arg, cb_complete, cb_safe,
947       reinterpret_cast<void**>(&c));
948   assert(r == 0);
949   return new AioCompletion(c);
950 }
951
952 int Rados::aio_watch_flush(AioCompletion* c) {
953   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
954   return impl->aio_watch_flush(c->pc);
955 }
956
957 int Rados::blacklist_add(const std::string& client_address,
958                          uint32_t expire_seconds) {
959   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
960   return impl->blacklist_add(client_address, expire_seconds);
961 }
962
963 config_t Rados::cct() {
964   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
965   return reinterpret_cast<config_t>(impl->cct());
966 }
967
968 int Rados::cluster_fsid(std::string* fsid) {
969   *fsid = "00000000-1111-2222-3333-444444444444";
970   return 0;
971 }
972
973 int Rados::conf_set(const char *option, const char *value) {
974   return rados_conf_set(reinterpret_cast<rados_t>(client), option, value);
975 }
976
977 int Rados::conf_get(const char *option, std::string &val) {
978   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
979   CephContext *cct = impl->cct();
980
981   char *str = NULL;
982   int ret = cct->_conf->get_val(option, &str, -1);
983   if (ret != 0) {
984     free(str);
985     return ret;
986   }
987
988   val = str;
989   free(str);
990   return 0;
991 }
992
993 int Rados::conf_parse_env(const char *env) const {
994   return rados_conf_parse_env(reinterpret_cast<rados_t>(client), env);
995 }
996
997 int Rados::conf_read_file(const char * const path) const {
998   return rados_conf_read_file(reinterpret_cast<rados_t>(client), path);
999 }
1000
1001 int Rados::connect() {
1002   return rados_connect(reinterpret_cast<rados_t>(client));
1003 }
1004
1005 uint64_t Rados::get_instance_id() {
1006   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1007   return impl->get_instance_id();
1008 }
1009
1010 int Rados::init(const char * const id) {
1011   return rados_create(reinterpret_cast<rados_t *>(&client), id);
1012 }
1013
1014 int Rados::ioctx_create(const char *name, IoCtx &io) {
1015   rados_ioctx_t p;
1016   int ret = rados_ioctx_create(reinterpret_cast<rados_t>(client), name, &p);
1017   if (ret) {
1018     return ret;
1019   }
1020
1021   io.close();
1022   io.io_ctx_impl = reinterpret_cast<IoCtxImpl*>(p);
1023   return 0;
1024 }
1025
1026 int Rados::ioctx_create2(int64_t pool_id, IoCtx &io)
1027 {
1028   rados_ioctx_t p;
1029   int ret = rados_ioctx_create2(reinterpret_cast<rados_t>(client), pool_id, &p);
1030   if (ret) {
1031     return ret;
1032   }
1033
1034   io.close();
1035   io.io_ctx_impl = reinterpret_cast<IoCtxImpl*>(p);
1036   return 0;
1037 }
1038
1039 int Rados::mon_command(std::string cmd, const bufferlist& inbl,
1040                        bufferlist *outbl, std::string *outs) {
1041   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1042
1043   std::vector<std::string> cmds;
1044   cmds.push_back(cmd);
1045   return impl->mon_command(cmds, inbl, outbl, outs);
1046 }
1047
1048 int Rados::service_daemon_register(const std::string& service,
1049                                    const std::string& name,
1050                                    const std::map<std::string,std::string>& metadata) {
1051   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1052   return impl->service_daemon_register(service, name, metadata);
1053 }
1054
1055 int Rados::service_daemon_update_status(const std::map<std::string,std::string>& status) {
1056   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1057   return impl->service_daemon_update_status(status);
1058 }
1059
1060 int Rados::pool_create(const char *name) {
1061   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1062   return impl->pool_create(name);
1063 }
1064
1065 int Rados::pool_delete(const char *name) {
1066   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1067   return impl->pool_delete(name);
1068 }
1069
1070 int Rados::pool_get_base_tier(int64_t pool, int64_t* base_tier) {
1071   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1072   return impl->pool_get_base_tier(pool, base_tier);
1073 }
1074
1075 int Rados::pool_list(std::list<std::string>& v) {
1076   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1077   std::list<std::pair<int64_t, std::string> > pools;
1078   int r = impl->pool_list(pools);
1079   if (r < 0) {
1080     return r;
1081   }
1082
1083   v.clear();
1084   for (std::list<std::pair<int64_t, std::string> >::iterator it = pools.begin();
1085        it != pools.end(); ++it) {
1086     v.push_back(it->second);
1087   }
1088   return 0;
1089 }
1090
1091 int Rados::pool_list2(std::list<std::pair<int64_t, std::string> >& v)
1092 {
1093   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1094   return impl->pool_list(v);
1095 }
1096
1097 int64_t Rados::pool_lookup(const char *name) {
1098   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1099   return impl->pool_lookup(name);
1100 }
1101
1102 int Rados::pool_reverse_lookup(int64_t id, std::string *name) {
1103   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1104   return impl->pool_reverse_lookup(id, name);
1105 }
1106
1107 void Rados::shutdown() {
1108   if (client == NULL) {
1109     return;
1110   }
1111   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1112   impl->put();
1113   client = NULL;
1114 }
1115
1116 void Rados::test_blacklist_self(bool set) {
1117 }
1118
1119 int Rados::wait_for_latest_osdmap() {
1120   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1121   return impl->wait_for_latest_osdmap();
1122 }
1123
1124 int Rados::watch_flush() {
1125   TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1126   return impl->watch_flush();
1127 }
1128
1129 WatchCtx::~WatchCtx() {
1130 }
1131
1132 WatchCtx2::~WatchCtx2() {
1133 }
1134
1135 } // namespace librados
1136
1137 int cls_cxx_create(cls_method_context_t hctx, bool exclusive) {
1138   librados::TestClassHandler::MethodContext *ctx =
1139     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1140   return ctx->io_ctx_impl->create(ctx->oid, exclusive);
1141 }
1142
1143 int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin) {
1144   librados::TestClassHandler::MethodContext *ctx =
1145     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1146
1147   librados::TestRadosClient *rados_client =
1148     ctx->io_ctx_impl->get_rados_client();
1149
1150   struct sockaddr_in sin;
1151   sin.sin_family = AF_INET;
1152   sin.sin_port = 0;
1153   inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
1154
1155   entity_addr_t entity_addr(entity_addr_t::TYPE_DEFAULT,
1156                             rados_client->get_nonce());
1157   entity_addr.in4_addr() = sin;
1158
1159   *origin = entity_inst_t(
1160     entity_name_t::CLIENT(rados_client->get_instance_id()),
1161     entity_addr);
1162   return 0;
1163 }
1164
1165 int cls_cxx_getxattr(cls_method_context_t hctx, const char *name,
1166                      bufferlist *outbl) {
1167   std::map<string, bufferlist> attrs;
1168   int r = cls_cxx_getxattrs(hctx, &attrs);
1169   if (r < 0) {
1170     return r;
1171   }
1172
1173   std::map<string, bufferlist>::iterator it = attrs.find(name);
1174   if (it == attrs.end()) {
1175     return -ENODATA;
1176   }
1177   *outbl = it->second;
1178   return 0;
1179 }
1180
1181 int cls_cxx_getxattrs(cls_method_context_t hctx, std::map<string, bufferlist> *attrset) {
1182   librados::TestClassHandler::MethodContext *ctx =
1183     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1184   return ctx->io_ctx_impl->xattr_get(ctx->oid, attrset);
1185 }
1186
1187 int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_obj,
1188                          uint64_t max_to_get, std::set<string> *keys, bool *more) {
1189   librados::TestClassHandler::MethodContext *ctx =
1190     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1191
1192   keys->clear();
1193   std::map<string, bufferlist> vals;
1194   int r = ctx->io_ctx_impl->omap_get_vals2(ctx->oid, start_obj, "", max_to_get,
1195                                            &vals, more);
1196   if (r < 0) {
1197     return r;
1198   }
1199
1200   for (std::map<string, bufferlist>::iterator it = vals.begin();
1201        it != vals.end(); ++it) {
1202     keys->insert(it->first);
1203   }
1204   return keys->size();
1205 }
1206
1207 int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key,
1208                         bufferlist *outbl) {
1209   librados::TestClassHandler::MethodContext *ctx =
1210     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1211
1212   std::map<string, bufferlist> vals;
1213   int r = ctx->io_ctx_impl->omap_get_vals(ctx->oid, "", key, 1024, &vals);
1214   if (r < 0) {
1215     return r;
1216   }
1217
1218   std::map<string, bufferlist>::iterator it = vals.find(key);
1219   if (it == vals.end()) {
1220     return -ENOENT;
1221   }
1222
1223   *outbl = it->second;
1224   return 0;
1225 }
1226
1227 int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_obj,
1228                          const string &filter_prefix, uint64_t max_to_get,
1229                          std::map<string, bufferlist> *vals, bool *more) {
1230   librados::TestClassHandler::MethodContext *ctx =
1231     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1232   int r = ctx->io_ctx_impl->omap_get_vals2(ctx->oid, start_obj, filter_prefix,
1233                                           max_to_get, vals, more);
1234   if (r < 0) {
1235     return r;
1236   }
1237   return vals->size();
1238 }
1239
1240 int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) {
1241   std::set<std::string> keys;
1242   keys.insert(key);
1243
1244   librados::TestClassHandler::MethodContext *ctx =
1245     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1246   return ctx->io_ctx_impl->omap_rm_keys(ctx->oid, keys);
1247 }
1248
1249 int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key,
1250                         bufferlist *inbl) {
1251   std::map<std::string, bufferlist> m;
1252   m[key] = *inbl;
1253   return cls_cxx_map_set_vals(hctx, &m);
1254 }
1255
1256 int cls_cxx_map_set_vals(cls_method_context_t hctx,
1257                          const std::map<string, bufferlist> *map) {
1258   librados::TestClassHandler::MethodContext *ctx =
1259     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1260   return ctx->io_ctx_impl->omap_set(ctx->oid, *map);
1261 }
1262
1263 int cls_cxx_read(cls_method_context_t hctx, int ofs, int len,
1264                  bufferlist *outbl) {
1265   return cls_cxx_read2(hctx, ofs, len, outbl, 0);
1266 }
1267
1268 int cls_cxx_read2(cls_method_context_t hctx, int ofs, int len,
1269                   bufferlist *outbl, uint32_t op_flags) {
1270   librados::TestClassHandler::MethodContext *ctx =
1271     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1272   return ctx->io_ctx_impl->read(ctx->oid, len, ofs, outbl);
1273 }
1274
1275 int cls_cxx_setxattr(cls_method_context_t hctx, const char *name,
1276                      bufferlist *inbl) {
1277   librados::TestClassHandler::MethodContext *ctx =
1278     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1279   return ctx->io_ctx_impl->xattr_set(ctx->oid, name, *inbl);
1280 }
1281
1282 int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) {
1283   librados::TestClassHandler::MethodContext *ctx =
1284     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1285   return ctx->io_ctx_impl->stat(ctx->oid, size, mtime);
1286 }
1287
1288 int cls_cxx_write(cls_method_context_t hctx, int ofs, int len,
1289                   bufferlist *inbl) {
1290   return cls_cxx_write2(hctx, ofs, len, inbl, 0);
1291 }
1292
1293 int cls_cxx_write2(cls_method_context_t hctx, int ofs, int len,
1294                    bufferlist *inbl, uint32_t op_flags) {
1295   librados::TestClassHandler::MethodContext *ctx =
1296     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1297   return ctx->io_ctx_impl->write(ctx->oid, *inbl, len, ofs, ctx->snapc);
1298 }
1299
1300 int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *inbl) {
1301   librados::TestClassHandler::MethodContext *ctx =
1302     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1303   return ctx->io_ctx_impl->write_full(ctx->oid, *inbl, ctx->snapc);
1304 }
1305
1306 int cls_cxx_list_watchers(cls_method_context_t hctx,
1307                           obj_list_watch_response_t *watchers) {
1308   librados::TestClassHandler::MethodContext *ctx =
1309     reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1310
1311   std::list<obj_watch_t> obj_watchers;
1312   int r = ctx->io_ctx_impl->list_watchers(ctx->oid, &obj_watchers);
1313   if (r < 0) {
1314     return r;
1315   }
1316
1317   for (auto &w : obj_watchers) {
1318     watch_item_t watcher;
1319     watcher.name = entity_name_t::CLIENT(w.watcher_id);
1320     watcher.cookie = w.cookie;
1321     watcher.timeout_seconds = w.timeout_seconds;
1322     watcher.addr.parse(w.addr, 0);
1323     watchers->entries.push_back(watcher);
1324   }
1325
1326   return 0;
1327 }
1328
1329 uint64_t cls_get_features(cls_method_context_t hctx) {
1330   return CEPH_FEATURES_SUPPORTED_DEFAULT;
1331 }
1332
1333 uint64_t cls_get_client_features(cls_method_context_t hctx) {
1334   return CEPH_FEATURES_SUPPORTED_DEFAULT;
1335 }
1336
1337 int cls_log(int level, const char *format, ...) {
1338   int size = 256;
1339   va_list ap;
1340   while (1) {
1341     char buf[size];
1342     va_start(ap, format);
1343     int n = vsnprintf(buf, size, format, ap);
1344     va_end(ap);
1345     if ((n > -1 && n < size) || size > 8196) {
1346       dout(level) << buf << dendl;
1347       return n;
1348     }
1349     size *= 2;
1350   }
1351   return 0;
1352 }
1353
1354 int cls_register(const char *name, cls_handle_t *handle) {
1355   librados::TestClassHandler *cls = get_class_handler();
1356   return cls->create(name, handle);
1357 }
1358
1359 int cls_register_cxx_method(cls_handle_t hclass, const char *method,
1360     int flags,
1361     cls_method_cxx_call_t class_call,
1362     cls_method_handle_t *handle) {
1363   librados::TestClassHandler *cls = get_class_handler();
1364   return cls->create_method(hclass, method, class_call, handle);
1365 }
1366
1367 int cls_register_cxx_filter(cls_handle_t hclass,
1368                             const std::string &filter_name,
1369                             cls_cxx_filter_factory_t fn,
1370                             cls_filter_handle_t *)
1371 {
1372   librados::TestClassHandler *cls = get_class_handler();
1373   return cls->create_filter(hclass, filter_name, fn);
1374 }