Explorar o código

feat(storage): dual-write mirror + boot backfill into LmdbDocumentStore

Stage 4 step 1+2 on feat/v2.0-spike. Every user-collection write that
flows through MemoryStore is now mirrored into doc_store_ via the new
applyDualWriteMirror helper. On boot, backfillIntoDocStore() walks
listCollections()+getAllDocuments() into LMDB synchronously before
gRPC accepts traffic, skipping when _meta.schema_version=2 is already
set by migrate_v1_to_v2.

Failure mode: catch + ERROR log + drift counter bump + mirror_healthy_
flipped to false. MemoryStore/WAL/replication stay authoritative; the
downstream read-flip task must check mirror_healthy_.load(acquire) and
mirror_drift_count_==0 before consulting doc_store_. System collections
(_-prefixed) are skipped so Stage 5 owns their format.

Coverage: tests/test_dual_write_mirror.cpp (29 assertions, 7 cases) —
null-store no-op, system-collection skip, INSERT/UPDATE/DELETE round
trip, failure path via ThrowingStore stub, MemoryStore-callback
integration, and backfill iteration pattern. Full suite 12/12 green.
fszontagh hai 2 meses
pai
achega
d997562630

+ 74 - 0
service/src/database_service.cpp

@@ -2,7 +2,9 @@
 #include "json_parse.hpp"
 #include "storage/document_store.hpp"
 #include "storage/document_store_lmdb.hpp"
+#include "storage/dual_write_mirror.hpp"
 #include "storage/lmdb_env.hpp"
+#include "storage/migrate_v1_to_v2.hpp"
 
 #include <grpcpp/grpcpp.h>
 #include <grpcpp/resource_quota.h>
@@ -193,6 +195,11 @@ bool DatabaseService::initialize() {
             }
         }
 
+        // v2.0 Stage 4 — synchronous backfill into doc_store_ before
+        // serving. Without this, only post-boot writes land in LMDB and
+        // the read-flip downstream would see an empty mirror.
+        backfillIntoDocStore();
+
         spdlog::info("Database service initialized successfully");
         return true;
 
@@ -216,6 +223,68 @@ bool DatabaseService::runMigrations() {
     return migrationRunner_->runMigrations();
 }
 
