typedef void *rbd_image_t;
typedef void *rbd_image_options_t;
+typedef void *rbd_pool_stats_t;
typedef void *rbd_completion_t;
typedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg);
rbd_config_source_t source;
} rbd_config_option_t;
+typedef enum {
+ RBD_POOL_STAT_OPTION_IMAGES,
+ RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
+ RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
+ RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
+ RBD_POOL_STAT_OPTION_TRASH_IMAGES,
+ RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
+ RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
+ RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
+} rbd_pool_stat_option_t;
+
CEPH_RBD_API void rbd_image_options_create(rbd_image_options_t* opts);
CEPH_RBD_API void rbd_image_options_destroy(rbd_image_options_t opts);
CEPH_RBD_API int rbd_image_options_set_string(rbd_image_options_t opts,
const char *namespace_name);
CEPH_RBD_API int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
size_t *size);
-CEPH_RBD_API int rbd_namespace_exists(rados_ioctx_t io, const char *namespace_name,
+CEPH_RBD_API int rbd_namespace_exists(rados_ioctx_t io,
+ const char *namespace_name,
bool *exists);
+CEPH_RBD_API int rbd_pool_init(rados_ioctx_t io, bool force);
+
+CEPH_RBD_API void rbd_pool_stats_create(rbd_pool_stats_t *stats);
+CEPH_RBD_API void rbd_pool_stats_destroy(rbd_pool_stats_t stats);
+CEPH_RBD_API int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
+ int stat_option,
+ uint64_t* stat_val);
+CEPH_RBD_API int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats);
+
#ifdef __cplusplus
}
#endif
class Image;
class ImageOptions;
+ class PoolStats;
typedef void *image_ctx_t;
typedef void *completion_t;
typedef void (*callback_t)(completion_t cb, void *arg);
int namespace_list(IoCtx& io_ctx, std::vector<std::string>* namespace_names);
int namespace_exists(IoCtx& io_ctx, const char *namespace_name, bool *exists);
+ int pool_init(IoCtx& io_ctx, bool force);
+ int pool_stats_get(IoCtx& io_ctx, PoolStats *pool_stats);
+
int pool_metadata_get(IoCtx &io_ctx, const std::string &key,
std::string *value);
int pool_metadata_set(IoCtx &io_ctx, const std::string &key,
rbd_image_options_t opts;
};
+class CEPH_RBD_API PoolStats {
+public:
+ PoolStats();
+ ~PoolStats();
+
+ PoolStats(const PoolStats&) = delete;
+ PoolStats& operator=(const PoolStats&) = delete;
+
+ int add(rbd_pool_stat_option_t option, uint64_t* opt_val);
+
+private:
+ friend class RBD;
+
+ rbd_pool_stats_t pool_stats;
+};
+
class CEPH_RBD_API UpdateWatchCtx {
public:
virtual ~UpdateWatchCtx() {}
api/Migration.cc
api/Mirror.cc
api/Namespace.cc
+ api/Pool.cc
api/PoolMetadata.cc
api/Snapshot.cc
api/Trash.cc
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/api/Pool.h"
+#include "include/rados/librados.hpp"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "common/Throttle.h"
+#include "cls/rbd/cls_rbd_client.h"
+#include "osd/osd_types.h"
+#include "librbd/Utils.h"
+#include "librbd/api/Config.h"
+#include "librbd/api/Image.h"
+#include "librbd/api/Trash.h"
+
+#define dout_subsys ceph_subsys_rbd
+
+namespace librbd {
+namespace api {
+
+namespace {
+
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::api::Pool::ImageStatRequest: " \
+ << __func__ << " " << this << ": " \
+ << "(id=" << m_image_id << "): "
+
+template <typename I>
+class ImageStatRequest {
+public:
+ ImageStatRequest(librados::IoCtx& io_ctx, SimpleThrottle& throttle,
+ const std::string& image_id, bool scan_snaps,
+ std::atomic<uint64_t>* bytes,
+ std::atomic<uint64_t>* max_bytes,
+ std::atomic<uint64_t>* snaps)
+ : m_cct(reinterpret_cast<CephContext*>(io_ctx.cct())),
+ m_io_ctx(io_ctx), m_throttle(throttle), m_image_id(image_id),
+ m_scan_snaps(scan_snaps), m_bytes(bytes), m_max_bytes(max_bytes),
+ m_snaps(snaps) {
+ m_throttle.start_op();
+ }
+
+ void send() {
+ get_head();
+ }
+
+protected:
+ void finish(int r) {
+ (*m_max_bytes) += m_max_size;
+ m_throttle.end_op(r);
+
+ delete this;
+ }
+
+private:
+ CephContext* m_cct;
+ librados::IoCtx& m_io_ctx;
+ SimpleThrottle& m_throttle;
+ const std::string& m_image_id;
+ bool m_scan_snaps;
+ std::atomic<uint64_t>* m_bytes;
+ std::atomic<uint64_t>* m_max_bytes;
+ std::atomic<uint64_t>* m_snaps;
+ bufferlist m_out_bl;
+
+ uint64_t m_max_size = 0;
+ ::SnapContext m_snapc;
+
+ void get_head() {
+ ldout(m_cct, 15) << dendl;
+
+ librados::ObjectReadOperation op;
+ cls_client::get_size_start(&op, CEPH_NOSNAP);
+ if (m_scan_snaps) {
+ cls_client::get_snapcontext_start(&op);
+ }
+
+ m_out_bl.clear();
+ auto aio_comp = util::create_rados_callback<
+ ImageStatRequest<I>, &ImageStatRequest<I>::handle_get_head>(this);
+ int r = m_io_ctx.aio_operate(util::header_name(m_image_id), aio_comp, &op,
+ &m_out_bl);
+ ceph_assert(r == 0);
+ aio_comp->release();
+ }
+
+ void handle_get_head(int r) {
+ ldout(m_cct, 15) << "r=" << r << dendl;
+
+ auto it = m_out_bl.cbegin();
+ if (r == 0) {
+ uint8_t order;
+ r = cls_client::get_size_finish(&it, &m_max_size, &order);
+ if (r == 0) {
+ (*m_bytes) += m_max_size;
+ }
+ }
+ if (m_scan_snaps && r == 0) {
+ r = cls_client::get_snapcontext_finish(&it, &m_snapc);
+ if (r == 0) {
+ (*m_snaps) += m_snapc.snaps.size();
+ }
+ }
+
+ if (r == -ENOENT) {
+ finish(r);
+ return;
+ } else if (r < 0) {
+ lderr(m_cct) << "failed to stat image: " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ if (!m_snapc.is_valid()) {
+ lderr(m_cct) << "snap context is invalid" << dendl;
+ finish(-EIO);
+ return;
+ }
+
+ get_snaps();
+ }
+
+ void get_snaps() {
+ if (!m_scan_snaps || m_snapc.snaps.empty()) {
+ finish(0);
+ return;
+ }
+
+ ldout(m_cct, 15) << dendl;
+ librados::ObjectReadOperation op;
+ for (auto snap_seq : m_snapc.snaps) {
+ cls_client::get_size_start(&op, snap_seq);
+ }
+
+ m_out_bl.clear();
+ auto aio_comp = util::create_rados_callback<
+ ImageStatRequest<I>, &ImageStatRequest<I>::handle_get_snaps>(this);
+ int r = m_io_ctx.aio_operate(util::header_name(m_image_id), aio_comp, &op,
+ &m_out_bl);
+ ceph_assert(r == 0);
+ aio_comp->release();
+ }
+
+ void handle_get_snaps(int r) {
+ ldout(m_cct, 15) << "r=" << r << dendl;
+
+ auto it = m_out_bl.cbegin();
+ for ([[maybe_unused]] auto snap_seq : m_snapc.snaps) {
+ uint64_t size;
+ if (r == 0) {
+ uint8_t order;
+ r = cls_client::get_size_finish(&it, &size, &order);
+ }
+ if (r == 0 && m_max_size < size) {
+ m_max_size = size;
+ }
+ }
+
+ if (r == -ENOENT) {
+ ldout(m_cct, 15) << "out-of-sync metadata" << dendl;
+ get_head();
+ } else if (r < 0) {
+ lderr(m_cct) << "failed to retrieve snap size: " << cpp_strerror(r)
+ << dendl;
+ finish(r);
+ } else {
+ finish(0);
+ }
+ }
+
+};
+
+template <typename I>
+void get_pool_stat_option_value(typename Pool<I>::StatOptions* stat_options,
+ rbd_pool_stat_option_t option,
+ uint64_t** value) {
+ auto it = stat_options->find(option);
+ if (it == stat_options->end()) {
+ *value = nullptr;
+ } else {
+ *value = it->second;
+ }
+}
+
+template <typename I>
+int get_pool_stats(librados::IoCtx& io_ctx, const ConfigProxy& config,
+ const std::vector<std::string>& image_ids, uint64_t* image_count,
+ uint64_t* provisioned_bytes, uint64_t* max_provisioned_bytes,
+ uint64_t* snapshot_count) {
+
+ bool scan_snaps = ((max_provisioned_bytes != nullptr) ||
+ (snapshot_count != nullptr));
+
+ SimpleThrottle throttle(
+ config.template get_val<uint64_t>("rbd_concurrent_management_ops"), true);
+ std::atomic<uint64_t> bytes{0};
+ std::atomic<uint64_t> max_bytes{0};
+ std::atomic<uint64_t> snaps{0};
+ for (auto& image_id : image_ids) {
+ if (throttle.pending_error()) {
+ break;
+ }
+
+ auto req = new ImageStatRequest<I>(io_ctx, throttle, image_id,
+ scan_snaps, &bytes, &max_bytes, &snaps);
+ req->send();
+ }
+
+ int r = throttle.wait_for_ret();
+ if (r < 0) {
+ return r;
+ }
+
+ if (image_count != nullptr) {
+ *image_count = image_ids.size();
+ }
+ if (provisioned_bytes != nullptr) {
+ *provisioned_bytes = bytes.load();
+ }
+ if (max_provisioned_bytes != nullptr) {
+ *max_provisioned_bytes = max_bytes.load();
+ }
+ if (snapshot_count != nullptr) {
+ *snapshot_count = snaps.load();
+ }
+
+ return 0;
+}
+
+} // anonymous namespace
+
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::api::Pool: " << __func__ << ": "
+
+template <typename I>
+int Pool<I>::init(librados::IoCtx& io_ctx, bool force) {
+ auto cct = reinterpret_cast<CephContext*>(io_ctx.cct());
+ ldout(cct, 10) << dendl;
+
+ int r = io_ctx.application_enable(pg_pool_t::APPLICATION_NAME_RBD, force);
+ if (r < 0) {
+ return r;
+ }
+
+ // TODO configure self-managed snapshots (and other one-time pool checks)
+
+ return 0;
+}
+
+template <typename I>
+int Pool<I>::add_stat_option(StatOptions* stat_options,
+ rbd_pool_stat_option_t option,
+ uint64_t* value) {
+ switch (option) {
+ case RBD_POOL_STAT_OPTION_IMAGES:
+ case RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES:
+ case RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES:
+ case RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS:
+ case RBD_POOL_STAT_OPTION_TRASH_IMAGES:
+ case RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES:
+ case RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES:
+ case RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS:
+ stat_options->emplace(option, value);
+ return 0;
+ default:
+ break;
+ }
+ return -ENOENT;
+}
+
+template <typename I>
+int Pool<I>::get_stats(librados::IoCtx& io_ctx, StatOptions* stat_options) {
+ auto cct = reinterpret_cast<CephContext*>(io_ctx.cct());
+ ldout(cct, 10) << dendl;
+
+ ConfigProxy config{cct->_conf};
+ api::Config<I>::apply_pool_overrides(io_ctx, &config);
+
+ uint64_t* image_count;
+ uint64_t* provisioned_bytes;
+ uint64_t* max_provisioned_bytes;
+ uint64_t* snapshot_count;
+
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_IMAGES, &image_count);
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
+ &provisioned_bytes);
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
+ &max_provisioned_bytes);
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snapshot_count);
+ if (image_count != nullptr || provisioned_bytes != nullptr ||
+ max_provisioned_bytes != nullptr || snapshot_count != nullptr) {
+ typename Image<I>::ImageNameToIds images;
+ int r = Image<I>::list_images(io_ctx, &images);
+ if (r < 0) {
+ return r;
+ }
+
+ std::vector<std::string> image_ids;
+ image_ids.reserve(images.size());
+ for (auto& it : images) {
+ image_ids.push_back(std::move(it.second));
+ }
+
+ r = get_pool_stats<I>(io_ctx, config, image_ids, image_count,
+ provisioned_bytes, max_provisioned_bytes,
+ snapshot_count);
+ if (r < 0) {
+ return r;
+ }
+ }
+
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_TRASH_IMAGES, &image_count);
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
+ &provisioned_bytes);
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
+ &max_provisioned_bytes);
+ get_pool_stat_option_value<I>(
+ stat_options, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &snapshot_count);
+ if (image_count != nullptr || provisioned_bytes != nullptr ||
+ max_provisioned_bytes != nullptr || snapshot_count != nullptr) {
+ std::vector<trash_image_info_t> trash_entries;
+ int r = Trash<I>::list(io_ctx, trash_entries);
+ if (r < 0 && r != -EOPNOTSUPP) {
+ return r;
+ }
+
+ std::vector<std::string> image_ids;
+ image_ids.reserve(trash_entries.size());
+ for (auto& it : trash_entries) {
+ image_ids.push_back(std::move(it.id));
+ }
+
+ r = get_pool_stats<I>(io_ctx, config, image_ids, image_count,
+ provisioned_bytes, max_provisioned_bytes,
+ snapshot_count);
+ if (r < 0) {
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+} // namespace api
+} // namespace librbd
+
+template class librbd::api::Pool<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_API_POOL_H
+#define CEPH_LIBRBD_API_POOL_H
+
+#include "include/int_types.h"
+#include "include/rbd/librbd.h"
+#include <map>
+
+namespace librados { class IoCtx; }
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace api {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+class Pool {
+public:
+ typedef std::map<rbd_pool_stat_option_t, uint64_t*> StatOptions;
+
+ static int init(librados::IoCtx& io_ctx, bool force);
+
+ static int add_stat_option(StatOptions* stat_options,
+ rbd_pool_stat_option_t option,
+ uint64_t* value);
+
+ static int get_stats(librados::IoCtx& io_ctx, StatOptions* stat_options);
+
+};
+
+} // namespace api
+} // namespace librbd
+
+extern template class librbd::api::Pool<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_API_POOL_H
#include "librbd/api/Migration.h"
#include "librbd/api/Mirror.h"
#include "librbd/api/Namespace.h"
+#include "librbd/api/Pool.h"
#include "librbd/api/PoolMetadata.h"
#include "librbd/api/Snapshot.h"
#include "librbd/api/Trash.h"
};
/*
- RBD
- */
+ * Pool stats
+ */
+ PoolStats::PoolStats() {
+ rbd_pool_stats_create(&pool_stats);
+ }
+
+ PoolStats::~PoolStats() {
+ rbd_pool_stats_destroy(pool_stats);
+ }
+
+ int PoolStats::add(rbd_pool_stat_option_t option, uint64_t* opt_val) {
+ return rbd_pool_stats_option_add_uint64(pool_stats, option, opt_val);
+ }
+
+ /*
+ * RBD
+ */
RBD::RBD()
{
}
return librbd::api::Namespace<>::exists(io_ctx, namespace_name, exists);
}
+ int RBD::pool_init(IoCtx& io_ctx, bool force) {
+ return librbd::api::Pool<>::init(io_ctx, force);
+ }
+
+ int RBD::pool_stats_get(IoCtx& io_ctx, PoolStats* stats) {
+ auto pool_stat_options =
+ reinterpret_cast<librbd::api::Pool<>::StatOptions*>(stats->pool_stats);
+ return librbd::api::Pool<>::get_stats(io_ctx, pool_stat_options);
+ }
+
int RBD::list(IoCtx& io_ctx, vector<string>& names)
{
TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
return librbd::api::Namespace<>::exists(io_ctx, namespace_name, exists);
}
+extern "C" int rbd_pool_init(rados_ioctx_t io, bool force) {
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
+
+ return librbd::api::Pool<>::init(io_ctx, force);
+}
+
+extern "C" void rbd_pool_stats_create(rbd_pool_stats_t *stats) {
+ *stats = reinterpret_cast<rbd_pool_stats_t>(
+ new librbd::api::Pool<>::StatOptions{});
+}
+
+extern "C" void rbd_pool_stats_destroy(rbd_pool_stats_t stats) {
+ auto pool_stat_options =
+ reinterpret_cast<librbd::api::Pool<>::StatOptions*>(stats);
+ delete pool_stat_options;
+}
+
+extern "C" int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
+ int stat_option,
+ uint64_t* stat_val) {
+ auto pool_stat_options =
+ reinterpret_cast<librbd::api::Pool<>::StatOptions*>(stats);
+ return librbd::api::Pool<>::add_stat_option(
+ pool_stat_options, static_cast<rbd_pool_stat_option_t>(stat_option),
+ stat_val);
+}
+
+extern "C" int rbd_pool_stats_get(
+ rados_ioctx_t io, rbd_pool_stats_t pool_stats) {
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
+
+ auto pool_stat_options =
+ reinterpret_cast<librbd::api::Pool<>::StatOptions*>(pool_stats);
+ return librbd::api::Pool<>::get_stats(io_ctx, pool_stat_options);
+}
+
extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p,
const char *destname)
{
ctypedef void* rados_ioctx_t
ctypedef void* rbd_image_t
ctypedef void* rbd_image_options_t
+ ctypedef void* rbd_pool_stats_t
ctypedef void *rbd_completion_t
ctypedef struct rbd_image_info_t:
char *value
rbd_config_source_t source
+ ctypedef enum rbd_pool_stat_option_t:
+ _RBD_POOL_STAT_OPTION_IMAGES "RBD_POOL_STAT_OPTION_IMAGES"
+ _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES"
+ _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES"
+ _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS "RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS"
+ _RBD_POOL_STAT_OPTION_TRASH_IMAGES "RBD_POOL_STAT_OPTION_TRASH_IMAGES"
+ _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES"
+ _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES"
+ _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS "RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS"
+
ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
ctypedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void* ptr)
void rbd_config_image_list_cleanup(rbd_config_option_t *options,
int max_options)
+ int rbd_pool_init(rados_ioctx_t, bint force)
+
+ void rbd_pool_stats_create(rbd_pool_stats_t *stats)
+ void rbd_pool_stats_destroy(rbd_pool_stats_t stats)
+ int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
+ int stat_option, uint64_t* stat_val)
+ int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats)
+
RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
RBD_CONFIG_SOURCE_IMAGE = _RBD_CONFIG_SOURCE_IMAGE
+RBD_POOL_STAT_OPTION_IMAGES = _RBD_POOL_STAT_OPTION_IMAGES
+RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
+RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
+RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS = _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
+RBD_POOL_STAT_OPTION_TRASH_IMAGES = _RBD_POOL_STAT_OPTION_TRASH_IMAGES
+RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
+RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
+RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS = _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
+
+
class Error(Exception):
pass
if ret != 0:
raise make_ex(ret, 'error renaming group')
+ def pool_init(self, ioctx, force):
+ """
+ Initialize an RBD pool
+ :param ioctx: determines which RADOS pool
+ :type ioctx: :class:`rados.Ioctx`
+ :param force: force init
+ :type force: bool
+ """
+ cdef:
+ rados_ioctx_t _ioctx = convert_ioctx(ioctx)
+ bint _force = force
+ with nogil:
+ ret = rbd_pool_init(_ioctx, _force)
+ if ret != 0:
+ raise make_ex(ret, 'error initializing pool')
+
+ def pool_stats_get(self, ioctx):
+ """
+ Return RBD pool stats
+
+ :param ioctx: determines which RADOS pool
+ :type ioctx: :class:`rados.Ioctx`
+ :returns: dict - contains the following keys:
+
+ * ``image_count`` (int) - image count
+
+ * ``image_provisioned_bytes`` (int) - image total HEAD provisioned bytes
+
+ * ``image_max_provisioned_bytes`` (int) - image total max provisioned bytes
+
+ * ``image_snap_count`` (int) - image snap count
+
+ * ``trash_count`` (int) - trash image count
+
+ * ``trash_provisioned_bytes`` (int) - trash total HEAD provisioned bytes
+
+ * ``trash_max_provisioned_bytes`` (int) - trash total max provisioned bytes
+
+ * ``trash_snap_count`` (int) - trash snap count
+
+ """
+ cdef:
+ rados_ioctx_t _ioctx = convert_ioctx(ioctx)
+ uint64_t _image_count = 0
+ uint64_t _image_provisioned_bytes = 0
+ uint64_t _image_max_provisioned_bytes = 0
+ uint64_t _image_snap_count = 0
+ uint64_t _trash_count = 0
+ uint64_t _trash_provisioned_bytes = 0
+ uint64_t _trash_max_provisioned_bytes = 0
+ uint64_t _trash_snap_count = 0
+ rbd_pool_stats_t _stats
+
+ rbd_pool_stats_create(&_stats)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGES,
+ &_image_count)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
+ &_image_provisioned_bytes)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
+ &_image_max_provisioned_bytes)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
+ &_image_snap_count)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_IMAGES,
+ &_trash_count)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
+ &_trash_provisioned_bytes)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
+ &_trash_max_provisioned_bytes)
+ rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS,
+ &_trash_snap_count)
+ try:
+ with nogil:
+ ret = rbd_pool_stats_get(_ioctx, _stats)
+ if ret != 0:
+ raise make_ex(ret, 'error retrieving pool stats')
+ else:
+ return {'image_count': _image_count,
+ 'image_provisioned_bytes': _image_provisioned_bytes,
+ 'image_max_provisioned_bytes': _image_max_provisioned_bytes,
+ 'image_snap_count': _image_snap_count,
+ 'trash_count': _trash_count,
+ 'trash_provisioned_bytes': _trash_provisioned_bytes,
+ 'trash_max_provisioned_bytes': _trash_max_provisioned_bytes,
+ 'trash_snap_count': _trash_snap_count}
+ finally:
+ rbd_pool_stats_destroy(_stats)
+
+
cdef class MirrorPeerIterator(object):
"""
Iterator over mirror peer info for a pool.
}
}
+TEST_F(TestLibRBD, PoolStatsPP)
+{
+ REQUIRE_FORMAT_V2();
+
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
+
+ librbd::RBD rbd;
+ std::string image_name;
+ uint64_t size = 2 << 20;
+ uint64_t expected_size = 0;
+ for (size_t idx = 0; idx < 4; ++idx) {
+ image_name = get_temp_image_name();
+
+ int order = 0;
+ ASSERT_EQ(0, create_image_pp(rbd, ioctx, image_name.c_str(), size, &order));
+ expected_size += size;
+ }
+
+ librbd::Image image;
+ ASSERT_EQ(0, rbd.open(ioctx, image, image_name.c_str(), NULL));
+ ASSERT_EQ(0, image.snap_create("snap1"));
+ ASSERT_EQ(0, image.resize(0));
+ ASSERT_EQ(0, image.close());
+ uint64_t expect_head_size = (expected_size - size);
+
+ uint64_t image_count;
+ uint64_t provisioned_bytes;
+ uint64_t max_provisioned_bytes;
+ uint64_t snap_count;
+ uint64_t trash_image_count;
+ uint64_t trash_provisioned_bytes;
+ uint64_t trash_max_provisioned_bytes;
+ uint64_t trash_snap_count;
+
+ librbd::PoolStats pool_stats1;
+ pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGES, &image_count);
+ pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
+ &provisioned_bytes);
+ ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
+
+ ASSERT_EQ(4U, image_count);
+ ASSERT_EQ(expect_head_size, provisioned_bytes);
+
+ pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
+ &max_provisioned_bytes);
+ ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
+ ASSERT_EQ(4U, image_count);
+ ASSERT_EQ(expect_head_size, provisioned_bytes);
+ ASSERT_EQ(expected_size, max_provisioned_bytes);
+
+ librbd::PoolStats pool_stats2;
+ pool_stats2.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snap_count);
+ pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
+ pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
+ ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats2));
+ ASSERT_EQ(1U, snap_count);
+ ASSERT_EQ(0U, trash_image_count);
+ ASSERT_EQ(0U, trash_snap_count);
+
+ ASSERT_EQ(0, rbd.trash_move(ioctx, image_name.c_str(), 0));
+
+ librbd::PoolStats pool_stats3;
+ pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
+ pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
+ &trash_provisioned_bytes);
+ pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
+ &trash_max_provisioned_bytes);
+ pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
+ ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats3));
+ ASSERT_EQ(1U, trash_image_count);
+ ASSERT_EQ(0U, trash_provisioned_bytes);
+ ASSERT_EQ(size, trash_max_provisioned_bytes);
+ ASSERT_EQ(1U, trash_snap_count);
+}
+
// poorman's ceph_assert()
namespace ceph {
void __ceph_assert_fail(const char *assertion, const char *file, int line,
if (r < 0) {
return r;
}
- ioctx.application_enable("rbd", true);
- return r;
+ librbd::RBD rbd;
+ return rbd.pool_init(ioctx, true);
}
bool is_librados_test_stub(librados::Rados &rados) {
rados.create_pool(pool_name)
global ioctx
ioctx = rados.open_ioctx(pool_name)
- ioctx.application_enable('rbd')
+ RBD().pool_init(ioctx, True)
global features
features = os.getenv("RBD_FEATURES")
features = int(features) if features is not None else 61
features=int(features))
else:
RBD().create(ioctx, image_name, IMG_SIZE, IMG_ORDER, old_format=True)
+ return image_name
def remove_image():
if image_name is not None:
for option in rbd.config_list(ioctx):
eq(option['source'], RBD_CONFIG_SOURCE_CONFIG)
+@require_new_format()
+def test_pool_stats():
+ rbd = RBD()
+
+ try:
+ image1 = create_image()
+ image2 = create_image()
+ image3 = create_image()
+ image4 = create_image()
+ with Image(ioctx, image4) as image:
+ image.create_snap('snap')
+ image.resize(0)
+
+ stats = rbd.pool_stats_get(ioctx)
+ eq(stats['image_count'], 4)
+ eq(stats['image_provisioned_bytes'], 3 * IMG_SIZE)
+ eq(stats['image_max_provisioned_bytes'], 4 * IMG_SIZE)
+ eq(stats['image_snap_count'], 1)
+ eq(stats['trash_count'], 0)
+ eq(stats['trash_provisioned_bytes'], 0)
+ eq(stats['trash_max_provisioned_bytes'], 0)
+ eq(stats['trash_snap_count'], 0)
+ finally:
+ rbd.remove(ioctx, image1)
+ rbd.remove(ioctx, image2)
+ rbd.remove(ioctx, image3)
+ with Image(ioctx, image4) as image:
+ image.remove_snap('snap')
+ rbd.remove(ioctx, image4)
+
def rand_data(size):
return os.urandom(size)
RBD().trash_move(ioctx, image_name, 1000)
assert_raises(PermissionError, RBD().trash_remove, ioctx, image_id)
+ RBD().trash_remove(ioctx, image_id, True)
def test_remove(self):
create_image()