yuqi1129 opened a new pull request, #13484:
URL: https://github.com/apache/gravitino/pull/13484

   ### What changes were proposed in this pull request?
   
   `fileset_meta` and `policy_meta` get an additive `occ_version` column. The 
CAS predicate and the unconditional increment move to it, and `current_version` 
goes back to meaning "the history version this row points at", advancing only 
when the fields `*_version_info` stores actually change.
   
   - **Schema:** the column in `schema-2.0.0-{mysql,postgresql,h2}.sql` and in 
the still-open `upgrade-1.3.0-to-2.0.0-*.sql`. `DEFAULT 1` is the whole 
backfill, because `occ_version` is only ever compared against itself on the 
same row: an upgraded row at `occ_version = 1` with `current_version = 7` is 
correct.
   - **Write path:** `updateFilesetPOWithVersion` and 
`buildNextPolicyPOVersion` always advance `occ_version`; when nothing stored 
changed they keep `current_version` / `last_version`, return no snapshot, and 
the services skip the version insert.
   - **SQL:** the CAS moves to `occ_version` in `updateFilesetMeta`, 
`updatePolicyMeta`, `softDeleteFilesetMetasByFilesetId` and 
`softDeletePolicyByIdAndVersion`. The fileset upsert advances `occ_version` 
instead of `current_version`.
   - **Read path: no query changes.** `current_version` moves only in the 
statement that inserts the snapshot it moves to, so a live row still points at 
exactly one active snapshot.
   
   One subtlety worth pointing at during review: `updateFilesetMeta`'s `NOT 
EXISTS` snapshot check is appended **only** when the alter allocates a version. 
An alter that allocates none keeps `current_version` where it is, and the 
snapshot it points at is supposed to exist, so the check would otherwise reject 
every such alter.
   
   ### Why are the changes needed?
   
   `current_version` was doing two jobs at once: it is the join key into 
`*_version_info`, and it was the value the CAS compared. Once OCC made the 
token advance on every alter (#12656, #12782), an audit-only or rename-only 
alter had to write a full snapshot just to keep the join resolvable — for a 
fileset that is one row per storage location — and the retention job removed 
them again. The history table recorded revisions that revised nothing.
   
   Fix: #12206
   
   **Scope note:** #12206's body is largely stale against `main`. The full-row 
comparisons it describes are gone (#12656 for fileset, #12782 for policy), and 
the `model_meta` insert it calls out already lists `current_version` / 
`last_version` (`ModelMetaBaseSQLProvider.java:36`, `:49`). What remained is 
the coupling named in the title. `table` / `view` / `function` share it and are 
left to a follow-up: their `current_version` has many more callers.
   
   ### Does this PR introduce _any_ user-facing change?
   
   No. Neither fileset nor policy version history is reachable through any 
public API — `FilesetVersionMapper` and `PolicyVersionMapper` are used only by 
the `current_version` join and the retention job, and `grep 
getCurrentVersion()` outside `storage/relational` has no hits, so nothing 
depends on it increasing monotonically. No API, configuration or read-path 
change.
   
   One benign behavioural consequence: because metadata-only alters no longer 
consume version numbers, retention evicts genuine content history more slowly 
than before.
   
   ### How was this patch tested?
   
   `TestFilesetMetaService` 60, `TestPolicyMetaService` 60, `TestPOConverters` 
41, `TestFilesetMetaBaseSQLProvider` 5, `TestFilesetMetaPostgreSQLProvider` 2 — 
168 tests, 0 failures. `-Werror` compile clean.
   
   New tests:
   
   - `testAlterWritesASnapshotOnlyWhenStoredContentChanges` — a fileset with 
two storage locations: a rename leaves `fileset_version_info` at 2 rows and 1 
distinct version while `occ_version` advances; a comment change takes it to 4 
rows and 2 versions; the fileset still reads back correctly. Added a 
`countFilesetVersionRows` helper, because the row count rather than the version 
count is what a snapshot costs.
   - `testDeleteRejectsAStaleVersionAfterAMetadataOnlyAlter` — pins the 
regression this decoupling creates. An audit-only alter no longer moves 
`current_version`, so a drop still guarded by it would stop detecting one and 
would delete a fileset the caller never observed in its current state. 
Mutation-checked: with the delete CAS on `current_version` it fails with 
`Expected OptimisticLockException to be thrown, but nothing was thrown`.
   - `testUpdateDropsTheSnapshotCheckWhenNoVersionIsAllocated` — pins the 
conditional `NOT EXISTS`.
   
   The `filesetSnapshotUnchanged` branch is mutation-checked too: disabling it 
makes `testUpdateFilesetPOVersion` fail (`expected: <1> but was: <2>`).
   
   Two existing tests were rewritten because they asserted the behaviour this 
PR reverses: `testMetadataOnlyPolicyAlterCreatesCompleteSnapshot` → 
`...AdvancesOnlyTheOccVersion`, and the tail of 
`testAlterReportsOptimisticLockConflictAndKeepsWinnerVersion`.
   
   **Not covered — evidence gaps, stated rather than implied:**
   
   - MySQL and PostgreSQL are exercised through their dialect SQL against H2, 
not against real engines. `occ_version INT UNSIGNED` (MySQL/H2) vs `INT` 
(PostgreSQL), and PostgreSQL's `ON CONFLICT ... DO UPDATE SET occ_version = 
fileset_meta.occ_version + 1`, have only SQL-text assertions behind them. 
`-PdockerTest=true` or CI is needed.
   - The legacy `maxStoredVersion` retry has converter-level coverage only 
(`TestPOConverters`), no DB-level test. That was already the case before this 
PR.
   - `insertFilesetMetaOnDuplicateKeyUpdate` has no production caller (the 
fileset overwrite path goes through `updateFilesetMeta`), so its change is 
covered by SQL-text tests only.
   


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

Reply via email to