93 lines
2.8 KiB
C++
93 lines
2.8 KiB
C++
//
|
|
// Created by Kirill Zhukov on 20.04.2025.
|
|
//
|
|
|
|
#include "RecoveryLog.h"
|
|
|
|
|
|
namespace usub::utils
|
|
{
|
|
RecoveryLog::RecoveryLog(const std::string& dbname)
|
|
: db_name_(dbname),
|
|
metadata_dir_("metadata/" + dbname + "/"),
|
|
log_file_(metadata_dir_ + "recovery.log")
|
|
{
|
|
ensure_metadata_dir();
|
|
this->log_out_.open(this->log_file_, std::ios::binary | std::ios::app);
|
|
if (!this->log_out_.is_open())
|
|
throw std::runtime_error("Failed to open recovery log for " + this->db_name_);
|
|
}
|
|
|
|
RecoveryLog::~RecoveryLog()
|
|
{
|
|
if (log_out_.is_open()) log_out_.close();
|
|
}
|
|
|
|
void RecoveryLog::log_put(const std::string& key, const std::string& value)
|
|
{
|
|
uint8_t op = 0;
|
|
uint32_t key_len = key.size();
|
|
uint32_t value_len = value.size();
|
|
this->log_out_.write(reinterpret_cast<const char*>(&op), sizeof(op));
|
|
this->log_out_.write(reinterpret_cast<const char*>(&key_len), sizeof(key_len));
|
|
this->log_out_.write(key.data(), key_len);
|
|
this->log_out_.write(reinterpret_cast<const char*>(&value_len), sizeof(value_len));
|
|
this->log_out_.write(value.data(), value_len);
|
|
this->log_out_.flush();
|
|
}
|
|
|
|
void RecoveryLog::log_delete(const std::string& key)
|
|
{
|
|
uint8_t op = 1;
|
|
uint32_t key_len = key.size();
|
|
this->log_out_.write(reinterpret_cast<const char*>(&op), sizeof(op));
|
|
this->log_out_.write(reinterpret_cast<const char*>(&key_len), sizeof(key_len));
|
|
this->log_out_.write(key.data(), key_len);
|
|
this->log_out_.flush();
|
|
}
|
|
|
|
void RecoveryLog::log_command(const core::Command& cmd)
|
|
{
|
|
cmd.serialize(this->log_out_);
|
|
this->log_out_.flush();
|
|
}
|
|
|
|
void RecoveryLog::ensure_metadata_dir() const
|
|
{
|
|
try
|
|
{
|
|
if (!std::filesystem::exists(metadata_dir_)) std::filesystem::create_directories(metadata_dir_);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << "Failed to create metadata directory: " << e.what() << std::endl;
|
|
}
|
|
}
|
|
|
|
|
|
void RecoveryLog::replay(const std::function<void(const core::Command&)>& callback) const
|
|
{
|
|
std::ifstream in(this->log_file_, std::ios::binary);
|
|
if (!in.is_open())
|
|
return;
|
|
|
|
while (in.peek() != EOF)
|
|
{
|
|
core::Command cmd = core::Command::deserialize(in);
|
|
callback(cmd);
|
|
}
|
|
}
|
|
void RecoveryLog::clear()
|
|
{
|
|
if (this->log_out_.is_open())
|
|
this->log_out_.close();
|
|
|
|
std::filesystem::remove(this->log_file_);
|
|
|
|
this->log_out_.open(this->log_file_, std::ios::binary | std::ios::app);
|
|
if (!this->log_out_.is_open())
|
|
throw std::runtime_error("Failed to reopen recovery log after clear for " + this->db_name_);
|
|
}
|
|
} // utils
|
|
// usub
|