]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-objectstore-tool: add a way to split filestore directories offline 11253/head
authorJosh Durgin <jdurgin@redhat.com>
Fri, 5 Aug 2016 18:45:00 +0000 (11:45 -0700)
committerJosh Durgin <jdurgin@redhat.com>
Thu, 29 Sep 2016 00:57:21 +0000 (17:57 -0700)
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 <jdurgin@redhat.com>
(cherry picked from commit e7b0428e0e8d8f5459311dc698d94a3ac4f04684)

Conflicts:
src/tools/ceph_objectstore_tool.cc
* remove c++11 auto usage
* change HashIndex::list_subdirs() call to use set instead of vector
* adjust to hammer signature of coll_t::is_pg()

src/os/CollectionIndex.h
src/os/FileStore.cc
src/os/FileStore.h
src/os/HashIndex.cc
src/os/HashIndex.h
src/tools/ceph_objectstore_tool.cc

index cf808c39c9e7ee6ae1e37f40034ffe54d0241ab6..9a2464cbd0a1f6927a55e0f1308781200c0ce88c 100644 (file)
@@ -197,6 +197,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() {}
 };
index c7f9bea31a9e3303bc43d4c276952f574bc578a1..cbf5cba0fc3fba5bfd42ddef3b77d6d114189350 100644 (file)
@@ -5403,6 +5403,21 @@ void FileStore::set_xattr_limits_via_conf()
     m_filestore_max_inline_xattrs = fs_xattrs;
 }
 
+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
index a9291b743c9bc3b214d8bb1cdb86fa04a6fa2239..c085aa1ed085a4fe784386c021a8bb3695383880 100644 (file)
@@ -655,6 +655,8 @@ public:
   void dump_stop();
   void dump_transactions(list<ObjectStore::Transaction*>& ls, uint64_t seq, OpSequencer *osr);
 
+  virtual int apply_layout_settings(const coll_t &cid);
+
 private:
   void _inject_failure();
 
index ead95b4024e60beb489097c8df7eb751e4cdef10..d785973a76664e1cb7c2673d09496ee3b45065e6 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "HashIndex.h"
 
+#include "common/errno.h"
 #include "common/debug.h"
 #define dout_subsys ceph_subsys_filestore
 
@@ -240,6 +241,59 @@ int HashIndex::_split(
     &mkdirred);
 }
 
+int HashIndex::split_dirs(const vector<string> &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;
+    }
+  }
+
+  set<string> subdirs;
+  r = list_subdirs(path, &subdirs);
+  if (r < 0) {
+    dout(10) << "error listing subdirs of " << path << ": "
+            << cpp_strerror(r) << dendl;
+    return r;
+  }
+  for (set<string>::const_iterator it = subdirs.begin();
+       it != subdirs.end(); ++it) {
+    vector<string> 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<string> 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<string> path;
index dad8ce31b8700e8a0156517e576ae5df88151dc7..a9ef11f458954deeaf01f4dcfa39afeda61a45d9 100644 (file)
@@ -159,6 +159,9 @@ public:
     CollectionIndex* dest
     );
 
+  /// @see CollectionIndex
+  virtual int apply_layout_settings();
+
 protected:
   int _init();
 
@@ -376,6 +379,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<string>& path, int level);
+
+  /// split each dir below the given path
+  int split_dirs(const vector<string> &path);
 };
 
 #endif
index de791196e34bd1ec72835172fb4b8df400341684..a30334f76984826b7bb3923abb31b483d9ee02c4 100644 (file)
@@ -3075,9 +3075,76 @@ 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<FileStore*>(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<coll_t> collections, filtered_colls;
+  r = os->list_collections(collections);
+  if (r < 0) {
+    cerr << "Error listing collections: " << cpp_strerror(r) << std::endl;
+    return r;
+  }
+
+  for (vector<coll_t>::const_iterator it = collections.begin();
+       it != collections.end(); ++it) {
+    spg_t coll_pgid;
+    snapid_t snapid;
+    if (it->is_pg(coll_pgid, snapid) &&
+       ((poolid >= 0 && coll_pgid.pool() == (uint64_t)poolid) ||
+        coll_pgid == pgid)) {
+      filtered_colls.push_back(*it);
+    }
+  }
+
+  size_t done = 0, total = filtered_colls.size();
+  for (vector<coll_t>::const_iterator it = filtered_colls.begin();
+       it != filtered_colls.end(); ++it) {
+    if (dry_run) {
+      cerr << "Would apply layout settings to " << *it << std::endl;
+    } else {
+      cerr << "Finished " << done << "/" << total << " collections" << "\r";
+      r = fs->apply_layout_settings(*it);
+      if (r < 0) {
+       cerr << "Error applying layout settings to " << *it << 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, object, objcmd, arg1, arg2, type, format;
+  string dpath, jpath, pgidstr, op, file, object, objcmd, arg1, arg2, type, format, pool;
   spg_t pgid;
   unsigned epoch = 0;
   ghobject_t ghobj;
@@ -3096,10 +3163,12 @@ int main(int argc, char **argv)
     ("journal-path", po::value<string>(&jpath),
      "path to journal, mandatory for filestore type")
     ("pgid", po::value<string>(&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<string>(&pool),
+     "Pool name, mandatory for apply-layout-settings if --pgid is not specified")
     ("op", po::value<string>(&op),
      "Arg is one of [info, log, remove, export, import, list, fix-lost, list-pgs, rm-past-intervals, set-allow-sharded-objects, 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<unsigned>(&epoch),
      "epoch# for get-osdmap and get-inc-osdmap, the current epoch in use if not specified")
     ("file", po::value<string>(&file),
@@ -3246,6 +3315,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);
@@ -3429,6 +3504,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.