From 1688debf7892d36c773c12d7d0b1b9b4cddc5f98 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 --- 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 aea0bb96a50c9..ffa8672ff3713 100755 --- a/src/test/ceph_objectstore_tool.py +++ b/src/test/ceph_objectstore_tool.py @@ -1072,6 +1072,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 12ae5aa6e0aed..a7aa0d1e07b7c 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -254,10 +254,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; @@ -1439,10 +1443,11 @@ int ObjectStoreTool::do_import(ObjectStore *store, OSDSuperblock& sb, 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 { @@ -1839,31 +1844,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) @@ -1881,7 +1940,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 << " can be a JSON object description as displayed" << std::endl; cerr << "by --op list." << std::endl; @@ -1922,6 +1981,7 @@ int main(int argc, char **argv) bool human_readable; bool force; Formatter *formatter; + bool head; po::options_description desc("Allowed options"); desc.add_options() @@ -1947,6 +2007,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") ; @@ -2004,6 +2065,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()); @@ -2238,7 +2301,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 { @@ -2525,7 +2588,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; } @@ -2782,7 +2845,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