/
smychkov
/
SStorage
Обзор
Документация
Войти
/
smychkov
/
SStorage
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
tests/test_wal_crash.cpp
107 строк
4 KB
Андрей Смычков
feat: WAL with fsync-per-write + group commit
25 апр 2026, 09:02
25 апр 2026, 09:02
3e7bc7b
Код
Авторство
О чём код?
//============================================================================ // Тесты на crash-сценарии WAL //============================================================================ // Используем fork(): child пишет в WAL, parent его убивает, // затем читает файл и проверяет целостность. //============================================================================ #include "../src/wal/wal.hpp" #include <csignal> #include <cstdio> #include <cstdlib> #include <filesystem> #include <iostream> #include <string> #include <sys/stat.h> #include <sys/wait.h> #include <thread> #include <unistd.h> using namespace sstorage; static int g_passed = 0; static int g_failed = 0; #define CHECK(cond) do { \ if (cond) { ++g_passed; } \ else { ++g_failed; std::cerr << "FAIL: " #cond " at line " << __LINE__ << "\n"; } \ } while (0) static std::string makeTempDir(const std::string& prefix) { std::string p = "/tmp/sstorage_" + prefix + "_" + std::to_string(::getpid()) + "_" + std::to_string(rand()); ::mkdir(p.c_str(), 0755); return p; } static void cleanupDir(const std::string& dir) { std::error_code ec; std::filesystem::remove_all(dir, ec); } int main() { //------------------------------------------------------------------------ // Сценарий: child записывает N записей с fsync, parent его килл-9, // потом читает WAL. Все подтверждённые append (вернувшие true) должны // быть на диске. //------------------------------------------------------------------------ auto dir = makeTempDir("wal_crash"); std::string confirmedFile = dir + "/confirmed.txt"; pid_t pid = ::fork(); if (pid == 0) { // Child: пишем 50 записей, после каждой подтверждаем в файл FILE* confirmed = ::fopen(confirmedFile.c_str(), "w"); WriteAheadLog wal(dir, 1); wal.open(); for (int i = 0; i < 50; ++i) { if (wal.append(Record("key" + std::to_string(i), "val" + std::to_string(i), i))) { ::fprintf(confirmed, "%d\n", i); ::fflush(confirmed); ::fsync(::fileno(confirmed)); } } // Долго блокируем — parent должен успеть убить ::fclose(confirmed); ::_exit(0); } // Parent: подождём немного и убьём ребёнка std::this_thread::sleep_for(std::chrono::milliseconds(200)); ::kill(pid, SIGKILL); int status; ::waitpid(pid, &status, 0); // Читаем список подтверждённых записей std::vector<int> confirmed; { FILE* f = ::fopen(confirmedFile.c_str(), "r"); if (f) { int n; while (::fscanf(f, "%d", &n) == 1) confirmed.push_back(n); ::fclose(f); } } // Читаем WAL auto records = WriteAheadLog::replay(WriteAheadLog::buildFilename(dir, 1)); // Главная гарантия: все confirmed записи должны быть в WAL CHECK(records.size() >= confirmed.size()); for (size_t i = 0; i < confirmed.size(); ++i) { std::string expected_key = "key" + std::to_string(confirmed[i]); bool found = false; for (const auto& r : records) { if (r.key() == expected_key) { found = true; break; } } CHECK(found); } std::cout << "test_wal_crash: confirmed=" << confirmed.size() << " replayed=" << records.size() << " passed=" << g_passed << " failed=" << g_failed << "\n"; cleanupDir(dir); return g_failed == 0 ? 0 : 1; }