Skip to content

Commit

Permalink
Add a lock to the wallet directory
Browse files Browse the repository at this point in the history
  • Loading branch information
meshcollider authored and furszy committed Jul 21, 2021
1 parent 1dc2219 commit a238a8d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 21 deletions.
66 changes: 46 additions & 20 deletions src/wallet/db.cpp
Expand Up @@ -20,6 +20,7 @@
#include <sys/stat.h>
#endif

#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/thread.hpp>


Expand Down Expand Up @@ -55,6 +56,24 @@ void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db)
}
}
}

bool LockEnvDirectory(const fs::path& env_path)
{
// Make sure only a single PIVX 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

//
Expand Down Expand Up @@ -98,13 +117,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);
Expand Down Expand Up @@ -137,7 +160,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;
Expand Down Expand Up @@ -266,25 +306,11 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walle
if (walletFile != wallet_file_path.filename().string())
return UIError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, walletDir.string()));

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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/wallet/db.h
Expand Up @@ -70,7 +70,7 @@ class CDBEnv
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);
Expand Down

0 comments on commit a238a8d

Please sign in to comment.