%dir %{_includedir}/rados
%{_includedir}/rados/librados.h
%{_includedir}/rados/rados_types.h
+%{_includedir}/rados/cls_flags.h
+%{_includedir}/rados/cls_traits.h
%{_libdir}/librados.so
%if %{with lttng}
%{_libdir}/librados_tp.so
%{_includedir}/rados/librados_fwd.hpp
%{_includedir}/rados/page.h
%{_includedir}/rados/rados_types.hpp
+%{_includedir}/rados/cls_flags.h
+%{_includedir}/rados/cls_traits.h
%files -n python%{python3_pkgversion}-rados
%{python3_sitearch}/rados.cpython*.so
usr/bin/librados-config
usr/include/rados/librados.h
usr/include/rados/rados_types.h
+usr/include/rados/cls_flags.h
+usr/include/rados/cls_traits.h
usr/lib/librados.so
usr/lib/librados_tp.so
usr/share/man/man8/librados-config.8
usr/include/rados/librados_fwd.hpp
usr/include/rados/page.h
usr/include/rados/rados_types.hpp
+usr/include/rados/cls_flags.h
+usr/include/rados/cls_traits.h
page.h
crc32c.h
rados/objclass.h
+ rados/cls_flags.h
+ rados/cls_traits.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rados)
if(WITH_LIBRADOSSTRIPER)
install(FILES
#include "common/ceph_time.h"
+// For compile-time policing of class calls.
+#include "include/rados/cls_traits.h"
+
namespace neorados {
class Object;
class IOContext;
void assert_exists();
void cmp_omap(const std::vector<cmp_assertion>& assertions);
- void exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- ceph::buffer::list* out,
- boost::system::error_code* ec = nullptr);
- void exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code,
- const ceph::buffer::list&) &&> f);
- void exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code, int,
- const ceph::buffer::list&) &&> f);
- void exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- boost::system::error_code* ec = nullptr);
-
+ protected:
+ // These methods being protected is part of the compile-time protection for
+ // read/write execs.
+ void exec_impl(std::string_view cls, std::string_view method,
+ const ceph::buffer::list& inbl,
+ ceph::buffer::list* out,
+ boost::system::error_code* ec);
+
+ void exec_impl(std::string_view cls, std::string_view method,
+ const ceph::buffer::list& inbl,
+ fu2::unique_function<void(boost::system::error_code,
+ const ceph::buffer::list&) &&> f);
+ void exec_impl(std::string_view cls, std::string_view method,
+ const ceph::buffer::list& inbl,
+ fu2::unique_function<void(boost::system::error_code, int,
+ const ceph::buffer::list&) &&> f);
+ void exec_impl(std::string_view cls, std::string_view method,
+ const ceph::buffer::list& inbl,
+ boost::system::error_code* ec);
+ // templates don't work well with default arguments.
+ void exec_impl(std::string_view cls, std::string_view method,
+ const ceph::buffer::list& inbl) {
+ exec_impl(cls, method, inbl, (boost::system::error_code*)nullptr);
+ }
+ void exec_impl(std::string_view cls, std::string_view method,
+ const ceph::buffer::list& inbl,
+ ceph::buffer::list* out) {
+ exec_impl(cls, method, inbl, out, (boost::system::error_code*)nullptr);
+ }
+ public:
+
+ template <typename Tag, typename ClassID, typename... Args>
+ void exec(const ClsMethod<Tag, ClassID>& method, const ceph::buffer::list& inbl, Args&&... args) {
+ static_assert(FlagTraits<Tag>::is_readonly,
+ "Attempt to call a non-readonly class method as part of a non-write op ");
+ exec_impl(method.cls, method.name, inbl, std::forward<Args>(args)...);
+ }
// Flags that apply to all ops in the operation vector
void balance_reads();
return std::move(*this);
}
- ReadOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- ceph::buffer::list* out,
- boost::system::error_code* ec = nullptr) & {
- Op::exec(cls, method, inbl, out, ec);
- return *this;
- }
- ReadOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- ceph::buffer::list* out,
- boost::system::error_code* ec = nullptr) && {
- Op::exec(cls, method, inbl, out, ec);
- return std::move(*this);
- }
-
- ReadOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code,
- const ceph::buffer::list&) &&> f) & {
- Op::exec(cls, method, inbl, std::move(f));
+ template <typename Tag, typename ClassID, typename... Args>
+ ReadOp& exec(const ClsMethod<Tag, ClassID>& method, Args&&... args) & {
+ static_assert(FlagTraits<Tag>::is_readonly,
+ "Attempt to call a non-readonly class method as part of read. ");
+ Op::exec_impl(method.cls, method.name, std::forward<Args>(args)...);
return *this;
}
- ReadOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code,
- const ceph::buffer::list&) &&> f) && {
- Op::exec(cls, method, inbl, std::move(f));
- return std::move(*this);
- }
- ReadOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code, int,
- const ceph::buffer::list&) &&> f) & {
- Op::exec(cls, method, inbl, std::move(f));
- return *this;
- }
- ReadOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code, int,
- const ceph::buffer::list&) &&> f) && {
- Op::exec(cls, method, inbl, std::move(f));
- return std::move(*this);
- }
-
- ReadOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- boost::system::error_code* ec = nullptr) & {
- Op::exec(cls, method, inbl, ec);
- return *this;
- }
- ReadOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- boost::system::error_code* ec = nullptr) && {
- Op::exec(cls, method, inbl, ec);
+ template <typename Tag, typename ClassID, typename... Args>
+ ReadOp&& exec(const ClsMethod<Tag, ClassID>& method, Args&&... args) && {
+ static_assert(FlagTraits<Tag>::is_readonly,
+ "Attempt to call a non-readonly class method as part of read. ");
+ Op::exec_impl(method.cls, method.name, std::forward<Args>(args)...);
return std::move(*this);
}
return std::move(*this);
}
- WriteOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- ceph::buffer::list* out,
- boost::system::error_code* ec = nullptr) & {
- Op::exec(cls, method, inbl, out, ec);
+ template <typename Tag, typename ClassID, typename... Args>
+ decltype(auto) exec(const ClsMethod<Tag, ClassID>& method, const ceph::buffer::list& inbl, Args&&... args) & {
+ Op::exec_impl(method.cls, method.name, inbl, std::forward<Args>(args)...);
return *this;
}
- WriteOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- ceph::buffer::list* out,
- boost::system::error_code* ec = nullptr) && {
- Op::exec(cls, method, inbl, out, ec);
- return std::move(*this);
- }
-
- WriteOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code,
- const ceph::buffer::list&) &&> f) & {
- Op::exec(cls, method, inbl, std::move(f));
- return *this;
- }
- WriteOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code,
- const ceph::buffer::list&) &&> f) && {
- Op::exec(cls, method, inbl, std::move(f));
- return std::move(*this);
- }
- WriteOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code, int,
- const ceph::buffer::list&) &&> f) & {
- Op::exec(cls, method, inbl, std::move(f));
- return *this;
- }
- WriteOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- fu2::unique_function<void(boost::system::error_code, int,
- const ceph::buffer::list&) &&> f) && {
- Op::exec(cls, method, inbl, std::move(f));
- return std::move(*this);
- }
-
- WriteOp& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- boost::system::error_code* ec = nullptr) & {
- Op::exec(cls, method, inbl, ec);
- return *this;
- }
- WriteOp&& exec(std::string_view cls, std::string_view method,
- const ceph::buffer::list& inbl,
- boost::system::error_code* ec = nullptr) && {
- Op::exec(cls, method, inbl, ec);
+ template <typename Tag, typename ClassID, typename... Args>
+ decltype(auto) exec(const ClsMethod<Tag, ClassID>& method, const ceph::buffer::list& inbl, Args&&... args) && {
+ Op::exec_impl(method.cls, method.name, inbl, std::forward<Args>(args)...);
return std::move(*this);
}
--- /dev/null
+#pragma once
+
+#define CLS_METHOD_RD 0x1 /// method executes read operations
+#define CLS_METHOD_WR 0x2 /// method executes write operations
+#define CLS_METHOD_PROMOTE 0x8 /// method cannot be proxied to base tier
\ No newline at end of file
--- /dev/null
+#pragma once
+#include <type_traits>
+#include "cls_flags.h"
+
+template <int Flags>
+struct MethodTag {};
+
+// Tags representing flags.
+using RdTag = MethodTag<CLS_METHOD_RD>;
+using WrTag = MethodTag<CLS_METHOD_WR>;
+using PromoteTag = MethodTag<CLS_METHOD_PROMOTE>;
+
+// Combinations of flags.
+using RdWrTag = MethodTag<CLS_METHOD_RD | CLS_METHOD_WR>;
+using RdPromoteTag = MethodTag<CLS_METHOD_RD | CLS_METHOD_PROMOTE>;
+using WrPromoteTag = MethodTag<CLS_METHOD_WR | CLS_METHOD_PROMOTE>;
+using RdWrPromoteTag = MethodTag<CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE>;
+
+template <typename Tag, typename ClassDef>
+struct ClsMethod {
+ const char* cls;
+ const char* name;
+
+ constexpr ClsMethod(const char* n) : cls(ClassDef::name), name(n) {}
+};
+
+// Traits to map Tags to properties
+template <typename T> struct FlagTraits;
+
+template <int Flags>
+struct FlagTraits<MethodTag<Flags>> {
+
+ static constexpr int value = Flags;
+ static constexpr bool is_readonly = (Flags & CLS_METHOD_WR) == 0;
+};
+
+template <typename Tag>
+constexpr bool is_safe_for_ro_v = FlagTraits<Tag>::is_readonly;
\ No newline at end of file
#include "librados_fwd.hpp"
#include "rados_types.hpp"
+#include "include/rados/cls_traits.h"
+
namespace libradosstriper
{
class RadosStriper;
void cmpext(uint64_t off, const bufferlist& cmp_bl, int *prval);
void cmpxattr(const char *name, uint8_t op, const bufferlist& val);
void cmpxattr(const char *name, uint8_t op, uint64_t v);
- void exec(const char *cls, const char *method, bufferlist& inbl);
- void exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *obl, int *prval);
- void exec(const char *cls, const char *method, bufferlist& inbl, ObjectOperationCompletion *completion);
+ protected:
+ void exec_impl(const char *cls, const char *method, bufferlist& inbl);
+ void exec_impl(const char *cls, const char *method, bufferlist& inbl, bufferlist *obl, int *prval);
+ void exec_impl(const char *cls, const char *method, bufferlist& inbl, ObjectOperationCompletion *completion);
+ public:
+
+ // By default only allow READ operations. ObjectWriteOperation overrides this
+ // to allow writes.
+ template <typename Tag, typename ClassID, typename... Args>
+ void exec(const ClsMethod<Tag, ClassID>& method, Args&&... args) {
+ static_assert(FlagTraits<Tag>::is_readonly,
+ "Attempt to call a non-readonly class method as part of read. ");
+ exec_impl(method.cls, method.name, std::forward<Args>(args)...);
+ }
+
/**
* Guard operation with a check that object version == ver
*
void unset_manifest();
friend class IoCtx;
+
+ /**
+ * Execute an OSD class method on an object
+ * See IoCtx::exec() for general description.
+ *
+ * Add an exec to write operation. Read or Write exec methods are permitted.
+ *
+ * @param method the method as defined in cls/<class>/cls_<class>_ops.h
+ * @param inbl where to find input
+ * @param obl (optional) where to store output
+ * @param prval (optional) storage for return value.
+ * @param completion (optional) completion callback.
+ */
+ template <typename Tag, typename ClassID, typename... Args>
+ void exec(const ClsMethod<Tag, ClassID>& method, Args&&... args) {
+ // Read or write operations are permitted, so allow this.
+ exec_impl(method.cls, method.name, std::forward<Args>(args)...);
+ }
};
/*
int rmxattr(const std::string& oid, const char *name);
int stat(const std::string& oid, uint64_t *psize, time_t *pmtime);
int stat2(const std::string& oid, uint64_t *psize, struct timespec *pts);
- int exec(const std::string& oid, const char *cls, const char *method,
- bufferlist& inbl, bufferlist& outbl);
+ protected:
+ // IoCtx needs a distinction between ro and rw to pick the correct flags
+ // for the operate call.
+ int exec_impl(const std::string& oid, const char *cls, const char *method,
+ bufferlist& inbl, bufferlist& outbl);
+ public:
+ /**
+ * Execute an OSD class method on an object
+ *
+ * The OSD has a plugin mechanism for performing complicated
+ * operations on an object atomically. These plugins are called
+ * classes. This function allows librados users to call the custom
+ * methods. The input and output formats are defined by the class.
+ * Classes in ceph.git can be found in src/cls subdirectories
+ *
+ * Synchronous variant of exec. Only reads are permitted through this
+ * interface.
+ *
+ * @param oid the object name
+ * @param method the method as defined in cls/<class>/cls_<class>_ops.h
+ * @param inbl where to find input
+ * @param outbl where to store output
+ * @returns return code (>=0 for success, otherwise stanard OSD errors)
+ */
+ template <typename Tag, typename ClassID>
+ int exec(const std::string& oid, const ClsMethod<Tag, ClassID>& method, bufferlist& inbl, bufferlist& outbl) {
+ static_assert(FlagTraits<Tag>::is_readonly,
+ "Attempt to call a non-readonly class method as part of read. ");
+ return exec_impl(oid, method.cls, method.name, inbl, outbl);
+ }
+
/**
* modify object tmap based on encoded update sequence
*
*/
int aio_cancel(AioCompletion *c);
- int aio_exec(const std::string& oid, AioCompletion *c, const char *cls, const char *method,
- bufferlist& inbl, bufferlist *outbl);
+
+ private:
+ int aio_exec_impl(const std::string& oid, AioCompletion *c, const char *cls, const char *method,
+ bufferlist& inbl, bufferlist *outbl);
+ public:
+ /**
+ * Execute an OSD class method on an object
+ * See exec() for general description.
+ *
+ * Asynchronous variant of exec. Only exec reads are permitted.
+ *
+ * @param oid the object name
+ * @param c aio completion
+ * @param method the method as defined in cls/<class>/cls_<class>_ops.h
+ * @param inbl where to find input
+ * @param outbl where to store output
+ */
+ template <typename Tag, typename ClassID>
+ int aio_exec(const std::string& oid, AioCompletion *c,
+ const ClsMethod<Tag, ClassID>& method, bufferlist& inbl, bufferlist *outbl) {
+ static_assert(FlagTraits<Tag>::is_readonly,
+ "Attempt to call a non-readonly class method as part of read. ");
+
+ return aio_exec_impl(oid, c, method.cls, method.name, inbl, outbl);
+ }
/*
* asynchronous version of unlock
#ifdef __cplusplus
#include "buffer.h"
+#include "include/rados/cls_traits.h"
extern "C" {
#endif
#define CLS_INIT(name) \
CEPH_CLS_API void __cls_init()
-#define CLS_METHOD_RD 0x1 /// method executes read operations
-#define CLS_METHOD_WR 0x2 /// method executes write operations
-#define CLS_METHOD_PROMOTE 0x8 /// method cannot be proxied to base tier
-
#define CLS_LOG(level, fmt, ...) \
cls_log(level, "<cls> %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#define CLS_ERR(fmt, ...) CLS_LOG(0, fmt, ##__VA_ARGS__)
* @param class_call
* @param handle
*/
-extern int cls_register_cxx_method(cls_handle_t hclass, const char *method, int flags,
+namespace detail {
+extern int cls_register_cxx_method_impl(cls_handle_t hclass, const char *method, int flags,
cls_method_cxx_call_t class_call, cls_method_handle_t *handle);
+}
+
+template <typename ClassDef>
+struct ClassRegistrar {
+ cls_handle_t h_class;
+
+ ClassRegistrar(cls_handle_t h) : h_class(h) {}
+
+ template <typename Tag>
+ void register_cxx_method(const ClsMethod<Tag, ClassDef>& method_def,
+ cls_method_cxx_call_t class_call,
+ cls_method_handle_t* handle) {
+
+ int flags = FlagTraits<Tag>::value;
+ detail::cls_register_cxx_method_impl(h_class, method_def.name, flags, class_call, handle);
+ }
+};
/**
* Create an object.
o->stat(nullptr, nullptr, nullptr);
}
-void librados::ObjectOperation::exec(const char *cls, const char *method,
- bufferlist& inbl)
+void librados::ObjectOperation::exec_impl(const char *cls, const char *method,
+ bufferlist& inbl)
{
ceph_assert(impl);
::ObjectOperation *o = &impl->o;
o->call(cls, method, inbl);
}
-void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl, int *prval)
+void librados::ObjectOperation::exec_impl(const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl, int *prval)
{
ceph_assert(impl);
::ObjectOperation *o = &impl->o;
}
};
-void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, librados::ObjectOperationCompletion *completion)
+void librados::ObjectOperation::exec_impl(const char *cls, const char *method,
+ bufferlist& inbl, librados::ObjectOperationCompletion *completion)
{
ceph_assert(impl);
::ObjectOperation *o = &impl->o;
return io_ctx_impl->stat2(obj, psize, pts);
}
-int librados::IoCtx::exec(const std::string& oid, const char *cls, const char *method,
+int librados::IoCtx::exec_impl(const std::string& oid, const char *cls, const char *method,
bufferlist& inbl, bufferlist& outbl)
{
object_t obj(oid);
return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off, snapid);
}
-int librados::IoCtx::aio_exec(const std::string& oid,
+int librados::IoCtx::aio_exec_impl(const std::string& oid,
librados::AioCompletion *c, const char *cls,
const char *method, bufferlist& inbl,
bufferlist *outbl)
reinterpret_cast<OpImpl*>(&impl)->op.omap_cmp(std::move(bl), nullptr);
}
-void Op::exec(std::string_view cls, std::string_view method,
- const bufferlist& inbl,
- cb::list* out,
- bs::error_code* ec) {
+void Op::exec_impl(std::string_view cls, std::string_view method,
+ const bufferlist& inbl,
+ cb::list* out,
+ bs::error_code* ec) {
reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec, out);
}
-
-void Op::exec(std::string_view cls, std::string_view method,
- const bufferlist& inbl,
- fu2::unique_function<void(bs::error_code,
- const cb::list&) &&> f) {
+void Op::exec_impl(std::string_view cls, std::string_view method,
+ const bufferlist& inbl,
+ fu2::unique_function<void(bs::error_code,
+ const cb::list&) &&> f) {
reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, std::move(f));
}
-
-void Op::exec(std::string_view cls, std::string_view method,
- const bufferlist& inbl,
- fu2::unique_function<void(bs::error_code, int,
- const cb::list&) &&> f) {
+void Op::exec_impl(std::string_view cls, std::string_view method,
+ const bufferlist& inbl,
+ fu2::unique_function<void(bs::error_code, int,
+ const cb::list&) &&> f) {
reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, std::move(f));
}
-
-void Op::exec(std::string_view cls, std::string_view method,
- const bufferlist& inbl, bs::error_code* ec) {
+void Op::exec_impl(std::string_view cls, std::string_view method,
+ const bufferlist& inbl, bs::error_code* ec) {
reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec);
}
return (hmethod != NULL);
}
-int cls_register_cxx_method(cls_handle_t hclass, const char *method,
+int detail::cls_register_cxx_method_impl(cls_handle_t hclass, const char *method,
int flags,
cls_method_cxx_call_t class_call, cls_method_handle_t *handle)
{