-
Notifications
You must be signed in to change notification settings - Fork 38.7k
init: don't delete PID file if it was not generated #28946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
|
You can test similarly to #28784: will@ubuntu in ~ :
₿ bitcoind -regtest -daemon=1
Bitcoin Core starting
will@ubuntu in ~ :
₿ file ~/.bitcoin/regtest/bitcoind.pid
/home/will/.bitcoin/regtest/bitcoind.pid: ASCII text
will@ubuntu in ~ :
₿ bitcoind -regtest -daemon=1
Error: Cannot obtain a lock on data directory /home/will/.bitcoin/regtest. Bitcoin Core is probably already running.
will@ubuntu in ~ :
₿ file ~/.bitcoin/regtest/bitcoind.pid
/home/will/.bitcoin/regtest/bitcoind.pid: cannot open `/home/will/.bitcoin/regtest/bitcoind.pid' (No such file or directory) |
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| LogPrintf("%s: Unable to remove PID file: File does not exist\n", __func__); | |
| LogPrintf("Unable to remove PID file: File does not exist\n"); |
nit: No need to take this over, if you change the function name, the warning is already unique, and user can enable to print the function name, if they really want to.
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: No need to pass node, when you only need args?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, that's nicer. Will fix.
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
5eefe8d to
98ba5ba
Compare
|
Thanks @maflcko, I took the suggestions in 98ba5ba0cc0cb94b51595248041db972a9ef5a09 |
stickies-v
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can be simplified
| try { | |
| if (!fs::remove(GetPidFile(args))) { | |
| LogPrintf("Unable to remove PID file: File does not exist\n"); | |
| } | |
| } catch (const fs::filesystem_error& e) { | |
| LogPrintf("Unable to remove PID file: %s\n", fsbridge::get_filesystem_error_message(e)); | |
| } | |
| if (std::error_code error; !fs::remove(GetPidFile(args), error)) { | |
| std::string msg{error ? error.message() : "File does not exist"}; | |
| LogPrintf("Unable to remove PID file: %s\n", msg); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is passing error codes our preferred error handling technique, or just slightly shorter?
I'd naturally opt for the former, and I think errors from it will be slightly more detailed, including an error msg instead of only error code (although it doesn't make much difference in this case), but can very easily be persuaded to switch to the latter if it's preferred...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just like the brevity of it. I'm using error.message() and not error.value() so the user will see a user friendly error message. Could include the pid path in the log line if preferred, probably helpful to the user to know which file to change permissions on indeed.
For example, with this patch and chmod a-w on the datadir this will print:
Unable to remove PID file: Permission denied
For a missing file, this will print
Unable to remove PID file: File does not exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've taken this in e56e8cdf9cda1712f4a415aa9af34ced3e78dfb2 and added the pid path to the log message.
test/functional/feature_filelock.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cookie file is not yet checked here, would leave that for the other pull
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, thanks. I wrote this commit on top as I was reviewing the other one, then cherry-picked and made it standalone. I guess this slipped through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fixed in e56e8cdf9cda1712f4a415aa9af34ced3e78dfb2
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#28784 stores the path in . I don't have a particularly strong conviction in either direction, but I'd use the same approach for both. Storing the location of the file to be deleted seems a bit more robust, so I think I'd lean towards this approach:static std::optional<std::string> g_generated_cookie
git diff on 98ba5ba0cc
diff --git a/src/init.cpp b/src/init.cpp
index afa0ab1ee6..f2d74db13f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -96,6 +96,7 @@
#include <cstdio>
#include <fstream>
#include <functional>
+#include <optional>
#include <set>
#include <string>
#include <thread>
@@ -155,7 +156,7 @@ static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
* The PID file facilities.
*/
static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
-static bool g_generated_pid{false};
+static std::optional<fs::path> g_generated_pid;
static fs::path GetPidFile(const ArgsManager& args)
{
@@ -164,25 +165,26 @@ static fs::path GetPidFile(const ArgsManager& args)
[[nodiscard]] static bool CreatePidFile(const ArgsManager& args)
{
- std::ofstream file{GetPidFile(args)};
+ const fs::path pid_path{GetPidFile(args)};
+ std::ofstream file{pid_path};
if (file) {
#ifdef WIN32
tfm::format(file, "%d\n", GetCurrentProcessId());
#else
tfm::format(file, "%d\n", getpid());
#endif
- g_generated_pid = true;
+ g_generated_pid = pid_path;
return true;
} else {
- return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), SysErrorString(errno)));
+ return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(pid_path), SysErrorString(errno)));
}
}
-static void RemovePidFile(const ArgsManager& args)
+static void RemovePidFile()
{
if (!g_generated_pid) return;
try {
- if (!fs::remove(GetPidFile(args))) {
+ if (!fs::remove(g_generated_pid.value())) {
LogPrintf("Unable to remove PID file: File does not exist\n");
}
} catch (const fs::filesystem_error& e) {
@@ -364,7 +366,7 @@ void Shutdown(NodeContext& node)
node.scheduler.reset();
node.kernel.reset();
- RemovePidFile(*node.args);
+ RemovePidFile();
LogPrintf("%s: done\n", __func__);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, looking at 28784 more closely it seems g_generated_cookie stores the cookie, not the path. My bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the idea of storing a bool with whether it has been generated or not, and use the {Get|Create|Remove}PidFile() functions as necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with the boolean approach if you prefer it. I just like the "we created this file, so let's remove this file" explicitness over "we created a file, so let's remove a file". But in practice, no big difference.
98ba5ba to
e56e8cd
Compare
|
ACK e56e8cdf9cda1712f4a415aa9af34ced3e78dfb2 |
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to just use GetPidFile()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that's cleaner. Fixed in 82f18e907a along with a typo in the commit message.
e56e8cd to
82f18e9
Compare
stickies-v
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 82f18e907a2af5a47e805861234de4672ed6d801
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: quick docstring would be nice
/**
* Remove PID file, but only if it was also generated by this process to avoid problems when
* multiple bitcoind processes are started on the same datadir.
*/
git diff on 82f18e907a
diff --git a/src/init.cpp b/src/init.cpp
index fced24a6ff..7a87467252 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -177,7 +177,10 @@ static fs::path GetPidFile(const ArgsManager& args)
return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), SysErrorString(errno)));
}
}
-
+/**
+ * Remove PID file, but only if it was also generated by this process to avoid problems when
+ * multiple bitcoind processes are started on the same datadir.
+ */
static void RemovePidFile(const ArgsManager& args)
{
if (!g_generated_pid) return;
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
| auto pid_path = GetPidFile(args); | |
| const auto pid_path{GetPidFile(args)}; |
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'm not sure how important the quoting is, could just use parentheses to make it a bit more concise?
| LogPrintf("Unable to remove PID file %s: %s\n", fs::quoted(fs::PathToString(pid_path)), msg); | |
| LogPrintf("Unable to remove PID file (%s): %s\n", fs::PathToString(pid_path), msg); |
|
@stickies-v took most of your suggestions in 2b28f7df2b7dd140e52e93ef3e1a330db8da32a9 |
82f18e9 to
2b28f7d
Compare
stickies-v
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 2b28f7df2b7dd140e52e93ef3e1a330db8da32a9
src/init.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think this more clearly explains the rationale without being too explicit about implementation
| /** | |
| * Whether this process has created a PID file. | |
| * Used when determining whether we should remove the PID file on shutdown. | |
| */ | |
| //! True if this process created the pid file, so we don't delete it too early if multiple processes were started |
Previously, starting a second bitcoind using the same datadir would correctly fail to init and shutdown. However during shutdown the PID file belonging to the first instance would be erroneously removed by the second process shutting down. Fix this to only delete the PID file if we created it.
2b28f7d to
8f6ab31
Compare
andrewtoth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 8f6ab31
romanz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 8f6ab31
|
ACK 8f6ab31 |
Previously, starting a second bitcoind using the same datadir would correctly fail to init and shutdown. However during shutdown the PID file belonging to the first instance would be erroneously removed by the second process shutting down. Fix this to only delete the PID file if we created it. Github-Pull: bitcoin#28946 Rebased-From: 8f6ab31
Previously, starting a second bitcoind using the same datadir would correctly fail to init and shutdown. However during shutdown the PID file belonging to the first instance would be erroneously removed by the second process shutting down. Fix this to only delete the PID file if we created it. Github-Pull: bitcoin#28946 Rebased-From: 8f6ab31
In a similar vein to #28784, if a second
bitcoindis started using the same datadir it will fail to start up, but during shutdown remove the PID file from the firstbitcoindinstance.