// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_UTILS_H #define CEPH_LIBRBD_UTILS_H #include "include/rados/librados.hpp" #include "include/rbd_types.h" #include "include/Context.h" #include "common/zipkin_trace.h" #include #include namespace librbd { class ImageCtx; namespace util { namespace detail { template void rados_callback(rados_completion_t c, void *arg) { reinterpret_cast(arg)->complete(rados_aio_get_return_value(c)); } template void rados_callback(rados_completion_t c, void *arg) { T *obj = reinterpret_cast(arg); int r = rados_aio_get_return_value(c); (obj->*MF)(r); } template void rados_state_callback(rados_completion_t c, void *arg) { T *obj = reinterpret_cast(arg); int r = rados_aio_get_return_value(c); Context *on_finish = (obj->*MF)(&r); if (on_finish != nullptr) { on_finish->complete(r); if (destroy) { delete obj; } } } template class C_CallbackAdapter : public Context { T *obj; public: C_CallbackAdapter(T *obj) : obj(obj) { } protected: void finish(int r) override { (obj->*MF)(r); } }; template class C_StateCallbackAdapter : public Context { T *obj; public: C_StateCallbackAdapter(T *obj) : obj(obj){ } protected: void complete(int r) override { Context *on_finish = (obj->*MF)(&r); if (on_finish != nullptr) { on_finish->complete(r); if (destroy) { delete obj; } } Context::complete(r); } void finish(int r) override { } }; template struct C_AsyncCallback : public Context { WQ *op_work_queue; Context *on_finish; C_AsyncCallback(WQ *op_work_queue, Context *on_finish) : op_work_queue(op_work_queue), on_finish(on_finish) { } void finish(int r) override { op_work_queue->queue(on_finish, r); } }; } // namespace detail std::string generate_image_id(librados::IoCtx &ioctx); template inline std::string generate_image_id(librados::IoCtx &ioctx) { return generate_image_id(ioctx); } const std::string group_header_name(const std::string &group_id); const std::string id_obj_name(const std::string &name); const std::string header_name(const std::string &image_id); const std::string old_header_name(const std::string &image_name); std::string unique_lock_name(const std::string &name, void *address); librados::AioCompletion *create_rados_callback(Context *on_finish); template librados::AioCompletion *create_rados_callback(T *obj) { return librados::Rados::aio_create_completion( obj, &detail::rados_callback, nullptr); } template librados::AioCompletion *create_rados_callback(T *obj) { return librados::Rados::aio_create_completion( obj, &detail::rados_callback, nullptr); } template librados::AioCompletion *create_rados_callback(T *obj) { return librados::Rados::aio_create_completion( obj, &detail::rados_state_callback, nullptr); } template Context *create_context_callback(T *obj) { return new detail::C_CallbackAdapter(obj); } template Context *create_context_callback(T *obj) { return new detail::C_StateCallbackAdapter(obj); } template Context *create_async_context_callback(I &image_ctx, Context *on_finish) { // use async callback to acquire a clean lock context return new detail::C_AsyncCallback< typename std::decay::type>( image_ctx.op_work_queue, on_finish); } template Context *create_async_context_callback(WQ *work_queue, Context *on_finish) { // use async callback to acquire a clean lock context return new detail::C_AsyncCallback(work_queue, on_finish); } // TODO: temporary until AioCompletion supports templated ImageCtx inline ImageCtx *get_image_ctx(ImageCtx *image_ctx) { return image_ctx; } /// helper for tracking in-flight async ops when coordinating /// a shut down of the invoking class instance class AsyncOpTracker { public: void start_op() { m_refs++; } void finish_op() { if (--m_refs == 0 && m_on_finish != nullptr) { Context *on_finish = nullptr; std::swap(on_finish, m_on_finish); on_finish->complete(0); } } template void wait(I &image_ctx, Context *on_finish) { assert(m_on_finish == nullptr); on_finish = create_async_context_callback(image_ctx, on_finish); if (m_refs == 0) { on_finish->complete(0); return; } m_on_finish = on_finish; } private: std::atomic m_refs = { 0 }; Context *m_on_finish = nullptr; }; uint64_t get_rbd_default_features(CephContext* cct); bool calc_sparse_extent(const bufferptr &bp, size_t sparse_size, uint64_t length, size_t *write_offset, size_t *write_length, size_t *offset); template inline ZTracer::Trace create_trace(const I &image_ctx, const char *trace_name, const ZTracer::Trace &parent_trace) { if (parent_trace.valid()) { return ZTracer::Trace(trace_name, &image_ctx.trace_endpoint, &parent_trace); } return ZTracer::Trace(); } } // namespace util } // namespace librbd #endif // CEPH_LIBRBD_UTILS_H