+bool DatabaseService::backfillIntoDocStore() {
+    if (!doc_store_ || !env_) {
+        // Env open failed earlier; nothing to backfill into. mirror_healthy_
+        // stays true (default) — there's no mirror to be unhealthy.
+        return true;
+    }
+
+    // Skip when migrate_v1_to_v2 already populated the env. That tool
+    // writes _meta.schema_version=2 atomically on success.
+    try {
+        if (smartbotic::db::storage::migration_complete(*env_)) {
+            spdlog::info("v2.0 backfill: env already migrated (schema_version=2), skipping");
+            return true;
+        }
+    } catch (const std::exception& e) {
+        spdlog::warn("v2.0 backfill: migration_complete probe failed: {} — "
+                     "treating env as fresh and proceeding with backfill",
+                     e.what());
+    }
+
+    const auto collections = store_->listCollections();
+    uint64_t total_docs = 0;
+    uint64_t total_failures = 0;
+    auto t0 = std::chrono::steady_clock::now();
+
+    for (const auto& collection : collections) {
+        if (collection.empty() || collection[0] == '_') continue;
+        const auto docs = store_->getAllDocuments(collection);
+        for (const auto& doc : docs) {
+            std::optional<Document> opt_doc(doc);
+            const uint64_t drift_before = mirror_drift_count_.load(std::memory_order_relaxed);
+            smartbotic::db::storage::applyDualWriteMirror(
+                doc_store_.get(), mirror_healthy_, mirror_drift_count_,
+                collection, doc.id, opt_doc, EventType::INSERT);
+            if (mirror_drift_count_.load(std::memory_order_relaxed) > drift_before) {
+                ++total_failures;
+            }
+            ++total_docs;
+            if (total_docs % 10000 == 0) {
+                sd_notify(0, "EXTEND_TIMEOUT_USEC=600000000");
+                const std::string status = "STATUS=v2.0 backfill: " +
+                                           std::to_string(total_docs) + " docs mirrored";
+                sd_notify(0, status.c_str());
+                spdlog::info("v2.0 backfill: {} docs mirrored ({} failures so far)",
+                             total_docs, total_failures);
+            }
+        }
+    }
+
+    const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+        std::chrono::steady_clock::now() - t0).count();
+    if (total_failures == 0) {
+        spdlog::info("v2.0 backfill: complete — {} docs across {} collections in {} ms",
+                     total_docs, collections.size(), elapsed);
+    } else {
+        spdlog::error("v2.0 backfill: completed with {} failures out of {} docs "
+                      "in {} ms — mirror_healthy_=false, reads must NOT flip to LMDB",
+                      total_failures, total_docs, elapsed);
+    }
+    return true;
+}
+
 void DatabaseService::start() {
     if (running_.exchange(true)) {
         return;
@@ -631,6 +700,11 @@ void DatabaseService::setupComponents() {
             store_->recordWalSequence(collection, id, walSeq);
         }
 
+        // v2.0 dual-write mirror — see storage/dual_write_mirror.hpp.
+        smartbotic::db::storage::applyDualWriteMirror(
+            doc_store_.get(), mirror_healthy_, mirror_drift_count_,
+            collection, id, doc, eventType);
+
         // Queue for replication broadcast
         if (replication_ && config_.replicationEnabled) {
             databasepb::ReplicationEntry entry;

+ 16 - 0
service/src/database_service.hpp

@@ -201,6 +201,14 @@ private:
     void applyReplicatedEntry(const databasepb::ReplicationEntry& entry);
     bool runMigrations();
 
+    // v2.0 Stage 4 — synchronous backfill of MemoryStore into doc_store_.
+    // Runs once at boot, after recovery + migrations, before gRPC accepts
+    // traffic. Skips when _meta.schema_version=2 marker exists (the env
+    // is already populated by migrate_v1_to_v2). Returns false only on
+    // catastrophic failure; per-doc errors flip mirror_healthy_=false but
+    // do not abort boot (the read-flip downstream is the gate).
+    bool backfillIntoDocStore();
+
     Config config_;
     std::atomic<bool> running_{false};
     std::atomic<bool> stopRequested_{false};
@@ -221,6 +229,14 @@ private:
     std::unique_ptr<smartbotic::db::storage::LmdbEnv> env_;
     std::unique_ptr<smartbotic::db::storage::DocumentStore> doc_store_;
 
+    // v2.0 dual-write health. The persist callback mirrors every user-
+    // collection write into doc_store_; on failure we log ERROR, bump the
+    // drift counter, and flip mirror_healthy_ to false. Downstream Stage 4
+    // tasks that flip reads onto doc_store_ MUST check mirror_healthy_
+    // before engaging — a degraded mirror means LMDB is missing writes.
+    std::atomic<bool> mirror_healthy_{true};
+    std::atomic<uint64_t> mirror_drift_count_{0};
+
     std::unique_ptr<PersistenceManager> persistence_;
     std::unique_ptr<HistoryStore> history_store_;  // v1.9.0 — disk-resident history
     std::unique_ptr<EncryptionManager> encryption_;

+ 64 - 0
service/src/storage/dual_write_mirror.hpp

@@ -0,0 +1,64 @@
+// v2.0 Stage 4 — dual-write mirror helper.
+//
+// Mirrors a MemoryStore-originating write into a DocumentStore (LMDB-backed
+// in production). Used inside DatabaseService's persist callback so every
+// user-collection insert/update/delete that flows through MemoryStore lands
+// in the v2.0 substrate too. Lives as a free function so the unit test in
+// tests/test_dual_write_mirror.cpp can exercise it without booting the full
+// service.
+//
+// Failure mode: catch + log ERROR + bump drift counter + flip
+// mirror_healthy_=false. Caller's MemoryStore + WAL + replication remain
+// authoritative until the read-flip task downstream engages — which it
+// MUST refuse to do while mirror_healthy_ is false.
+//
+// System collections (`_`-prefixed) are deliberately skipped: Stage 5 owns
+// the format for `_views` / `_files` / `_meta` / `_collections` sub-dbs.
+
+#pragma once
+
+#include <atomic>
+#include <optional>
+#include <string>
+
+#include <spdlog/spdlog.h>
+
+#include "document.hpp"
+#include "memory_store.hpp"
+#include "storage/document_store.hpp"
+
+namespace smartbotic::db::storage {
+
+inline void applyDualWriteMirror(
+    DocumentStore* doc_store,
+    std::atomic<bool>& mirror_healthy,
+    std::atomic<uint64_t>& mirror_drift_count,
+    const std::string& collection,
+    const std::string& id,
+    const std::optional<smartbotic::database::Document>& doc,
+    smartbotic::database::EventType eventType) {
+
+    if (!doc_store) return;
+    if (collection.empty() || collection[0] == '_') return;
+
+    try {
+        switch (eventType) {
+            case smartbotic::database::EventType::INSERT:
+            case smartbotic::database::EventType::UPDATE:
+                if (doc) doc_store->put(collection, id, *doc);
+                break;
+            case smartbotic::database::EventType::DELETE:
+                doc_store->del(collection, id);
+                break;
+            default:
+                break;
+        }
+    } catch (const std::exception& e) {
+        spdlog::error("v2.0 mirror failed coll={} id={} op={}: {}",
+                      collection, id, static_cast<int>(eventType), e.what());
+        mirror_drift_count.fetch_add(1, std::memory_order_relaxed);
+        mirror_healthy.store(false, std::memory_order_release);
+    }
+}
+
+}  // namespace smartbotic::db::storage

+ 43 - 0
tests/CMakeLists.txt

@@ -429,6 +429,48 @@ else()
     target_link_libraries(test_migrate_v1_to_v2 PRIVATE lz4)
 endif()
 
+# v2.0 Stage 4 — dual-write mirror unit + integration test.
+# Links the MemoryStore + LMDB substrate the same way test_migrate_v1_to_v2 does,
+# but skips persistence/snapshot/wal since the mirror helper does not touch them.
+add_executable(test_dual_write_mirror
+    test_dual_write_mirror.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/memory_store.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/config/collection_config_manager.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/persistence/history_store.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/persistence/wal.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/json_parse.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/doc_binary.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/storage/lmdb_env.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/storage/lmdb_txn.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/storage/lmdb_dbi.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src/storage/document_store_lmdb.cpp
+)
+
+target_include_directories(test_dual_write_mirror PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}/../service/src
+    ${LMDB_INCLUDE_DIR}
+    ${yyjson_INCLUDE_DIRS}
+)
+
+target_link_libraries(test_dual_write_mirror PRIVATE ${LMDB_LIBRARY})
+target_link_libraries(test_dual_write_mirror PRIVATE ${yyjson_LIBRARIES})
+
+if(TARGET nlohmann_json::nlohmann_json)
+    target_link_libraries(test_dual_write_mirror PRIVATE nlohmann_json::nlohmann_json)
+else()
+    target_include_directories(test_dual_write_mirror PRIVATE ${NLOHMANN_JSON_INCLUDE_DIRS})
+endif()
+
+if(TARGET spdlog::spdlog)
+    target_link_libraries(test_dual_write_mirror PRIVATE spdlog::spdlog)
+else()
+    target_link_libraries(test_dual_write_mirror PRIVATE ${SPDLOG_LIBRARIES})
+    target_include_directories(test_dual_write_mirror PRIVATE ${SPDLOG_INCLUDE_DIRS})
+endif()
+
+find_package(Threads REQUIRED)
+target_link_libraries(test_dual_write_mirror PRIVATE Threads::Threads)
+
 # Register with CTest
 enable_testing()
 add_test(NAME vector_storage COMMAND test_vector_storage)
@@ -442,3 +484,4 @@ add_test(NAME doc_binary COMMAND test_doc_binary)
 add_test(NAME lmdb_env COMMAND test_lmdb_env)
 add_test(NAME document_store COMMAND test_document_store)
 add_test(NAME migrate_v1_to_v2 COMMAND test_migrate_v1_to_v2)
+add_test(NAME dual_write_mirror COMMAND test_dual_write_mirror)

+ 290 - 0
tests/test_dual_write_mirror.cpp

@@ -0,0 +1,290 @@
+// v2.0 Stage 4 — dual-write mirror tests.
+//
+// Covers `applyDualWriteMirror` directly (unit) and the integration path
+// where it's installed as a MemoryStore::setPersistCallback (matching the
+// shape DatabaseService uses). Failure path uses a throwing DocumentStore
+// stub to verify health flag + drift counter behavior without needing to
+// induce a real LMDB error.
+
+#include <algorithm>
+#include <atomic>
+#include <cassert>
+#include <cstdlib>
+#include <filesystem>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <stdexcept>
+#include <string>
+#include <unistd.h>
+
+#include <nlohmann/json.hpp>
+
+#include "document.hpp"
+#include "memory_store.hpp"
+#include "storage/document_store.hpp"
+#include "storage/document_store_lmdb.hpp"
+#include "storage/dual_write_mirror.hpp"
+#include "storage/lmdb_env.hpp"
+
+namespace fs = std::filesystem;
+
+using smartbotic::database::Document;
+using smartbotic::database::EventType;
+using smartbotic::database::MemoryStore;
+using smartbotic::db::storage::applyDualWriteMirror;
+using smartbotic::db::storage::DocumentStore;
+using smartbotic::db::storage::LmdbDocumentStore;
+using smartbotic::db::storage::LmdbEnv;
+using smartbotic::db::storage::LmdbEnvOpts;
+using smartbotic::db::storage::ScanResult;
+
+namespace {
+
+int g_pass = 0;
+int g_fail = 0;
+
+void check(bool cond, const char* msg) {
+    if (cond) {
+        ++g_pass;
+    } else {
+        ++g_fail;
+        std::cerr << "FAIL: " << msg << "\n";
+    }
+}
+
+std::string make_tmpdir(const char* tag) {
+    static std::atomic<int> counter{0};
+    int n = counter.fetch_add(1);
+    std::string path = "/tmp/dual-write-mirror-test-" + std::to_string(::getpid()) +
+                       "-" + std::to_string(n) + "-" + tag;
+    std::error_code ec;
+    fs::remove_all(path, ec);
+    return path;
+}
+
+struct TmpEnv {
+    std::string path;
+    LmdbEnv env;
+    explicit TmpEnv(const char* tag)
+        : path(make_tmpdir(tag)),
+          env(LmdbEnvOpts{path, 64ULL << 20, 256, 126, false}) {}
+    ~TmpEnv() {
+        std::error_code ec;
+        fs::remove_all(path, ec);
+    }
+    TmpEnv(const TmpEnv&) = delete;
+    TmpEnv& operator=(const TmpEnv&) = delete;
+};
+
+Document make_doc(const std::string& id,
+                  const std::string& collection,
+                  const nlohmann::json& data) {
+    Document d;
+    d.id = id;
+    d.collection = collection;
+    d.set_data(data);
+    d.createdAt = 1731628800000ULL;
+    d.updatedAt = 1731628800000ULL;
+    d.version = 1;
+    d.lastAccessedAt = 1731628800000ULL;
+    return d;
+}
+
+// DocumentStore stub whose put/del always throw — exercises the failure
+// path without forcing a real LMDB error.
+class ThrowingStore : public DocumentStore {
+public:
+    void put(std::string_view, std::string_view, const Document&) override {
+        throw std::runtime_error("simulated mirror failure");
+    }
+    std::optional<Document> get(std::string_view, std::string_view) override {
+        return std::nullopt;
+    }
+    bool del(std::string_view, std::string_view) override {
+        throw std::runtime_error("simulated mirror failure");
+    }
+    uint64_t count(std::string_view) override { return 0; }
+    ScanResult scan(std::string_view, const smartbotic::database::Query&) override {
+        return {};
+    }
+    std::vector<std::string> list_collections() override { return {}; }
+    bool drop_collection(std::string_view) override { return false; }
+};
+
+// ---------- Unit-level tests on applyDualWriteMirror ----------
+
+void test_unit_null_store_is_noop() {
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+    Document d = make_doc("u1", "users", {{"name", "alice"}});
+    applyDualWriteMirror(nullptr, healthy, drift, "users", "u1", d, EventType::INSERT);
+    check(healthy.load(), "null doc_store: stays healthy");
+    check(drift.load() == 0, "null doc_store: drift unchanged");
+}
+
+void test_unit_system_collection_skipped() {
+    TmpEnv tmp("system-skip");
+    LmdbDocumentStore store(tmp.env);
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+    Document d = make_doc("v1", "_views", {{"name", "v1"}});
+    applyDualWriteMirror(&store, healthy, drift, "_views", "v1", d, EventType::INSERT);
+
+    auto names = store.list_collections();
+    check(std::find(names.begin(), names.end(), "_views") == names.end(),
+          "system collection: not created in LMDB");
+    check(healthy.load(), "system collection: stays healthy");
+    check(drift.load() == 0, "system collection: drift unchanged");
+}
+
+void test_unit_insert_update_delete_round_trip() {
+    TmpEnv tmp("round-trip");
+    LmdbDocumentStore store(tmp.env);
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+
+    Document d1 = make_doc("u1", "users", {{"name", "alice"}});
+    applyDualWriteMirror(&store, healthy, drift, "users", "u1", d1, EventType::INSERT);
+    auto got = store.get("users", "u1");
+    check(got.has_value(), "insert: doc landed in LMDB");
+    check(got->data().value("name", "") == "alice", "insert: data preserved");
+
+    Document d1b = make_doc("u1", "users", {{"name", "alice-updated"}});
+    applyDualWriteMirror(&store, healthy, drift, "users", "u1", d1b, EventType::UPDATE);
+    got = store.get("users", "u1");
+    check(got.has_value() && got->data().value("name", "") == "alice-updated",
+          "update: LMDB sees new value");
+
+    applyDualWriteMirror(&store, healthy, drift, "users", "u1", std::nullopt, EventType::DELETE);
+    check(!store.get("users", "u1").has_value(), "delete: LMDB doc gone");
+
+    check(healthy.load(), "round-trip: stays healthy");
+    check(drift.load() == 0, "round-trip: zero drift");
+}
+
+void test_unit_failure_marks_degraded() {
+    ThrowingStore store;
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+
+    Document d = make_doc("u1", "users", {{"name", "alice"}});
+    applyDualWriteMirror(&store, healthy, drift, "users", "u1", d, EventType::INSERT);
+    check(!healthy.load(), "failure: mirror_healthy_ flipped to false");
+    check(drift.load() == 1, "failure: drift counter == 1");
+
+    applyDualWriteMirror(&store, healthy, drift, "users", "u1", std::nullopt, EventType::DELETE);
+    check(!healthy.load(), "failure(delete): stays degraded");
+    check(drift.load() == 2, "failure(delete): drift counter == 2");
+}
+
+void test_unit_insert_without_doc_is_noop() {
+    TmpEnv tmp("insert-no-doc");
+    LmdbDocumentStore store(tmp.env);
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+
+    applyDualWriteMirror(&store, healthy, drift, "users", "u1", std::nullopt, EventType::INSERT);
+    check(!store.get("users", "u1").has_value(), "INSERT with nullopt doc: no LMDB write");
+    check(healthy.load() && drift.load() == 0, "INSERT with nullopt doc: clean");
+}
+
+// ---------- Integration via MemoryStore callback ----------
+//
+// Mirrors the DatabaseService wiring: install a callback on MemoryStore
+// that calls applyDualWriteMirror with the live doc_store_ + health flags,
+// then drive insert/update/delete through MemoryStore's public API and
+// verify LMDB sees each op.
+
+void test_integration_via_memory_store_callback() {
+    TmpEnv tmp("integration");
+    LmdbDocumentStore doc_store(tmp.env);
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+
+    MemoryStore::Config cfg;
+    cfg.nodeId = "test-node";
+    cfg.maxMemoryBytes = 64ULL * 1024 * 1024;
+    MemoryStore mem(cfg);
+    mem.setPersistCallback([&](const std::string& coll, const std::string& id,
+                                const std::optional<Document>& d, EventType ev) {
+        applyDualWriteMirror(&doc_store, healthy, drift, coll, id, d, ev);
+    });
+
+    Document d1 = make_doc("u1", "users", {{"name", "alice"}});
+    std::string inserted_id = mem.insert("users", d1);
+    check(inserted_id == "u1", "memstore insert: returns id");
+    check(doc_store.get("users", "u1").has_value(), "mem→lmdb: insert mirrored");
+
+    Document d1b = make_doc("u1", "users", {{"name", "alice-2"}});
+    d1b.version = 1;
+    bool updated = mem.update("users", "u1", d1b);
+    check(updated, "memstore update: success");
+    auto got = doc_store.get("users", "u1");
+    check(got.has_value() && got->data().value("name", "") == "alice-2",
+          "mem→lmdb: update mirrored");
+
+    bool removed = mem.remove("users", "u1");
+    check(removed, "memstore remove: success");
+    check(!doc_store.get("users", "u1").has_value(), "mem→lmdb: delete mirrored");
+
+    check(healthy.load() && drift.load() == 0, "integration: clean run");
+}
+
+// Simulates DatabaseService::backfillIntoDocStore — populate MemoryStore
+// without a persist callback (no live mirror), then walk listCollections +
+// getAllDocuments and feed each doc into applyDualWriteMirror with
+// EventType::INSERT. Verifies LMDB ends up with every user doc and no
+// system-collection docs.
+void test_backfill_iteration_pattern() {
+    TmpEnv tmp("backfill");
+    LmdbDocumentStore doc_store(tmp.env);
+    std::atomic<bool> healthy{true};
+    std::atomic<uint64_t> drift{0};
+
+    MemoryStore::Config cfg;
+    cfg.nodeId = "test-node";
+    cfg.maxMemoryBytes = 64ULL * 1024 * 1024;
+    MemoryStore mem(cfg);
+    // No persist callback — simulating "data loaded from snapshot/WAL".
+
+    mem.insert("users", make_doc("u1", "users", {{"name", "alice"}}));
+    mem.insert("users", make_doc("u2", "users", {{"name", "bob"}}));
+    mem.insert("orders", make_doc("o1", "orders", {{"total", 42}}));
+    // System collection write — should be excluded by the filter inside the
+    // helper, even when fed through the same iteration loop.
+    mem.insert("_views", make_doc("v1", "_views", {{"name", "v1"}}));
+
+    // Backfill loop — same shape as DatabaseService::backfillIntoDocStore.
+    for (const auto& coll : mem.listCollections()) {
+        if (coll.empty() || coll[0] == '_') continue;
+        for (const auto& doc : mem.getAllDocuments(coll)) {
+            std::optional<Document> opt(doc);
+            applyDualWriteMirror(&doc_store, healthy, drift,
+                                 coll, doc.id, opt, EventType::INSERT);
+        }
+    }
+
+    check(doc_store.get("users", "u1").has_value(), "backfill: u1 mirrored");
+    check(doc_store.get("users", "u2").has_value(), "backfill: u2 mirrored");
+    check(doc_store.get("orders", "o1").has_value(), "backfill: o1 mirrored");
+    auto names = doc_store.list_collections();
+    check(std::find(names.begin(), names.end(), "_views") == names.end(),
+          "backfill: _views NOT created in LMDB");
+    check(healthy.load() && drift.load() == 0, "backfill: clean");
+}
+
+}  // namespace
+
+int main() {
+    test_unit_null_store_is_noop();
+    test_unit_system_collection_skipped();
+    test_unit_insert_update_delete_round_trip();
+    test_unit_failure_marks_degraded();
+    test_unit_insert_without_doc_is_noop();
+    test_integration_via_memory_store_callback();
+    test_backfill_iteration_pattern();
+
+    std::cout << "dual_write_mirror: " << g_pass << " passed, " << g_fail << " failed\n";
+    return g_fail == 0 ? 0 : 1;
+}