Skip to content

Commit

Permalink
ceph-objectstore-tool: add a way to split filestore directories offline
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jdurgin committed Sep 9, 2016
1 parent e354918 commit e7b0428
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/os/filestore/CollectionIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ class CollectionIndex {
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() {}
};
Expand Down
15 changes: 15 additions & 0 deletions src/os/filestore/FileStore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5695,6 +5695,21 @@ uint64_t FileStore::estimate_objects_overhead(uint64_t num_objects)
return res;
}

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
Expand Down
2 changes: 2 additions & 0 deletions src/os/filestore/FileStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,8 @@ class FileStore : public JournalingObjectStore,
void dump_stop();
void dump_transactions(vector<Transaction>& ls, uint64_t seq, OpSequencer *osr);

virtual int apply_layout_settings(const coll_t &cid);

private:
void _inject_failure();

Expand Down
54 changes: 54 additions & 0 deletions src/os/filestore/HashIndex.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "HashIndex.h"

#include "common/errno.h"
#include "common/debug.h"
#define dout_subsys ceph_subsys_filestore

Expand Down Expand Up @@ -303,6 +304,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;
}
}

vector<string> subdirs;
r = list_subdirs(path, &subdirs);
if (r < 0) {
dout(10) << "error listing subdirs of " << path << ": "
<< cpp_strerror(r) << dendl;
return r;
}
for (vector<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;
Expand Down
6 changes: 6 additions & 0 deletions src/os/filestore/HashIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ class HashIndex : public LFNIndex {
CollectionIndex* dest
);

/// @see CollectionIndex
virtual int apply_layout_settings();

protected:
int _init();

Expand Down Expand Up @@ -432,6 +435,9 @@ class HashIndex : public LFNIndex {
/// 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
84 changes: 81 additions & 3 deletions src/tools/ceph_objectstore_tool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "os/ObjectStore.h"
#include "os/filestore/FileJournal.h"
#include "os/filestore/FileStore.h"
#ifdef HAVE_LIBFUSE
#include "os/FuseStore.h"
#endif
Expand Down Expand Up @@ -2259,9 +2260,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<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 (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, argnspace;
string dpath, jpath, pgidstr, op, file, mountpoint, object, objcmd, arg1, arg2, type, format, argnspace, pool;
boost::optional<std::string> nspace;
spg_t pgid;
unsigned epoch = 0;
Expand All @@ -2281,10 +2346,12 @@ int main(int argc, char **argv)
("journal-path", po::value<string>(&jpath),
"path to journal, use if tool can't find it")
("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, 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<unsigned>(&epoch),
"epoch# for get-osdmap and get-inc-osdmap, the current epoch in use if not specified")
("file", po::value<string>(&file),
Expand Down Expand Up @@ -2409,6 +2476,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);
Expand Down Expand Up @@ -2601,6 +2674,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.
Expand Down

0 comments on commit e7b0428

Please sign in to comment.