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

YUNG_CHENG updated HDDS-16273:
------------------------------
    Description: 
h2. Problem

When a follower OM bootstraps or installs a Ratis snapshot, a single SST file 
whose size is greater than or equal to 
ozone.om.ratis.snapshot.max.total.sst.size can never be transferred, and the 
follower retries forever without any error.
h2. Code path

In OMDBCheckpointServletInodeBasedXfer.collectFilesFromDir() the size budget is 
checked *before*
the file is recorded and *before* it is added to sstFilesToExclude:

long fileSize = Files.size(dbFile);
if (maxTotalSstSize.get() - fileSize <= 0)

{ return false; }

bytesRecorded += omdbArchiver.recordFileEntry(dbFile.toFile(), fileId);
...
sstFilesToExclude.add(fileId);

maxTotalSstSize is rebuilt at its full configured value on every HTTP request, 
so a file with
size >= budget fails the check in every round. The false return propagates to 
shouldContinue, which skips omdbArchiver.setCompleted(true), so the tarball 
carries neither the file nor the completion marker. 
OMDBArchiver.writeToArchive() does not throw on an empty file map and the 
servlet still returns HTTP 200.

On the follower, RDBSnapshotProvider.downloadDBSnapshotFromLeader() is an 
unbounded while(true) whose only exit is ratisSnapshotComplete(). The exclusion 
list for the next request is rebuilt from 
HAUtils.getExistingFiles(candidateDir), which is unchanged, so the leader makes 
the same zero-progress decision indefinitely. No error, no bound, no progress. 
The wedged thread also holds the synchronized OzoneManager monitor via 
installSnapshotFromLeader().

Note the comparison is "<= 0", so a file exactly equal to the budget also 
stalls.
h2. Regression

The legacy servlet does not have this bug. OMDBCheckpointServlet.processDir() 
calls processFile()
first and evaluates the budget afterwards, so it overshoots by one file and 
always makes progress.
The check-before-record ordering was introduced with the inode-based transfer 
in HDDS-12984 (commit 96390ac142), which became the default in HDDS-14721 
(ozone.om.db.checkpoint.use.inode.based.transfer=true).
HDDS-14403 raised the default budget from 100 MB to 10 GiB, which masks the bug 
but does not fix it.
h2. Impact

OM follower bootstrap / install-snapshot never completes. Reachable whenever
ozone.om.ratis.snapshot.max.total.sst.size is tuned down, or when a snapshot 
SST exceeds the
configured value. Only the snapshot-data phases are bounded (snapshot dirs, SST 
backup dir,
compaction log dir); the active om.db phase is unbounded.
h2. Existing coverage

TestOMRatisSnapshotTransfer sets the limit to the *sum* of SST sizes halved, 
which by
construction never produces a single file larger than the whole budget, so the 
failing case is untested.
h2. Proposed fix

Only enforce the budget once the current request has already collected at least 
one file, so every round transfers at least one file and the transfer always 
makes progress. This restores the legacy overshoot-by-one behaviour. 
Additionally, bound the follower loop so a zero-progress round fails with a 
diagnosable IOException instead of spinning forever.

  was:
h2. Problem

When a follower OM bootstraps or installs a Ratis snapshot, a single SST file 
whose size is greater than or equal to 
ozone.om.ratis.snapshot.max.total.sst.size can never be transferred, and the 
follower retries forever without any error.
h2. Code path

In OMDBCheckpointServletInodeBasedXfer.collectFilesFromDir() the size budget is 
checked *before*
the file is recorded and *before* it is added to sstFilesToExclude:

long fileSize = Files.size(dbFile);
if (maxTotalSstSize.get() - fileSize <= 0)

{ return false; }

bytesRecorded += omdbArchiver.recordFileEntry(dbFile.toFile(), fileId);
...sstFilesToExclude.add(fileId);

maxTotalSstSize is rebuilt at its full configured value on every HTTP request, 
so a file with
size >= budget fails the check in every round. The false return propagates to 
shouldContinue, which skips omdbArchiver.setCompleted(true), so the tarball 
carries neither the file nor the completion marker. 
OMDBArchiver.writeToArchive() does not throw on an empty file map and the 
servlet still returns HTTP 200.

On the follower, RDBSnapshotProvider.downloadDBSnapshotFromLeader() is an 
unbounded while(true) whose only exit is ratisSnapshotComplete(). The exclusion 
list for the next request is rebuilt from 
HAUtils.getExistingFiles(candidateDir), which is unchanged, so the leader makes 
the same zero-progress decision indefinitely. No error, no bound, no progress. 
The wedged thread also holds the synchronized OzoneManager monitor via 
installSnapshotFromLeader().

Note the comparison is "<= 0", so a file exactly equal to the budget also 
stalls.
h2. Regression

