33    int ret = db.get_mpf()->get_fileid(fileid.
value);
 
   35        throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Can't open database %s (get_fileid failed with %d)", filename, ret));
 
   39        if (fileid == item.second && &fileid != &item.second) {
 
   40            throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Can't open database %s (duplicates fileid %s from %s)", filename,
 
   41                HexStr(item.second.value), item.first));
 
   47std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> g_dbenvs 
GUARDED_BY(cs_db); 
 
   64    auto inserted = g_dbenvs.emplace(
fs::PathToString(env_directory), std::weak_ptr<BerkeleyEnvironment>());
 
   65    if (inserted.second) {
 
   66        auto env = std::make_shared<BerkeleyEnvironment>(env_directory);
 
   67        inserted.first->second = env;
 
   70    return inserted.first->second.lock();
 
   88            database.
m_db->close(0);
 
   89            database.
m_db.reset();
 
   93    FILE* error_file = 
nullptr;
 
   94    dbenv->get_errfile(&error_file);
 
   96    int ret = 
dbenv->close(0);
 
   98        LogPrintf(
"BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret));
 
  100        DbEnv((u_int32_t)0).remove(
strPath.c_str(), 0);
 
  102    if (error_file) fclose(error_file);
 
  109    dbenv.reset(
new DbEnv(DB_CXX_NO_EXCEPTIONS));
 
  135        LogPrintf(
"Cannot obtain a lock on wallet directory %s. Another instance may be using it.\n", 
strPath);
 
  140    fs::path pathLogDir = pathIn / 
"database";
 
  142    fs::path pathErrorFile = pathIn / 
"db.log";
 
  145    unsigned int nEnvFlags = 0;
 
  147        nEnvFlags |= DB_PRIVATE;
 
  150    dbenv->set_cachesize(0, 0x100000, 1); 
 
  151    dbenv->set_lg_bsize(0x10000);
 
  152    dbenv->set_lg_max(1048576);
 
  153    dbenv->set_lk_max_locks(40000);
 
  154    dbenv->set_lk_max_objects(40000);
 
  156    dbenv->set_flags(DB_AUTO_COMMIT, 1);
 
  157    dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
 
  158    dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
 
  170        LogPrintf(
"BerkeleyEnvironment::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
 
  171        int ret2 = 
dbenv->close(0);
 
  173            LogPrintf(
"BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
 
  177        if (ret == DB_RUNRECOVERY) {
 
  178            err += 
Untranslated(
" ") + 
_(
"This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet");
 
  195    dbenv->set_cachesize(1, 0, 1);
 
  196    dbenv->set_lg_bsize(10485760 * 4);
 
  197    dbenv->set_lg_max(10485760);
 
  198    dbenv->set_lk_max_locks(10000);
 
  199    dbenv->set_lk_max_objects(10000);
 
  200    dbenv->set_flags(DB_AUTO_COMMIT, 1);
 
  201    dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
 
  202    int ret = 
dbenv->open(
nullptr,
 
  212        throw std::runtime_error(
strprintf(
"BerkeleyEnvironment::MakeMock: Error %d opening database environment.", ret));
 
  221    m_dbt.set_flags(DB_DBT_MALLOC);
 
  231    if (m_dbt.get_data() != 
nullptr) {
 
  237        if (m_dbt.get_flags() & DB_DBT_MALLOC) {
 
  238            free(m_dbt.get_data());
 
  245    return m_dbt.get_data();
 
  250    return m_dbt.get_size();
 
  253BerkeleyBatch::SafeDbt::operator Dbt*()
 
  275        int result = db.verify(
strFile.c_str(), 
nullptr, 
nullptr, 0);
 
  287    dbenv->txn_checkpoint(0, 0, 0);
 
  290    dbenv->lsn_reset(
strFile.c_str(), 0);
 
  314    if (!
Exists(std::string(
"version"))) {
 
  324    unsigned int nFlags = DB_THREAD | DB_CREATE;
 
  329        if (!
env->Open(open_err))
 
  330            throw std::runtime_error(
"BerkeleyDatabase: Failed to open database environment.");
 
  332        if (
m_db == 
nullptr) {
 
  334            std::unique_ptr<Db> pdb_temp = std::make_unique<Db>(
env->dbenv.get(), 0);
 
  336            bool fMockDb = 
env->IsMock();
 
  338                DbMpoolFile* mpf = pdb_temp->get_mpf();
 
  339                ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
 
  341                    throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Failed to configure for no temp file backing for database %s", 
strFile));
 
  345            ret = pdb_temp->open(
nullptr,                             
 
  346                            fMockDb ? 
nullptr : 
strFile.c_str(),      
 
  347                            fMockDb ? 
strFile.c_str() : 
"main",       
 
  353                throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Error %d, can't open database %s", ret, 
strFile));
 
  361            m_db.reset(pdb_temp.release());
 
  373    unsigned int nMinutes = 0;
 
  416            database.
m_db->close(0);
 
  417            database.
m_db.reset();
 
  426    std::unique_lock<RecursiveMutex> lock(cs_db);
 
  429            if (db.second.get().m_refcount > 0) 
return false;
 
  439    for (
const std::string& filename : 
filenames) {
 
  460                bool fSuccess = 
true;
 
  462                std::string strFileRes = 
strFile + 
".rewrite";
 
  465                    std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(
env->dbenv.get(), 0);
 
  467                    int ret = pdbCopy->open(
nullptr,               
 
  474                        LogPrintf(
"BerkeleyBatch::Rewrite: Can't create database file %s\n", strFileRes);
 
  491                                strncmp((
const char*)ssKey.
data(), pszSkip, std::min(ssKey.
size(), strlen(pszSkip))) == 0)
 
  493                            if (strncmp((
const char*)ssKey.
data(), 
"\x07version", 8) == 0) {
 
  498                            Dbt datKey(ssKey.
data(), ssKey.
size());
 
  499                            Dbt datValue(ssValue.
data(), ssValue.
size());
 
  500                            int ret2 = pdbCopy->put(
nullptr, &datKey, &datValue, DB_NOOVERWRITE);
 
  509                        if (pdbCopy->close(0))
 
  516                    Db dbA(
env->dbenv.get(), 0);
 
  517                    if (dbA.remove(
strFile.c_str(), 
nullptr, 0))
 
  519                    Db dbB(
env->dbenv.get(), 0);
 
  520                    if (dbB.rename(strFileRes.c_str(), 
nullptr, 
strFile.c_str(), 0))
 
  524                    LogPrintf(
"BerkeleyBatch::Rewrite: Failed to rewrite database file %s\n", strFileRes);
 
  542        bool no_dbs_accessed = 
true;
 
  544            std::string strFile = db_it.first;
 
  545            int nRefCount = db_it.second.get().m_refcount;
 
  546            if (nRefCount < 0) 
continue;
 
  548            if (nRefCount == 0) {
 
  552                dbenv->txn_checkpoint(0, 0, 0);
 
  555                    dbenv->lsn_reset(strFile.c_str(), 0);
 
  559                no_dbs_accessed = 
false;
 
  565            if (no_dbs_accessed) {
 
  566                dbenv->log_archive(&listp, DB_ARCH_REMOVE);
 
  580    if (!lockDb) 
return false;
 
  583    for (
auto& it : 
env->m_databases) {
 
  584        if (it.second.get().m_refcount > 0) 
return false;
 
  618                if (fs::is_directory(pathDest))
 
  622                    if (fs::equivalent(pathSrc, pathDest)) {
 
  627                    fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
 
  630                } 
catch (
const fs::filesystem_error& e) {
 
  667    if (
m_cursor == 
nullptr) 
return false;
 
  671    int ret = 
m_cursor->get(datKey, datValue, DB_NEXT);
 
  672    if (ret == DB_NOTFOUND) {
 
  729    DbEnv::version(&major, &minor, 
nullptr);
 
  734    if (major != DB_VERSION_MAJOR || minor < DB_VERSION_MINOR) {
 
  735        LogPrintf(
"BerkeleyDB database version conflict: header version is %d.%d, library version is %d.%d\n",
 
  736            DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor);
 
  745    return DbEnv::version(
nullptr, 
nullptr, 
nullptr);
 
  753    SafeDbt datKey(key.data(), key.size());
 
  757    if (ret == 0 && datValue.
get_data() != 
nullptr) {
 
  769        assert(!
"Write called on database in read-only mode");
 
  771    SafeDbt datKey(key.data(), key.size());
 
  773    SafeDbt datValue(value.data(), value.size());
 
  775    int ret = 
pdb->put(
activeTxn, datKey, datValue, (overwrite ? 0 : DB_NOOVERWRITE));
 
  784        assert(!
"Erase called on database in read-only mode");
 
  786    SafeDbt datKey(key.data(), key.size());
 
  789    return (ret == 0 || ret == DB_NOTFOUND);
 
  797    SafeDbt datKey(key.data(), key.size());
 
  817    if (
env) 
env->m_db_in_use.notify_all();
 
  822    return std::make_unique<BerkeleyBatch>(*
this, 
false, flush_on_close);
 
  828    std::unique_ptr<BerkeleyDatabase> db;
 
  832        std::shared_ptr<BerkeleyEnvironment> env = 
GetBerkeleyEnv(data_file.parent_path());
 
  833        if (env->m_databases.count(data_filename)) {
 
  838        db = std::make_unique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
 
std::unique_ptr< BerkeleyDatabase > MakeBerkeleyDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Return object giving access to Berkeley database at specified path.
std::string BerkeleyDatabaseVersion()
bool BerkeleyDatabaseSanityCheck()
Perform sanity check of runtime BDB version versus linked BDB version.
std::shared_ptr< BerkeleyEnvironment > GetBerkeleyEnv(const fs::path &env_directory)
Get BerkeleyEnvironment given a directory path.
static const unsigned int DEFAULT_WALLET_DBLOGSIZE
static const bool DEFAULT_WALLET_PRIVDB
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
RAII class that automatically cleanses its data on destruction.
u_int32_t get_size() const
const void * get_data() const
RAII class that provides access to a Berkeley database.
bool TxnCommit() override
bool WriteKey(CDataStream &&key, CDataStream &&value, bool overwrite=true) override
bool ReadKey(CDataStream &&key, CDataStream &value) override
bool StartCursor() override
void CloseCursor() override
BerkeleyBatch(BerkeleyDatabase &database, const bool fReadOnly, bool fFlushOnCloseIn=true)
BerkeleyEnvironment * env
bool EraseKey(CDataStream &&key) override
~BerkeleyBatch() override
BerkeleyDatabase & m_database
bool HasKey(CDataStream &&key) override
bool ReadAtCursor(CDataStream &ssKey, CDataStream &ssValue, bool &complete) override
An instance of this class represents one database.
std::shared_ptr< BerkeleyEnvironment > env
Pointer to shared database environment.
void IncrementUpdateCounter() override
void ReloadDbEnv() override
std::unique_ptr< DatabaseBatch > MakeBatch(bool flush_on_close=true) override
Make a BerkeleyBatch connected to this database.
~BerkeleyDatabase() override
bool Rewrite(const char *pszSkip=nullptr) override
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
void AddRef() override
Indicate the a new database user has began using the database.
void Flush() override
Make sure all changes are flushed to database file.
void Open() override
Open the database if it is not already opened.
bool PeriodicFlush() override
void RemoveRef() override
Indicate that database user has stopped using the database and that it could be flushed or closed.
void Close() override
Flush to the database file and close the database.
std::unique_ptr< Db > m_db
Database pointer.
bool Verify(bilingual_str &error)
Verifies the environment and database file.
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
std::unordered_map< std::string, WalletDatabaseFileId > m_fileids
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
fs::path Directory() const
std::map< std::string, std::reference_wrapper< BerkeleyDatabase > > m_databases
bool Open(bilingual_str &error)
std::unique_ptr< DbEnv > dbenv
std::condition_variable_any m_db_in_use
void CheckpointLSN(const std::string &strFile)
void Flush(bool fShutdown)
BerkeleyEnvironment()
Construct an in-memory mock Berkeley environment for testing.
void CloseDb(const std::string &strFile)
Double ended buffer combining vector and stream-like interfaces.
void write(const char *pch, size_t nSize)
bool Write(const K &key, const T &value, bool fOverwrite=true)
bool Exists(const K &key)
std::atomic< unsigned int > nUpdateCounter
std::atomic< int > m_refcount
Counts the number of active database users to be sure that the database is not closed while someone i...
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
fs::path BDBDataFile(const fs::path &wallet_path)
#define LogPrint(category,...)
Filesystem operations and types.
static auto quoted(const std::string &s)
static bool exists(const path &p)
static std::string PathToString(const path &path)
Convert path object to byte string.
static path PathFromString(const std::string &string)
Convert byte string to path object.
FILE * fopen(const fs::path &p, const char *mode)
std::string get_filesystem_error_message(const fs::filesystem_error &e)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
u_int8_t value[DB_FILE_ID_LEN]
bool operator==(const WalletDatabaseFileId &rhs) const
#define AssertLockNotHeld(cs)
#define TRY_LOCK(cs, name)
bool error(const char *fmt, const Args &... args)
int64_t GetTimeMillis()
Returns the system time (not mockable)
void UninterruptibleSleep(const std::chrono::microseconds &n)
bilingual_str _(const char *psz)
Translation function.
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
static const char * filenames[]
bool LockDirectory(const fs::path &directory, const std::string lockfile_name, bool probe_only)
void UnlockDirectory(const fs::path &directory, const std::string &lockfile_name)
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by Boost's create_directories if the requested directory exists.