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

Siyao Meng updated HDDS-17026:
------------------------------
    Attachment: TestBugMC10DbLoadReservationLeak.java

> Datanode container create that fails with an unchecked exception leaks the 
> reserved container size on the volume until restart
> ------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-17026
>                 URL: https://issues.apache.org/jira/browse/HDDS-17026
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Minor
>         Attachments: 
> MC-10-release-reservation-on-unchecked-create-failure.patch, 
> TestBugMC10DbLoadReservationLeak.java
>
>
> h3. Mechanism
> {{KeyValueContainer.create}} reserves the container size ({{maxSize}}, 5 GB 
> by default) on the volume that {{chooseVolume}} picks. 
> {{KeyValueHandler.handleCreateContainer}} gives that reservation back only in 
> its {{catch (StorageContainerException)}} branch. When {{create}} fails with 
> an unchecked exception after the volume was chosen, the exception passes that 
> branch, {{KeyValueHandler.handle}} turns it into a 
> {{CONTAINER_INTERNAL_ERROR}} response, and the volume's committed bytes stay 
> raised by the full container size. Nothing recomputes committed bytes while 
> the datanode runs, so each such attempt adds another {{maxSize}} until 
> restart. Present since HDDS-12810 (2.1.0), which moved the reservation into 
> {{chooseVolume}}; 2.0.0 is not affected (checked in the ozone-2.0.0, 2.1.0 
> and 2.2.1 tags).
> h3. Trigger
> Today this is reached through the state described in HDDS-11485: a data 
> volume whose per-volume DB did not load at restart (for example its 
> {{DS-<id>}} directory or {{container.db}} is gone, or a dedicated DB volume 
> was lost) stays in service with {{dbParentDir}} unset. Every container create 
> placed on it, including the implicit create {{HddsDispatcher}} issues for the 
> first write to a new container, throws {{NullPointerException("dbParentDir == 
> null")}} from {{KeyValueContainerLocationUtil.getContainerDBFile}} after the 
> reservation. Any other unchecked failure in {{create}} after the volume is 
> chosen leaks the same way.
> h3. Impact
> * Each failed create leaves {{maxSize}} committed on the volume. In the 
> reproduction three creates left 15 GB committed on an empty volume, and the 
> storage report sent to SCM carries it.
> * The volume choosing policy counts committed bytes against the volume's free 
> space, so the phantom bytes grow until they fill it; after that the policy 
> stops picking the volume (by code reading, not run). On the known trigger 
> every create on that volume fails anyway, so the harm is the wrong committed 
> and free space figures, on the datanode and in what SCM sees.
> * The creates themselves fail either way; this report is only about the space 
> they leave reserved.
> h3. Reproduction
> PASS on unmodified source. [^TestBugMC10DbLoadReservationLeak.java] 
> ({{hadoop-hdds/container-service}}, target path and Maven command in the 
> class comment) formats a data volume whose DB lives on a dedicated DB volume, 
> loses the DB disk and drops it from the configuration, then rebuilds the 
> volume set with a real {{StorageVolumeChecker}}, loads the DBs and runs the 
> startup volume check. The volume is {{NORMAL}} with {{isDbLoaded=false}} and 
> {{dbParentDir=null}}. Three CreateContainer requests go through 
> {{KeyValueHandler.handle}}; each returns {{CONTAINER_INTERNAL_ERROR}} with 
> "dbParentDir == null", no container is added, and committed bytes grow to 
> 5368709120, 10737418240 and 16106127360. A later volume check still finds the 
> volume healthy and its report carries 3 x 5 GB committed. A passing test 
> means the defect is present.
> h3. Patch
> [^MC-10-release-reservation-on-unchecked-create-failure.patch], against 
> cce1ca28944886218132f01c0e271c1fd0700078. It also applies to master at 
> 2536fe9cbc3.
> {{handleCreateContainer}} now releases the reservation in its {{finally}} 
> block whenever the container was not created, instead of only in the 
> {{StorageContainerException}} branch. {{ContainerData.releaseCommitSpace}}, 
> unchanged, already gives back the space only while the reservation is still 
> held and then clears the flag, so a path that already released it is not 
> released twice, and the branch for an already existing container, which 
> reserves nothing, is unaffected. Volume state handling is not changed: with 
> the patch such a volume still stays in service and the creates still fail, 
> but nothing stays reserved. The root cause of that volume state is tracked in 
> HDDS-11485; this fix is independent of it.
> Covered by {{testCreateContainerReleasesSpaceOnUncheckedFailure}} in the 
> existing {{TestKeyValueHandler}}: a schema V3 volume with its working 
> directory but no per-volume DB, one CreateContainer through 
> {{KeyValueHandler.handle}}. Without the change it fails with "expected: 0L 
> but was: 5368709120L"; with it the volume has no committed bytes. The new 
> {{testCreateContainerKeepsSpaceOfCreatedContainer}} covers the guard: a 
> successful create keeps {{maxSize}} committed with the reservation flag set, 
> and a repeated create of the same container leaves both unchanged; it fails 
> if the release is made unconditional. The existing 
> {{testCreateContainerWithFailure}}, which makes {{ContainerSet.addContainer}} 
> throw {{StorageContainerException}}, covers the checked path and passes 
> unchanged. With the change the handler, container, dispatcher, persistence 
> and {{OzoneContainer}} suites (551 tests) pass and checkstyle is clean. With 
> the patch the reproduction fails at its committed bytes check after the first 
> create, while the volume is still {{NORMAL}}.
> Found by TLA+ model checking and code review of the datanode volume and 
> per-disk RocksDB lifecycle paths under HDDS-15926, on commit 
> cce1ca28944886218132f01c0e271c1fd0700078. Checked against HDDS issues and 
> apache/ozone pull requests for duplicates before filing. Related but not 
> duplicates: HDDS-11485 (the volume state that reaches this today) and 
> HDDS-17009 (releases the reservation on a volume that the retry loop in 
> {{KeyValueContainer.create}} gives up on; the two patches are independent and 
> apply together). 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