Merge pull request #24830 from dillaman/wip-rbd-pool-stats

rbd: expose pool stats summary tool

Reviewed-by: Mykola Golub <mgolub@suse.com>
This commit is contained in:
Mykola Golub 2018-11-10 12:23:40 +02:00 committed by GitHub
commit 56412bf6d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 846 additions and 11 deletions

View File

@ -59,6 +59,7 @@ extern "C" {
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);
@ -264,6 +265,17 @@ typedef struct {
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,
@ -1103,9 +1115,19 @@ CEPH_RBD_API int rbd_namespace_remove(rados_ioctx_t io,
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

View File

@ -29,6 +29,7 @@ namespace librbd {
class Image;
class ImageOptions;
class PoolStats;
typedef void *image_ctx_t;
typedef void *completion_t;
typedef void (*callback_t)(completion_t cb, void *arg);
@ -290,6 +291,9 @@ public:
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,
@ -329,6 +333,22 @@ private:
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() {}

View File

@ -31,6 +31,7 @@ set(librbd_internal_srcs
api/Migration.cc
api/Mirror.cc
api/Namespace.cc
api/Pool.cc
api/PoolMetadata.cc
api/Snapshot.cc
api/Trash.cc

354
src/librbd/api/Pool.cc Normal file
View File

@ -0,0 +1,354 @@
// -*- 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>;

39
src/librbd/api/Pool.h Normal file
View File

@ -0,0 +1,39 @@
// -*- 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

View File

@ -33,6 +33,7 @@
#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"
@ -284,8 +285,23 @@ namespace librbd {
};
/*
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()
{
}
@ -650,6 +666,16 @@ namespace librbd {
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));
@ -3036,6 +3062,44 @@ extern "C" int rbd_namespace_exists(rados_ioctx_t io,
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)
{

View File

@ -87,6 +87,7 @@ cdef extern from "rbd/librbd.h" nogil:
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:
@ -228,6 +229,16 @@ cdef extern from "rbd/librbd.h" nogil:
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)
@ -536,6 +547,14 @@ cdef extern from "rbd/librbd.h" nogil:
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
@ -607,6 +626,16 @@ RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
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
@ -1818,6 +1847,94 @@ class RBD(object):
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.

View File

@ -107,6 +107,7 @@
object-map check Verify the object map is correct.
object-map rebuild Rebuild an invalid object map.
pool init Initialize pool for use by RBD.
pool stats Display pool statistics.
remove (rm) Delete an image.
rename (mv) Rename image within pool.
resize Resize (expand or shrink) image.
@ -1837,6 +1838,23 @@
--force force initialize pool for RBD use if registered by
another application
rbd help pool stats
usage: rbd pool stats [--pool <pool>] [--namespace <namespace>]
[--format <format>] [--pretty-format]
<pool-name>
Display pool statistics.
Positional arguments
<pool-name> pool name
Optional arguments
-p [ --pool ] arg pool name
--namespace arg namespace name
--format arg output format (plain, json, or xml) [default: plain]
--pretty-format pretty formatting (json and xml)
Note: legacy v1 images are not included in stats
rbd help remove
usage: rbd remove [--pool <pool>] [--namespace <namespace>] [--image <image>]
[--no-progress]

View File

@ -7363,6 +7363,82 @@ TEST_F(TestLibRBD, ConfigPP)
}
}
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,

View File

@ -115,9 +115,9 @@ int create_image_data_pool(librados::Rados &rados, std::string &data_pool, bool
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) {

View File

@ -51,7 +51,7 @@ def setup_module():
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
@ -92,6 +92,7 @@ def create_image():
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:
@ -377,6 +378,36 @@ def test_config_list():
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)
@ -1806,6 +1837,7 @@ class TestTrash(object):
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()

View File

@ -6,7 +6,7 @@
#include "tools/rbd/Utils.h"
#include "include/stringify.h"
#include "common/errno.h"
#include "osd/osd_types.h"
#include "common/Formatter.h"
#include <iostream>
#include <boost/program_options.hpp>
@ -37,8 +37,8 @@ int execute_init(const po::variables_map &vm,
return r;
}
r = io_ctx.application_enable(pg_pool_t::APPLICATION_NAME_RBD,
vm["force"].as<bool>());
librbd::RBD rbd;
r = rbd.pool_init(io_ctx, vm["force"].as<bool>());
if (r == -EOPNOTSUPP) {
std::cerr << "rbd: luminous or later release required." << std::endl;
} else if (r == -EPERM) {
@ -52,9 +52,101 @@ int execute_init(const po::variables_map &vm,
return 0;
}
Shell::Action action(
void get_arguments_stats(po::options_description *positional,
po::options_description *options) {
at::add_pool_options(positional, options);
at::add_namespace_option(options, at::ARGUMENT_MODIFIER_NONE);
at::add_format_options(options);
}
int execute_stats(const po::variables_map &vm,
const std::vector<std::string> &ceph_global_init_args) {
size_t arg_index = 0;
std::string pool_name = utils::get_pool_name(vm, &arg_index);
std::string namespace_name = utils::get_namespace_name(vm, &arg_index);
at::Format::Formatter formatter;
int r = utils::get_formatter(vm, &formatter);
if (r < 0) {
return r;
}
librados::Rados rados;
librados::IoCtx io_ctx;
r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
if (r < 0) {
return r;
}
librbd::RBD rbd;
uint64_t image_count;
uint64_t provisioned_bytes;
uint64_t snap_count;
uint64_t trash_count;
uint64_t trash_provisioned_bytes;
uint64_t trash_snap_count;
librbd::PoolStats pool_stats;
pool_stats.add(RBD_POOL_STAT_OPTION_IMAGES, &image_count);
pool_stats.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
&provisioned_bytes);
pool_stats.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snap_count);
pool_stats.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_count);
pool_stats.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
&trash_provisioned_bytes);
pool_stats.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
r = rbd.pool_stats_get(io_ctx, &pool_stats);
if (r < 0) {
std::cerr << "rbd: failed to query pool stats: " << cpp_strerror(r)
<< std::endl;
return r;
}
if (formatter) {
formatter->open_object_section("stats");
formatter->open_object_section("images");
formatter->dump_unsigned("count", image_count);
formatter->dump_unsigned("provisioned_bytes", provisioned_bytes);
formatter->dump_unsigned("snap_count", snap_count);
formatter->close_section();
formatter->open_object_section("trash");
formatter->dump_unsigned("count", trash_count);
formatter->dump_unsigned("provisioned_bytes", trash_provisioned_bytes);
formatter->dump_unsigned("snap_count", trash_snap_count);
formatter->close_section();
formatter->close_section();
formatter->flush(std::cout);
} else {
std::cout << "Total Images: " << image_count;
if (trash_count > 0) {
std::cout << " (" << trash_count << " in trash)";
}
std::cout << std::endl;
std::cout << "Total Snapshots: " << snap_count;
if (trash_count > 0) {
std::cout << " (" << trash_snap_count << " in trash)";
}
std::cout << std::endl;
std::cout << "Provisioned Size: " << byte_u_t(provisioned_bytes);
if (trash_count > 0) {
std::cout << " (" << byte_u_t(trash_provisioned_bytes) << " in trash)";
}
std::cout << std::endl;
}
return 0;
}
Shell::Action init_action(
{"pool", "init"}, {}, "Initialize pool for use by RBD.", "",
&get_arguments_init, &execute_init);
&get_arguments_init, &execute_init);
Shell::Action stat_action(
{"pool", "stats"}, {}, "Display pool statistics.",
"Note: legacy v1 images are not included in stats",
&get_arguments_stats, &execute_stats);
} // namespace pool
} // namespace action