yams/tests/common/metadata_test_db.h
Trevon 090a5ca69c
fix(testing): stabilize TSAN coverage, harden daemon shutdown, and speed up KG/storage paths (#53)
* perf(search, metadata): add KG write buffer, score cache, adaptive budgets

* perf(indexing): wire KGWriteBuffer into indexing service

   Converts per-document addEdgesUnique calls into batched flush via
   KGWriteBuffer.  500-doc ingest: 500 SQL round-trips → 1 batch.

   Verified: 14.2× edge insert gap (14.8K→195K edges/s) in kg_edge bench.
   Tests: 10/10 Catch2 pass (105 assertions).

* perf(storage): add fsync durability, parallel batch, read integrity

* test(storage): add stress, crash-sim, cold-cache, batch benchmarks

* fix: CI optimizations and work coordinator shutdown fix

* fix(testing): stabilize TSAN coverage gate

* fix: harden KG flush, score cache, and benches

   - keep KG buffers intact when batch commit fails
   - count flushed edges per batch instead of lifetime totals
   - guard the Simeon score cache and clear it on rebuild
   - fall back to fsync when F_FULLFSYNC fails on macOS
   - remove interactive sudo from cold-cache benchmarks
2026-06-26 17:57:02 -04:00

109 lines
4 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright 2025 YAMS Contributors
#pragma once
#include <chrono>
#include <cstdlib>
#include <filesystem>
#include <random>
#include <stdexcept>
#include <string>
#include <string_view>
#include "../../include/yams/metadata/database.h"
#include "../../include/yams/metadata/migration.h"
namespace yams::test {
inline std::filesystem::path make_temp_sqlite_path(std::string_view prefix = "yams_test_") {
namespace fs = std::filesystem;
const char* env = std::getenv("YAMS_TEST_TMPDIR");
const auto base = (env && *env) ? fs::path(env) : fs::temp_directory_path();
std::error_code ec;
fs::create_directories(base, ec);
std::uniform_int_distribution<int> dist(0, 9999);
thread_local std::mt19937_64 rng{std::random_device{}()};
for (int attempt = 0; attempt < 512; ++attempt) {
const auto stamp = std::chrono::steady_clock::now().time_since_epoch().count();
auto candidate = base / (std::string(prefix) + std::to_string(stamp) + "_" +
std::to_string(dist(rng)) + ".db");
fs::remove(candidate, ec);
if (!fs::exists(candidate)) {
return candidate;
}
}
throw std::runtime_error("failed to allocate temporary sqlite path");
}
inline void remove_sqlite_artifacts(const std::filesystem::path& dbPath) {
std::error_code ec;
std::filesystem::remove(dbPath, ec);
std::filesystem::remove(std::filesystem::path(dbPath.string() + "-wal"), ec);
std::filesystem::remove(std::filesystem::path(dbPath.string() + "-shm"), ec);
}
class MetadataDbTemplate {
public:
explicit MetadataDbTemplate(std::string_view prefix = "yams_metadata_template_")
: templatePath_(make_temp_sqlite_path(prefix)) {
metadata::Database db;
auto openResult = db.open(templatePath_.string(), metadata::ConnectionMode::Create);
if (!openResult) {
throw std::runtime_error("failed to open metadata template db: " +
openResult.error().message);
}
metadata::MigrationManager manager(db);
auto initResult = manager.initialize();
if (!initResult) {
db.close();
throw std::runtime_error("failed to initialize metadata template migrations: " +
initResult.error().message);
}
manager.registerMigrations(metadata::YamsMetadataMigrations::getAllMigrations());
auto migrateResult = manager.migrate();
if (!migrateResult) {
db.close();
throw std::runtime_error("failed to migrate metadata template db: " +
migrateResult.error().message);
}
db.close();
}
~MetadataDbTemplate() { remove_sqlite_artifacts(templatePath_); }
MetadataDbTemplate(const MetadataDbTemplate&) = delete;
MetadataDbTemplate& operator=(const MetadataDbTemplate&) = delete;
[[nodiscard]] std::filesystem::path clone(std::string_view prefix) const {
auto target = make_temp_sqlite_path(prefix);
std::filesystem::copy_file(templatePath_, target,
std::filesystem::copy_options::overwrite_existing);
copyOptionalSidecar("-wal", target);
copyOptionalSidecar("-shm", target);
return target;
}
private:
void copyOptionalSidecar(const char* suffix, const std::filesystem::path& target) const {
const auto source = std::filesystem::path(templatePath_.string() + suffix);
if (!std::filesystem::exists(source)) {
return;
}
std::filesystem::copy_file(source, std::filesystem::path(target.string() + suffix),
std::filesystem::copy_options::overwrite_existing);
}
std::filesystem::path templatePath_;
};
inline const MetadataDbTemplate& migrated_metadata_db_template() {
static const MetadataDbTemplate templateDb{};
return templateDb;
}
} // namespace yams::test