// // 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/" + db_name + "/"), 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 (this->log_out.is_open()) { this->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::ensure_metadata_dir() const { try { if (!std::filesystem::exists(this->metadata_dir)) { std::filesystem::create_directories(this->metadata_dir); } } catch (const std::exception& e) { std::cerr << "Failed to create metadata dir: " << e.what() << std::endl; } } void RecoveryLog::replay( const std::function& callback) const { std::ifstream in(log_file, std::ios::binary); if (!in.is_open()) return; while (in.peek() != EOF) { uint8_t op; in.read(reinterpret_cast(&op), sizeof(op)); Hash128 key; in.read(reinterpret_cast(&key), sizeof(key)); if (op == 0) // PUT { uint32_t value_size; in.read(reinterpret_cast(&value_size), sizeof(value_size)); std::string value(value_size, '\0'); in.read(&value[0], value_size); callback(key, value, false); } else if (op == 1) // DELETE { callback(key, "", true); } else { throw std::runtime_error("Invalid RecoveryLog format"); } } } } // utils // usub