fc7ad5bb69
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.
76 lines
2.3 KiB
C++
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);
|
|
}
|