mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-30 02:20:39 +00:00
feat(ledger): attribute deferrals and timeouts to ledger acquisition
Both counters are recorded in TimeoutCounter, a base shared by five subclasses with different job limits, so they pooled every lane together. The documented fingerprint for a stalled acquisition is deferrals rising while timeouts stay flat -- but a saturated replay lane reproduces that shape while ledger acquisition is healthy, and the two counters being compared were not drawn from the same population. Adds ledger-acquisition-scoped counts alongside the totals, discriminated by the job name already held at both call sites, so no new state and no signature change. The all-lane counters stay for callers that want them. Their exporters went in with the preceding commit, which shared a file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,9 +93,11 @@ public:
|
||||
* advance the retry count toward give-up.
|
||||
*/
|
||||
void
|
||||
recordDeferral()
|
||||
recordDeferral(bool ledgerAcquisition = false)
|
||||
{
|
||||
deferrals_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (ledgerAcquisition)
|
||||
ledgerDeferrals_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,9 +107,11 @@ public:
|
||||
* separate from deferrals.
|
||||
*/
|
||||
void
|
||||
recordTimeout()
|
||||
recordTimeout(bool ledgerAcquisition = false)
|
||||
{
|
||||
timeouts_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (ledgerAcquisition)
|
||||
ledgerTimeouts_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,6 +175,32 @@ public:
|
||||
return timeouts_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deferrals that belong to ledger acquisition only.
|
||||
*
|
||||
* @ref getDeferrals covers every TimeoutCounter subclass, so a busy
|
||||
* replay or transaction-set lane inflates it. Compare this against
|
||||
* @ref getLedgerTimeouts to judge ledger acquisition on its own.
|
||||
*/
|
||||
[[nodiscard]] std::uint64_t
|
||||
getLedgerDeferrals() const
|
||||
{
|
||||
return ledgerDeferrals_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeouts that belong to ledger acquisition only.
|
||||
*
|
||||
* The partner of @ref getLedgerDeferrals: rising deferrals with flat
|
||||
* timeouts here means ledger acquisition's give-up path is disarmed,
|
||||
* which the all-lane counters cannot show.
|
||||
*/
|
||||
[[nodiscard]] std::uint64_t
|
||||
getLedgerTimeouts() const
|
||||
{
|
||||
return ledgerTimeouts_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of acquisitions that exhausted their retry budget.
|
||||
*/
|
||||
@@ -224,6 +254,16 @@ private:
|
||||
*/
|
||||
std::atomic<std::uint64_t> deferrals_{0};
|
||||
|
||||
/**
|
||||
* Deferrals attributable to ledger acquisition alone.
|
||||
*/
|
||||
std::atomic<std::uint64_t> ledgerDeferrals_{0};
|
||||
|
||||
/**
|
||||
* Timeouts attributable to ledger acquisition alone.
|
||||
*/
|
||||
std::atomic<std::uint64_t> ledgerTimeouts_{0};
|
||||
|
||||
/**
|
||||
* Timer bodies that ran and advanced the retry count.
|
||||
*/
|
||||
|
||||
@@ -67,7 +67,7 @@ TimeoutCounter::queueJob(ScopedLockType& sl)
|
||||
// Counted separately from timeouts: this path re-arms the timer
|
||||
// without running invokeOnTimer, so timeouts_ does not advance and the
|
||||
// give-up test that reads it cannot fire while the lane stays full.
|
||||
app_.getAcquireStats().recordDeferral();
|
||||
app_.getAcquireStats().recordDeferral(isLedgerAcquisition());
|
||||
JLOG(journal_.debug()) << "Deferring " << queueJobParameter_.jobName
|
||||
<< " timer due to load";
|
||||
setTimer(sl);
|
||||
@@ -92,7 +92,7 @@ TimeoutCounter::invokeOnTimer()
|
||||
if (!progress_)
|
||||
{
|
||||
++timeouts_;
|
||||
app_.getAcquireStats().recordTimeout();
|
||||
app_.getAcquireStats().recordTimeout(isLedgerAcquisition());
|
||||
JLOG(journal_.debug()) << "Timeout(" << timeouts_ << ") "
|
||||
<< " acquiring " << hash_;
|
||||
onTimer(false, sl);
|
||||
|
||||
@@ -139,6 +139,23 @@ protected:
|
||||
|
||||
QueueJobParameter queueJobParameter_;
|
||||
|
||||
/**
|
||||
* Whether this counter belongs to ledger acquisition.
|
||||
*
|
||||
* Deferrals and timeouts are recorded in this base class, so they would
|
||||
* otherwise pool every subclass together: a saturated replay lane would
|
||||
* look exactly like a stalled ledger acquisition. The job name already
|
||||
* identifies the subclass, so it is the cheapest discriminator available
|
||||
* and needs no extra state.
|
||||
*
|
||||
* @return True for the InboundLedger lane, false for every other.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isLedgerAcquisition() const
|
||||
{
|
||||
return queueJobParameter_.jobName == "InboundLedger";
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Calls onTimer() if in the right state.
|
||||
|
||||
Reference in New Issue
Block a user