// ----------------------------------------------------------------------
// File: quarkdb-validate-checkpoint.cc
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2020 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "../deps/CLI11.hpp"
#include "utils/FileUtils.hh"
#include "ShardDirectory.hh"
#include "StateMachine.hh"
#include "raft/RaftJournal.hh"
#define SSTR(message) static_cast(std::ostringstream().flush() << message).str()
struct PathValidator : public CLI::Validator {
PathValidator() : Validator("PATH") {
func_ = [](const std::string &path) {
std::string err;
if(!quarkdb::directoryExists(path, err)) {
return SSTR("'" << path << "' does not exist.");
}
return std::string();
};
}
};
int main(int argc, char** argv) {
//----------------------------------------------------------------------------
// Setup variables
//----------------------------------------------------------------------------
CLI::App app("Tool to validate QuarkDB checkpoints (backups)");
PathValidator pathValidator;
std::string optPath;
bool acceptStandalone = false;
bool eos = false;
//----------------------------------------------------------------------------
// Setup options
//----------------------------------------------------------------------------
app.add_option("--path", optPath, "The path to the QuarkDB checkpoint")
->required()
->check(pathValidator);
app.add_flag("--accept-standalone", acceptStandalone, "No need to ensure that the raft journal is present -- use this flag for standalone instances");
app.add_flag("--eos", eos, "This QuarkDB instance contains the EOS namespace; additionally check eos-file-md and eos-container-md");
//----------------------------------------------------------------------------
// Parse
//----------------------------------------------------------------------------
try {
app.parse(argc, argv);
} catch (const CLI::ParseError &e) {
return app.exit(e);
}
//----------------------------------------------------------------------------
// Can we set-up a ShardDirectory?
//----------------------------------------------------------------------------
qdb_info("Attempting to open ShardDirectory...");
quarkdb::ShardDirectory shardDirectory(optPath);
qdb_info("--- OK!");
//----------------------------------------------------------------------------
// Can we open the StateMachine?
//----------------------------------------------------------------------------
qdb_info("Attempting to open StateMachine...");
quarkdb::StateMachine *stateMachine = shardDirectory.getStateMachine();
qdb_info("--- OK! LAST-APPLIED: " << stateMachine->getLastApplied());
//----------------------------------------------------------------------------
// Check eos namespace parameters?
//----------------------------------------------------------------------------
if(eos) {
size_t len = 0;
rocksdb::Status st = stateMachine->lhlen("eos-file-md", len);
if(!st.ok()) {
qdb_error("Status not ok when retrieving eos-file-md: " << st.ToString());
return 1;
}
if(len == 0) {
qdb_error("eos-file-md length is zero!");
return 1;
}
qdb_info("eos-file-md length: " << len);
st = stateMachine->lhlen("eos-container-md", len);
if(!st.ok()) {
qdb_error("Status not ok when retrieving eos-container-md: " << st.ToString());
return 1;
}
if(len == 0) {
qdb_error("eos-container-md length is zero!");
return 1;
}
qdb_info("eos-container-md length: " << len);
}
//----------------------------------------------------------------------------
// Does the raft journal directory even exist?
//----------------------------------------------------------------------------
std::string err;
if(!shardDirectory.hasRaftJournal(err)) {
if(acceptStandalone) {
qdb_info("raft-journal directory not found, likely a standalone instance");
return 0;
}
qdb_error("raft-journal not found!");
return 1;
}
//----------------------------------------------------------------------------
// Yes, let's open it
//----------------------------------------------------------------------------
qdb_info("Attempting to open RaftJournal...");
quarkdb::RaftJournal *raftJournal = shardDirectory.getRaftJournal();
qdb_info("--- OK! LOG-SIZE: " << raftJournal->getLogSize() << ", COMMIT-INDEX: " << raftJournal->getCommitIndex() << ", LOG-START: " << raftJournal->getLogStart());
//----------------------------------------------------------------------------
// Ensure LAST-APPLIED makes sense
//----------------------------------------------------------------------------
if(stateMachine->getLastApplied() > raftJournal->getCommitIndex()) {
qdb_error("LAST-APPLIED does not make sense given the current COMMIT-INDEX!");
return 1;
}
if(stateMachine->getLastApplied() < raftJournal->getLogStart()) {
qdb_error("LAST-APPLIED does not make sense given the current LOG-START!");
return 1;
}
return 0;
}