perf: stop per-frame SQLite writes and console spam, make perf.log opt-in
- Explorer: the tip check runs every frame the Explorer tab is open, and it read both tip rows and rewrote them each time (two autocommit WAL writes per frame). A steady tip is now kept in memory and skips SQLite. A new tip writes both rows in one savepoint, so a crash between them can't pair a new height with the old hash. A test checks that 100 steady checks write nothing. - Console: while the daemon was in the Error state the Console tab added its error line on every poll, i.e. every frame, re-laying out the whole buffer each time. It prints once per error now: on entering Error, when the message changes, or after another crash (EmbeddedDaemon::getUnexpectedExitCount(), never reset). setState writes the message before the state, so a reader that sees Error sees that error's message. The stray " ===" suffix is gone. - perf.log: the profiler appended a block every 300 frames on every run and never rotated the file (tens of MB a day for a wallet left open). It is now off unless the app starts with DRAGONX_PERFLOG=1; otherwise its zone hooks are near no-ops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -256,11 +256,13 @@ std::vector<std::string> EmbeddedDaemon::getChainParams()
|
||||
|
||||
void EmbeddedDaemon::setState(State s, const std::string& message)
|
||||
{
|
||||
state_ = s;
|
||||
// Message first, state second: a reader that sees Error must also see that error's message, not the
|
||||
// previous one (the console prints the message when it sees the state change).
|
||||
if (!message.empty() && s == State::Error) {
|
||||
std::lock_guard<std::mutex> lk(error_mutex_); // dedicated mutex — never taken with output_mutex_ held
|
||||
last_error_ = message;
|
||||
}
|
||||
state_ = s;
|
||||
|
||||
if (state_callback_) {
|
||||
state_callback_(s, message);
|
||||
@@ -1098,6 +1100,7 @@ void EmbeddedDaemon::monitorProcess()
|
||||
}
|
||||
|
||||
crash_count_++;
|
||||
unexpected_exits_++; // before setState(Error): a reader that sees Error sees the new count
|
||||
|
||||
// Build informative error message with full diagnostic details
|
||||
std::string error_msg = "dragonxd exited unexpectedly (" + translateWindowsExitCode(exit_code) + ")";
|
||||
@@ -1671,6 +1674,7 @@ void EmbeddedDaemon::monitorProcess()
|
||||
return;
|
||||
}
|
||||
crash_count_++;
|
||||
unexpected_exits_++; // before setState(Error): a reader that sees Error sees the new count
|
||||
setState(State::Error, "dragonxd exited unexpectedly (" + exitInfo + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -446,6 +446,9 @@ public:
|
||||
int getCrashCount() const { return crash_count_.load(); }
|
||||
/** Reset crash counter (call on successful connection or manual restart) */
|
||||
void resetCrashCount() { crash_count_ = 0; }
|
||||
/** Unexpected exits since this object was created; never reset (unlike the crash count), so a
|
||||
* reader can tell a new crash from an error it has already reported. */
|
||||
std::uint64_t getUnexpectedExitCount() const { return unexpected_exits_.load(); }
|
||||
|
||||
private:
|
||||
void setState(State s, const std::string& message = "");
|
||||
@@ -494,6 +497,7 @@ private:
|
||||
std::string stratum_allowip_; // -stratumallowip subnet (empty = daemon default: loopback only)
|
||||
std::string wallet_file_; // -wallet=<name> for the active wallet; empty/"wallet.dat" = default
|
||||
std::atomic<int> crash_count_{0}; // consecutive crash counter
|
||||
std::atomic<std::uint64_t> unexpected_exits_{0}; // all unexpected exits (see getUnexpectedExitCount)
|
||||
std::atomic<bool> rescan_on_next_start_{false}; // -rescan flag for next start
|
||||
std::atomic<bool> zap_on_next_start_{false}; // -zapwallettxes=2 flag for next start
|
||||
std::atomic<bool> salvage_on_next_start_{false}; // -salvagewallet flag for next start
|
||||
|
||||
Reference in New Issue
Block a user