Siyao Meng created HDDS-17743:
---------------------------------

             Summary: DAG snapshot diff reads value pruned compaction backup 
SST files and drops every change in them
                 Key: HDDS-17743
                 URL: https://issues.apache.org/jira/browse/HDDS-17743
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: CR-5-full-diff-fallback-for-pruned-delta-files.patch, 
TestBugCR5PrunedBackupSst.java

h3. Mechanism
{{RocksDBCheckpointDiffer.getSSTFullPath}} resolves a delta file to its copy in 
the compaction backup directory whenever that copy exists. 
{{RocksDBCheckpointDiffer.pruneSstFileValues}} rewrites the compaction inputs 
in that directory with an SST file writer: empty values and sequence number 0. 
{{DagDiffSequentialReader}} reads the delta through 
{{LatestVersionedKWayMergeIterator.overRawSstFilesFromSequence}}, which keeps 
only rows with a sequence number above the from snapshot's 
{{dbTxSequenceNumber}}, so every row of a pruned file is dropped, tombstones 
included. The values are gone too: even without the sequence check the DAG 
reader could not use these rows, because it parses the values, so relaxing the 
check for sequence 0 rows is not a fix. Nothing falls back to a full diff, and 
the job ends DONE.

h3. Trigger
{{ozone.om.snapshot.diff.optimized.enabled=true}}, native library loaded (DAG 
path, the default; the pruner runs whenever the library loads, every 10 minutes 
by default):
# Take snapshot snap1, write keys, take snapshot snap2.
# A compaction merges the SST file flushed for snap2 with other files. The file 
is kept in the backup directory and later pruned.
# Request the diff snap1 to snap2, or to a later snapshot.

A trivial move of the file to another level does not record a compaction and 
does not queue the file for pruning, so tiny test data may need keys on both 
sides of the new ones to get a merging compaction.

h3. Impact
The report misses every CREATE, MODIFY, DELETE and RENAME held in the pruned 
files; in the reproduction both reports are empty instead of five CREATEs. A 
diff over a pair whose delta files have since been compacted and pruned is 
affected, whether the file is still in the to snapshot (snap1 to snap2) or 
exists only in the backup directory (snap1 to a snapshot taken after the 
compaction). The report is persisted and returned for every later read of the 
pair.

h3. Reproduction
[^TestBugCR5PrunedBackupSst.java] ({{hadoop-ozone/integration-test}}, needs 
{{-Drocks_tools_native}}) writes keys through the client on a mini cluster, 
takes the snapshots, then runs the OM DB compaction and the pruner directly for 
timing and checks that the pruner pruned files. A control diff before pruning 
reports the five CREATEs. After pruning, snap1 to snap2 (ordered) and snap1 to 
snap3 are both empty on the unfixed code ({{Expecting actual: [] to contain 
exactly in any order: [+ ./m0, + ./m1, + ./m2, + ./m3, + ./m4]}}); with the 
patch both list the five CREATEs.

h3. Patch
[^CR-5-full-diff-fallback-for-pruned-delta-files.patch], against 
d3b75c75bf9ad475551202477c3a21a3f4b968b7. It also applies to master at 
bbc8505e00d.

New {{SstFileSetReader.hasExternalSstFile}} checks for the 
{{rocksdb.external_sst_file.version}} table property, which the SST file writer 
adds to every file it writes and flush or compaction outputs do not have. When 
a table's DAG delta contains such a file, 
{{SnapshotDiffManager.scanTablesForDiff}} logs it and uses the full diff reader 
for that table, which scans both snapshot tables and does not read the delta 
files. Any delta file written by an SST file writer takes this fallback: value 
pruned backup files, and by code reading also the files that snapshot 
defragmentation ingests (off by default; not run). Delta files produced by 
flush or compaction keep the DAG path. The fallback goes through the full diff 
reader, whose updateID gate has its own defect, HDDS-17742; until that is fixed 
the fallback can still miss changes once deep cleaning or a snapshot purge has 
updated the from snapshot. A diff over pruned files is now correct but costs a 
scan of both snapshot tables. Reading the delta from the snapshot checkpoints 
instead of the backup directory was not chosen because it does not cover delta 
files that exist only in the backup directory.

Covered by {{testDagDiffAfterBackupSstValuePruning}} in the existing 
{{TestOptimizedSnapshotDiff}} (native): it compacts, prunes, asserts that files 
were pruned, expects the five CREATEs in unordered and ordered reports, and 
asserts that the fallback was logged. Without the change both reports are 
empty. {{testHasExternalSstFile}} in the existing {{TestSstFileSetReader}} 
checks the new method on a file written by the SST file writer (true) and on a 
file flushed by a DB (false). With the change {{TestOptimizedSnapshotDiff}}, 
{{TestRocksDBCheckpointDiffer}}, {{TestSstFileSetReader}}, the snapshot diff 
unit suites and {{TestSnapshotDiffManager}} pass, and checkstyle is clean.


Found by code review of the OM optimized snapshot diff paths, as part of the 
TLA+ verification effort 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