Add a lock to the wallet directory
This commit is contained in:
parent
bbc91b7699
commit
e60cb99c58
2 changed files with 47 additions and 21 deletions
|
@ -18,6 +18,7 @@
|
|||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/sync/file_lock.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace {
|
||||
|
@ -52,6 +53,24 @@ void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LockEnvDirectory(const fs::path& env_path)
|
||||
{
|
||||
// Make sure only a single Bitcoin process is using the wallet directory.
|
||||
fs::path lock_file_path = env_path / ".lock";
|
||||
FILE* file = fsbridge::fopen(lock_file_path, "a"); // empty lock file; created if it doesn't exist.
|
||||
if (file) fclose(file);
|
||||
|
||||
try {
|
||||
static boost::interprocess::file_lock lock(lock_file_path.string().c_str());
|
||||
if (!lock.try_lock()) {
|
||||
return false;
|
||||
}
|
||||
} catch (const boost::interprocess::interprocess_exception& e) {
|
||||
return error("Error obtaining lock on wallet directory %s: %s.", env_path.string(), e.what());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//
|
||||
|
@ -95,13 +114,17 @@ void CDBEnv::Close()
|
|||
EnvShutdown();
|
||||
}
|
||||
|
||||
bool CDBEnv::Open(const fs::path& pathIn)
|
||||
bool CDBEnv::Open(const fs::path& pathIn, bool retry)
|
||||
{
|
||||
if (fDbEnvInit)
|
||||
return true;
|
||||
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
if (!LockEnvDirectory(pathIn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strPath = pathIn.string();
|
||||
fs::path pathLogDir = pathIn / "database";
|
||||
TryCreateDirectories(pathLogDir);
|
||||
|
@ -134,7 +157,24 @@ bool CDBEnv::Open(const fs::path& pathIn)
|
|||
S_IRUSR | S_IWUSR);
|
||||
if (ret != 0) {
|
||||
dbenv->close(0);
|
||||
return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
|
||||
LogPrintf("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
|
||||
if (retry) {
|
||||
// try moving the database env out of the way
|
||||
fs::path pathDatabaseBak = pathIn / strprintf("database.%d.bak", GetTime());
|
||||
try {
|
||||
fs::rename(pathLogDir, pathDatabaseBak);
|
||||
LogPrintf("Moved old %s to %s. Retrying.\n", pathLogDir.string(), pathDatabaseBak.string());
|
||||
} catch (const fs::filesystem_error&) {
|
||||
// failure is ok (well, not really, but it's not worse than what we started with)
|
||||
}
|
||||
// try opening it again one more time
|
||||
if (!Open(pathIn, false)) {
|
||||
// if it still fails, it probably means we can't even create the database env
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fDbEnvInit = true;
|
||||
|
@ -269,25 +309,11 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walle
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!bitdb.Open(walletDir))
|
||||
{
|
||||
// try moving the database env out of the way
|
||||
fs::path pathDatabase = walletDir / "database";
|
||||
fs::path pathDatabaseBak = walletDir / strprintf("database.%d.bak", GetTime());
|
||||
try {
|
||||
fs::rename(pathDatabase, pathDatabaseBak);
|
||||
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
|
||||
} catch (const fs::filesystem_error&) {
|
||||
// failure is ok (well, not really, but it's not worse than what we started with)
|
||||
}
|
||||
|
||||
// try again
|
||||
if (!bitdb.Open(walletDir)) {
|
||||
// if it still fails, it probably means we can't even create the database env
|
||||
errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
|
||||
return false;
|
||||
}
|
||||
if (!bitdb.Open(walletDir, true)) {
|
||||
errorStr = strprintf(_("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it."), walletDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
|
||||
bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
|
||||
|
||||
bool Open(const fs::path& path);
|
||||
bool Open(const fs::path& path, bool retry = 0);
|
||||
void Close();
|
||||
void Flush(bool fShutdown);
|
||||
void CheckpointLSN(const std::string& strFile);
|
||||
|
|
Loading…
Reference in a new issue