[ 
https://issues.apache.org/jira/browse/HDDS-16450?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Siyao Meng updated HDDS-16450:
------------------------------
    Description: 
h3. Finding
Retained DELETE ops re-increment ReplicaDeleteTimeoutTotal / 
EcReplicaDeleteTimeoutTotal on every scrubber cycle, so one logical delete 
inflates the operator-facing JMX timeout metric N-fold; no safety impact 
(subscribers are idempotent), only a permanently distorted monitoring signal, 
so Low.

h3. Classification
* Verdict: REPRODUCED
* Severity: Low
* Source: Specula TLA+ model checking and confirmation debate, finding CR-3

h3. Reproduce
{noformat}
Ozone commit: 9fbf9ee0cb1bd2f5f5d437b6719ebbe5309351fb
Specula:      v1.1.0 (commit c6aa3dfa)
Target:       scm-pending-replica-ops
Guidance:     
campaigns/ozone-9fbf9ee/targets/014-scm-pending-replica-ops/.prompt-extra.md
{noformat}
{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 
\
  "scm-pending-replica-ops|apache/ozone|Java|Use the target-specific 
.prompt-extra.md"
{code}
Discovered under HDDS-16431 (Specula TLA+ verification effort). The TLA+ 
specification, counterexample, and confirmation debate live in the Specula run 
artifacts.

Generated with Specula (Claude Opus 4.8).

h3. Steps to reproduce

Precondition: a DELETE replica op is scheduled via scheduleDeleteReplica and 
its deadline passes without the datanode confirming the delete.

1. The periodic ExpiredContainerReplicaOpScrubber calls removeExpiredEntries(). 
The op is expired, so ReplicaDeleteTimeoutTotal (or 
EcReplicaDeleteTimeoutTotal) is incremented and subscribers are notified with 
timedOut=true. Unlike an ADD op, the DELETE op is intentionally kept in the map 
(HDDS-12127: ReplicationManager must resend it).
2. On the next scrubber cycle the same unchanged op is still past its deadline, 
so removeExpiredEntries increments the DELETE timeout metric again and 
re-notifies subscribers.
3. This repeats once per scrubber cycle for as long as the op stays in the map, 
so a single logical delete inflates the operator-facing JMX timeout counter 
N-fold, while an ADD op (removed on first expiry) is counted exactly once.

Observed with a focused unit test: three scrubber cycles over one retained 
DELETE produce ReplicaDeleteTimeoutTotal=3 (should be 1), whereas the ADD 
control stays at 1.

h3. Root cause

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ContainerReplicaPendingOps.java:
 in removeExpiredEntries, the DELETE branch keeps the op in the map 
(HDDS-12127) but still falls through to expiredOps.add(op) and 
updateTimeoutMetrics(op) on every pass. Because the op's deadline is unchanged, 
each subsequent scrubber cycle re-observes it as expired and re-counts it. 
updateTimeoutMetrics has been unchanged since the metric was introduced 
(HDDS-6896) and was never reconsidered when retain-on-expiry was added. The 
@Metric doc states the counter is "Number of container replicas which timed out 
before being deleted" (per replica), so re-counting one replica violates the 
documented semantics. No safety impact: the DELETE+timedOut subscribers are 
idempotent (RM resends, SCMNodeManager ignores non-ADD, MoveManager treats an 
already-gone move as a no-op); the only effect is the distorted metric.

h3. Suggested fix

Add a per-op timeoutCounted flag to ContainerReplicaOp. In 
removeExpiredEntries, count and notify a retained DELETE op only the first time 
it expires for its current deadline, then set the flag; ADD ops are unchanged 
(removed on first expiry). A resend goes through addReplica, which builds a new 
ContainerReplicaOp with the flag defaulting to false, so a distinct logical 
delete is counted again on its own expiry. This preserves the retain-and-resend 
design while making the DELETE timeout metric reflect distinct logical 
operations. See [^HDDS-16450.001.patch].

Patch is an AI-drafted proposal (Specula + Claude); pending human build, full 
test, and review before merge.


  was:
h3. Finding
Retained DELETE ops re-increment ReplicaDeleteTimeoutTotal / 
EcReplicaDeleteTimeoutTotal on every scrubber cycle, so one logical delete 
inflates the operator-facing JMX timeout metric N-fold; no safety impact 
(subscribers are idempotent), only a permanently distorted monitoring signal, 
so Low.

h3. Classification
* Verdict: REPRODUCED
* Severity: Low
* Source: Specula TLA+ model checking and confirmation debate, finding CR-3

h3. Reproduce
{noformat}
Ozone commit: 9fbf9ee0cb1bd2f5f5d437b6719ebbe5309351fb
Specula:      v1.1.0 (commit c6aa3dfa)
Target:       scm-pending-replica-ops
Guidance:     
campaigns/ozone-9fbf9ee/targets/014-scm-pending-replica-ops/.prompt-extra.md
{noformat}
{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 
\
  "scm-pending-replica-ops|apache/ozone|Java|Use the target-specific 
.prompt-extra.md"
{code}
Discovered under HDDS-16431 (Specula TLA+ verification effort). The TLA+ 
specification, counterexample, and confirmation debate live in the Specula run 
artifacts.

Generated with Specula (Claude Opus 4.8).


> Retained DELETE ops inflate ReplicaDeleteTimeout JMX metrics N-fold per 
> logical delete
> --------------------------------------------------------------------------------------
>
>                 Key: HDDS-16450
>                 URL: https://issues.apache.org/jira/browse/HDDS-16450
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Minor
>         Attachments: HDDS-16450.001.patch
>
>
> h3. Finding
> Retained DELETE ops re-increment ReplicaDeleteTimeoutTotal / 
> EcReplicaDeleteTimeoutTotal on every scrubber cycle, so one logical delete 
> inflates the operator-facing JMX timeout metric N-fold; no safety impact 
> (subscribers are idempotent), only a permanently distorted monitoring signal, 
> so Low.
> h3. Classification
> * Verdict: REPRODUCED
> * Severity: Low
> * Source: Specula TLA+ model checking and confirmation debate, finding CR-3
> h3. Reproduce
> {noformat}
> Ozone commit: 9fbf9ee0cb1bd2f5f5d437b6719ebbe5309351fb
> Specula:      v1.1.0 (commit c6aa3dfa)
> Target:       scm-pending-replica-ops
> Guidance:     
> campaigns/ozone-9fbf9ee/targets/014-scm-pending-replica-ops/.prompt-extra.md
> {noformat}
> {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 \
>   "scm-pending-replica-ops|apache/ozone|Java|Use the target-specific 
> .prompt-extra.md"
> {code}
> Discovered under HDDS-16431 (Specula TLA+ verification effort). The TLA+ 
> specification, counterexample, and confirmation debate live in the Specula 
> run artifacts.
> Generated with Specula (Claude Opus 4.8).
> h3. Steps to reproduce
> Precondition: a DELETE replica op is scheduled via scheduleDeleteReplica and 
> its deadline passes without the datanode confirming the delete.
> 1. The periodic ExpiredContainerReplicaOpScrubber calls 
> removeExpiredEntries(). The op is expired, so ReplicaDeleteTimeoutTotal (or 
> EcReplicaDeleteTimeoutTotal) is incremented and subscribers are notified with 
> timedOut=true. Unlike an ADD op, the DELETE op is intentionally kept in the 
> map (HDDS-12127: ReplicationManager must resend it).
> 2. On the next scrubber cycle the same unchanged op is still past its 
> deadline, so removeExpiredEntries increments the DELETE timeout metric again 
> and re-notifies subscribers.
> 3. This repeats once per scrubber cycle for as long as the op stays in the 
> map, so a single logical delete inflates the operator-facing JMX timeout 
> counter N-fold, while an ADD op (removed on first expiry) is counted exactly 
> once.
> Observed with a focused unit test: three scrubber cycles over one retained 
> DELETE produce ReplicaDeleteTimeoutTotal=3 (should be 1), whereas the ADD 
> control stays at 1.
> h3. Root cause
> hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ContainerReplicaPendingOps.java:
>  in removeExpiredEntries, the DELETE branch keeps the op in the map 
> (HDDS-12127) but still falls through to expiredOps.add(op) and 
> updateTimeoutMetrics(op) on every pass. Because the op's deadline is 
> unchanged, each subsequent scrubber cycle re-observes it as expired and 
> re-counts it. updateTimeoutMetrics has been unchanged since the metric was 
> introduced (HDDS-6896) and was never reconsidered when retain-on-expiry was 
> added. The @Metric doc states the counter is "Number of container replicas 
> which timed out before being deleted" (per replica), so re-counting one 
> replica violates the documented semantics. No safety impact: the 
> DELETE+timedOut subscribers are idempotent (RM resends, SCMNodeManager 
> ignores non-ADD, MoveManager treats an already-gone move as a no-op); the 
> only effect is the distorted metric.
> h3. Suggested fix
> Add a per-op timeoutCounted flag to ContainerReplicaOp. In 
> removeExpiredEntries, count and notify a retained DELETE op only the first 
> time it expires for its current deadline, then set the flag; ADD ops are 
> unchanged (removed on first expiry). A resend goes through addReplica, which 
> builds a new ContainerReplicaOp with the flag defaulting to false, so a 
> distinct logical delete is counted again on its own expiry. This preserves 
> the retain-and-resend design while making the DELETE timeout metric reflect 
> distinct logical operations. See [^HDDS-16450.001.patch].
> Patch is an AI-drafted proposal (Specula + Claude); pending human build, full 
> test, and review before merge.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to