From: dongdong tao Date: Sun, 10 Dec 2017 07:21:28 +0000 (+0800) Subject: cephfs-journal-tool: support purge queue X-Git-Tag: v13.0.2~171^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=63efbd9280c7d0892a3687292803566106c8ce55;p=ceph.git cephfs-journal-tool: support purge queue Add option "--journal" to identify the journal type. this patch can fully support mode "journal" and "header" for purge queue. As mode "event" is only specific for "mdlog", "journal" and "header" mode only contain pure "Journaler" operation. Signed-off-by: dongdong tao --- diff --git a/src/tools/cephfs/Dumper.cc b/src/tools/cephfs/Dumper.cc index 22ef544a8f36..67252eaa326f 100644 --- a/src/tools/cephfs/Dumper.cc +++ b/src/tools/cephfs/Dumper.cc @@ -33,7 +33,7 @@ #define HEADER_LEN 4096 -int Dumper::init(mds_role_t role_) +int Dumper::init(mds_role_t role_, const std::string &type) { role = role_; @@ -45,15 +45,21 @@ int Dumper::init(mds_role_t role_) auto fs = fsmap->get_filesystem(role.fscid); assert(fs != nullptr); - JournalPointer jp(role.rank, fs->mds_map.get_metadata_pool()); - int jp_load_result = jp.load(objecter); - if (jp_load_result != 0) { - std::cerr << "Error loading journal: " << cpp_strerror(jp_load_result) << std::endl; - return jp_load_result; + if (type == "mdlog") { + JournalPointer jp(role.rank, fs->mds_map.get_metadata_pool()); + int jp_load_result = jp.load(objecter); + if (jp_load_result != 0) { + std::cerr << "Error loading journal: " << cpp_strerror(jp_load_result) << std::endl; + return jp_load_result; + } else { + ino = jp.front; + } + } else if (type == "purge_queue") { + ino = MDS_INO_PURGE_QUEUE + role.rank; } else { - ino = jp.front; - return 0; + ceph_abort(); // should not get here } + return 0; } diff --git a/src/tools/cephfs/Dumper.h b/src/tools/cephfs/Dumper.h index f95a06290dbe..aad7b3e10a59 100644 --- a/src/tools/cephfs/Dumper.h +++ b/src/tools/cephfs/Dumper.h @@ -36,7 +36,7 @@ public: Dumper() : ino(-1) {} - int init(mds_role_t role_); + int init(mds_role_t role_, const std::string &type); int recover_journal(Journaler *journaler); int dump(const char *dumpfile); int undump(const char *dumpfile); diff --git a/src/tools/cephfs/JournalScanner.cc b/src/tools/cephfs/JournalScanner.cc index 7c359a9c4355..cb2ea244a09d 100644 --- a/src/tools/cephfs/JournalScanner.cc +++ b/src/tools/cephfs/JournalScanner.cc @@ -16,6 +16,7 @@ #include "mds/JournalPointer.h" #include "mds/events/ESubtreeMap.h" +#include "mds/PurgeQueue.h" #include "JournalScanner.h" @@ -33,12 +34,12 @@ int JournalScanner::scan(bool const full) { int r = 0; - r = scan_pointer(); + r = set_journal_ino(); if (r < 0) { return r; } - if (pointer_present) { + if (!is_mdlog || pointer_present) { r = scan_header(); if (r < 0) { return r; @@ -56,6 +57,22 @@ int JournalScanner::scan(bool const full) } +int JournalScanner::set_journal_ino() +{ + int r = 0; + if (type == "purge_queue") { + ino = MDS_INO_PURGE_QUEUE + rank; + } + else if (type == "mdlog"){ + r = scan_pointer(); + is_mdlog = true; + } + else { + ceph_abort(); // should not get here + } + return r; +} + int JournalScanner::scan_pointer() { // Issue read @@ -257,36 +274,52 @@ int JournalScanner::scan_events() read_offset += consumed; break; } - - LogEvent *le = LogEvent::decode(le_bl); - - if (le) { - dout(10) << "Valid entry at 0x" << std::hex << read_offset << std::dec << dendl; - - if (le->get_type() == EVENT_SUBTREEMAP - || le->get_type() == EVENT_SUBTREEMAP_TEST) { - ESubtreeMap *sle = dynamic_cast(le); - if (sle->expire_pos > read_offset) { - errors.insert(std::make_pair( - read_offset, EventError( - -ERANGE, - "ESubtreeMap has expire_pos ahead of its own position"))); + bool valid_entry = true; + if (is_mdlog) { + LogEvent *le = LogEvent::decode(le_bl); + + if (le) { + dout(10) << "Valid entry at 0x" << std::hex << read_offset << std::dec << dendl; + + if (le->get_type() == EVENT_SUBTREEMAP + || le->get_type() == EVENT_SUBTREEMAP_TEST) { + ESubtreeMap *sle = dynamic_cast(le); + if (sle->expire_pos > read_offset) { + errors.insert(std::make_pair( + read_offset, EventError( + -ERANGE, + "ESubtreeMap has expire_pos ahead of its own position"))); + } } - } - if (filter.apply(read_offset, *le)) { - events[read_offset] = EventRecord(le, consumed); + if (filter.apply(read_offset, *le)) { + events[read_offset] = EventRecord(le, consumed); + } else { + delete le; + } } else { - delete le; + valid_entry = false; } - events_valid.push_back(read_offset); - read_offset += consumed; + } else if (type == "purge_queue"){ + PurgeItem pi; + try { + bufferlist::iterator q = le_bl.begin(); + ::decode(pi, q); + } catch (const buffer::error &err) { + valid_entry = false; + } } else { + ceph_abort(); // should not get here + } + if (!valid_entry) { dout(10) << "Invalid entry at 0x" << std::hex << read_offset << std::dec << dendl; gap = true; gap_start = read_offset; read_offset += consumed; break; + } else { + events_valid.push_back(read_offset); + read_offset += consumed; } } } @@ -325,7 +358,7 @@ JournalScanner::~JournalScanner() */ bool JournalScanner::is_healthy() const { - return (pointer_present && pointer_valid + return ((!is_mdlog || (pointer_present && pointer_valid)) && header_present && header_valid && ranges_invalid.empty() && objects_missing.empty()); @@ -367,12 +400,13 @@ void JournalScanner::report(std::ostream &out) const { out << "Overall journal integrity: " << (is_healthy() ? "OK" : "DAMAGED") << std::endl; - if (!pointer_present) { - out << "Pointer not found" << std::endl; - } else if (!pointer_valid) { - out << "Pointer could not be decoded" << std::endl; + if (is_mdlog) { + if (!pointer_present) { + out << "Pointer not found" << std::endl; + } else if (!pointer_valid) { + out << "Pointer could not be decoded" << std::endl; + } } - if (!header_present) { out << "Header not found" << std::endl; } else if (!header_valid) { diff --git a/src/tools/cephfs/JournalScanner.h b/src/tools/cephfs/JournalScanner.h index e6aaa05e11e2..dad7dc5ac65c 100644 --- a/src/tools/cephfs/JournalScanner.h +++ b/src/tools/cephfs/JournalScanner.h @@ -36,6 +36,7 @@ class JournalScanner // Input constraints const int rank; + std::string type; JournalFilter const filter; void gap_advance(); @@ -44,10 +45,13 @@ class JournalScanner JournalScanner( librados::IoCtx &io_, int rank_, + const std::string &type_, JournalFilter const &filter_) : io(io_), rank(rank_), + type(type_), filter(filter_), + is_mdlog(false), pointer_present(false), pointer_valid(false), header_present(false), @@ -56,9 +60,12 @@ class JournalScanner JournalScanner( librados::IoCtx &io_, - int rank_) : + int rank_, + const std::string &type_) : io(io_), rank(rank_), + type(type_), + is_mdlog(false), pointer_present(false), pointer_valid(false), header_present(false), @@ -67,6 +74,7 @@ class JournalScanner ~JournalScanner(); + int set_journal_ino(); int scan(bool const full=true); int scan_pointer(); int scan_header(); @@ -77,7 +85,7 @@ class JournalScanner std::string obj_name(inodeno_t ino, uint64_t offset) const; // The results of the scan - inodeno_t ino; // Corresponds to JournalPointer.front + inodeno_t ino; // Corresponds to journal ino according their type class EventRecord { public: EventRecord() : log_event(NULL), raw_size(0) {} @@ -97,8 +105,9 @@ class JournalScanner typedef std::map EventMap; typedef std::map ErrorMap; typedef std::pair Range; - bool pointer_present; - bool pointer_valid; + bool is_mdlog; + bool pointer_present; //mdlog specific + bool pointer_valid; //mdlog specific bool header_present; bool header_valid; Journaler::Header *header; diff --git a/src/tools/cephfs/JournalTool.cc b/src/tools/cephfs/JournalTool.cc index 4a30634f40a0..2af6a918c3fa 100644 --- a/src/tools/cephfs/JournalTool.cc +++ b/src/tools/cephfs/JournalTool.cc @@ -64,7 +64,10 @@ void JournalTool::usage() << "General options:\n" << " --rank=filesystem:mds-rank Journal rank (required if multiple\n" << " file systems, default is rank 0 on\n" - << " the only filesystem otherwise.\n" + << " the only filesystem otherwise.)\n" + << " --journal= Journal type (purge_queue means\n" + << " this journal is used to queue for purge operation,\n" + << " default is mdlog, and only mdlog support event mode)\n" << "\n" << "Special options\n" << " --alternate-pool Alternative metadata pool to target\n" @@ -92,12 +95,23 @@ int JournalTool::main(std::vector &argv) std::vector::iterator arg = argv.begin(); std::string rank_str; - if(!ceph_argparse_witharg(argv, arg, &rank_str, "--rank", (char*)NULL)) { + if (!ceph_argparse_witharg(argv, arg, &rank_str, "--rank", (char*)NULL)) { // Default: act on rank 0. Will give the user an error if they // try invoking this way when they have more than one filesystem. rank_str = "0"; } + if (!ceph_argparse_witharg(argv, arg, &type, "--journal", (char*)NULL)) { + // Default is mdlog + type = "mdlog"; + } + + r = validate_type(type); + if (r != 0) { + derr << "journal type is not correct." << dendl; + return r; + } + r = role_selector.parse(*fsmap, rank_str); if (r != 0) { derr << "Couldn't determine MDS rank." << dendl; @@ -145,6 +159,8 @@ int JournalTool::main(std::vector &argv) // Execution // ========= + // journal and header are general journal mode + // event mode is only specific for mdlog for (auto role : role_selector.get_roles()) { rank = role.rank; dout(4) << "Executing for rank " << rank << dendl; @@ -152,7 +168,7 @@ int JournalTool::main(std::vector &argv) r = main_journal(argv); } else if (mode == std::string("header")) { r = main_header(argv); - } else if (mode == std::string("event")) { + } else if (type == std::string("mdlog") && mode == std::string("event")) { r = main_event(argv); } else { derr << "Bad command '" << mode << "'" << dendl; @@ -168,6 +184,13 @@ int JournalTool::main(std::vector &argv) return r; } +int JournalTool::validate_type(const std::string &type) +{ + if (type == "mdlog" || type == "purge_queue") { + return 0; + } + return -1; +} /** * Handle arguments for 'journal' mode @@ -218,7 +241,7 @@ int JournalTool::main_journal(std::vector &argv) int JournalTool::main_header(std::vector &argv) { JournalFilter filter; - JournalScanner js(input, rank, filter); + JournalScanner js(input, rank, type, filter); int r = js.scan(false); if (r < 0) { std::cerr << "Unable to scan journal" << std::endl; @@ -369,7 +392,7 @@ int JournalTool::main_event(std::vector &argv) // Execute command // =============== - JournalScanner js(input, rank, filter); + JournalScanner js(input, rank, type, filter); if (command == "get") { r = js.scan(); if (r) { @@ -516,7 +539,7 @@ int JournalTool::journal_inspect() int r; JournalFilter filter; - JournalScanner js(input, rank, filter); + JournalScanner js(input, rank, type, filter); r = js.scan(); if (r) { std::cerr << "Failed to scan journal (" << cpp_strerror(r) << ")" << std::endl; @@ -540,7 +563,7 @@ int JournalTool::journal_inspect() int JournalTool::journal_export(std::string const &path, bool import) { int r = 0; - JournalScanner js(input, rank); + JournalScanner js(input, rank, type); if (!import) { /* @@ -563,7 +586,7 @@ int JournalTool::journal_export(std::string const &path, bool import) */ { Dumper dumper; - r = dumper.init(mds_role_t(role_selector.get_ns(), rank)); + r = dumper.init(mds_role_t(role_selector.get_ns(), rank), type); if (r < 0) { derr << "dumper::init failed: " << cpp_strerror(r) << dendl; return r; @@ -586,16 +609,16 @@ int JournalTool::journal_reset(bool hard) { int r = 0; Resetter resetter; - r = resetter.init(); + r = resetter.init(mds_role_t(role_selector.get_ns(), rank), type, hard); if (r < 0) { derr << "resetter::init failed: " << cpp_strerror(r) << dendl; return r; } if (hard) { - r = resetter.reset_hard(mds_role_t(role_selector.get_ns(), rank)); + r = resetter.reset_hard(); } else { - r = resetter.reset(mds_role_t(role_selector.get_ns(), rank)); + r = resetter.reset(); } return r; diff --git a/src/tools/cephfs/JournalTool.h b/src/tools/cephfs/JournalTool.h index d3944144ddcf..c31203f7369e 100644 --- a/src/tools/cephfs/JournalTool.h +++ b/src/tools/cephfs/JournalTool.h @@ -37,6 +37,8 @@ class JournalTool : public MDSUtility // Bit hacky, use this `rank` member to control behaviour of the // various main_ functions. mds_rank_t rank; + + std::string type; // Entry points int main_journal(std::vector &argv); @@ -78,6 +80,8 @@ class JournalTool : public MDSUtility bufferlist *out_bl); int consume_inos(const std::set &inos); + //validate type + int validate_type(const std::string &type); public: void usage(); JournalTool() : diff --git a/src/tools/cephfs/Resetter.cc b/src/tools/cephfs/Resetter.cc index 32ada622982c..cbc9a353ce1b 100644 --- a/src/tools/cephfs/Resetter.cc +++ b/src/tools/cephfs/Resetter.cc @@ -26,7 +26,50 @@ #define dout_context g_ceph_context #define dout_subsys ceph_subsys_mds -int Resetter::reset(mds_role_t role) +int Resetter::init(mds_role_t role_, const std::string &type, bool hard) +{ + role = role_; + int r = MDSUtility::init(); + if (r < 0) { + return r; + } + + auto fs = fsmap->get_filesystem(role.fscid); + assert(nullptr != fs); + + is_mdlog = false; + if (type == "mdlog") { + JournalPointer jp(role.rank, fs->mds_map.get_metadata_pool()); + int rt = 0; + if (hard) { + jp.front = role.rank + MDS_INO_LOG_OFFSET; + jp.back = 0; + rt = jp.save(objecter); + if (rt != 0) { + derr << "Error writing journal pointer: " << cpp_strerror(rt) << dendl; + return rt; + } + ino = jp.front; // only need to reset ino for mdlog + } else { + rt = jp.load(objecter); + if (rt != 0) { + std::cerr << "Error loading journal: " << cpp_strerror(rt) << + ", pass --force to forcibly reset this journal" << std::endl; + return rt; + } else { + ino = jp.front; + } + } + is_mdlog = true; + } else if (type == "purge_queue") { + ino = MDS_INO_PURGE_QUEUE + role.rank; + } else { + ceph_abort(); // should not get here + } + return 0; +} + +int Resetter::reset() { Mutex mylock("Resetter::reset::lock"); Cond cond; @@ -35,18 +78,9 @@ int Resetter::reset(mds_role_t role) auto fs = fsmap->get_filesystem(role.fscid); assert(fs != nullptr); - int64_t const pool_id = fs->mds_map.get_metadata_pool(); - - JournalPointer jp(role.rank, pool_id); - int jp_load_result = jp.load(objecter); - if (jp_load_result != 0) { - std::cerr << "Error loading journal: " << cpp_strerror(jp_load_result) << - ", pass --force to forcibly reset this journal" << std::endl; - return jp_load_result; - } - Journaler journaler("resetter", jp.front, - pool_id, + Journaler journaler("resetter", ino, + fs->mds_map.get_metadata_pool(), CEPH_FS_ONDISK_MAGIC, objecter, 0, 0, &finisher); @@ -101,34 +135,24 @@ int Resetter::reset(mds_role_t role) if (r != 0) { return r; } - - r = _write_reset_event(&journaler); - if (r != 0) { - return r; + + if (is_mdlog) { + r = _write_reset_event(&journaler); // reset envent is specific for mdlog journal + if (r != 0) { + return r; + } } - cout << "done" << std::endl; return 0; } -int Resetter::reset_hard(mds_role_t role) +int Resetter::reset_hard() { auto fs = fsmap->get_filesystem(role.fscid); - assert(fs != nullptr); - int64_t const pool_id = fs->mds_map.get_metadata_pool(); - - JournalPointer jp(role.rank, pool_id); - jp.front = role.rank + MDS_INO_LOG_OFFSET; - jp.back = 0; - int r = jp.save(objecter); - if (r != 0) { - derr << "Error writing journal pointer: " << cpp_strerror(r) << dendl; - return r; - } - - Journaler journaler("resetter", jp.front, - pool_id, + + Journaler journaler("resetter", ino, + fs->mds_map.get_metadata_pool(), CEPH_FS_ONDISK_MAGIC, objecter, 0, 0, &finisher); journaler.set_writeable(); @@ -142,23 +166,29 @@ int Resetter::reset_hard(mds_role_t role) Mutex::Locker l(lock); journaler.write_head(&cond); } - r = cond.wait(); + + int r = cond.wait(); if (r != 0) { derr << "Error writing journal header: " << cpp_strerror(r) << dendl; return r; } - + + if (is_mdlog) // reset event is specific for mdlog journal { Mutex::Locker l(lock); r = _write_reset_event(&journaler); + if (r != 0) { + derr << "Error writing EResetJournal: " << cpp_strerror(r) << dendl; + return r; + } } - if (r != 0) { - derr << "Error writing EResetJournal: " << cpp_strerror(r) << dendl; - return r; + + if (is_mdlog) { + dout(4) << "Successfully wrote new journal pointer and header for rank " + << role << dendl; + } else { + dout(4) << "Successfully wrote header for rank " << role << dendl; } - - dout(4) << "Successfully wrote new journal pointer and header for rank " - << role << dendl; return 0; } diff --git a/src/tools/cephfs/Resetter.h b/src/tools/cephfs/Resetter.h index 115f6ffeecbc..6998e4598f4c 100644 --- a/src/tools/cephfs/Resetter.h +++ b/src/tools/cephfs/Resetter.h @@ -26,18 +26,25 @@ class Journaler; * of the file to dump to. */ class Resetter : public MDSUtility { +private: + mds_role_t role; + inodeno_t ino; + bool is_mdlog; + protected: int _write_reset_event(Journaler *journaler); public: Resetter() {} + ~Resetter() {} + int init(mds_role_t role_, const std::string &type, bool hard); /** * For use when no journal header/pointer was present: write one * out from scratch. */ - int reset_hard(mds_role_t role); - int reset(mds_role_t role); + int reset_hard(); + int reset(); }; #endif /* JOURNAL_RESETTER_H_ */