From: Kefu Chai Date: Fri, 11 Dec 2015 10:13:20 +0000 (+0800) Subject: librados: add get_inconsistent_pgs() to librados X-Git-Tag: v10.1.0~303^2~13 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=cb4efbd72fc31e42a1dca55192e51b6ea4cdecf1;p=ceph.git librados: add get_inconsistent_pgs() to librados to list the inconsistent PGs of given pool, it's a wrapper around the "ceph pg ls" command. Fixes: #13505 Signed-off-by: Kefu Chai --- diff --git a/src/include/rados/librados.h b/src/include/rados/librados.h index 087b4c68a490..0239061cd810 100644 --- a/src/include/rados/librados.h +++ b/src/include/rados/librados.h @@ -614,6 +614,25 @@ CEPH_RADOS_API int rados_wait_for_latest_osdmap(rados_t cluster); */ 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 * diff --git a/src/include/rados/librados.hpp b/src/include/rados/librados.hpp index 22ba38b6180e..e1593db3cbef 100644 --- a/src/include/rados/librados.hpp +++ b/src/include/rados/librados.hpp @@ -1117,6 +1117,17 @@ namespace librados IoCtxImpl *io_ctx_impl; }; + struct PlacementGroupImpl; + struct CEPH_RADOS_API PlacementGroup { + PlacementGroup(); + PlacementGroup(const PlacementGroup&); + ~PlacementGroup(); + bool parse(const char*); + std::unique_ptr impl; + }; + + CEPH_RADOS_API std::ostream& operator<<(std::ostream&, const PlacementGroup&); + class CEPH_RADOS_API Rados { public: @@ -1185,6 +1196,15 @@ namespace librados 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* pgs); + /// get/wait for the most recent osdmap int wait_for_latest_osdmap(); diff --git a/src/librados/librados.cc b/src/librados/librados.cc index e9014b5ac3d9..31b795dc3904 100644 --- a/src/librados/librados.cc +++ b/src/librados/librados.cc @@ -17,6 +17,7 @@ #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" @@ -2301,6 +2302,97 @@ int librados::Rados::cluster_fsid(string *fsid) 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* pgs) + { + vector 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 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* pgs) +{ + return ::get_inconsistent_pgs(*client, pool_id, pgs); +} + int librados::Rados::wait_for_latest_osdmap() { return client->wait_for_latest_osdmap(); @@ -2714,6 +2806,45 @@ extern "C" int rados_pool_list(rados_t cluster, char *buf, size_t len) 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 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) {