| 444 | |
| 445 | |
| 446 | BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr) |
| 447 | { |
| 448 | fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); |
| 449 | fFlushOnClose = fFlushOnCloseIn; |
| 450 | env = database.env; |
| 451 | if (database.IsDummy()) { |
| 452 | return; |
| 453 | } |
| 454 | const std::string &strFilename = database.strFile; |
| 455 | |
| 456 | bool fCreate = strchr(pszMode, 'c') != nullptr; |
| 457 | unsigned int nFlags = DB_THREAD; |
| 458 | if (fCreate) |
| 459 | nFlags |= DB_CREATE; |
| 460 | |
| 461 | { |
| 462 | LOCK(cs_db); |
| 463 | if (!env->Open(false /* retry */)) |
| 464 | throw std::runtime_error("BerkeleyBatch: Failed to open database environment."); |
| 465 | |
| 466 | pdb = env->mapDb[strFilename]; |
| 467 | if (pdb == nullptr) { |
| 468 | int ret; |
| 469 | std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0); |
| 470 | |
| 471 | bool fMockDb = env->IsMock(); |
| 472 | if (fMockDb) { |
| 473 | DbMpoolFile* mpf = pdb_temp->get_mpf(); |
| 474 | ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); |
| 475 | if (ret != 0) { |
| 476 | throw std::runtime_error(strprintf("BerkeleyBatch: Failed to configure for no temp file backing for database %s", strFilename)); |
| 477 | } |
| 478 | } |
| 479 | |
| 480 | ret = pdb_temp->open(nullptr, // Txn pointer |
| 481 | fMockDb ? nullptr : strFilename.c_str(), // Filename |
| 482 | fMockDb ? strFilename.c_str() : "main", // Logical db name |
| 483 | DB_BTREE, // Database type |
| 484 | nFlags, // Flags |
| 485 | 0); |
| 486 | |
| 487 | if (ret != 0) { |
| 488 | throw std::runtime_error(strprintf("BerkeleyBatch: Error %d, can't open database %s", ret, strFilename)); |
| 489 | } |
| 490 | |
| 491 | // Call CheckUniqueFileid on the containing BDB environment to |
| 492 | // avoid BDB data consistency bugs that happen when different data |
| 493 | // files in the same environment have the same fileid. |
| 494 | // |
| 495 | // Also call CheckUniqueFileid on all the other g_dbenvs to prevent |
| 496 | // bitcoin from opening the same data file through another |
| 497 | // environment when the file is referenced through equivalent but |
| 498 | // not obviously identical symlinked or hard linked or bind mounted |
| 499 | // paths. In the future a more relaxed check for equal inode and |
| 500 | // device ids could be done instead, which would allow opening |
| 501 | // different backup copies of a wallet at the same time. Maybe even |
| 502 | // more ideally, an exclusive lock for accessing the database could |
| 503 | // be implemented, so no equality checks are needed at all. (Newer |