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

Siyao Meng updated HDDS-17069:
------------------------------
    Attachment: TestBugCR2OpenContainerCountDrift.java

> Recon's per datanode open container count drifts from the containers that are 
> actually open
> -------------------------------------------------------------------------------------------
>
>                 Key: HDDS-17069
>                 URL: https://issues.apache.org/jira/browse/HDDS-17069
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Minor
>         Attachments: 
> CR-2-count-open-containers-per-pipeline-from-state.patch, 
> TestBugCR2OpenContainerCountDrift.java
>
>
> h3. Mechanism
> {{NodeEndpoint.getDatanodes}} fills {{openContainers}} of each datanode in 
> {{/api/v1/datanodes}} by adding up 
> {{ReconContainerManager.getPipelineToOpenContainer()}} over the datanode's 
> pipelines. That map is a counter: {{addNewContainer}} increments it and 
> {{transitionOpenToClosing}} decrements it, and nothing rebuilds or checks it. 
> Three paths make it wrong:
> * An UNHEALTHY (or INVALID, DELETED) replica report of an OPEN container. 
> Recon's own step, {{checkContainerStateAndUpdate}}, skips 
> {{transitionOpenToClosing}} for unhealthy replicas (a check that dates from 
> HDDS-4029 and was moved there by HDDS-5126), and SCM's shared 
> {{AbstractContainerReportHandler}} then moves the container to CLOSING 
> through {{updateContainerState}}, which does not touch the counter. The count 
> stays one too high.
> * Two datanodes reporting the same new container. 
> {{ContainerStateManagerImpl.addContainer}} silently skips a container that 
> already exists, but {{addNewContainer}} increments anyway. Reports from 
> different datanodes are handled in parallel, and the window includes an SCM 
> call.
> * Restart. The map starts empty and is not rebuilt from the OPEN containers 
> Recon loads, so they count as zero, and the first two paths keep adding to 
> whatever is left.
> h3. Trigger
> A datanode reporting an unhealthy replica of an open container, reports of a 
> new container from two of the pipeline's datanodes that race (both pass the 
> existence check before either adds the container), or a Recon restart.
> h3. Impact
> Wrong per datanode open container count in Recon's datanode API and UI, 
> growing over the life of a pipeline and reset to zero by each restart. In the 
> attached run: two reports of one new container gave a count of 2 with one 
> OPEN container; after an UNHEALTHY then a CLOSED report the container was 
> CLOSED and the count stayed 1; after a restart the OPEN container was loaded 
> and the pipeline had no count. Display only: nothing else reads the counter.
> h3. Reproduction
> [^TestBugCR2OpenContainerCountDrift.java] goes in {{hadoop-ozone/recon}} 
> (target path and Maven command in the class comment) and passes on unmodified 
> source when the bug is present. It uses a real {{ReconContainerManager}} and 
> {{ReconPipelineManager}} on RocksDB and delivers reports through the real 
> {{ReconIncrementalContainerReportHandler}}. Only the SCM RPC peer is mocked. 
> The concurrent case handles the second datanode's report inside the first 
> one's SCM call, so it is deterministic. The restart case builds a new 
> container manager over the same Recon SCM DB.
> h3. Patch
> [^CR-2-count-open-containers-per-pipeline-from-state.patch], against 
> 916aa1d9949cbb10f2750a40c8704340893131a2. It also applies to master at 
> d77edaa6c15.
> The counter is removed. {{getPipelineToOpenContainer()}} now counts Recon's 
> OPEN containers per pipeline from {{getContainers(OPEN)}}, which uses the 
> container state index, and {{NodeEndpoint.getDatanodes}} calls it once per 
> request instead of once per pipeline per datanode. The count can no longer 
> drift, and nothing needs rebuilding at startup.
> Covered by the new 
> {{TestReconContainerManager.testOpenContainerCountWhenContainerAddedAgain}}, 
> {{TestReconContainerManager.testOpenContainerCountAfterRestart}} and 
> {{TestReconIncrementalContainerReportHandler.testOpenContainerCountAfterUnhealthyReplicaReport}};
>  all fail without the change (count 2 instead of 1, no count after the 
> restart, and 1 left for a CLOSED container). 
> {{testTransitionOpenToClosingDoesNotDecrementCountOnFailure}} set the removed 
> counter directly; its check that {{transitionOpenToClosing}} of an unknown 
> container throws {{ContainerNotFoundException}} is kept as 
> {{testTransitionOpenToClosingOfUnknownContainer}}. With the change the Recon 
> {{scm}}, {{fsck}} and {{api}} unit tests pass, checkstyle is clean, and the 
> attached tests no longer show the bug.
> Found by code review of the datanode container report and Recon container 
> tracking paths, as part of the TLA+ verification effort under HDDS-15926, on 
> commit 916aa1d9949cbb10f2750a40c8704340893131a2. Checked against HDDS issues 
> and apache/ozone pull requests for duplicates before filing. Related but not 
> duplicates: HDDS-5314 (resolved, introduced the counter), HDDS-5126 
> (resolved, moved the unhealthy replica check into its current method), 
> HDDS-15308 (resolved, reworked Recon's report driven transitions), HDDS-14560 
> (resolved, per disk open containers, does not use this counter). The attached 
> patch is a proposal for review. Generated with Specula (Claude Opus 5.5).



--
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