peterxcli commented on code in PR #11141:
URL: https://github.com/apache/ozone/pull/11141#discussion_r3879715772
##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java:
##########
@@ -1174,6 +1175,27 @@ protected String getDBMultipartOpenKey(String
volumeName, String bucketName,
.getMultipartKey(volumeName, bucketName, keyName, uploadID);
}
+ /**
+ * Resolves the start of the MVCC visibility interval for the key version
being committed.
+ *
+ * <p>hsync commits the same objectID repeatedly while appending blocks, and
an MPU overwrite
+ * reuses the existing key's objectID. The interval start must stay at the
transaction where the
+ * objectID first became visible in the key table, otherwise a snapshot
taken between two commits
+ * would fall outside the interval and its blocks could be reclaimed.
Returns null before the
+ * layout feature is finalized, which leaves reclaimability on the
previous-snapshot lookup path.
+ */
+ protected static Long resolveSeqNumMin(OzoneManager ozoneManager, OmKeyInfo
keyToDelete,
+ OmKeyInfo committedKeyInfo, long trxnLogIndex) {
+ if
(!ozoneManager.getVersionManager().isAllowed(OMLayoutFeature.SNAPSHOT_RECLAIM_SEQ_NUM))
{
+ return null;
+ }
Review Comment:
Good catch — this is a real correctness bug, not just a rollout wrinkle.
Concretely:
1. Key committed at txn 100 with objectID 5 before finalization, so no
interval.
2. Snapshot S created at txn 150; `S.keyTable` holds that version.
3. Layout feature finalized.
4. Same objectID re-committed at txn 200 (hsync re-commit, or an MPU
overwrite, both of which
carry the key table objectID forward). Old code stamped `seqNumMin = 200`.
5. Version deleted at txn 300, giving interval `[200, 300)`.
6. Checked against S at 150: not inside the interval, so reclaimable — while
S still references
the blocks. The lookup path would have matched on objectID and kept them.
Fixed by returning `keyToDelete.getSeqNumMin()` whenever the objectID is
carried over, which
collapses both cases: preserve when it exists, and return null when it does
not, leaving the
version on the lookup path. `prepareKeyForDelete` then leaves `seqNumMax`
unset too, so nothing
downstream sees a partial interval. Self-healing: any version written under
a fresh objectID gets
a real interval.
Covered in `testSeqNumMinPreservedAcrossCommitsOfSameObjectId`.
##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/filter/ReclaimableKeyFilter.java:
##########
@@ -116,6 +134,50 @@ protected Boolean isReclaimable(Table.KeyValue<String,
OmKeyInfo> deletedKeyInfo
return false;
}
+ /**
+ * Decides reclaimability from the key version's MVCC visibility interval,
without reading any
+ * snapshot DB.
+ *
+ * <p>A snapshot sees this key version when
+ * {@code seqNumMin <= snapshotCreateTxnIndex < seqNumMax}. Only the
immediately previous snapshot
+ * in the chain has to be checked: {@link
OmSnapshotManager#createOmSnapshotCheckpoint} drains the
+ * bucket's deletedTable from the active DB as soon as a snapshot checkpoint
is taken, so every
+ * entry reachable here has {@code seqNumMax} greater than the previous
snapshot's create index.
+ * Any older snapshot inside the interval therefore implies the previous
snapshot is inside it
+ * too.
+ *
+ * @return {@code TRUE} when no snapshot can see this version, {@code FALSE}
when the previous
+ * snapshot can see it, and {@code null} when the interval metadata
is absent and the
+ * caller must fall back to previous snapshot lookups.
+ */
+ private Boolean isReclaimableByVisibilityInterval(OmKeyInfo deletedKeyInfo)
throws IOException {
+ Long seqNumMin = deletedKeyInfo.getSeqNumMin();
+ Long seqNumMax = deletedKeyInfo.getSeqNumMax();
+ if (!intervalOptimizationEnabled || seqNumMin == null || seqNumMax ==
null) {
+ return null;
+ }
+ SnapshotInfo previousSnapshotInfo = getPreviousSnapshotInfo(1);
+ if (previousSnapshotInfo == null) {
+ // No previous snapshot in the chain, so no snapshot can reference this
key version.
+ return true;
Review Comment:
Agreed, and worth doing — the whole "check only the previous snapshot"
argument rests on that
invariant, so it should be asserted rather than assumed.
`seqNumMax <= previousSnapshotCreateIndex` is exactly the signature of the
dangerous case: it means
the entry closed before the previous snapshot was created, which under the
drain-at-checkpoint
behaviour cannot happen, and which is precisely when an *older* snapshot
could sit inside the
interval unchecked. Old code answered "reclaimable" there without validation.
Added the guard, and with `seqNumMax > previousSnapshotCreateIndex` now
established the verdict
reduces to `seqNumMin > previousSnapshotCreateIndex`. A tripped guard is
observable: it returns
null, so the entry counts under the fallback metric.
Two tests moved as a result — the old `seqNumMax`-exclusive and
empty-interval cases both construct
intervals that close at or before the previous snapshot, so they are now
folded into
`testIntervalClosingBeforePreviousSnapshotFallsBackToSnapshotLookup`, which
asserts fallback.
##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/DeletingServiceMetrics.java:
##########
@@ -70,6 +70,15 @@ public final class DeletingServiceMetrics {
private MutableGaugeLong numKeysPurged;
@Metric("Total no. of rename entries purged")
private MutableGaugeLong numRenameEntriesPurged;
+ /*
+ * Reclaimability decision source metrics. Tracks how often a deleted key
version could be judged
+ * from its MVCC visibility interval versus how often the previous snapshot
had to be read.
+ */
+ @Metric("Total no. of deleted key versions judged reclaimable from their
visibility interval, "
+ + "with no previous snapshot read")
Review Comment:
Correct — the counter increments when the interval fast path declines, and
the lookup path can
still return without touching a snapshot DB (for example
`getPreviousSnapshotKeyInfo` returns early
when there is no previous key manager).
Reworded to describe the path rather than assert a read:
"Total no. of deleted key versions that fell back to the previous snapshot
lookup path".
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]