mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-27 23:38:08 +00:00
docs(telemetry): acquire, store and validate are hashSpan roots on this branch
The parenting section still described them as ambient spans that could land under an RPC command or under consensus.accept.apply. On this branch all three derive their trace id from the ledger hash and are roots of the per-ledger trace, whatever thread creates them.
This commit is contained in:
@@ -409,12 +409,12 @@ from `result_->state` at
|
||||
|
||||
### Ledger Spans
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ----------------- | ----------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ledger.build` | BuildLedger.cpp | `ledger_seq`, `close_time_ripple_epoch_s`, `close_time_correct`, `close_resolution_ms` | Ledger build during consensus |
|
||||
| `ledger.validate` | LedgerMaster.cpp | `ledger_hash`, `ledger_seq`, `validations` | Ledger promoted to validated |
|
||||
| `ledger.store` | LedgerMaster.cpp | `ledger_hash`, `ledger_seq` | Ledger stored in history |
|
||||
| `ledger.acquire` | InboundLedger.cpp | `ledger_hash`, `ledger_seq`, `acquire_reason`, `timeouts`, `peer_count`, `outcome` | Fetch a missing ledger from peers (parent varies — see [known issues](#where-telemetry-parenting-differs-from-protocol-flow)) |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ----------------- | ----------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `ledger.build` | BuildLedger.cpp | `ledger_seq`, `close_time_ripple_epoch_s`, `close_time_correct`, `close_resolution_ms` | Ledger build during consensus |
|
||||
| `ledger.validate` | LedgerMaster.cpp | `ledger_hash`, `ledger_seq`, `validations` | Ledger promoted to validated |
|
||||
| `ledger.store` | LedgerMaster.cpp | `ledger_hash`, `ledger_seq` | Ledger stored in history |
|
||||
| `ledger.acquire` | InboundLedger.cpp | `ledger_hash`, `ledger_seq`, `acquire_reason`, `timeouts`, `peer_count`, `outcome` | Fetch a missing ledger from peers (always a root on the ledger-hash trace) |
|
||||
|
||||
`ledger.acquire` sets only `ledger_hash`, `ledger_seq` and `acquire_reason` when the span opens
|
||||
in `init()`. `outcome` has three values, written on two different paths:
|
||||
@@ -1140,7 +1140,7 @@ call edge. Read a trace with these in mind:
|
||||
| `consensus.round` uses a deterministic trace ID from the previous ledger hash. | This makes **all validators share one trace ID** (a cross-node shared root), not a per-node parent. The real round-to-round edge is `endConsensus → beginConsensus`. |
|
||||
| `consensus.accept` (main thread) and `consensus.accept.apply` (JtAccept worker) are wired via a captured context. | The real edge is the queued `JtAccept` job, a thread hand-off ([RCLConsensus.cpp:483](../src/xrpld/app/consensus/RCLConsensus.cpp#L483)). `consensus.accept.apply` is a scoped guard, so the spans `doAccept` creates after it (`ledger.build`, `txq.cleanup`, `txq.accept`, `ledger.store`, `ledger.validate`) nest under it; those are real containment edges. |
|
||||
| `pathfind.update_all` parents nothing from the original `pathfind.request`. | The causal link is the ledger-close job on `JtUpdatePf`, not span nesting. |
|
||||
| `ledger.acquire` and its downstream `ledger.store` / `ledger.validate`. | Reached via the `AcqDone` job, not parent inheritance. All three are non-scoped `SpanGuard::span` spans, so none of them parents the others; each takes whatever ambient span its own caller happens to have active. See the `ledger.*` known issue below. |
|
||||
| `ledger.acquire` and its downstream `ledger.store` / `ledger.validate`. | Reached via the `AcqDone` job, not parent inheritance. All three are `hashSpan` roots keyed on the ledger hash, so none of them parents the others and none inherits its caller's span; they share one trace instead. |
|
||||
| `peer.*.receive` (fresh `kConsumer` root) and `consensus.*.receive` on the same message. | Two **sequential stages of one synchronous handler**, not parent/child; on a duplicate/untrusted drop the `consensus.*.receive` is never created. |
|
||||
| Receive spans adopt the sender's `trace_id` + `span_id` as a genuine cross-node parent. | Deliberate: the receive span becomes a child of a **different node's** span (a cross-node context marker, not an in-process edge). `tx.receive` is asymmetric — it borrows only the sender's `span_id` and re-derives its own `trace_id` from `txID`. |
|
||||
|
||||
@@ -1167,41 +1167,15 @@ are pending a code fix:
|
||||
happened to be active on the worker that picked the job up. A gRPC call
|
||||
appearing beneath an unrelated transaction's trace is this bug, not a real
|
||||
call edge.
|
||||
- **`ledger.acquire` / `ledger.store` / `ledger.validate` are not reliably roots
|
||||
either.** All three use `SpanGuard::span`
|
||||
([InboundLedger.cpp:113](../src/xrpld/app/ledger/detail/InboundLedger.cpp#L113),
|
||||
[LedgerMaster.cpp:470](../src/xrpld/app/ledger/detail/LedgerMaster.cpp#L470),
|
||||
[1003](../src/xrpld/app/ledger/detail/LedgerMaster.cpp#L1003)), which inherits the
|
||||
ambient span ([SpanGuard.cpp:233](../src/libxrpl/telemetry/SpanGuard.cpp#L233))
|
||||
rather than `freshRoot`
|
||||
([245](../src/libxrpl/telemetry/SpanGuard.cpp#L245)) — the same defect as
|
||||
`grpc.*` above. Whether they come out as roots depends purely on the caller:
|
||||
- **Root, as documented.** On the `JtAdvance` / `AcqDone` job path
|
||||
(`LedgerMaster::doAdvance`, `RCLConsensus::Adaptor::acquireLedger` →
|
||||
[RCLConsensus.cpp:171](../src/xrpld/app/consensus/RCLConsensus.cpp#L171)) no
|
||||
span is active on the worker, so nothing is inherited. `acquireSpan_` itself is
|
||||
a non-scoped `SpanGuard`, so it never becomes the ambient parent of the
|
||||
`ledger.store` / `ledger.validate` that follow it.
|
||||
- **Mis-parented.** `InboundLedgers::acquire` is also called **synchronously from
|
||||
an RPC handler** — `ledger_request` → `rpc::getOrAcquireLedger`
|
||||
([RPCLedgerHelpers.cpp:483](../src/xrpld/rpc/detail/RPCLedgerHelpers.cpp#L483))
|
||||
— which runs inside the scoped `rpc.command.<name>` span
|
||||
([RPCHandler.cpp:168](../src/xrpld/rpc/detail/RPCHandler.cpp#L168)). There
|
||||
`ledger.acquire` becomes a child of that RPC command, and when `init()` is
|
||||
satisfied from the local store the `ledger.store` / `ledger.validate` it calls
|
||||
([InboundLedger.cpp:164](../src/xrpld/app/ledger/detail/InboundLedger.cpp#L164),
|
||||
[168](../src/xrpld/app/ledger/detail/InboundLedger.cpp#L168)) land there as
|
||||
siblings. A ledger acquisition nested under an `rpc.command.*` trace is this
|
||||
bug, not a real call edge.
|
||||
- **Nested under `consensus.accept.apply`, by design.** On the consensus path
|
||||
`buildLCL → storeLedger` ([RCLConsensus.cpp:997](../src/xrpld/app/consensus/RCLConsensus.cpp#L997))
|
||||
and `consensusBuilt → checkAccept` ([RCLConsensus.cpp:799](../src/xrpld/app/consensus/RCLConsensus.cpp#L799))
|
||||
run inside `doAccept`, whose `consensus.accept.apply` span is a scoped guard
|
||||
([RCLConsensus.cpp:634](../src/xrpld/app/consensus/RCLConsensus.cpp#L634)), so the
|
||||
`ledger.store` and `ledger.validate` created there are its children. That is a
|
||||
real containment edge. A `ledger.store` under `consensus.accept.apply` and a
|
||||
second one as a root for the same ledger is the normal shape when a node both
|
||||
builds a ledger and fetches it.
|
||||
- **`ledger.acquire` / `ledger.store` / `ledger.validate` are true roots on the
|
||||
ledger-hash trace.** All three use `SpanGuard::hashSpan`
|
||||
([InboundLedger.cpp:128](../src/xrpld/app/ledger/detail/InboundLedger.cpp#L128),
|
||||
[LedgerMaster.cpp:181](../src/xrpld/app/ledger/detail/LedgerMaster.cpp#L181)), which
|
||||
derives the trace id from the ledger hash and never inherits the ambient span. So
|
||||
the caller does not matter: an acquire started from the `ledger_request` RPC, a
|
||||
store reached from `buildLCL` inside `doAccept`, and a validate reached from
|
||||
`checkAccept` all come out as roots of the same per-ledger trace. Two `ledger.store`
|
||||
roots for one ledger is the normal shape when a node both fetches and builds it.
|
||||
|
||||
**`ledger.build` and `tx.apply` use the same ambient-parent construct and land
|
||||
on the intended edges.** `ledger.build` is a plain `ScopedSpanGuard`
|
||||
|
||||
Reference in New Issue
Block a user