// // 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(&op), sizeof(op)); this->log_out_.write(reinterpret_cast(&key_len), sizeof(key_len)); this->log_out_.write(key.data(), key_len); this->log_out_.write(reinterpret_cast(&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(&op), sizeof(op)); this->log_out_.write(reinterpret_cast(&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& 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