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

Siyao Meng updated HDDS-17020:
------------------------------
    Attachment: TestBugCR1FailVolumeHoldsVolumeSetLock.java

> Datanode volume failure closes the failed volume's RocksDB while holding the 
> volume set write lock, stalling container creates and node reports
> -----------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-17020
>                 URL: https://issues.apache.org/jira/browse/HDDS-17020
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Major
>         Attachments: TestBugCR1FailVolumeHoldsVolumeSetLock.java
>
>
> h3. Mechanism
> {{MutableVolumeSet.handleVolumeFailures}} and {{MutableVolumeSet.failVolume}} 
> call {{HddsVolume.failVolume}} while holding the volume set write lock, and 
> with schema V3 that closes the volume's per disk RocksDB in place: 
> {{RDBStore.close}} flushes the DB, then {{RocksDatabase.close}} runs 
> {{cancelAllBackgroundWork(true)}} and {{waitAndClose}} waits, without a 
> timeout, until every open reference to the DB is released. Since HDDS-14800 a 
> RocksDB iterator holds a DB reference until it is closed, and the comment in 
> {{waitAndClose}} expects the wait to be short. The data scanner keeps its 
> block iterator open while it scans a block, so it is the long holder: one 
> block at {{hdds.container.scrub.volume.bytes.per.second}} (default 5 MB/s), 
> about 51 s for a 256 MB block.
> Until the close returns, everything that takes the volume set read lock 
> waits: {{MutableVolumeSet.getStorageReport}} (node report), 
> {{KeyValueContainer.create}} on every volume, and 
> {{KeyValueHandler.populateContainerPathFields}} (container import, including 
> disk balancer moves). The fatal volume failure check and the failed volume 
> listener ({{ContainerSet.handleVolumeFailures}}) only run after the close.
> h3. Trigger
> # The data scanner is scanning a block of a container on volume V, holding 
> its block iterator.
> # The volume checker fails V, and {{handleVolumeFailures}} closes V's DB 
> under the write lock.
> No client action is involved.
> h3. Impact
> * While the close waits, container creates and imports on all volumes of the 
> datanode wait. This includes the create that {{HddsDispatcher}} runs for the 
> first WriteChunk, PutBlock or PutSmallFile of a new container, so client 
> writes to new containers stall on every volume of the datanode. Reads and 
> writes on existing containers do not take the lock.
> * Node report generation waits; heartbeats continue with the last published 
> node report.
> * The failed volume listener does not run until the close returns, so the 
> containers of the failed volume stay in the container set and in container 
> reports, and SCM keeps counting those replicas and does not re-replicate 
> them. The failed volume tolerance check is not applied either.
> * Measured: the stall lasts as long as the reference is held, here 2 s. The 
> bound is the longest of the reference hold, the flush and the background work 
> cancel; for the scanner see above (arithmetic, not run).
> * Argued, not reproduced: for as long as the scanner's read or the flush 
> blocks on the failing disk (indefinitely on a hung device), all of the above 
> persist. A hung disk is the case a disk check timeout fails a volume for.
> h3. Reproduction
> PASS, deterministic, unmodified source. 
> [^TestBugCR1FailVolumeHoldsVolumeSetLock.java] 
> ({{hadoop-hdds/container-service}}) uses two schema V3 data volumes, keeps a 
> block iterator on the first volume's DB open as the data scanner does during 
> a block scan, and calls {{MutableVolumeSet.failVolume}} on that volume. For 
> the 2 s the iterator is held, {{failVolume}}, {{getStorageReport}} and a 
> container create with the round robin policy (which then lands on the healthy 
> volume) all stay unfinished; after the iterator is closed all three complete. 
> It shows the lock being held across the close, not a hung disk read. A 
> passing test means the defect is present.
> h3. Suggested fix
> No patch is attached; the order of the failure handling steps is for review. 
> Under the write lock, only mark the volume failed and move it to the failed 
> volume map. Close its DB after the fatal check and the failed volume listener 
> have run, or asynchronously, so that a hanging close does not hold back the 
> container sweep and the full container report. Other paths need the same 
> treatment:
> * {{MutableVolumeSet.failVolume}} is public and some direct callers already 
> hold the write lock ({{VersionEndpointTask.checkVolumeSet}}, 
> {{ScmHAFinalizeUpgradeActionDatanode}}); others call it outside 
> {{handleVolumeFailures}} ({{ContainerReader}}, {{HddsDatanodeService}}). 
> Moving the close only inside {{handleVolumeFailures}} leaves those closing 
> under the lock.
> * {{DbVolume.failVolume}} closes every DB on a DB volume under the DB volume 
> set write lock, and {{OzoneContainer.getNodeReport}} also reads that set's 
> storage report, so the same stall applies there for each DB on the DB volume.
> 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. Affects 2.2.0 and 
> later (the iterator reference dates from HDDS-14800; the flush under the lock 
> is older). Related but not duplicates: HDDS-14800, and HDDS-16119, which 
> removed the volume set lock from the metrics path for a similar reason. 
> 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