[
https://issues.apache.org/jira/browse/HDDS-16470?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18125918#comment-18125918
]
Siyao Meng commented on HDDS-16470:
-----------------------------------
Verification run complete. The Specula pipeline ran all phases against the
pinned commit: code analysis, TLA+ specification generation, harness and trace
collection, trace validation plus TLC model checking, bug confirmation with the
adversarial Challenger debate, the spec repair loop, and severity
classification.
h3. Run environment
{noformat}
Ozone commit: 20e6a1c0f6039248373efd3eb1d7f2afcf7f1535
Specula: v1.2.0
Agent/model: claude-code, Claude Opus 5 (1M context)
Effort: medium
TLC limits: 28G memory, 8 workers
Total: 6h 51m agent time, 265.8M tokens, about $220
{noformat}
h3. Result
15 candidate findings were consolidated from model checking (MC-1 to MC-6) and
code review (CR-1 to CR-9). The spec repair loop ran two rounds, resolved all 8
repair requests, and surfaced 4 more model checking violations (MC-7 to MC-10).
All 19 were investigated individually.
||Disposition||Count||
|Reproduced|3|
|False positive|14|
|Dropped (already tracked upstream)|2|
Severity of the 3 reproduced findings: 2 Critical, 1 High. All three reached
debate consensus. MC-2 and MC-4 were confirmed three times each, once in the
first pass and once in each repair round.
h3. Reproduced findings
* (Critical) The dedup record keyed by {{ClientInvocationId(clientId, callId)}}
lives only in the in-memory Ratis retry cache. Nothing persists or rebuilds it,
while the Raft log and the applied index are durable. After a clean OM restart,
a client retry of a write that already committed and applied misses
{{checkRetryCache}}, runs {{preExecute}} again, and a second log entry with the
same invocation ID is committed and applied. Reproduced with {{renameKey}}: the
rename that succeeded is reported to the caller as {{KEY_ALREADY_EXISTS}}.
[MC-2]
* (High) The retry cache probe, {{preExecute}}, and the Ratis submit are three
separate steps. {{checkRetryCache}} is a read-only {{getIfPresent}}, and the
record it looks for is created only inside the Ratis submit, after
{{OMExecutionFlow}} has already run {{preExecute}}. A duplicate attempt that
arrives while the first is still in {{preExecute}} misses the probe, runs
{{preExecute}} a second time, and is only then absorbed by Ratis. For snapshot
create this increments {{inFlightSnapshotCount}} twice and decrements it once,
so with {{ozone.om.fs.snapshot.max.limit}} set to 8 the eighth
{{createSnapshot}} is refused with 7 snapshots present. The leak persists until
a leadership change resets the counter. [MC-4]
* (Critical) {{RetryInvocationHandler}} pins {{Client.callId}} in a ThreadLocal
before every attempt, with no {{finally}}, and only the {{Client.Call}}
constructor clears it. With follower read enabled, a DNS refresh between two
attempts nulls the cached OM proxy, and the next attempt throws in the follower
loop of {{HadoopRpcOMFollowerReadFailoverProxyProvider}} before any RPC is
issued. The pin is never cleared, so every later request on that thread,
including one from an unrelated client to a healthy OM, fails with
{{IllegalStateException}} at {{Client.setCallIdAndRetryCount}}. [CR-4]
h3. Filed
||Finding||Issue||Attachment||
|MC-2|HDDS-16743|proposed fix patch (persists recent replies in the OM DB) with
a regression test, plus the reproduction test alone|
|MC-4|HDDS-16744|fix patch with a regression test|
|CR-4|HDDS-16745|fix patch with a regression test|
h3. Novelty
* MC-4 and CR-4 were classified as new. HDDS-13357 touches
{{inFlightSnapshotCount}} accounting but not the probe gap.
* MC-2 was classified as known and unfixed, with HDDS-16736 as the nearest
existing issue. HDDS-16736 covers the S3 gRPC trigger for the same dependency
of non idempotent requests on the retry cache. The restart trigger here is a
different path on the default Hadoop RPC transport, so it is filed separately
as HDDS-16743.
h3. Dropped
* CR-6: two configuration keys set the same retry cache expiry. Tracked by
HDDS-16254.
* CR-8: {{getOMResponseFromRaftClientReply}} dereferences the reply message
with no null guard. Tracked by HDDS-11360.
h3. False positives
MC-1, MC-3, MC-5 to MC-10, CR-1 to CR-3, CR-5, CR-7 and CR-9 were investigated
and dismissed. Notable negatives: the retry cache record is rebuilt on every
replica that applies the entry, so a plain failover to a surviving peer is
covered (MC-3); Hadoop RPC pins one {{(clientId, callId)}} per logical
invocation across attempts (CR-1); the client ack follows the Raft log fsync
and commit (CR-3).
h3. Reproduce
{code:none}
specula run --agent=claude-code --effort=medium --model='claude-opus-5[1m]' \
--max-parallel=2 --enable-reviews --confirm-debate \
--tlc-memory-limit=28G --tlc-worker-limit=8 \
"om-retry-cache|apache/ozone|Java|Use the target-specific guidance"
{code}
h3. Caveats
* MC-2 holds for a single OM, a whole cluster restart, or a restarted node that
regains leadership. It needs the entry to have been flushed to the OM DB before
the restart: an OM that stops before the flush replays the entry from the Raft
log and recreates the record. Its reproduction reused the instrumented harness
checkout at the same commit; both agents checked that the trace instrumentation
does not affect dedup.
* MC-4 was reproduced with timing assistance only (two attempts of one
invocation released from a latch, no product code modified). Only the snapshot
counter consequence was demonstrated. The same ordering applies to other
{{preExecute}} side effects such as SCM {{allocateBlock}}, but those were
argued, not exercised.
* CR-4 needs both {{ozone.client.follower.read.enabled}} and
{{ozone.client.failover.resolve-needed}}, which default to false. Its scope was
narrowed during the debate to the follower loop arm; the other exits named in
the original candidate were conceded as unreachable.
* The first confirmation pass rejected the issue records for MC-4 and CR-4 on
format, and the run had to be restarted by hand to record them. Their
investigator and Challenger verdicts did not change.
* Model checking and trace validation ran against 9 collected trace scenarios
covering dedup hit, the probe gap, failover, expiry, restart, invocation
identity, stale reply, NotLeader, and the S3 auth path.
Generated with Specula (Claude Opus 5).
> [Specula] Verify om-retry-cache (Apache Ozone master @20e6a1c)
> --------------------------------------------------------------
>
> Key: HDDS-16470
> URL: https://issues.apache.org/jira/browse/HDDS-16470
> Project: Apache Ozone
> Issue Type: Sub-task
> Reporter: Siyao Meng
> Assignee: Siyao Meng
> Priority: Minor
> Labels: help-wanted, specula
> Attachments: om-retry-cache.guidance.md
>
>
> This is a runnable Apache Ozone formal-verification target for the Specula
> pipeline (TLA+ model checking plus trace validation against the real code).
> It has not been run yet. Anyone can pick it up: run Specula against the
> pinned commit, then report findings on this issue. Part of umbrella
> HDDS-15926.
> h3. Target
> {{om-retry-cache}}. Scope and code entry points are in the attached guidance
> file [^om-retry-cache.guidance.md].
> h3. Run environment
> {noformat}
> Apache Ozone commit: 20e6a1c0f6039248373efd3eb1d7f2afcf7f1535
> Specula: https://github.com/specula-org/Specula (v1.1.0 or later)
> Toolchain: JDK 21, ~28 GB RAM for TLC, an LLM coding agent
> (claude-code or codex adapter)
> Runtime: hours per target; needs an agent API budget
> {noformat}
> h3. How to run
> # Clone Specula and install per its README; clone apache/ozone and check out
> the pinned commit above.
> # Place the attached guidance file as the target's .prompt-extra.md (see the
> Specula README for target layout).
> # Run:
> {code:none}
> specula run --agent=claude-code --effort=medium --keep-original
> --max-parallel=2 \
> --enable-reviews --confirm-debate --tlc-memory-limit=28G
> --tlc-worker-limit=8 \
> "om-retry-cache|apache/ozone|Java|Use the target-specific .prompt-extra.md"
> {code}
> # Deliverables land under the run's {{.specula-output/}}:
> {{confirmed-bugs.md}}, {{bug-severity.md}}, {{summary.md}}, and
> {{confirmation/<id>/investigation.md}}.
> h3. Reporting results
> Comment here with the outcome (0 findings is still useful: it records the
> target as covered at this commit). For each confirmed bug, file a separate
> Ozone Bug and link it to this issue with the "Testing" link type ("Testing
> discovered").
> h3. Notes
> * Code entry-point line numbers in the guidance were captured at an earlier
> commit and may have shifted on this head; treat them as approximate. Specula
> re-analyzes the source, so the run does not depend on them.
> * Recon-building targets need a local Specula patch to skip Maven {{target/}}
> out-of-tree symlinks in {{snapshotlib._validate_source_tree}}, else the run
> crashes at finalize.
> * effort=medium is the tested default for large targets; effort=high can hit
> per-turn timeouts on the biggest ones.
> * Findings are proposals, to be confirmed by human review and testing before
> any fix is merged.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]