You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@ozone.apache.org by "ASF GitHub Bot (Jira)" <ji...@apache.org> on 2026/06/11 06:06:00 UTC
[jira] [Updated] (HDDS-15524) [DiskBalancer] Container parallel moves can overwrite pending source replica deletions
[ https://issues.apache.org/jira/browse/HDDS-15524?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
ASF GitHub Bot updated HDDS-15524:
----------------------------------
Labels: pull-request-available (was: )
> [DiskBalancer] Container parallel moves can overwrite pending source replica deletions
> --------------------------------------------------------------------------------------
>
> Key: HDDS-15524
> URL: https://issues.apache.org/jira/browse/HDDS-15524
> Project: Apache Ozone
> Issue Type: Sub-task
> Affects Versions: 2.2.0
> Reporter: Gargi Jaiswal
> Assignee: Gargi Jaiswal
> Priority: Major
> Labels: pull-request-available
>
> In {{DiskBalancerService.java}} *at lines 642-643 :*
>
> {code:java}
> pendingDeletionContainers.put(clock.millis() + replicaDeletionDelay, container);{code}
> {quote}After a successful container move, the old replica is queued for deletion in {{{}pendingDeletionContainers{}}}, keyed by {{{}clock.millis() + replicaDeletionDelay{}}}. That key has only millisecond precision, so if two moves finish in the same millisecond, they get the same key.
> Because the {*}map stores one container per key{*}, the second {{put()}} overwrites the first. The overwritten container is never scheduled for deletion, so its old replica stays on disk and wastes space. With {{{}parallelThread > 1{}}}, this is realistic under normal load.{quote}
> The key is: *{color:#172b4d}{{clock.millis() + replicaDeletionDelay}}{color}*
> Both parts are the same for every thread finishing at the same millisecond: * {{{}*clock.millis()*{}}}{*}—{*} wall clock, millisecond resolution. All JVM threads share the same clock.
> * {{{}*replicaDeletionDelay*{}}}{*}—{*} a single constant (default 5 minutes = 300,000 ms) shared by the whole service.
> *Step-by-step analysis*
> Assume {color:#00875a}{{replicaDeletionDelay = 300,000 ms}}{color} and{color:#00875a} {{parallelThread = 5}}{color}.
> Five container moves run in parallel. Moves for containers C-101 and C-202 both finish at {color:#00875a}{{clock.millis() = 1,000,000}}{color}:
>
> {code:java}
> Thread-1 (moving C-101):
> key = 1,000,000 + 300,000 = 1,300,000
> pendingDeletionContainers.put(1_300_000, C-101_old_replica)
> Map now: { 1_300_000 → C-101_old }
>
> Thread-2 (moving C-202), same millisecond:
> key = 1,000,000 + 300,000 = 1,300,000 <------ identical key! pendingDeletionContainers.put(1_300_000, C-202_old_replica)
> Map now: { 1_300_000 → C-202_old } <--------- C-101_old silently GONE{code}
> C-101's old replica has been permanently lost from the pending-deletion queue. It will never be scheduled for deletion. * C-202's old replica gets deleted correctly.
> * C-101's old replica is never visited. It sits on the source disk forever.
> * The container is marked {{{}DELETED{}}}in metadata (line 605), so it won't be served.
> * But its data directory(chunks,{{{}container.db{}}},{{{}.container{}}}descriptor) remains on the source disk.
> * {{{}decrementUsedSpace{}}}is only called inside{{{}deleteContainer(){}}}, so the source volume'sused-space counter is never corrected.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@ozone.apache.org
For additional commands, e-mail: issues-help@ozone.apache.org