Siyao Meng created HDDS-17243:
---------------------------------

             Summary: Quota repair counts pending deletes of a bucket again for 
every snapshot of another bucket that holds a copy of them
                 Key: HDDS-17243
                 URL: https://issues.apache.org/jira/browse/HDDS-17243
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: 
CR-13-quota-repair-scans-only-own-bucket-rows-of-snapshot-db.patch, 
TestBugCR13SnapshotDbCrossBucketCount.java

h3. Mechanism
{{QuotaRepairTask.recalculateSnapshotDbPendingDeleteQuota}} recomputes 
{{snapshotUsedBytes}} and {{snapshotUsedNamespace}} from the active DB 
checkpoint and from every snapshot DB on the repaired buckets' snapshot chains. 
For a snapshot DB it scans the whole {{deletedTable}} and {{deletedDirTable}} 
({{recalculateDeletedKeyUsages}}, {{recalculateDeletedDirNamespace}}) and 
credits each row to the bucket it belongs to.

A snapshot DB is a checkpoint of the whole OM DB. 
{{OmSnapshotManager.createOmSnapshotCheckpoint}} removes only the snapshot's 
own bucket prefix from the active {{deletedTable}}, {{deletedDirTable}} and 
{{snapshotRenamedTable}}, so the pending deletes of every other bucket stay in 
the active DB and are also copied into the snapshot DB. The repair counts them 
once from the active DB checkpoint and once more from every snapshot DB of 
another bucket that holds a copy. The code that reads or changes a snapshot's 
deleted tables ({{SnapshotDeletingService}} through 
{{KeyManagerImpl.getDeletedKeyEntries}} and {{getDeletedDirEntries}}, 
{{OMSnapshotMoveTableKeysRequest}}) always restricts itself to the snapshot's 
bucket prefix, so the copies are never removed from the snapshot DB, and the 
repair keeps counting them even after the real entries have been purged from 
the active DB.

h3. Trigger
* A snapshot of bucket A taken while bucket B (any other bucket in the cluster) 
had pending deletes in the active {{deletedTable}} or {{deletedDirTable}}.
* A quota repair that includes both buckets ({{ozone repair om quota start}}, 
admin only; a repair without {{--buckets}} includes every bucket). The repair 
scans only the snapshots of the buckets it repairs, so a repair of bucket B 
alone is not affected.

h3. Impact
* {{snapshotUsedBytes}} and {{snapshotUsedNamespace}} of bucket B end too high 
by one copy of its rows per snapshot DB of another bucket that holds them 
(reproduced: 6000 bytes and 2 entries where 3000 and 1 are correct, with one 
snapshot of another bucket; 3000 bytes where 1000 is correct, with two). The 
value is written to RocksDB, and every later repair computes the same excess 
again while those snapshots exist.
* By the code, not run: the quota checks use used plus snapshotUsed, so bucket 
B can reject writes with {{QUOTA_EXCEEDED}} before it reaches its quota. On a 
real cluster the excess can be smaller than one full copy per snapshot, because 
{{SstFilteringService}} drops the SST files of a snapshot DB that hold no key 
of the snapshot's own bucket, and with them some of the copies.

h3. Reproduction
[^TestBugCR13SnapshotDbCrossBucketCount.java] goes into 
{{hadoop-ozone/ozone-manager}} (target package and Maven command in the class 
comment) and passes on unmodified source while the bug is present. It deletes 
one key of bucket B, takes a snapshot of bucket A with the real 
{{OMSnapshotCreateRequest}}, then runs {{QuotaRepairTask}} and applies the 
request it submits: bucket B ends at 6000 bytes and 2 entries. A control 
without the snapshot ends at 3000 and 1.

h3. Patch
[^CR-13-quota-repair-scans-only-own-bucket-rows-of-snapshot-db.patch] applies 
on top of the patch of HDDS-17241 (against 
20d95ed37fe35013b5320713665db03c06ee36fa plus that patch); the two also apply 
to master at 64d4a791502. It does not conflict with the patch for deleted 
snapshots that are not purged yet (filed separately): either applies on top of 
the patch of HDDS-17241 alone or together with the other, in either order.

The snapshot DB scan now iterates only the snapshot's own bucket prefix, 
{{/volume/bucket/}} in {{deletedTable}} and {{/volumeId/bucketId/}} in 
{{deletedDirTable}}: the same rows that snapshot create removes from the active 
DB and that {{SnapshotDeletingService}} moves. Each pending entry is then 
counted once, from the active DB or from the one snapshot DB that holds it, 
also for a bucket with several snapshots. The scan of the active DB checkpoint 
is unchanged, and a snapshot DB scan now reads only its own bucket's rows 
instead of every deleted row in the cluster. This also takes 
{{SstFilteringService}} out of the picture: it deletes SST files of a snapshot 
DB that hold only other buckets' rows without updating the snapshot's 
{{lastTransactionInfo}}, so before this change a filter run during the repair 
could change what was counted without the check of HDDS-17241 noticing.

Covered by {{testQuotaRepairCountsOnlyOwnBucketRowsOfSnapshotDb}} in the 
existing {{TestQuotaRepairTask}}: two FSO buckets with deleted keys and 
directories, and two snapshots of one of them. The first bucket's name and ID 
are string prefixes of the other bucket's, so the test also shows that the scan 
stops at the path separator. On top of the HDDS-17241 patch it fails without 
the change ("expected: <1000> but was: <3000>"); with it, 
{{TestQuotaRepairTask}} and {{TestOMQuotaRepairRequest}} (22 tests) pass, 
{{TestOzoneRepairShell}} on a mini cluster passes with both snapshot scan 
patches applied, and checkstyle is clean. With the patch the reproduction's 
snapshot test fails because bucket B is repaired to 3000 and 1, and its control 
passes.

Found during review of a fix for the OM quota repair, as part of the TLA+ 
verification effort under HDDS-15926, on commit 
20d95ed37fe35013b5320713665db03c06ee36fa. Related to HDDS-17241, whose fix 
changes the same loop. 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
(v8.20.10#820010)

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

Reply via email to