Files
ObsidianDragon/src/daemon/daemon_controller.cpp
T
DanSandClaude Opus 4.8 7e7804e577 perf(daemon): skip the UI-thread datadir lock wait
Starting the daemon polls for an already-running node holding the
datadir, sleeping up to three 100 ms intervals to let a shutting-down
node clear out. When a start runs on the UI thread, that is up to 300 ms
of blocking sleep on the render thread.

- The lock-wait poll count is now a parameter. A start invoked on the UI
  thread passes 0, which does a single check and never sleeps; every
  other caller keeps the three-poll wait. The default is unchanged, so
  background starts behave exactly as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 06:26:13 -05:00

174 lines
4.8 KiB
C++

#include "daemon_controller.h"
#include "../config/settings.h"
#include "../util/platform.h"
#include <algorithm>
#include <filesystem>
#include <system_error>
namespace dragonx {
namespace daemon {
DaemonController::DaemonController()
: daemon_(std::make_unique<EmbeddedDaemon>())
{
}
DaemonController::~DaemonController() = default;
void DaemonController::setStateCallback(StateCallback callback)
{
daemon_->setStateCallback(std::move(callback));
}
void DaemonController::syncSettings(const config::Settings* settings)
{
if (!settings) return;
daemon_->setDebugCategories(settings->getDebugCategories());
daemon_->setMaxConnections(settings->getMaxConnections());
daemon_->setStratumHosting(settings->getStratumHost(), settings->getStratumAllowIp());
std::string walletFile = settings->getActiveWalletFile();
// The Wallets dialog opens an out-of-datadir wallet by linking it into the datadir under a
// "wallet-ip-<hash>.dat" name. If that link went dangling (the external file was moved / a USB was
// unplugged between sessions), don't let the daemon create a fresh EMPTY wallet at that name — fall
// back to the default this launch. fs::exists follows the link, so it's false for a dangling one.
if (walletFile.rfind("wallet-ip-", 0) == 0) {
std::error_code ec;
if (!std::filesystem::exists(util::Platform::getDragonXDataDir() + "/" + walletFile, ec))
walletFile = "wallet.dat";
}
daemon_->setWalletFile(walletFile);
}
bool DaemonController::start(const config::Settings* settings, int lockWaitPolls)
{
syncSettings(settings);
return daemon_->start("", lockWaitPolls);
}
void DaemonController::stop(int waitMs)
{
daemon_->stop(waitMs);
}
void DaemonController::markStopRequested()
{
daemon_->markStopRequested();
}
bool DaemonController::isRunning() const
{
return daemon_->isRunning();
}
bool DaemonController::externalDaemonDetected() const
{
return daemon_->externalDaemonDetected();
}
void DaemonController::clearExternalDaemonDetected()
{
daemon_->clearExternalDaemonDetected();
}
DaemonController::State DaemonController::state() const
{
return daemon_->getState();
}
std::string DaemonController::lastError() const
{
// By value — getLastError() now returns a mutex-locked COPY, so forwarding it by reference would
// dangle (bind a reference to that temporary). (M-04 follow-through)
return daemon_ ? daemon_->getLastError() : std::string();
}
int DaemonController::crashCount() const
{
return daemon_->getCrashCount();
}
int DaemonController::lastBlockHeight() const
{
return daemon_ ? daemon_->getLastBlockHeight() : 0;
}
double DaemonController::memoryUsageMB() const
{
return daemon_ ? daemon_->getMemoryUsageMB() : 0.0;
}
std::function<double()> DaemonController::memoryProbe() const
{
return daemon_ ? daemon_->memoryProbe() : std::function<double()>{};
}
std::vector<std::string> DaemonController::recentLines(std::size_t count) const
{
return daemon_ ? daemon_->getRecentLines(count) : std::vector<std::string>{};
}
std::size_t DaemonController::outputEnd() const { return daemon_ ? daemon_->getOutputEnd() : 0; }
std::string DaemonController::outputSince(std::size_t& offset) const
{
return daemon_ ? daemon_->getOutputSince(offset) : std::string{};
}
void DaemonController::resetCrashCount()
{
daemon_->resetCrashCount();
}
void DaemonController::setRescanOnNextStart(bool enabled)
{
daemon_->setRescanOnNextStart(enabled);
}
bool DaemonController::rescanOnNextStart() const
{
return daemon_->rescanOnNextStart();
}
void DaemonController::setZapOnNextStart(bool enabled)
{
daemon_->setZapOnNextStart(enabled);
}
void DaemonController::setSalvageOnNextStart(bool enabled)
{
daemon_->setSalvageOnNextStart(enabled);
}
void DaemonController::setReindexOnNextStart(bool enabled)
{
daemon_->setReindexOnNextStart(enabled);
}
bool DaemonController::zapOnNextStart() const
{
return daemon_->zapOnNextStart();
}
void DaemonController::prepareLifecycleOperation(const LifecycleDecision& decision,
const config::Settings* settings)
{
if (settings) syncSettings(settings);
if (decision.resetCrashCount) resetCrashCount();
if (decision.setRescanOnNextStart) setRescanOnNextStart(true);
if (decision.setZapOnNextStart) setZapOnNextStart(true);
}
DaemonController::ShutdownDecision DaemonController::shutdownDecision(
bool keepDaemonRunning, bool stopExternalDaemon) const
{
return evaluateShutdownPolicy(static_cast<bool>(daemon_),
daemon_ && daemon_->externalDaemonDetected(),
keepDaemonRunning,
stopExternalDaemon);
}
} // namespace daemon
} // namespace dragonx