@ -20,6 +20,40 @@
# include <boost/thread.hpp>
# include <boost/thread.hpp>
namespace {
//! Make sure database has a unique fileid within the environment. If it
//! doesn't, throw an error. BDB caches do not work properly when more than one
//! open database has the same fileid (values written to one database may show
//! up in reads to other databases).
//!
//! BerkeleyDB generates unique fileids by default
//! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html),
//! so bitcoin should never create different databases with the same fileid, but
//! this error can be triggered if users manually copy database files.
void CheckUniqueFileid ( const CDBEnv & env , const std : : string & filename , Db & db )
{
if ( env . IsMock ( ) ) return ;
u_int8_t fileid [ DB_FILE_ID_LEN ] ;
int ret = db . get_mpf ( ) - > get_fileid ( fileid ) ;
if ( ret ! = 0 ) {
throw std : : runtime_error ( strprintf ( " CDB: Can't open database %s (get_fileid failed with %d) " , filename , ret ) ) ;
}
for ( const auto & item : env . mapDb ) {
u_int8_t item_fileid [ DB_FILE_ID_LEN ] ;
if ( item . second & & item . second - > get_mpf ( ) - > get_fileid ( item_fileid ) = = 0 & &
memcmp ( fileid , item_fileid , sizeof ( fileid ) ) = = 0 ) {
const char * item_filename = nullptr ;
item . second - > get_dbname ( & item_filename , nullptr ) ;
throw std : : runtime_error ( strprintf ( " CDB: Can't open database %s (duplicates fileid %s from %s) " , filename ,
HexStr ( std : : begin ( item_fileid ) , std : : end ( item_fileid ) ) ,
item_filename ? item_filename : " (unknown database) " ) ) ;
}
}
}
} // namespace
//
//
// CDB
// CDB
//
//
@ -403,6 +437,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb
if ( ret ! = 0 ) {
if ( ret ! = 0 ) {
throw std : : runtime_error ( strprintf ( " CDB: Error %d, can't open database %s " , ret , strFilename ) ) ;
throw std : : runtime_error ( strprintf ( " CDB: Error %d, can't open database %s " , ret , strFilename ) ) ;
}
}
CheckUniqueFileid ( * env , strFilename , * pdb_temp ) ;
pdb = pdb_temp . release ( ) ;
pdb = pdb_temp . release ( ) ;
env - > mapDb [ strFilename ] = pdb ;
env - > mapDb [ strFilename ] = pdb ;