Files
triangles_v5/src/txdb-factory.cpp
T
Krystie fc7ad5bb69 rocksdb: apply T010 review fixes (H1/H2/H3/M4) + CF routing disabled
H1: init.cpp now detects crashed migrations (MIGRATION_INCOMPLETE marker)
    and retries instead of opening a partial RocksDB. Refuses to start if
    the marker persists after migration attempt.
H2: LevelDB ExistsRaw now returns false for keys deleted in the active
    batch, matching ReadRaw and the RocksDB backend. Fixes latent
    cross-backend consensus split in intra-batch spend checks.
H3: All RocksDB close paths now go through close_rocksdb() which
    destroys CF handles before deleting the DB. Fixes RocksDB assertion
    / UB on shutdown and version-reset.
M4: Migration marker write is now flushed + verified (refuses to start
    migration if marker can't be written).

CF routing permanently disabled: GetCF() always returns nullptr (default
column family). The read path (NewIterator, LoadBlockIndex) only iterates
the default CF, so writes routed to per-prefix CFs were invisible to scans.
This is why -chaindb=rocksdb compiled clean but was never runtime-valid.
Existing CF-enabled DBs still open (handles retained for cleanup) but no
routing occurs. CF-aware iteration is a future follow-up.

txdb-factory: RocksDB is now the default backend (was still leveldb).
Tests updated for RocksDB-as-default expectations.

From Claude's ROCKSDB-T010-REVIEW-2026-07-01 audit on E:\repos\triangles.
2026-07-01 16:09:25 -07:00

76 lines
2.3 KiB
C++

// Copyright (c) 2026 The Triangles developers.
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "txdb.h"
#include "util.h"
#include <filesystem>
#include <stdexcept>
#include <string>
namespace fs = std::filesystem;
namespace {
// Pick the backend on every call. The daemon sets -chaindb once at startup
// and never changes it, so the per-call cost (a GetArg + tolower loop on a
// short string) is negligible compared to the cost of opening the chain DB.
// The earlier static-cache version broke test_chaindb_runtime, which
// legitimately toggles -chaindb across test cases to exercise both backends
// in the same process. Caching would freeze the first-seen choice.
enum class ChainDbKind { LevelDB, RocksDB };
ChainDbKind ResolveChainDbKind()
{
// RocksDB is the default backend. LevelDB remains selectable with
// -chaindb=leveldb and is retained as the migration source and fallback;
// its removal is deferred to a later phase after live-chain validation.
std::string s = GetArg("-chaindb", std::string("rocksdb"));
for (auto& c : s) c = std::tolower(static_cast<unsigned char>(c));
if (s == "leveldb")
return ChainDbKind::LevelDB;
if (s == "rocksdb")
return ChainDbKind::RocksDB;
throw std::runtime_error(
"-chaindb=" + s + " is not a recognized backend. "
"Valid values: leveldb, rocksdb.");
}
} // anonymous namespace
std::unique_ptr<CTxDBBase> MakeChainDB(const char* pszMode)
{
switch (ResolveChainDbKind()) {
case ChainDbKind::LevelDB:
return std::unique_ptr<CTxDBBase>(new CTxDB(pszMode));
case ChainDbKind::RocksDB:
return std::unique_ptr<CTxDBBase>(new CRocksTxDB(pszMode));
}
// Unreachable — ResolveChainDbKind throws on bad input.
return nullptr;
}
bool IsRocksDbChainBackend()
{
return ResolveChainDbKind() == ChainDbKind::RocksDB;
}
std::filesystem::path GetChainDataDir()
{
switch (ResolveChainDbKind()) {
case ChainDbKind::LevelDB: return GetDataDir() / "txleveldb";
case ChainDbKind::RocksDB: return GetDataDir() / "rocksdb";
}
return GetDataDir() / "txleveldb"; // unreachable
}
void WipeChainDataDir()
{
fs::path p = GetChainDataDir();
if (fs::exists(p))
fs::remove_all(p);
}