*/
CEPH_RADOS_API int rados_pool_list(rados_t cluster, char *buf, size_t len);
+/**
+ * List inconsistent placement groups of the given pool
+ *
+ * Gets a list of inconsistent placement groups as NULL-terminated strings.
+ * The placement group names will be placed in the supplied buffer one after
+ * another. After the last name, there will be two 0 types in a row.
+ *
+ * If len is too short to fit all the placement group entries we need, we will
+ * fill as much as we can.
+ *
+ * @param cluster cluster handle
+ * @param pool pool ID
+ * @param buf output buffer
+ * @param len output buffer length
+ * @returns length of the buffer we would need to list all pools
+ */
+CEPH_RADOS_API int rados_inconsistent_pg_list(rados_t cluster, int64_t pool,
+ char *buf, size_t len);
+
/**
* Get a configuration handle for a rados cluster handle
*
IoCtxImpl *io_ctx_impl;
};
+ struct PlacementGroupImpl;
+ struct CEPH_RADOS_API PlacementGroup {
+ PlacementGroup();
+ PlacementGroup(const PlacementGroup&);
+ ~PlacementGroup();
+ bool parse(const char*);
+ std::unique_ptr<PlacementGroupImpl> impl;
+ };
+
+ CEPH_RADOS_API std::ostream& operator<<(std::ostream&, const PlacementGroup&);
+
class CEPH_RADOS_API Rados
{
public:
int cluster_stat(cluster_stat_t& result);
int cluster_fsid(std::string *fsid);
+ /**
+ * List inconsistent placement groups in the given pool
+ *
+ * @param pool_id the pool id
+ * @param pgs [out] the inconsistent PGs
+ */
+ int get_inconsistent_pgs(int64_t pool_id,
+ std::vector<PlacementGroup>* pgs);
+
/// get/wait for the most recent osdmap
int wait_for_latest_osdmap();
#include "common/config.h"
#include "common/errno.h"
#include "common/ceph_argparse.h"
+#include "common/ceph_json.h"
#include "common/common_init.h"
#include "common/TracepointProvider.h"
#include "common/hobject.h"
return client->get_fsid(fsid);
}
+namespace librados {
+ struct PlacementGroupImpl {
+ pg_t pgid;
+ };
+
+ PlacementGroup::PlacementGroup()
+ : impl{new PlacementGroupImpl}
+ {}
+
+ PlacementGroup::PlacementGroup(const PlacementGroup& pg)
+ : impl{new PlacementGroupImpl}
+ {
+ impl->pgid = pg.impl->pgid;
+ }
+
+ PlacementGroup::~PlacementGroup()
+ {}
+
+ bool PlacementGroup::parse(const char* s)
+ {
+ return impl->pgid.parse(s);
+ }
+}
+
+std::ostream& librados::operator<<(std::ostream& out,
+ const librados::PlacementGroup& pg)
+{
+ return out << pg.impl->pgid;
+}
+
+namespace {
+ int decode_json(JSONObj *obj, pg_t& pg)
+ {
+ string pg_str;
+ JSONDecoder::decode_json("pgid", pg_str, obj);
+ if (pg.parse(pg_str.c_str())) {
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ int get_inconsistent_pgs(librados::RadosClient& client,
+ int64_t pool_id,
+ std::vector<librados::PlacementGroup>* pgs)
+ {
+ vector<string> cmd = {
+ "{\"prefix\": \"pg ls\","
+ "\"pool\": " + std::to_string(pool_id) + ","
+ "\"states\": [\"inconsistent\"],"
+ "\"format\": \"json\"}"
+ };
+ bufferlist inbl, outbl;
+ string outstring;
+ int ret = client.mon_command(cmd, inbl, &outbl, &outstring);
+ if (ret) {
+ return ret;
+ }
+ if (!outbl.length()) {
+ // no pg returned
+ return ret;
+ }
+ JSONParser parser;
+ if (!parser.parse(outbl.c_str(), outbl.length())) {
+ return -EINVAL;
+ }
+ if (!parser.is_array()) {
+ return -EINVAL;
+ }
+ vector<string> v = parser.get_array_elements();
+ for (auto i : v) {
+ JSONParser pg_json;
+ if (!pg_json.parse(i.c_str(), i.length())) {
+ return -EINVAL;
+ }
+ librados::PlacementGroup pg;
+ if (decode_json(&pg_json, pg.impl->pgid)) {
+ return -EINVAL;
+ }
+ pgs->emplace_back(pg);
+ }
+ return 0;
+ }
+}
+
+int librados::Rados::get_inconsistent_pgs(int64_t pool_id,
+ std::vector<PlacementGroup>* pgs)
+{
+ return ::get_inconsistent_pgs(*client, pool_id, pgs);
+}
+
int librados::Rados::wait_for_latest_osdmap()
{
return client->wait_for_latest_osdmap();
return retval;
}
+CEPH_RADOS_API int rados_inconsistent_pg_list(rados_t cluster, int64_t pool_id,
+ char *buf, size_t len)
+{
+ tracepoint(librados, rados_inconsistent_pg_list_enter, cluster, len);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ std::vector<librados::PlacementGroup> pgs;
+ int r = ::get_inconsistent_pgs(*client, pool_id, &pgs);
+ if (r < 0) {
+ tracepoint(librados, rados_inconsistent_pg_list_exit, r);
+ return r;
+ }
+
+ if (len > 0 && !buf) {
+ tracepoint(librados, rados_inconsistent_pg_list_exit, -EINVAL);
+ return -EINVAL;
+ }
+
+ char *b = buf;
+ if (b)
+ memset(b, 0, len);
+ int needed = 0;
+ for (const auto pg : pgs) {
+ std::ostringstream ss;
+ ss << pg;
+ auto s = ss.str();
+ unsigned rl = s.length() + 1;
+ if (len >= rl) {
+ tracepoint(librados, rados_inconsistent_pg_list_pg, p);
+ strncat(b, s.c_str(), rl);
+ b += rl;
+ len -= rl;
+ }
+ needed += rl;
+ }
+ int retval = needed + 1;
+ tracepoint(librados, rados_inconsistent_pg_list_exit, retval);
+ return retval;
+}
+
static void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen)
{
if (outbuf) {