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:
2026-10-03 19:52:09 -05:00
co-authored by Claude Opus 5.5
parent 2d29a04981
commit 16e0ee9947
11 changed files with 116 additions and 17 deletions
+4
View File
@@ -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