From 53dc87f82642de769a7ea11554552e6db06a3e65 Mon Sep 17 00:00:00 2001 From: David Zafman Date: Wed, 14 Oct 2015 22:04:05 -0700 Subject: [PATCH] ceph-objectstore-tool: Enhanced dump command replaces dump-info Show object stat information from objectstore Show SnapSet if present Add --head for search by object name Signed-off-by: David Zafman (cherry picked from commit 1688debf7892d36c773c12d7d0b1b9b4cddc5f98) --- src/test/ceph_objectstore_tool.py | 22 +++++++ src/tools/ceph_objectstore_tool.cc | 101 ++++++++++++++++++++++++----- 2 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/test/ceph_objectstore_tool.py b/src/test/ceph_objectstore_tool.py index 848444d6ee796..49f28ec883e6c 100755 --- a/src/test/ceph_objectstore_tool.py +++ b/src/test/ceph_objectstore_tool.py @@ -1036,6 +1036,28 @@ def main(argv): except: pass + # Test dump + print "Test dump" + for nspace in db.keys(): + for basename in db[nspace].keys(): + file = os.path.join(DATADIR, nspace + "-" + basename + "__head") + JSON = db[nspace][basename]['json'] + GETNAME = "/tmp/getbytes.{pid}".format(pid=pid) + for pg in OBJREPPGS: + OSDS = get_osds(pg, OSDDIR) + for osd in OSDS: + DIR = os.path.join(OSDDIR, os.path.join(osd, os.path.join("current", "{pg}_head".format(pg=pg)))) + fnames = [f for f in os.listdir(DIR) if os.path.isfile(os.path.join(DIR, f)) + and f.split("_")[0] == basename and f.split("_")[4] == nspace] + if not fnames: + continue + cmd = (CFSD_PREFIX + " '{json}' dump | grep '\"snap\": 1,' > /dev/null").format(osd=osd, json=JSON) + logging.debug(cmd) + ret = call(cmd, shell=True) + if ret != 0: + logging.error("Invalid dump for {json}".format(json=JSON)) + ERRORS += 1 + print "Test list-attrs get-attr" ATTRFILE = r"/tmp/attrs.{pid}".format(pid=pid) VALFILE = r"/tmp/val.{pid}".format(pid=pid) diff --git a/src/tools/ceph_objectstore_tool.cc b/src/tools/ceph_objectstore_tool.cc index 72f830295b4a1..22596428efe19 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -571,10 +571,14 @@ struct pgid_object_list { struct lookup_ghobject : public action_on_object_t { pgid_object_list _objects; const string _name; + bool _need_snapset; - lookup_ghobject(const string& name) : _name(name) { } + lookup_ghobject(const string& name, bool need_snapset = false) : _name(name), + _need_snapset(need_snapset) { } virtual int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) { + if (_need_snapset && !ghobj.hobj.has_snapset()) + return 0; if (_name.length() == 0 || ghobj.hobj.oid.name == _name) _objects.insert(coll, ghobj); return 0; @@ -2273,10 +2277,11 @@ int do_import(ObjectStore *store, OSDSuperblock& sb, bool force, string pgidstr) return 0; } -int do_list(ObjectStore *store, string pgidstr, string object, Formatter *formatter, bool debug, bool human_readable) +int do_list(ObjectStore *store, string pgidstr, string object, + Formatter *formatter, bool debug, bool human_readable, bool head) { int r; - lookup_ghobject lookup(object); + lookup_ghobject lookup(object, head); if (pgidstr.length() > 0) { r = action_on_all_objects_in_pg(store, pgidstr, lookup, debug); } else { @@ -2643,31 +2648,85 @@ struct do_fix_lost : public action_on_object_t { } }; -int print_obj_info(ObjectStore *store, coll_t coll, ghobject_t &ghobj, Formatter* formatter) +int get_snapset(ObjectStore *store, coll_t coll, ghobject_t &ghobj, SnapSet &ss) { bufferlist attr; - int r = store->getattr(coll, ghobj, OI_ATTR, attr); + int r = store->getattr(coll, ghobj, SS_ATTR, attr); if (r < 0) { - cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", " + cerr << "Error getting snapset on : " << make_pair(coll, ghobj) << ", " << cpp_strerror(r) << std::endl; return r; } - object_info_t oi; bufferlist::iterator bp = attr.begin(); try { - ::decode(oi, bp); + ::decode(ss, bp); } catch (...) { r = -EINVAL; - cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", " + cerr << "Error decoding snapset on : " << make_pair(coll, ghobj) << ", " << cpp_strerror(r) << std::endl; return r; } - formatter->open_object_section("info"); - oi.dump(formatter); + return 0; +} + +int print_obj_info(ObjectStore *store, coll_t coll, ghobject_t &ghobj, Formatter* formatter) +{ + int r = 0; + formatter->open_object_section("obj"); + formatter->open_object_section("id"); + ghobj.dump(formatter); + formatter->close_section(); + + bufferlist attr; + int gr = store->getattr(coll, ghobj, OI_ATTR, attr); + if (gr < 0) { + r = gr; + cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", " + << cpp_strerror(r) << std::endl; + } else { + object_info_t oi; + bufferlist::iterator bp = attr.begin(); + try { + ::decode(oi, bp); + formatter->open_object_section("info"); + oi.dump(formatter); + formatter->close_section(); + } catch (...) { + r = -EINVAL; + cerr << "Error decoding attr on : " << make_pair(coll, ghobj) << ", " + << cpp_strerror(r) << std::endl; + } + } + struct stat st; + int sr = store->stat(coll, ghobj, &st, true); + if (sr < 0) { + r = sr; + cerr << "Error stat on : " << make_pair(coll, ghobj) << ", " + << cpp_strerror(r) << std::endl; + } else { + formatter->open_object_section("stat"); + formatter->dump_int("size", st.st_size); + formatter->dump_int("blksize", st.st_blksize); + formatter->dump_int("blocks", st.st_blocks); + formatter->dump_int("nlink", st.st_nlink); + formatter->close_section(); + } + + if (ghobj.hobj.has_snapset()) { + SnapSet ss; + int snr = get_snapset(store, coll, ghobj, ss); + if (snr < 0) { + r = snr; + } else { + formatter->open_object_section("SnapSet"); + ss.dump(formatter); + formatter->close_section(); + } + } formatter->close_section(); formatter->flush(cout); cout << std::endl; - return 0; + return r; } void usage(po::options_description &desc) @@ -2685,7 +2744,7 @@ void usage(po::options_description &desc) cerr << "ceph-objectstore-tool ... list-attrs" << std::endl; cerr << "ceph-objectstore-tool ... list-omap" << std::endl; cerr << "ceph-objectstore-tool ... remove" << std::endl; - cerr << "ceph-objectstore-tool ... dump-info" << std::endl; + cerr << "ceph-objectstore-tool ... dump" << std::endl; cerr << std::endl; cerr << "ceph-objectstore-tool import-rados [file]" << std::endl; cerr << std::endl; @@ -2728,6 +2787,7 @@ int main(int argc, char **argv) bool human_readable, no_overwrite; bool force; Formatter *formatter; + bool head; po::options_description desc("Allowed options"); desc.add_options() @@ -2753,6 +2813,7 @@ int main(int argc, char **argv) ("force", "Ignore some types of errors and proceed with operation - USE WITH CAUTION: CORRUPTION POSSIBLE NOW OR IN THE FUTURE") ("skip-journal-replay", "Disable journal replay") ("skip-mount-omap", "Disable mounting of omap") + ("head", "Find head/snapdir when searching for objects by name") ("dry-run", "Don't modify the objectstore") ("no-overwrite", "For import-rados don't overwrite existing files") ; @@ -2814,6 +2875,8 @@ int main(int argc, char **argv) if (vm.count("skip-mount-omap")) flags |= SKIP_MOUNT_OMAP; + head = (vm.count("head") > 0); + vector ceph_options; env_to_vec(ceph_options); ceph_options.reserve(ceph_options.size() + ceph_option_strings.size()); @@ -3078,7 +3141,7 @@ int main(int argc, char **argv) json_spirit::Value v; try { if (!json_spirit::read(object, v)) { - lookup_ghobject lookup(object); + lookup_ghobject lookup(object, head); if (action_on_all_objects(fs, lookup, debug)) { throw std::runtime_error("Internal error"); } else { @@ -3361,7 +3424,7 @@ int main(int argc, char **argv) } if (op == "list") { - ret = do_list(fs, pgidstr, object, formatter, debug, human_readable); + ret = do_list(fs, pgidstr, object, formatter, debug, human_readable, head); if (ret < 0) { cerr << "do_list failed: " << cpp_strerror(ret) << std::endl; } @@ -3610,7 +3673,13 @@ int main(int argc, char **argv) if (fd != STDIN_FILENO) close(fd); goto out; - } else if (objcmd == "dump-info") { + } else if (objcmd == "dump") { + // There should not be any other arguments + if (vm.count("arg1") || vm.count("arg2")) { + usage(desc); + ret = 1; + goto out; + } ret = print_obj_info(fs, coll, ghobj, formatter); goto out; } -- 2.39.5