Siyao Meng created HDDS-17733:
---------------------------------

             Summary: Snapshot diff page token is not checked against the 
current report
                 Key: HDDS-17733
                 URL: https://issues.apache.org/jira/browse/HDDS-17733
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: MC-8-reject-page-token-not-in-current-report.patch

h3. Mechanism
A snapshot diff page token is the suffix of the key of the next report row. 
Each page request looks up the job of the snapshot pair again, and 
{{SnapshotDiffManager.createPageResponse}} scans from {{<jobId>-<token>}}, the 
row the token names, without checking that this row belongs to the current 
report.

A report is stored in one of two key formats: dependency ordered rows are 
{{<jobId>-0<20 digits>}}, unordered rows are {{<jobId>-<1..4><20 digits>}}. 
When the job of a snapshot pair has been regenerated as an unordered report 
between two page requests of a dependency ordered report, the token of the 
earlier run sorts before every row of the new run, and the resumed read 
continues from the first row of the new run.

h3. Trigger
Requires {{ozone.om.snapshot.diff.optimized.enabled}} = true (default false) 
and an FSO bucket, where dependency ordered reports are produced (added by 
HDDS-15391, not in any release).
# A client reads page 1 of a dependency ordered report and keeps the token.
# The job expires through {{SnapshotDiffCleanupService}} 
({{ozone.om.snapshot.diff.job.report.persistent.time}}, 7 days by default, 
counted from job creation).
# An unordered report is requested for the same snapshot pair and completes.
# The client requests the next page with its token.

h3. Impact
The resumed read returns the whole new report, so the rows of the pages already 
read appear twice; for a 5 entry report read with page size 2 the client 
assembles 7 rows. No error is returned.

h3. Reproduction
This issue has no standalone reproduction; the regression test in the patch is 
the reproduction. 
{{TestSnapshotDiffManager#testCreatePageResponseRejectsTokenOfRegeneratedReport}}
 applies a token of a dependency ordered run to an unordered report of the same 
snapshot pair and expects it to be rejected. On 
d3b75c75bf9ad475551202477c3a21a3f4b968b7 it fails with "Expected 
java.io.IOException to be thrown, but nothing was thrown", because the scan 
restarts at the first row.

h3. Patch
[^MC-8-reject-page-token-not-in-current-report.patch], against 
d3b75c75bf9ad475551202477c3a21a3f4b968b7. It also applies to master at 
bbc8505e00d.

{{createPageResponse}} now looks up the row the token names before scanning 
and, for a report with entries, rejects a token that names no row of the 
current report with "Token ... does not belong to the current report of this 
snapshot diff. The report may have been regenerated, retry from the first page 
without a token." A token of the current report pages exactly as before; the 
cost is one point lookup per page request that carries a token. The token 
format is unchanged.

The new test also checks that a token of the current report still returns the 
rows from the one it names. Without the change it fails as above; with it 
{{TestSnapshotDiffManager}} (85 tests) and the mini cluster suite 
{{TestOmSnapshotFsoWithoutNativeLib}} pass and checkstyle is clean.

Found by TLA+ model checking and code review of the OM optimized snapshot diff 
paths under HDDS-15926, on commit d3b75c75bf9ad475551202477c3a21a3f4b968b7. 
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
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to