From 3cb0a5e0b0517701ad3b44bdf6d4b60d6a51e8ee Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Fri, 5 Aug 2016 11:45:00 -0700 Subject: [PATCH] ceph-objectstore-tool: add a way to split filestore directories offline Use the usual split code, and split each dir that meets the usual split criteria. This can be run with lower than usual split settings, to avoid costly online splits. To make sure the directories are not merged again, use a load merge threshold (e.g. filestore merge threshold = 1), and adjust the split multiplier accordingly. Fixes: http://tracker.ceph.com/issues/17220 Signed-off-by: Josh Durgin (cherry picked from commit e7b0428e0e8d8f5459311dc698d94a3ac4f04684) Conflicts: src/os/filestore/FileStore.cc src/tools/ceph_objectstore_tool.cc (trivial resolution) --- src/os/filestore/CollectionIndex.h | 2 + src/os/filestore/FileStore.cc | 14 +++++ src/os/filestore/FileStore.h | 2 + src/os/filestore/HashIndex.cc | 54 +++++++++++++++++++ src/os/filestore/HashIndex.h | 6 +++ src/tools/ceph_objectstore_tool.cc | 84 ++++++++++++++++++++++++++++-- 6 files changed, 159 insertions(+), 3 deletions(-) diff --git a/src/os/filestore/CollectionIndex.h b/src/os/filestore/CollectionIndex.h index 942dc233e6562..cbdc5d6afdac1 100644 --- a/src/os/filestore/CollectionIndex.h +++ b/src/os/filestore/CollectionIndex.h @@ -190,6 +190,8 @@ protected: uint64_t expected_num_objs ///< [in] expected number of objects this collection has ) { assert(0); return 0; } + virtual int apply_layout_settings() { assert(0); return 0; } + /// Virtual destructor virtual ~CollectionIndex() {} }; diff --git a/src/os/filestore/FileStore.cc b/src/os/filestore/FileStore.cc index 9e183a6f6e42c..ce1cfe262046c 100644 --- a/src/os/filestore/FileStore.cc +++ b/src/os/filestore/FileStore.cc @@ -5731,6 +5731,20 @@ void FileStore::set_xattr_limits_via_conf() } } +int FileStore::apply_layout_settings(const coll_t &cid) +{ + dout(20) << __func__ << " " << cid << dendl; + Index index; + int r = get_index(cid, &index); + if (r < 0) { + dout(10) << "Error getting index for " << cid << ": " << cpp_strerror(r) + << dendl; + return r; + } + + return index->apply_layout_settings(); +} + // -- FSSuperblock -- void FSSuperblock::encode(bufferlist &bl) const diff --git a/src/os/filestore/FileStore.h b/src/os/filestore/FileStore.h index a5cd75d5e5304..d1fd595b99feb 100644 --- a/src/os/filestore/FileStore.h +++ b/src/os/filestore/FileStore.h @@ -686,6 +686,8 @@ public: void dump_stop(); void dump_transactions(vector& ls, uint64_t seq, OpSequencer *osr); + virtual int apply_layout_settings(const coll_t &cid); + private: void _inject_failure(); diff --git a/src/os/filestore/HashIndex.cc b/src/os/filestore/HashIndex.cc index b1bf7024fd218..606e1f57d90b0 100644 --- a/src/os/filestore/HashIndex.cc +++ b/src/os/filestore/HashIndex.cc @@ -19,6 +19,7 @@ #include "HashIndex.h" +#include "common/errno.h" #include "common/debug.h" #define dout_subsys ceph_subsys_filestore @@ -303,6 +304,59 @@ int HashIndex::_split( &mkdirred); } +int HashIndex::split_dirs(const vector &path) { + dout(20) << __func__ << " " << path << dendl; + subdir_info_s info; + int r = get_info(path, &info); + if (r < 0) { + dout(10) << "error looking up info for " << path << ": " + << cpp_strerror(r) << dendl; + return r; + } + + if (must_split(info)) { + r = initiate_split(path, info); + if (r < 0) { + dout(10) << "error initiating split on " << path << ": " + << cpp_strerror(r) << dendl; + return r; + } + + r = complete_split(path, info); + if (r < 0) { + dout(10) << "error completing split on " << path << ": " + << cpp_strerror(r) << dendl; + return r; + } + } + + vector subdirs; + r = list_subdirs(path, &subdirs); + if (r < 0) { + dout(10) << "error listing subdirs of " << path << ": " + << cpp_strerror(r) << dendl; + return r; + } + for (vector::const_iterator it = subdirs.begin(); + it != subdirs.end(); ++it) { + vector subdir_path(path); + subdir_path.push_back(*it); + r = split_dirs(subdir_path); + if (r < 0) { + return r; + } + } + + return r; +} + +int HashIndex::apply_layout_settings() { + vector path; + dout(10) << __func__ << " split multiple = " << split_multiplier + << " merge threshold = " << merge_threshold << dendl; + return split_dirs(path); +} + int HashIndex::_init() { subdir_info_s info; vector path; diff --git a/src/os/filestore/HashIndex.h b/src/os/filestore/HashIndex.h index 461eddcac9366..73150c7cba63a 100644 --- a/src/os/filestore/HashIndex.h +++ b/src/os/filestore/HashIndex.h @@ -160,6 +160,9 @@ public: CollectionIndex* dest ); + /// @see CollectionIndex + virtual int apply_layout_settings(); + protected: int _init(); @@ -432,6 +435,9 @@ private: /// Create the given levels of sub directories from the given root. /// The contents of *path* is not changed after calling this function. int recursive_create_path(vector& path, int level); + + /// split each dir below the given path + int split_dirs(const vector &path); }; #endif diff --git a/src/tools/ceph_objectstore_tool.cc b/src/tools/ceph_objectstore_tool.cc index 74348bcf43b23..980be30f10aad 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -26,6 +26,7 @@ #include "os/ObjectStore.h" #include "os/filestore/FileJournal.h" +#include "os/filestore/FileStore.h" #ifdef HAVE_LIBFUSE #include "os/FuseStore.h" #endif @@ -2202,9 +2203,73 @@ int mydump_journal(Formatter *f, string journalpath, bool m_journal_dio) return r; } +int apply_layout_settings(ObjectStore *os, const OSDSuperblock &superblock, + const string &pool_name, const spg_t &pgid, bool dry_run) +{ + int r = 0; + + FileStore *fs = dynamic_cast(os); + if (!fs) { + cerr << "Nothing to do for non-filestore backend" << std::endl; + return 0; // making this return success makes testing easier + } + + OSDMap curmap; + bufferlist bl; + r = get_osdmap(os, superblock.current_epoch, curmap, bl); + if (r) { + cerr << "Can't find local OSDMap: " << cpp_strerror(r) << std::endl; + return r; + } + + int64_t poolid = -1; + if (pool_name.length()) { + poolid = curmap.lookup_pg_pool_name(pool_name); + if (poolid < 0) { + cerr << "Couldn't find pool " << pool_name << ": " << cpp_strerror(poolid) + << std::endl; + return poolid; + } + } + + vector collections, filtered_colls; + r = os->list_collections(collections); + if (r < 0) { + cerr << "Error listing collections: " << cpp_strerror(r) << std::endl; + return r; + } + + for (auto const &coll : collections) { + spg_t coll_pgid; + if (coll.is_pg(&coll_pgid) && + ((poolid >= 0 && coll_pgid.pool() == (uint64_t)poolid) || + coll_pgid == pgid)) { + filtered_colls.push_back(coll); + } + } + + size_t done = 0, total = filtered_colls.size(); + for (auto const &coll : filtered_colls) { + if (dry_run) { + cerr << "Would apply layout settings to " << coll << std::endl; + } else { + cerr << "Finished " << done << "/" << total << " collections" << "\r"; + r = fs->apply_layout_settings(coll); + if (r < 0) { + cerr << "Error applying layout settings to " << coll << std::endl; + return r; + } + } + ++done; + } + + cerr << "Finished " << total << "/" << total << " collections" << "\r" << std::endl; + return r; +} + int main(int argc, char **argv) { - string dpath, jpath, pgidstr, op, file, mountpoint, object, objcmd, arg1, arg2, type, format; + string dpath, jpath, pgidstr, op, file, mountpoint, object, objcmd, arg1, arg2, type, format, pool; spg_t pgid; unsigned epoch = 0; ghobject_t ghobj; @@ -2223,10 +2288,12 @@ int main(int argc, char **argv) ("journal-path", po::value(&jpath), "path to journal, mandatory for filestore type") ("pgid", po::value(&pgidstr), - "PG id, mandatory for info, log, remove, export, rm-past-intervals, mark-complete") + "PG id, mandatory for info, log, remove, export, rm-past-intervals, mark-complete, and mandatory for apply-layout-settings if --pool is not specified") + ("pool", po::value(&pool), + "Pool name, mandatory for apply-layout-settings if --pgid is not specified") ("op", po::value(&op), "Arg is one of [info, log, remove, mkfs, fsck, fuse, export, import, list, fix-lost, list-pgs, rm-past-intervals, dump-journal, dump-super, meta-list, " - "get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete]") + "get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, apply-layout-settings]") ("epoch", po::value(&epoch), "epoch# for get-osdmap and get-inc-osdmap, the current epoch in use if not specified") ("file", po::value(&file), @@ -2347,6 +2414,12 @@ int main(int argc, char **argv) usage(desc); myexit(1); } + if (op == "apply-layout-settings" && !(vm.count("pool") ^ vm.count("pgid"))) { + cerr << "apply-layout-settings requires either --pool or --pgid" + << std::endl; + usage(desc); + myexit(1); + } if (op != "list" && vm.count("object") && !vm.count("objcmd")) { cerr << "Invalid syntax, missing command" << std::endl; usage(desc); @@ -2539,6 +2612,11 @@ int main(int argc, char **argv) goto out; } + if (op == "apply-layout-settings") { + ret = apply_layout_settings(fs, superblock, pool, pgid, dry_run); + goto out; + } + if (op != "list" && vm.count("object")) { // Special case: Create pgmeta_oid if empty string specified // This can't conflict with any actual object names. -- 2.39.5