The legacy servlet does not have this bug. OMDBCheckpointServlet.processDir() 
calls processFile()
first and evaluates the budget afterwards, so it overshoots by one file and 
always makes progress.
The check-before-record ordering was introduced with the inode-based transfer 
in HDDS-12984 (commit 96390ac142), which became the default in HDDS-14721 
(ozone.om.db.checkpoint.use.inode.based.transfer=true).
HDDS-14403 raised the default budget from 100 MB to 10 GiB, which masks the bug 
but does not fix it.
h2. Impact

OM follower bootstrap / install-snapshot never completes. Reachable whenever
ozone.om.ratis.snapshot.max.total.sst.size is tuned down, or when a snapshot 
SST exceeds the
configured value. Only the snapshot-data phases are bounded (snapshot dirs, SST 
backup dir,
compaction log dir); the active om.db phase is unbounded.
h2. Existing coverage

TestOMRatisSnapshotTransfer sets the limit to the *sum* of SST sizes halved, 
which by
construction never produces a single file larger than the whole budget, so the 
failing case is untested.
h2. Proposed fix

Only enforce the budget once the current request has already collected at least 
one file, so every round transfers at least one file and the transfer always 
makes progress. This restores the legacy overshoot-by-one behaviour. 
Additionally, bound the follower loop so a zero-progress round fails with a 
diagnosable IOException instead of spinning forever.


> OM bootstrap never completes when a single SST file is larger than 
> ozone.om.ratis.snapshot.max.total.sst.size
> -------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-16273
>                 URL: https://issues.apache.org/jira/browse/HDDS-16273
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: YUNG_CHENG
>            Assignee: YUNG_CHENG
>            Priority: Major
>
> h2. Problem
> When a follower OM bootstraps or installs a Ratis snapshot, a single SST file 
> whose size is greater than or equal to 
> ozone.om.ratis.snapshot.max.total.sst.size can never be transferred, and the 
> follower retries forever without any error.
> h2. Code path
> In OMDBCheckpointServletInodeBasedXfer.collectFilesFromDir() the size budget 
> is checked *before*
> the file is recorded and *before* it is added to sstFilesToExclude:
> long fileSize = Files.size(dbFile);
> if (maxTotalSstSize.get() - fileSize <= 0)
> { return false; }
> bytesRecorded += omdbArchiver.recordFileEntry(dbFile.toFile(), fileId);
> ...
> sstFilesToExclude.add(fileId);
> maxTotalSstSize is rebuilt at its full configured value on every HTTP 
> request, so a file with
> size >= budget fails the check in every round. The false return propagates to 
> shouldContinue, which skips omdbArchiver.setCompleted(true), so the tarball 
> carries neither the file nor the completion marker. 
> OMDBArchiver.writeToArchive() does not throw on an empty file map and the 
> servlet still returns HTTP 200.
> On the follower, RDBSnapshotProvider.downloadDBSnapshotFromLeader() is an 
> unbounded while(true) whose only exit is ratisSnapshotComplete(). The 
> exclusion list for the next request is rebuilt from 
> HAUtils.getExistingFiles(candidateDir), which is unchanged, so the leader 
> makes the same zero-progress decision indefinitely. No error, no bound, no 
> progress. The wedged thread also holds the synchronized OzoneManager monitor 
> via installSnapshotFromLeader().
> Note the comparison is "<= 0", so a file exactly equal to the budget also 
> stalls.
> h2. Regression
> The legacy servlet does not have this bug. OMDBCheckpointServlet.processDir() 
> calls processFile()
> first and evaluates the budget afterwards, so it overshoots by one file and 
> always makes progress.
> The check-before-record ordering was introduced with the inode-based transfer 
> in HDDS-12984 (commit 96390ac142), which became the default in HDDS-14721 
> (ozone.om.db.checkpoint.use.inode.based.transfer=true).
> HDDS-14403 raised the default budget from 100 MB to 10 GiB, which masks the 
> bug but does not fix it.
> h2. Impact
> OM follower bootstrap / install-snapshot never completes. Reachable whenever
> ozone.om.ratis.snapshot.max.total.sst.size is tuned down, or when a snapshot 
> SST exceeds the
> configured value. Only the snapshot-data phases are bounded (snapshot dirs, 
> SST backup dir,
> compaction log dir); the active om.db phase is unbounded.
> h2. Existing coverage
> TestOMRatisSnapshotTransfer sets the limit to the *sum* of SST sizes halved, 
> which by
> construction never produces a single file larger than the whole budget, so 
> the failing case is untested.
> h2. Proposed fix
> Only enforce the budget once the current request has already collected at 
> least one file, so every round transfers at least one file and the transfer 
> always makes progress. This restores the legacy overshoot-by-one behaviour. 
> Additionally, bound the follower loop so a zero-progress round fails with a 
> diagnosable IOException instead of spinning forever.



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