diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6812b8..7060561 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,6 +74,7 @@ set(CORE_SOURCES rpcsmessage.cpp zmqpublishnotifier.cpp txdb-base.cpp + txdb.cpp txdb-leveldb.cpp utxosnapshot.cpp snapshotnet.cpp diff --git a/src/bootstrap.cpp b/src/bootstrap.cpp index 20569ce..5876698 100644 --- a/src/bootstrap.cpp +++ b/src/bootstrap.cpp @@ -3,6 +3,7 @@ #include "bootstrap.h" #include "utxosnapshot.h" +#include "txdb.h" #include #include @@ -718,16 +719,16 @@ bool DownloadBootstrap(const std::string& host, return false; } - // Check if the archive included a trusted pre-built index (txleveldb/) - // with a valid snapshot.manifest. If verified, keep it to skip the + // Check if the archive included a trusted pre-built index for the active + // backend with a valid snapshot.manifest. If verified, keep it to skip the // multi-hour FastImportBlockFile() rebuild. - fs::path txleveldb = dataDir / "txleveldb"; + fs::path chainDbPath = dataDir / GetActiveChainDbDirName(); fs::path database = dataDir / "database"; fs::path manifestPath = dataDir / "snapshot.manifest"; bool keepIndex = false; - if (fs::exists(manifestPath) && fs::exists(txleveldb)) { + if (fs::exists(manifestPath) && fs::exists(chainDbPath)) { SnapshotManifest manifest; std::string manifestError; @@ -754,9 +755,9 @@ bool DownloadBootstrap(const std::string& host, if (!keepIndex) { // No valid manifest or verification failed - delete the index. // FastImportBlockFile() will rebuild from blk0001.dat on next startup. - printf("Bootstrap: removing extracted txleveldb/ (will rebuild index from blk0001.dat)\n"); - if (fs::exists(txleveldb)) - fs::remove_all(txleveldb); + printf("Bootstrap: removing extracted %s/ (will rebuild index from blk0001.dat)\n", GetActiveChainDbDirName()); + if (fs::exists(chainDbPath)) + fs::remove_all(chainDbPath); } // Always remove BDB database/ dir (wallet environment from another machine) @@ -791,7 +792,7 @@ bool DownloadUtxoSnapshot(const std::string& host, printf("Bootstrap: UTXO snapshot downloaded, loading into database...\n"); - // Load the snapshot into a fresh txleveldb + // Load the snapshot into a fresh active chain DB if (!UtxoSnapshot::LoadSnapshot(tmpPath, dataDir, strError)) { fs::remove(tmpPath); return false; diff --git a/src/init.cpp b/src/init.cpp index 39b919c..735e209 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -250,7 +250,7 @@ void Shutdown(void* parg) pNotificationQueue = NULL; } -// CTxDB().Close(); +// CActiveTxDB().Close(); bitdb.Flush(false); bitdb.Flush(true); fs::remove(GetPidFile()); @@ -955,7 +955,7 @@ bool AppInit2() // Try UTXO snapshot first (fast: ~2-10 MB download) bool success = false; bool triedUtxoSnapshot = false; - if (needsBootstrap && !fs::exists(dataPath / "txleveldb")) { + if (needsBootstrap && !fs::exists(dataPath / GetActiveChainDbDirName())) { uiInterface.InitMessage(_("Downloading UTXO snapshot...")); printf("Bootstrap: trying UTXO snapshot from %s (fast path)...\n", host.c_str()); @@ -992,13 +992,13 @@ bool AppInit2() #endif // ********************************************************* Step 6c: manual UTXO snapshot loading - // If utxo-snapshot.bin exists in data dir and no txleveldb, load it. + // If utxo-snapshot.bin exists in data dir and no active chain DB, load it. { fs::path dataPath = GetDataDir(); fs::path snapshotFile = dataPath / "utxo-snapshot.bin"; - fs::path txleveldbDir = dataPath / "txleveldb"; + fs::path chainDbDir = dataPath / GetActiveChainDbDirName(); - if (fs::exists(snapshotFile) && !fs::exists(txleveldbDir)) { + if (fs::exists(snapshotFile) && !fs::exists(chainDbDir)) { printf("Found utxo-snapshot.bin — loading UTXO snapshot...\n"); uiInterface.InitMessage(_("Loading UTXO snapshot...")); @@ -1024,7 +1024,7 @@ bool AppInit2() if (GetBoolArg("-loadblockindextest")) { - CTxDB txdb("r"); + CActiveTxDB txdb("r"); txdb.LoadBlockIndex(); PrintBlockTree(); return false; @@ -1037,9 +1037,9 @@ bool AppInit2() { printf("Reindex requested: removing block index database...\n"); uiInterface.InitMessage(_("Removing block index for reindex...")); - fs::path txleveldbPath = GetDataDir() / "txleveldb"; - if (fs::exists(txleveldbPath)) - fs::remove_all(txleveldbPath); + fs::path chainDbPath = GetDataDir() / GetActiveChainDbDirName(); + if (fs::exists(chainDbPath)) + fs::remove_all(chainDbPath); } uiInterface.InitMessage(_("Loading block index...")); @@ -1224,7 +1224,7 @@ bool AppInit2() bool fScannedWithIndex = false; if (fAddressIndex && !GetBoolArg("-rescan")) { - CTxDB txdb("r"); + CActiveTxDB txdb("r"); int nAddressIndexStartHeight = 0; uint256 hashAddressIndexBestChain = 0; if (txdb.ReadAddressIndexStartHeight(nAddressIndexStartHeight) && diff --git a/src/main.cpp b/src/main.cpp index f5649fd..586da9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -931,7 +931,7 @@ bool CTransaction::ReadFromDisk(CTxDBBase& txdb, COutPoint prevout) bool CTransaction::ReadFromDisk(COutPoint prevout) { - CTxDB txdb("r"); + CActiveTxDB txdb("r"); CTxIndex txindex; return ReadFromDisk(txdb, prevout, txindex); } @@ -1064,7 +1064,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) { // Load the block this tx is in CTxIndex txindex; - if (!CTxDB("r").ReadTxIndex(GetHash(), txindex)) + if (!CActiveTxDB("r").ReadTxIndex(GetHash(), txindex)) return 0; if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos)) return 0; @@ -1487,7 +1487,7 @@ bool CMerkleTx::AcceptToMemoryPool(CTxDBBase& txdb, bool fCheckInputs) bool CMerkleTx::AcceptToMemoryPool() { - CTxDB txdb("r"); + CActiveTxDB txdb("r"); return AcceptToMemoryPool(txdb); } @@ -1515,7 +1515,7 @@ bool CWalletTx::AcceptWalletTransaction(CTxDBBase& txdb, bool fCheckInputs) bool CWalletTx::AcceptWalletTransaction() { - CTxDB txdb("r"); + CActiveTxDB txdb("r"); return AcceptWalletTransaction(txdb); } @@ -1548,7 +1548,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) return true; } } - CTxDB txdb("r"); + CActiveTxDB txdb("r"); CTxIndex txindex; if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) { @@ -1858,7 +1858,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew) if (pindexNew->nChainTrust > nBestInvalidTrust) { nBestInvalidTrust = pindexNew->nChainTrust; - CTxDB().WriteBestInvalidTrust(CBigNum(nBestInvalidTrust)); + CActiveTxDB().WriteBestInvalidTrust(CBigNum(nBestInvalidTrust)); uiInterface.NotifyBlocksChanged(); } @@ -3171,7 +3171,7 @@ bool CBlock::GetCoinAge(uint64_t& nCoinAge) const { nCoinAge = 0; - CTxDB txdb("r"); + CActiveTxDB txdb("r"); for (const CTransaction& tx : vtx) { uint64_t nTxCoinAge; @@ -3250,7 +3250,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const u pindexNew->phashBlock = &((*mi).first); // Write to disk block index - CTxDB txdb; + CActiveTxDB txdb; if (!txdb.TxnBegin()) return false; txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); @@ -3897,7 +3897,7 @@ bool LoadBlockIndex(bool fAllowNew) // // Load block index // - CTxDB txdb("cr+"); + CActiveTxDB txdb("cr+"); if (!txdb.LoadBlockIndex()) return false; @@ -4181,7 +4181,7 @@ bool FastImportBlockFile() LOCK(cs_main); CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION); - CTxDB txdb; + CActiveTxDB txdb; txdb.TxnBegin(); unsigned int nPos = 0; @@ -4783,7 +4783,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) printf("IBD-DIAG: inv received: %d blocks, %d tx from %s (our height=%d)\n", nBlockInv, nTxInv, pfrom->addr.ToString().c_str(), nBestHeight); - CTxDB txdb("r"); + CActiveTxDB txdb("r"); int nNew = 0, nAlready = 0, nAboveBest = 0; int nFirstInvHeight = -1, nLastInvHeight = -1; for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) @@ -5129,7 +5129,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vector vWorkQueue; vector vEraseQueue; CDataStream vMsg(vRecv); - CTxDB txdb("r"); + CActiveTxDB txdb("r"); CTransaction tx; vRecv >> tx; @@ -6107,24 +6107,55 @@ bool SendMessages(CNode* pto, bool fSendTrickle) (int)pto->mapAskFor.size()); nLastStallLog = GetTime(); } - // Use the walk-forward progress point if available, to avoid - // restarting from pindexBest (which hits the CBlockLocator - // exponential gap and starts the walk-forward from scratch). - pto->pindexLastGetBlocksBegin = NULL; - if (nHighestInvWalk > nBestHeight && hashHighestInvWalk != 0 && - mapBlockIndex.count(hashHighestInvWalk)) + // During IBD, avoid falling back to legacy getblocks recovery + // anchored at pindexBest or a stale inv walk point. That path can + // repeatedly resolve the locator to the same low common ancestor + // on a weak peer set, which looks like a sync "freeze" near an + // early height (for example around 570) even though the real bug + // is the recovery loop. Keep stall recovery header-driven instead + // so the planner tip advances from the newest known header state. + if (IsInitialBlockDownload()) { - pto->PushGetBlocks(mapBlockIndex[hashHighestInvWalk], uint256(0)); - printf("SYNC-DIAG: stall re-request from walk=%d (not best=%d)\n", - nHighestInvWalk, nBestHeight); - } else { - pto->PushGetBlocks(pindexBest, uint256(0)); + pto->pindexLastGetHeadersBegin = NULL; + + uint256 hashLocatorTip = hashBestHeaderSync; + if (hashLocatorTip == 0 && nHighestInvWalk > nBestHeight && + hashHighestInvWalk != 0 && mapBlockIndex.count(hashHighestInvWalk)) + { + hashLocatorTip = hashHighestInvWalk; + } + + unsigned int nRefilled = RequestHeaderSyncRefillAllPeers( + hashLocatorTip, + 0, + "stall-recovery"); + unsigned int nQueued = QueueHeaderSyncBlocksParallel(HEADER_DOWNLOAD_WINDOW); + + printf("SYNC-DIAG: stall recovery used headers-first path (locator=%s, refillPeers=%u, queued=%u)\n", + hashLocatorTip.ToString().substr(0,20).c_str(), + nRefilled, + nQueued); + } + else + { + // Outside IBD, preserve the older walk-forward getblocks + // behavior since we're no longer building out a header planner. + pto->pindexLastGetBlocksBegin = NULL; + if (nHighestInvWalk > nBestHeight && hashHighestInvWalk != 0 && + mapBlockIndex.count(hashHighestInvWalk)) + { + pto->PushGetBlocks(mapBlockIndex[hashHighestInvWalk], uint256(0)); + printf("SYNC-DIAG: stall re-request from walk=%d (not best=%d)\n", + nHighestInvWalk, nBestHeight); + } + else + { + pto->PushGetBlocks(pindexBest, uint256(0)); + } + + pto->pindexLastGetHeadersBegin = NULL; + pto->PushGetHeaders(pindexBest, uint256(0)); } - // Also send getheaders during stall to restart the header planner. - // Without this, a drained header cache stays empty because only - // getblocks is sent on stall, which can't refill mapHeaderSync. - pto->pindexLastGetHeadersBegin = NULL; - pto->PushGetHeaders(pindexBest, uint256(0)); nLastBlockReceived = GetTime(); } } @@ -6212,7 +6243,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) vector vGetData; int64_t nNow = GetTime() * 1000000; - CTxDB txdb("r"); + CActiveTxDB txdb("r"); // During IBD, send larger getdata batches since PoS blocks are small // and the bottleneck is round-trip latency, not bandwidth. unsigned int nGetDataBatchSize = IsInitialBlockDownload() ? 4000 : 1000; diff --git a/src/txdb-base.h b/src/txdb-base.h index 46a164d..892508e 100644 --- a/src/txdb-base.h +++ b/src/txdb-base.h @@ -80,6 +80,13 @@ public: bool IsReadOnly() const { return fReadOnly; } + // Wrapper accessors for backend forwarding (used by CActiveTxDB). + bool ReadRawBytes(const std::string& key, std::string& value) const { return ReadRaw(key, value); } + bool WriteRawBytes(const std::string& key, const std::string& value) { return WriteRaw(key, value); } + bool EraseRawBytes(const std::string& key) { return EraseRaw(key); } + bool ExistsRawBytes(const std::string& key) const { return ExistsRaw(key); } + std::unique_ptr NewRawIterator() const { return NewIterator(); } + // ── Schema versioning ──────────────────────────────────────────────────── bool ReadVersion(int& nVersion); bool WriteVersion(int nVersion); diff --git a/src/txdb.cpp b/src/txdb.cpp new file mode 100644 index 0000000..c4cd42b --- /dev/null +++ b/src/txdb.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2026 The Triangles developers. +// Distributed under the MIT/X11 software license. + +#include "txdb.h" + +#include "util.h" + +bool UseRocksDbBackend() +{ +#ifdef BUILD_ROCKSDB + return GetBoolArg("-rocksdb", false); +#else + return false; +#endif +} + +const char* GetActiveChainDbBackendName() +{ +#ifdef BUILD_ROCKSDB + return UseRocksDbBackend() ? "rocksdb" : "leveldb"; +#else + return "leveldb"; +#endif +} + +const char* GetActiveChainDbDirName() +{ +#ifdef BUILD_ROCKSDB + return UseRocksDbBackend() ? "rocksdb" : "txleveldb"; +#else + return "txleveldb"; +#endif +} + +CActiveTxDB::CActiveTxDB(const char* pszMode) +{ +#ifdef BUILD_ROCKSDB + if (UseRocksDbBackend()) + impl.reset(new CRocksTxDB(pszMode)); + else + impl.reset(new CTxDB(pszMode)); +#else + impl.reset(new CTxDB(pszMode)); +#endif +} + +CActiveTxDB::~CActiveTxDB() = default; + +void CActiveTxDB::Close() { impl->Close(); } +bool CActiveTxDB::TxnBegin() { return impl->TxnBegin(); } +bool CActiveTxDB::TxnCommit() { return impl->TxnCommit(); } +bool CActiveTxDB::TxnAbort() { return impl->TxnAbort(); } +bool CActiveTxDB::LoadBlockIndex() { return impl->LoadBlockIndex(); } + +bool CActiveTxDB::ReadRaw(const std::string& key, std::string& value) const { return impl->ReadRawBytes(key, value); } +bool CActiveTxDB::WriteRaw(const std::string& key, const std::string& value) { return impl->WriteRawBytes(key, value); } +bool CActiveTxDB::EraseRaw(const std::string& key) { return impl->EraseRawBytes(key); } +bool CActiveTxDB::ExistsRaw(const std::string& key) const { return impl->ExistsRawBytes(key); } +std::unique_ptr CActiveTxDB::NewIterator() const { return impl->NewRawIterator(); } diff --git a/src/txdb.h b/src/txdb.h index 1f73299..1c0be09 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -7,5 +7,37 @@ #define TRIANGLES_TXDB_H #include "txdb-leveldb.h" +#ifdef BUILD_ROCKSDB +#include "txdb-rocksdb.h" +#endif + +#include + +bool UseRocksDbBackend(); +const char* GetActiveChainDbBackendName(); +const char* GetActiveChainDbDirName(); + +class CActiveTxDB final : public CTxDBBase +{ +public: + explicit CActiveTxDB(const char* pszMode = "r+"); + ~CActiveTxDB() override; + + void Close() override; + bool TxnBegin() override; + bool TxnCommit() override; + bool TxnAbort() override; + bool LoadBlockIndex() override; + +protected: + bool ReadRaw(const std::string& key, std::string& value) const override; + bool WriteRaw(const std::string& key, const std::string& value) override; + bool EraseRaw(const std::string& key) override; + bool ExistsRaw(const std::string& key) const override; + std::unique_ptr NewIterator() const override; + +private: + std::unique_ptr impl; +}; #endif // TRIANGLES_TXDB_H diff --git a/src/utxosnapshot.cpp b/src/utxosnapshot.cpp index ed8558c..a17b760 100644 --- a/src/utxosnapshot.cpp +++ b/src/utxosnapshot.cpp @@ -16,6 +16,13 @@ #include #include #include +#ifdef BUILD_ROCKSDB +#include +#include +#include +#include +#include +#endif #include @@ -64,7 +71,7 @@ bool DumpSnapshot(const fs::path& destPath, // Count UTXOs first int nUtxoCount = 0; { - CTxDB txdbRead("r"); + CActiveTxDB txdbRead("r"); txdbRead.SumUtxoValues(nUtxoCount); } @@ -271,47 +278,104 @@ bool LoadSnapshot(const fs::path& snapshotPath, printf("UtxoSnapshot: loading snapshot at height %d (%d headers, %d UTXOs)\n", height, numHeaders, numUtxos); - // Create fresh LevelDB directory - fs::path txleveldbPath = dataDir / "txleveldb"; - if (fs::exists(txleveldbPath)) - fs::remove_all(txleveldbPath); - fs::create_directories(txleveldbPath); + // Create fresh chain DB directory for the active backend. + const bool useRocksDb = UseRocksDbBackend(); + fs::path chainDbPath = dataDir / GetActiveChainDbDirName(); + if (fs::exists(chainDbPath)) + fs::remove_all(chainDbPath); + fs::create_directories(chainDbPath); - // Open LevelDB directly (not via CTxDB - it's not initialized yet) - leveldb::Options options; int nCacheSizeMB = GetArg("-dbcache", 2048); - options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576); - options.filter_policy = leveldb::NewBloomFilterPolicy(10); - options.write_buffer_size = 64 * 1048576; - options.max_open_files = 1000; - options.create_if_missing = true; - leveldb::DB* pdb = NULL; - leveldb::Status status = leveldb::DB::Open(options, txleveldbPath.string(), &pdb); - if (!status.ok()) { + leveldb::Options options; + options.block_cache = NULL; + options.filter_policy = NULL; +#ifdef BUILD_ROCKSDB + rocksdb::DB* rdb = NULL; + std::shared_ptr rocksCache; + rocksdb::BlockBasedTableOptions rocksTableOptions; +#endif + + if (useRocksDb) { +#ifdef BUILD_ROCKSDB + rocksdb::Options rocksOptions; + rocksOptions.create_if_missing = true; + rocksOptions.compression = rocksdb::kSnappyCompression; + rocksOptions.write_buffer_size = 64 * 1048576; + rocksOptions.max_open_files = 1000; + rocksCache = rocksdb::NewLRUCache(static_cast(nCacheSizeMB) * 1048576); + rocksTableOptions.block_cache = rocksCache; + rocksTableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, false)); + rocksOptions.table_factory.reset(rocksdb::NewBlockBasedTableFactory(rocksTableOptions)); + rocksdb::Status rocksStatus = rocksdb::DB::Open(rocksOptions, chainDbPath.string(), &rdb); + if (!rocksStatus.ok()) { + fclose(file); + strError = "Cannot create RocksDB: " + rocksStatus.ToString(); + return false; + } +#else fclose(file); - delete options.filter_policy; - delete options.block_cache; - strError = "Cannot create LevelDB: " + status.ToString(); + strError = "RocksDB snapshot load requested but binary was built without RocksDB"; return false; +#endif + } else { + options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576); + options.filter_policy = leveldb::NewBloomFilterPolicy(10); + options.write_buffer_size = 64 * 1048576; + options.max_open_files = 1000; + options.create_if_missing = true; + + leveldb::Status status = leveldb::DB::Open(options, chainDbPath.string(), &pdb); + if (!status.ok()) { + fclose(file); + delete options.filter_policy; + delete options.block_cache; + strError = "Cannot create LevelDB: " + status.ToString(); + return false; + } } SHA256_CTX sha256; SHA256_Init(&sha256); - leveldb::WriteBatch batch; bool success = true; unsigned int nBatchSize = 0; + leveldb::WriteBatch batch; +#ifdef BUILD_ROCKSDB + rocksdb::WriteBatch rocksBatch; +#endif + + auto batchPut = [&](const std::string& key, const std::string& value) { + if (useRocksDb) { +#ifdef BUILD_ROCKSDB + rocksBatch.Put(key, value); +#endif + } else { + batch.Put(key, value); + } + nBatchSize++; + }; auto flushBatch = [&]() -> bool { if (nBatchSize == 0) return true; - leveldb::Status s = pdb->Write(leveldb::WriteOptions(), &batch); - if (!s.ok()) { - strError = "LevelDB write failed: " + s.ToString(); - return false; + if (useRocksDb) { +#ifdef BUILD_ROCKSDB + rocksdb::Status s = rdb->Write(rocksdb::WriteOptions(), &rocksBatch); + if (!s.ok()) { + strError = "RocksDB write failed: " + s.ToString(); + return false; + } + rocksBatch.Clear(); +#endif + } else { + leveldb::Status s = pdb->Write(leveldb::WriteOptions(), &batch); + if (!s.ok()) { + strError = "LevelDB write failed: " + s.ToString(); + return false; + } + batch.Clear(); } - batch.Clear(); nBatchSize = 0; return true; }; @@ -352,8 +416,7 @@ bool LoadSnapshot(const fs::path& snapshotPath, CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue << diskindex; - batch.Put(ssKey.str(), ssValue.str()); - nBatchSize++; + batchPut(ssKey.str(), ssValue.str()); if (nBatchSize >= 1000) { if (!flushBatch()) { success = false; break; } @@ -401,8 +464,7 @@ bool LoadSnapshot(const fs::path& snapshotPath, CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue << entry; - batch.Put(ssKey.str(), ssValue.str()); - nBatchSize++; + batchPut(ssKey.str(), ssValue.str()); if (nBatchSize >= 50000) { if (!flushBatch()) { success = false; break; } @@ -433,37 +495,50 @@ bool LoadSnapshot(const fs::path& snapshotPath, // Write metadata if (success) { - leveldb::WriteBatch metaBatch; - - // hashBestChain CDataStream ssKey1(SER_DISK, CLIENT_VERSION); ssKey1 << std::string("hashBestChain"); CDataStream ssVal1(SER_DISK, CLIENT_VERSION); ssVal1 << blockHash; - metaBatch.Put(ssKey1.str(), ssVal1.str()); - // dbformat = 3 CDataStream ssKey2(SER_DISK, CLIENT_VERSION); ssKey2 << std::string("dbformat"); CDataStream ssVal2(SER_DISK, CLIENT_VERSION); ssVal2 << (int)3; - metaBatch.Put(ssKey2.str(), ssVal2.str()); - // version CDataStream ssKey3(SER_DISK, CLIENT_VERSION); ssKey3 << std::string("version"); CDataStream ssVal3(SER_DISK, CLIENT_VERSION); ssVal3 << DATABASE_VERSION; - metaBatch.Put(ssKey3.str(), ssVal3.str()); - leveldb::Status s = pdb->Write(leveldb::WriteOptions(), &metaBatch); - if (!s.ok()) { - success = false; - strError = "Failed to write metadata: " + s.ToString(); + if (useRocksDb) { +#ifdef BUILD_ROCKSDB + rocksdb::WriteBatch metaBatch; + metaBatch.Put(ssKey1.str(), ssVal1.str()); + metaBatch.Put(ssKey2.str(), ssVal2.str()); + metaBatch.Put(ssKey3.str(), ssVal3.str()); + rocksdb::Status s = rdb->Write(rocksdb::WriteOptions(), &metaBatch); + if (!s.ok()) { + success = false; + strError = "Failed to write RocksDB metadata: " + s.ToString(); + } +#endif + } else { + leveldb::WriteBatch metaBatch; + metaBatch.Put(ssKey1.str(), ssVal1.str()); + metaBatch.Put(ssKey2.str(), ssVal2.str()); + metaBatch.Put(ssKey3.str(), ssVal3.str()); + leveldb::Status s = pdb->Write(leveldb::WriteOptions(), &metaBatch); + if (!s.ok()) { + success = false; + strError = "Failed to write metadata: " + s.ToString(); + } } } - // Clean up LevelDB + // Clean up chain DB +#ifdef BUILD_ROCKSDB + delete rdb; +#endif delete pdb; delete options.filter_policy; delete options.block_cache; @@ -473,8 +548,8 @@ bool LoadSnapshot(const fs::path& snapshotPath, if (!success) { // Remove corrupted/incomplete database printf("UtxoSnapshot: load failed: %s\n", strError.c_str()); - if (fs::exists(txleveldbPath)) - fs::remove_all(txleveldbPath); + if (fs::exists(chainDbPath)) + fs::remove_all(chainDbPath); return false; }