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

Siyao Meng updated HDDS-17008:
------------------------------
    Attachment: CR-15-reserve-before-container-visible-at-load.patch

> Duplicate container resolved by another volume's ContainerReader at datanode 
> start can leave a reservation for the deleted copy
> -------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-17008
>                 URL: https://issues.apache.org/jira/browse/HDDS-17008
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Minor
>         Attachments: CR-15-reserve-before-container-visible-at-load.patch, 
> TestBugCR15DuplicateSwapReservationRace.java
>
>
> h3. Mechanism
> At start, {{OzoneContainer.buildContainerSet}} runs one {{ContainerReader}} 
> per volume on a shared {{ContainerSet}}. 
> {{ContainerReader.verifyAndFixupContainerData}} adds a container to the set 
> and only then reserves its space ({{commitSpace}}). Nothing orders these two 
> steps against the other readers. If the same OPEN container is on another 
> volume with a higher BCSID (or CLOSED), that volume's reader can find the 
> first copy in the set, swap it out, delete it from disk and release its 
> reservation in between. That release does nothing, because nothing is 
> reserved yet. The first reader then reserves space for the copy that was just 
> deleted.
> h3. Trigger
> The same container on two volumes at datanode start, the stale copy OPEN, and 
> the stale copy's reader descheduled between {{addContainer}} and 
> {{commitSpace}} for as long as the other reader needs for the whole duplicate 
> handling, including removing the stale copy from disk. The precondition is 
> rare: the disk balancer refuses to move OPEN containers, so it does not 
> create such a duplicate. One possible route (argued, not run) is a volume 
> that fails with an OPEN copy, the container being replicated as CLOSED to 
> another volume of the same datanode, and the failed volume coming back at the 
> next start. The window is narrow as well: a run of 400 duplicate pairs 
> without timing help did not hit it.
> h3. Impact
> The volume of the deleted copy keeps one container size (minus the copy's 
> used bytes) committed until the next restart, refuses that much new data, and 
> reports it in the storage report. No data is lost.
> h3. Reproduction
> [^TestBugCR15DuplicateSwapReservationRace.java] 
> ({{hadoop-hdds/container-service}}) uses two real volumes, the same container 
> with BCSID 5 and 10, and real {{ContainerReader}}s. The only help is timing: 
> a {{ContainerSet}} spy runs the real {{addContainer}} and then holds the 
> stale copy's reader on a latch until the other reader has finished. Output: 
> {{kept copy on fresh volume=true, stale copy dir exists=false, stale volume 
> committed=5368709120, fresh volume committed=5368709120}}. A passing test 
> means the defect is present.
> h3. Patch
> [^CR-15-reserve-before-container-visible-at-load.patch], against 
> cce1ca28944886218132f01c0e271c1fd0700078. It also applies to master at 
> 2536fe9cbc3. Released 2.1.0 and later have the same code.
> The reader reserves before it adds the container to the set, so a copy is 
> reserved from the moment another reader can see it, and a {{finally}} 
> releases the copy's own reservation when it is not kept (duplicate not 
> swapped, or the add or duplicate resolution failed before the copy entered 
> the set). A failure after the copy entered the set (removing the swapped out 
> copy, or the container ID table update) leaves the reservations as they are 
> today: the copy in the set unreserved, the swapped out copy still reserved. 
> When the new copy wins, the existing copy is released as before. Covered by 
> the new {{TestContainerReader.testDuplicateSwappedWhileFirstCopyIsLoading}}, 
> which fails without the change ({{expected: 0L but was: 5368698880L}}), and 
> by a new check in the existing {{testMultipleContainerReader}} that each 
> volume's committed bytes match the OPEN containers kept on it. With the 
> change the reader, container, persistence and handler suites pass (332 tests) 
> and checkstyle is clean.
> Not covered: {{ContainerSet.addContainer}} also adds the container ID to the 
> volume's list after the map insert, and the swap removes it from there. A 
> slightly shifted interleaving could leave the ID of the deleted copy in the 
> stale volume's list (argued, not run).
> Found by code review of the datanode volume and per-disk RocksDB lifecycle 
> paths, as part of the TLA+ verification effort under HDDS-15926, on commit 
> cce1ca28944886218132f01c0e271c1fd0700078. Checked against HDDS issues and 
> apache/ozone pull requests for duplicates before filing. 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