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 <tdd21151186@gmail.com>
#define HEADER_LEN 4096
-int Dumper::init(mds_role_t role_)
+int Dumper::init(mds_role_t role_, const std::string &type)
{
role = 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;
}
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);
#include "mds/JournalPointer.h"
#include "mds/events/ESubtreeMap.h"
+#include "mds/PurgeQueue.h"
#include "JournalScanner.h"
{
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;
}
+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
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<ESubtreeMap*>(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<ESubtreeMap*>(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;
}
}
}
*/
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());
{
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) {
// Input constraints
const int rank;
+ std::string type;
JournalFilter const filter;
void gap_advance();
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),
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),
~JournalScanner();
+ int set_journal_ino();
int scan(bool const full=true);
int scan_pointer();
int scan_header();
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) {}
typedef std::map<uint64_t, EventRecord> EventMap;
typedef std::map<uint64_t, EventError> ErrorMap;
typedef std::pair<uint64_t, uint64_t> 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;
<< "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=<mdlog|purge_queue> 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 <name> Alternative metadata pool to target\n"
std::vector<const char*>::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;
// 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;
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;
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
int JournalTool::main_header(std::vector<const char*> &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;
// Execute command
// ===============
- JournalScanner js(input, rank, filter);
+ JournalScanner js(input, rank, type, filter);
if (command == "get") {
r = js.scan();
if (r) {
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;
int JournalTool::journal_export(std::string const &path, bool import)
{
int r = 0;
- JournalScanner js(input, rank);
+ JournalScanner js(input, rank, type);
if (!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;
{
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;
// 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<const char*> &argv);
bufferlist *out_bl);
int consume_inos(const std::set<inodeno_t> &inos);
+ //validate type
+ int validate_type(const std::string &type);
public:
void usage();
JournalTool() :
#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;
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);
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();
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;
}
* 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_ */