fix: self-heal a corrupt/torn notarizations DB instead of aborting startup
A torn or corrupt notarizations (dPoW) leveldb -- a 0-byte log left by a torn snapshot, or a corrupt MANIFEST -- threw at open and was caught by the block-DB load try/catch, aborting startup with a misleading Error-opening-block-database message and forcing a full resync. The notarizations DB is non-essential and node-regenerable, so on open failure move it aside (notarizations.corrupt, preserving the data in case the error was transient) and regenerate a fresh one; if the fresh recreate also fails it still propagates as fatal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
22
src/init.cpp
22
src/init.cpp
@@ -1087,8 +1087,8 @@ static const int64_t g_nMinCoinCacheMB = 256; // never thrash below this working
|
|||||||
|
|
||||||
// Scheduled task: nudge nCoinCacheUsage toward "use all RAM except the reserve". If free RAM is below
|
// Scheduled task: nudge nCoinCacheUsage toward "use all RAM except the reserve". If free RAM is below
|
||||||
// the reserve we shrink the target (the next per-block flush releases the excess); if there is spare
|
// the reserve we shrink the target (the next per-block flush releases the excess); if there is spare
|
||||||
// RAM we grow it back toward the startup ceiling. Lock-free: it only reads system memory and writes
|
// RAM we grow it back toward the startup ceiling. nCoinCacheUsage is std::atomic<size_t>, so this
|
||||||
// the aligned size_t threshold that the flush path reads.
|
// cross-thread write (vs the cs_main-held reads in FlushStateToDisk/VerifyDB) is well-defined, no lock needed.
|
||||||
static void AdjustCoinCacheForMemoryPressure()
|
static void AdjustCoinCacheForMemoryPressure()
|
||||||
{
|
{
|
||||||
if (g_nMaxCoinCacheUsage == 0)
|
if (g_nMaxCoinCacheUsage == 0)
|
||||||
@@ -2072,7 +2072,25 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
|
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
|
||||||
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
||||||
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
||||||
|
try {
|
||||||
pnotarizations = new NotarizationDB(100*1024*1024, false, fReindex);
|
pnotarizations = new NotarizationDB(100*1024*1024, false, fReindex);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
// The notarizations (dPoW) DB is non-essential and node-regenerable. It has been seen to
|
||||||
|
// snapshot/flush torn (0-byte log -> leveldb "Database I/O error" on reopen), which
|
||||||
|
// previously aborted startup with a spurious "Error opening block database" and forced a
|
||||||
|
// full resync. Wipe and recreate it instead of failing hard.
|
||||||
|
LogPrintf("%s: notarizations DB failed to open (%s); moving aside and regenerating (non-fatal)\n", __FUNCTION__, e.what());
|
||||||
|
// Move (do NOT delete) the old DB aside, so a transient open failure (fd
|
||||||
|
// exhaustion, disk full, permissions) cannot permanently destroy notarization
|
||||||
|
// history. If the recreate below also fails it propagates as fatal and the old
|
||||||
|
// data survives in notarizations.corrupt for recovery.
|
||||||
|
{
|
||||||
|
boost::filesystem::path ndir = GetDataDir() / "notarizations";
|
||||||
|
boost::filesystem::remove_all(ndir.string() + ".corrupt");
|
||||||
|
boost::filesystem::rename(ndir, ndir.string() + ".corrupt");
|
||||||
|
}
|
||||||
|
pnotarizations = new NotarizationDB(100*1024*1024, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (fReindex) {
|
if (fReindex) {
|
||||||
|
|||||||
Reference in New Issue
Block a user