upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/db.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.cpp')
-rw-r--r--src/db.cpp36
1 files changed, 36 insertions, 0 deletions
diff --git a/src/db.cpp b/src/db.cpp
index ce7b875..16f2e91 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -13,6 +13,39 @@
13// CDB 13// CDB
14// 14//
15 15
16// Closes a Berkeley DB cursor however the function exits.
17//
18// Three functions opened one and none of them ever closed it. Berkeley DB
19// requires every cursor to be closed before the handle it came from, and
20// ~CDB() calls Close(), which calls pdb->close() inside a catch-all that
21// swallows whatever it returns. So the violation was real and silent.
22//
23// An open cursor also holds read locks. That is what made the first version of
24// the startup chain repair (#61) hang: it opened a write transaction beside
25// the cursor CTxDB::LoadBlockIndex was still holding, and waited on it forever
26// with nothing in any log. The repair had to be moved to the caller.
27//
28// Each of these functions has several early returns, so a guard is safer than
29// remembering to close on every one of them. Same fix Bitcoin made in
30// c5c7911da, alongside its zombie-socket and double-close work.
31class CAutoCursor
32{
33public:
34 explicit CAutoCursor(Dbc* pcursorIn) : pcursor(pcursorIn) { }
35 ~CAutoCursor()
36 {
37 if (pcursor)
38 {
39 try { pcursor->close(); }
40 catch (...) { } // closing on the way out must not throw
41 }
42 }
43private:
44 Dbc* pcursor;
45 CAutoCursor(const CAutoCursor&);
46 void operator=(const CAutoCursor&);
47};
48
16static CCriticalSection cs_db; 49static CCriticalSection cs_db;
17static bool fDbEnvInit = false; 50static bool fDbEnvInit = false;
18DbEnv dbenv(0u); 51DbEnv dbenv(0u);
@@ -266,6 +299,7 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>&
266 Dbc* pcursor = GetCursor(); 299 Dbc* pcursor = GetCursor();
267 if (!pcursor) 300 if (!pcursor)
268 return false; 301 return false;
302 CAutoCursor cursorGuard(pcursor);
269 303
270 unsigned int fFlags = DB_SET_RANGE; 304 unsigned int fFlags = DB_SET_RANGE;
271 loop 305 loop
@@ -375,6 +409,7 @@ bool CTxDB::LoadBlockIndex()
375 Dbc* pcursor = GetCursor(); 409 Dbc* pcursor = GetCursor();
376 if (!pcursor) 410 if (!pcursor)
377 return false; 411 return false;
412 CAutoCursor cursorGuard(pcursor);
378 413
379 unsigned int fFlags = DB_SET_RANGE; 414 unsigned int fFlags = DB_SET_RANGE;
380 loop 415 loop
@@ -544,6 +579,7 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
544 Dbc* pcursor = GetCursor(); 579 Dbc* pcursor = GetCursor();
545 if (!pcursor) 580 if (!pcursor)
546 return false; 581 return false;
582 CAutoCursor cursorGuard(pcursor);
547 583
548 loop 584 loop
549 { 585 {