mirror of
https://github.com/ceph/ceph
synced 2025-01-20 10:01:45 +00:00
tools/cephfs: Update for JournalPointer
Signed-off-by: John Spray <john.spray@inktank.com>
This commit is contained in:
parent
d52eeaba42
commit
fc1d6da713
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user