diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2013-01-29 01:44:19 +0100 |
---|---|---|
committer | Pieter Wuille <pieterw@google.com> | 2013-01-30 04:30:02 +0100 |
commit | 421218d3040279c84616891e8d14b05576b07c57 (patch) | |
tree | a1d1546c823d593008866a3790c0c71cbe4c10de | |
parent | 7851033dd687e826df82c1ec841480710468ce8c (diff) |
Deal with LevelDB errors
-rw-r--r-- | src/init.cpp | 4 | ||||
-rw-r--r-- | src/leveldb.cpp | 16 | ||||
-rw-r--r-- | src/leveldb.h | 23 | ||||
-rw-r--r-- | src/main.cpp | 70 |
4 files changed, 74 insertions, 39 deletions
diff --git a/src/init.cpp b/src/init.cpp index c87850b664..2f37dad56c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -187,9 +187,9 @@ bool AppInit(int argc, char* argv[]) fRet = AppInit2(); } catch (std::exception& e) { - PrintException(&e, "AppInit()"); + PrintExceptionContinue(&e, "AppInit()"); } catch (...) { - PrintException(NULL, "AppInit()"); + PrintExceptionContinue(NULL, "AppInit()"); } if (!fRet) Shutdown(NULL); diff --git a/src/leveldb.cpp b/src/leveldb.cpp index 9e2f32a171..b41764f51f 100644 --- a/src/leveldb.cpp +++ b/src/leveldb.cpp @@ -12,6 +12,18 @@ #include <boost/filesystem.hpp> +void HandleError(const leveldb::Status &status) throw(leveldb_error) { + if (status.ok()) + return; + if (status.IsCorruption()) + throw leveldb_error("Database corrupted"); + if (status.IsIOError()) + throw leveldb_error("Database I/O error"); + if (status.IsNotFound()) + throw leveldb_error("Database entry missing"); + throw leveldb_error("Unknown database error"); +} + static leveldb::Options GetOptions(size_t nCacheSize) { leveldb::Options options; options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); @@ -57,12 +69,12 @@ CLevelDB::~CLevelDB() { options.env = NULL; } -bool CLevelDB::WriteBatch(CLevelDBBatch &batch, bool fSync) { +bool CLevelDB::WriteBatch(CLevelDBBatch &batch, bool fSync) throw(leveldb_error) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); if (!status.ok()) { printf("LevelDB write failure: %s\n", status.ToString().c_str()); + HandleError(status); return false; } return true; } - diff --git a/src/leveldb.h b/src/leveldb.h index 0b83432072..79262edbb5 100644 --- a/src/leveldb.h +++ b/src/leveldb.h @@ -11,6 +11,14 @@ #include <boost/filesystem/path.hpp> +class leveldb_error : public std::runtime_error +{ +public: + leveldb_error(const std::string &msg) : std::runtime_error(msg) {} +}; + +void HandleError(const leveldb::Status &status) throw(leveldb_error); + // Batch of changes queued to be written to a CLevelDB class CLevelDBBatch { @@ -72,7 +80,7 @@ public: CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); ~CLevelDB(); - template<typename K, typename V> bool Read(const K& key, V& value) { + template<typename K, typename V> bool Read(const K& key, V& value) throw(leveldb_error) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); ssKey << key; @@ -84,6 +92,7 @@ public: if (status.IsNotFound()) return false; printf("LevelDB read failure: %s\n", status.ToString().c_str()); + HandleError(status); } try { CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); @@ -94,13 +103,13 @@ public: return true; } - template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) { + template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) { CLevelDBBatch batch; batch.Write(key, value); return WriteBatch(batch, fSync); } - template<typename K> bool Exists(const K& key) { + template<typename K> bool Exists(const K& key) throw(leveldb_error) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); ssKey << key; @@ -112,24 +121,25 @@ public: if (status.IsNotFound()) return false; printf("LevelDB read failure: %s\n", status.ToString().c_str()); + HandleError(status); } return true; } - template<typename K> bool Erase(const K& key, bool fSync = false) { + template<typename K> bool Erase(const K& key, bool fSync = false) throw(leveldb_error) { CLevelDBBatch batch; batch.Erase(key); return WriteBatch(batch, fSync); } - bool WriteBatch(CLevelDBBatch &batch, bool fSync = false); + bool WriteBatch(CLevelDBBatch &batch, bool fSync = false) throw(leveldb_error); // not available for LevelDB; provide for compatibility with BDB bool Flush() { return true; } - bool Sync() { + bool Sync() throw(leveldb_error) { CLevelDBBatch batch; return WriteBatch(batch, true); } @@ -141,4 +151,3 @@ public: }; #endif // BITCOIN_LEVELDB_H -
\ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 82ef88b855..412f4d7a07 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -800,7 +800,11 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs) { - return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs); + try { + return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs); + } catch(std::runtime_error &e) { + return state.Abort(_("System error: ") + e.what()); + } } bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx) @@ -1256,8 +1260,12 @@ bool ConnectBestBlock(CValidationState &state) { if (fRequestShutdown) break; CValidationState state; - if (!SetBestChain(state, pindexSwitch)) - return false; + try { + if (!SetBestChain(state, pindexSwitch)) + return false; + } catch(std::runtime_error &e) { + return state.Abort(_("System error: ") + e.what()); + } } return true; } @@ -1687,7 +1695,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) return error("ConnectBlock() : FindUndoPos failed"); if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash())) - return state.Abort(_("Error: failed to write undo data")); + return state.Abort(_("Failed to write undo data")); // update nUndoPos in block index pindex->nUndoPos = pos.nPos; @@ -1698,12 +1706,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi CDiskBlockIndex blockindex(pindex); if (!pblocktree->WriteBlockIndex(blockindex)) - return state.Abort(_("Error: failed to write block index")); + return state.Abort(_("Failed to write block index")); } if (fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) - return state.Abort(_("Error: failed to write transaction index")); + return state.Abort(_("Failed to write transaction index")); // add this block to the view's block chain assert(view.SetBestBlock(pindex)); @@ -1757,7 +1765,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { CBlock block; if (!block.ReadFromDisk(pindex)) - return state.Abort(_("Error: failed to read block")); + return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); if (!block.DisconnectBlock(state, pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); @@ -1777,7 +1785,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) BOOST_FOREACH(CBlockIndex *pindex, vConnect) { CBlock block; if (!block.ReadFromDisk(pindex)) - return state.Abort(_("Error: failed to read block")); + return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); if (!block.ConnectBlock(state, pindex, view)) { if (state.IsInvalid()) { @@ -1815,7 +1823,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) FlushBlockFile(); pblocktree->Sync(); if (!pcoinsTip->Flush()) - return state.Abort(_("Error: failed to write to coin database")); + return state.Abort(_("Failed to write to coin database")); } // At this point, all changes have been done to the database. @@ -1921,7 +1929,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) setBlockIndexValid.insert(pindexNew); if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew))) - return state.Abort(_("Error: failed to write block index")); + return state.Abort(_("Failed to write block index")); // New best? if (!ConnectBestBlock(state)) @@ -1936,7 +1944,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) } if (!pblocktree->Flush()) - return state.Abort(_("Error: failed to sync block index")); + return state.Abort(_("Failed to sync block index")); uiInterface.NotifyBlocksChanged(); return true; @@ -1990,7 +1998,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd } if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) - return state.Abort(_("Error: failed to write file info")); + return state.Abort(_("Failed to write file info")); if (fUpdatedLast) pblocktree->WriteLastBlockFile(nLastBlockFile); @@ -2008,15 +2016,15 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne pos.nPos = infoLastBlockFile.nUndoSize; nNewSize = (infoLastBlockFile.nUndoSize += nAddSize); if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) - return state.Abort(_("Error: failed to write block info")); + return state.Abort(_("Failed to write block info")); } else { CBlockFileInfo info; if (!pblocktree->ReadBlockFileInfo(nFile, info)) - return state.Abort(_("Error: failed to read block info")); + return state.Abort(_("Failed to read block info")); pos.nPos = info.nUndoSize; nNewSize = (info.nUndoSize += nAddSize); if (!pblocktree->WriteBlockFileInfo(nFile, info)) - return state.Abort(_("Error: failed to write block info")); + return state.Abort(_("Failed to write block info")); } unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; @@ -2154,17 +2162,21 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) } // Write block to history file - unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - if (dbp != NULL) - blockPos = *dbp; - if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) - return error("AcceptBlock() : FindBlockPos failed"); - if (dbp == NULL) - if (!WriteToDisk(blockPos)) - return state.Abort(_("Error: failed to write block")); - if (!AddToBlockIndex(state, blockPos)) - return error("AcceptBlock() : AddToBlockIndex failed"); + try { + unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + if (dbp != NULL) + blockPos = *dbp; + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) + return error("AcceptBlock() : FindBlockPos failed"); + if (dbp == NULL) + if (!WriteToDisk(blockPos)) + return state.Abort(_("Failed to write block")); + if (!AddToBlockIndex(state, blockPos)) + return error("AcceptBlock() : AddToBlockIndex failed"); + } catch(std::runtime_error &e) { + return state.Abort(_("System error: ") + e.what()); + } // Relay inventory, but don't relay old inventory during initial block download int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); @@ -2432,7 +2444,7 @@ bool AbortNode(const std::string &strMessage) { fRequestShutdown = true; strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MODAL); StartShutdown(); return false; } @@ -2801,7 +2813,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) int64 nStart = GetTimeMillis(); int nLoaded = 0; - { + try { CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); uint64 nStartByte = 0; if (dbp) { @@ -2858,6 +2870,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } } fclose(fileIn); + } catch(std::runtime_error &e) { + AbortNode(_("Error: system error: ") + e.what()); } if (nLoaded > 0) printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart); |