fix(daemon): make the "keep the node running?" prompt actually appear
Quitting during a witness rebuild is supposed to ask before stopping the node, because a stop throws the rebuild away and a killed node replays and redoes it. The guard almost never fired: - it returned false for any daemon >= v1.3.0, on the false premise that v1.3.0 checkpoints a rebuild (it does not; nothing survives a kill) - it read a 16 KB debug.log tail and compared the last progress line with the newest line, so any unrelated line during the rebuild's silent second phase turned it off; and on POSIX that file is stale - daemon_version, which the bypass needed, is zeroed when a busy node drops the connection Now a DaemonBusyTracker (src/daemon/daemon_busy_detect.h, pure) follows dragonxd's own markers in order: rebuilding (Phase-1 / legacy markers, ended by the completion line, an abort line or the next UpdateTip) and replaying (Activating best chain ... Done Loading), reset by a new banner or "Shutdown: done". It is fed from the owned output on the UI thread, including the backlog skipped after a restore. The quit guard prompts when the quit would stop the node and it is rebuilding, or has been alive but only timing out / refusing as busy for >= 30 s. A replay alone never prompts: stopping it is safe. The stop loop uses the same signal to never offer Kill during a rebuild. Also: - daemon output offsets are absolute, so a reader that falls behind a trim of the 1 MB buffer no longer skips new output (which could hide a start or end marker) - a quit deferred while minimized restores and raises the window, and the wizard renders the prompt, so it is never waiting unseen Verified live with the fake daemon: quitting mid-rebuild now shows the prompt for a v1.3.0 node and leaves the node alone; a silent busy node prompts after 30 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -146,16 +146,26 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Get new output since a given offset (thread-safe).
|
||||
* Returns the new text and updates offset to the current size.
|
||||
* Returns the new text and advances offset. Offsets are absolute positions in everything ever
|
||||
* appended (start from 0), so trimming old output never shifts them: a reader that falls behind a
|
||||
* trim only loses the trimmed part, not output that is still buffered.
|
||||
*/
|
||||
std::string getOutputSince(size_t& offset) const {
|
||||
std::lock_guard<std::mutex> lk(output_mutex_);
|
||||
if (offset >= process_output_.size()) {
|
||||
offset = process_output_.size();
|
||||
return outputSince(process_output_, output_total_, offset);
|
||||
}
|
||||
|
||||
/** getOutputSince() on a buffer holding the LAST buffer.size() of `total` bytes ever appended. */
|
||||
static std::string outputSince(const std::string& buffer, size_t total, size_t& offset)
|
||||
{
|
||||
const size_t base = total - buffer.size(); // absolute position of buffer[0]
|
||||
if (offset < base) offset = base; // trimmed before it was read: resume at what's left
|
||||
if (offset >= total) {
|
||||
offset = total;
|
||||
return {};
|
||||
}
|
||||
std::string result = process_output_.substr(offset);
|
||||
offset = process_output_.size();
|
||||
std::string result = buffer.substr(offset - base);
|
||||
offset = total;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -361,6 +371,7 @@ private:
|
||||
mutable std::mutex error_mutex_; // protects last_error_ (written by main + monitor threads)
|
||||
mutable std::mutex output_mutex_; // protects process_output_
|
||||
std::string process_output_;
|
||||
size_t output_total_ = 0; // bytes ever appended (the absolute end of process_output_)
|
||||
StateCallback state_callback_;
|
||||
|
||||
// Process handle
|
||||
|
||||
Reference in New Issue
Block a user