tools/cephfs: Update for JournalPointer

Signed-off-by: John Spray <john.spray@inktank.com>
This commit is contained in:
John Spray 2014-05-12 18:39:33 +01:00
parent d52eeaba42
commit fc1d6da713
4 changed files with 91 additions and 21 deletions

View File

@ -13,6 +13,7 @@
#include "include/rados/librados.hpp"
#include "mds/JournalPointer.h"
#include "JournalScanner.h"
@ -29,11 +30,19 @@ int JournalScanner::scan(bool const full)
{
int r = 0;
r = scan_header();
r = scan_pointer();
if (r < 0) {
return r;
}
if (full) {
if (pointer_present) {
r = scan_header();
if (r < 0) {
return r;
}
}
if (full && header_present) {
r = scan_events();
if (r < 0) {
return r;
@ -43,12 +52,47 @@ int JournalScanner::scan(bool const full)
return 0;
}
int JournalScanner::scan_pointer()
{
// Issue read
std::string const pointer_oid = obj_name(MDS_INO_LOG_POINTER_OFFSET + rank, 0);
bufferlist pointer_bl;
int r = io.read(pointer_oid, pointer_bl, INT_MAX, 0);
if (r == -ENOENT) {
// 'Successfully' discovered the pointer is missing.
derr << "Pointer " << pointer_oid << " is absent" << dendl;
return 0;
} else if (r < 0) {
// Error preventing us interrogating pointer
derr << "Pointer " << pointer_oid << " is unreadable" << dendl;
return r;
} else {
dout(4) << "Pointer " << pointer_oid << " is readable" << dendl;
pointer_present = true;
JournalPointer jp;
try {
bufferlist::iterator q = pointer_bl.begin();
jp.decode(q);
} catch(buffer::error e) {
derr << "Pointer " << pointer_oid << " is corrupt: " << e.what() << dendl;
return 0;
}
pointer_valid = true;
ino = jp.front;
return 0;
}
}
int JournalScanner::scan_header()
{
int r;
bufferlist header_bl;
std::string header_name = obj_name(0, rank);
std::string header_name = obj_name(0);
dout(4) << "JournalScanner::scan: reading header object '" << header_name << "'" << dendl;
r = io.read(header_name, header_bl, INT_MAX, 0);
if (r < 0) {
@ -110,7 +154,7 @@ int JournalScanner::scan_events()
for (uint64_t obj_offset = (read_offset / object_size); ; obj_offset++) {
// Read this journal segment
bufferlist this_object;
std::string const oid = obj_name(obj_offset, rank);
std::string const oid = obj_name(obj_offset);
r = io.read(oid, this_object, INT_MAX, 0);
// Handle absent journal segments
@ -258,7 +302,10 @@ JournalScanner::~JournalScanner()
*/
bool JournalScanner::is_healthy() const
{
return (header_present && header_valid && ranges_invalid.empty() && objects_missing.empty());
return (pointer_present && pointer_valid
&& header_present && header_valid
&& ranges_invalid.empty()
&& objects_missing.empty());
}
@ -272,27 +319,40 @@ bool JournalScanner::is_readable() const
/**
* Calculate the object name for a given offset in a particular MDS's journal
* Calculate the object name for a given offset
*/
std::string JournalScanner::obj_name(uint64_t offset, int const rank)
std::string JournalScanner::obj_name(inodeno_t ino, uint64_t offset) const
{
char header_name[60];
snprintf(header_name, sizeof(header_name), "%llx.%08llx",
(unsigned long long)(MDS_INO_LOG_OFFSET + rank),
char name[60];
snprintf(name, sizeof(name), "%llx.%08llx",
(unsigned long long)(ino),
(unsigned long long)offset);
return std::string(header_name);
return std::string(name);
}
std::string JournalScanner::obj_name(uint64_t offset) const
{
return obj_name(ino, offset);
}
/*
* Write a human readable summary of the journal health
*/
void JournalScanner::report(std::ostream &out) const
{
out << "Overall journal integrity: " << (is_healthy() ? "OK" : "DAMAGED") << std::endl;
if (!header_present) {
out << "Header not found" << std::endl;
if (!pointer_present) {
out << "Pointer not found" << std::endl;
} else if (!pointer_valid) {
out << "Pointer could not be decoded" << std::endl;
}
if (header_present && !header_valid) {
if (!header_present) {
out << "Header not found" << std::endl;
} else if (!header_valid) {
out << "Header could not be decoded" << std::endl;
}

View File

@ -48,6 +48,8 @@ class JournalScanner
io(io_),
rank(rank_),
filter(filter_),
pointer_present(false),
pointer_valid(false),
header_present(false),
header_valid(false),
header(NULL) {};
@ -57,6 +59,8 @@ class JournalScanner
int rank_) :
io(io_),
rank(rank_),
pointer_present(false),
pointer_valid(false),
header_present(false),
header_valid(false),
header(NULL) {};
@ -64,13 +68,16 @@ class JournalScanner
~JournalScanner();
int scan(bool const full=true);
int scan_pointer();
int scan_header();
int scan_events();
void report(std::ostream &out) const;
static std::string obj_name(uint64_t offset, int const rank);
std::string obj_name(uint64_t offset) const;
std::string obj_name(inodeno_t ino, uint64_t offset) const;
// The results of the scan
inodeno_t ino; // Corresponds to JournalPointer.front
class EventRecord {
public:
EventRecord() : log_event(NULL), raw_size(0) {}
@ -80,6 +87,8 @@ class JournalScanner
};
typedef std::map<uint64_t, EventRecord> EventMap;
typedef std::pair<uint64_t, uint64_t> Range;
bool pointer_present;
bool pointer_valid;
bool header_present;
bool header_valid;
Journaler::Header *header;

View File

@ -232,7 +232,7 @@ int JournalTool::main_header(std::vector<const char*> &argv)
dout(4) << "Writing object..." << dendl;
bufferlist header_bl;
::encode(*(js.header), header_bl);
io.write_full(JournalScanner::obj_name(0, rank), header_bl);
io.write_full(js.obj_name(0), header_bl);
dout(4) << "Write complete." << dendl;
std::cout << "Successfully updated header." << std::endl;
} else {
@ -341,7 +341,7 @@ int JournalTool::main_event(std::vector<const char*> &argv)
if (filter.get_range(start, end)) {
// Special case for range filter: erase a numeric range in the log
uint64_t range = end - start;
int r = erase_region(start, range);
int r = erase_region(js, start, range);
if (r) {
derr << "Failed to erase region 0x" << std::hex << start << "~0x" << range << std::dec
<< ": " << cpp_strerror(r) << dendl;
@ -352,7 +352,7 @@ int JournalTool::main_event(std::vector<const char*> &argv)
for (JournalScanner::EventMap::iterator i = js.events.begin(); i != js.events.end(); ++i) {
dout(4) << "Erasing offset 0x" << std::hex << i->first << std::dec << dendl;
int r = erase_region(i->first, i->second.raw_size);
int r = erase_region(js, i->first, i->second.raw_size);
if (r) {
derr << "Failed to erase event 0x" << std::hex << i->first << std::dec
<< ": " << cpp_strerror(r) << dendl;
@ -647,7 +647,7 @@ int JournalTool::replay_offline(EMetaBlob &metablob, bool const dry_run)
* Erase a region of the log by overwriting it with ENoOp
*
*/
int JournalTool::erase_region(uint64_t const pos, uint64_t const length)
int JournalTool::erase_region(JournalScanner const &js, uint64_t const pos, uint64_t const length)
{
// To erase this region, we use our preamble, the encoding overhead
// of an ENoOp, and our trailing start ptr. Calculate how much padding
@ -692,7 +692,7 @@ int JournalTool::erase_region(uint64_t const pos, uint64_t const length)
uint64_t obj_offset = (pos / object_size);
int r = 0;
while(log_data.length()) {
std::string const oid = JournalScanner::obj_name(obj_offset, rank);
std::string const oid = js.obj_name(obj_offset);
uint32_t offset_in_obj = write_offset % object_size;
uint32_t write_len = min(log_data.length(), object_size - offset_in_obj);

View File

@ -22,6 +22,7 @@
#include "JournalFilter.h"
class EMetaBlob;
class JournalScanner;
/**
@ -57,7 +58,7 @@ class JournalTool : public MDSUtility
int replay_offline(EMetaBlob &metablob, bool const dry_run);
// Splicing
int erase_region(uint64_t const pos, uint64_t const length);
int erase_region(JournalScanner const &jp, uint64_t const pos, uint64_t const length);
public:
void usage();