diff options
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 36 |
1 files changed, 36 insertions, 0 deletions
| @@ -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. | ||
| 31 | class CAutoCursor | ||
| 32 | { | ||
| 33 | public: | ||
| 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 | } | ||
| 43 | private: | ||
| 44 | Dbc* pcursor; | ||
| 45 | CAutoCursor(const CAutoCursor&); | ||
| 46 | void operator=(const CAutoCursor&); | ||
| 47 | }; | ||
| 48 | |||
| 16 | static CCriticalSection cs_db; | 49 | static CCriticalSection cs_db; |
| 17 | static bool fDbEnvInit = false; | 50 | static bool fDbEnvInit = false; |
| 18 | DbEnv dbenv(0u); | 51 | DbEnv 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 | { |