CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL) , activeTxn(NULL) { int ret; fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; if (strFilename.empty()) return; bool fCreate = strchr(pszMode, 'c') != NULL; unsigned int nFlags = DB_THREAD; if (fCreate) nFlags |= DB_CREATE; { LOCK(bitdb.cs_db); if (!bitdb.Open(GetDataDir())) throw runtime_error("CDB: Failed to open database environment."); strFile = strFilename; ++bitdb.mapFileUseCount[strFile]; pdb = bitdb.mapDb[strFile]; if (pdb == NULL) { pdb = new Db(bitdb.dbenv, 0); bool fMockDb = bitdb.IsMock(); if (fMockDb) { DbMpoolFile* mpf = pdb->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); if (ret != 0) throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile)); } ret = pdb->open(NULL, // Txn pointer fMockDb ? NULL : strFile.c_str(), // Filename fMockDb ? strFile.c_str() : "main", // Logical db name DB_BTREE, // Database type nFlags, // Flags 0); if (ret != 0) { delete pdb; pdb = NULL; --bitdb.mapFileUseCount[strFile]; strFile = ""; throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); } if (fCreate && !Exists(string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; WriteVersion(CLIENT_VERSION); fReadOnly = fTmp; } bitdb.mapDb[strFile] = pdb; } } }
bool BerkeleyQ::connect() { if (NULL != db) return true; try { int ret = 0; uint env_flags = DB_CREATE | /* Create the environment if it does not exist */ DB_INIT_LOCK | /* Initialize the locking subsystem */ DB_INIT_MPOOL | /* Initialize the memory pool (in-memory cache) */ DB_PRIVATE | /* Region files are not backed by the * filesystem. Instead, they are backed by * heap memory. */ DB_THREAD; DbEnv* env = new DbEnv(0); ret = env->set_cachesize(0, /* 0 gigabytes */ 50 * 1024 * 1024, /* 50 megabytes */ 1); /* Create 1 cache. All memory will * be allocated contiguously. */ env->open(NULL, env_flags, 0); db = new Db(env, 0); // Instantiate the Db object db->open(NULL, // Transaction pointer NULL, // Database file name NULL, // Optional logical database name DB_BTREE, // Database access method DB_CREATE | DB_THREAD, // Open flags 0); // File mode (using defaults) DbMpoolFile* mp = db->get_mpf(); ret = mp->set_flags(DB_MPOOL_NOFILE, 1); db->get_env()->lock_id(&locker_id); start(); } catch(DbException &e) { db = NULL; q_error("failed connecting to berkeley. %s", e.what()); } catch(std::exception &e) { db = NULL; q_error("failed connecting to berkeley. %s", e.what()); } catch (...) { db = NULL; q_error("failed connecting to berkeley. unknown error"); } return (NULL != db); }
// // run -- // Get a set of pages. // int MpoolExample::run(int hits, int pagesize, int npages) { db_pgno_t pageno; int cnt, ret; void *p; // Open the file in the environment. DbMpoolFile *mfp; if ((ret = memp_fcreate(&mfp, 0)) != 0) { cerr << "MpoolExample: memp_fcreate failed: " << strerror(ret) << "\n"; return (EXIT_FAILURE); } mfp->open(MPOOL, 0, 0, pagesize); cout << "retrieve " << hits << " random pages... "; srand((unsigned int)time(NULL)); for (cnt = 0; cnt < hits; ++cnt) { pageno = (rand() % npages) + 1; if ((ret = mfp->get(&pageno, NULL, 0, &p)) != 0) { cerr << "MpoolExample: unable to retrieve page " << (unsigned long)pageno << ": " << strerror(ret) << "\n"; return (EXIT_FAILURE); } if (*(db_pgno_t *)p != pageno) { cerr << "MpoolExample: wrong page retrieved (" << (unsigned long)pageno << " != " << *(int *)p << ")\n"; return (EXIT_FAILURE); } if ((ret = mfp->put(p, DB_PRIORITY_UNCHANGED, 0)) != 0) { cerr << "MpoolExample: unable to return page " << (unsigned long)pageno << ": " << strerror(ret) << "\n"; return (EXIT_FAILURE); } } cout << "successful.\n"; // Close the pool. if ((ret = close(0)) != 0) { cerr << "MpoolExample: " << strerror(ret) << "\n"; return (EXIT_FAILURE); } return (EXIT_SUCCESS); }
BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr) { fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; env = database.env; if (database.IsDummy()) { return; } const std::string &strFilename = database.strFile; bool fCreate = strchr(pszMode, 'c') != nullptr; unsigned int nFlags = DB_THREAD; if (fCreate) nFlags |= DB_CREATE; { LOCK(cs_db); if (!env->Open(false /* retry */)) throw std::runtime_error("BerkeleyBatch: Failed to open database environment."); pdb = env->mapDb[strFilename]; if (pdb == nullptr) { int ret; std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0); bool fMockDb = env->IsMock(); if (fMockDb) { DbMpoolFile* mpf = pdb_temp->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); if (ret != 0) { throw std::runtime_error(strprintf("BerkeleyBatch: Failed to configure for no temp file backing for database %s", strFilename)); } } ret = pdb_temp->open(nullptr, // Txn pointer fMockDb ? nullptr : strFilename.c_str(), // Filename fMockDb ? strFilename.c_str() : "main", // Logical db name DB_BTREE, // Database type nFlags, // Flags 0); if (ret != 0) { throw std::runtime_error(strprintf("BerkeleyBatch: Error %d, can't open database %s", ret, strFilename)); } // Call CheckUniqueFileid on the containing BDB environment to // avoid BDB data consistency bugs that happen when different data // files in the same environment have the same fileid. // // Also call CheckUniqueFileid on all the other g_dbenvs to prevent // bitcoin from opening the same data file through another // environment when the file is referenced through equivalent but // not obviously identical symlinked or hard linked or bind mounted // paths. In the future a more relaxed check for equal inode and // device ids could be done instead, which would allow opening // different backup copies of a wallet at the same time. Maybe even // more ideally, an exclusive lock for accessing the database could // be implemented, so no equality checks are needed at all. (Newer // versions of BDB have an set_lk_exclusive method for this // purpose, but the older version we use does not.) for (const auto& env : g_dbenvs) { CheckUniqueFileid(env.second, strFilename, *pdb_temp, this->env->m_fileids[strFilename]); } pdb = pdb_temp.release(); env->mapDb[strFilename] = pdb; if (fCreate && !Exists(std::string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; WriteVersion(CLIENT_VERSION); fReadOnly = fTmp; } } ++env->mapFileUseCount[strFilename]; strFile = strFilename; } }