#include "include/rados/librados.hpp"
+#include "mds/JournalPointer.h"
#include "JournalScanner.h"
{
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;
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) {
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
*/
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());
}
/**
- * 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;
}
io(io_),
rank(rank_),
filter(filter_),
+ pointer_present(false),
+ pointer_valid(false),
header_present(false),
header_valid(false),
header(NULL) {};
int rank_) :
io(io_),
rank(rank_),
+ pointer_present(false),
+ pointer_valid(false),
header_present(false),
header_valid(false),
header(NULL) {};
~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) {}
};
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;
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 {
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;
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;
* 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
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);