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

   ### What changes were proposed in this pull request?
   
   Schema cascade delete can race with concurrent child metadata writes and 
leave active orphan rows in version tables. This change ensures every child 
update transaction acquires the parent schema shared lock 
(`lockSchemaForEntityWrite`) as its first operation, so a cascade delete cannot 
interleave with an in-flight child write.
   
   Changes:
   - **TableMetaService.updateTable**: Always lock the parent schema row 
unconditionally (previously only locked when `isSchemaChanged=true`). For 
cross-schema moves, lock both source and destination schemas in a consistent 
order (by schemaId) to prevent deadlocks.
   - **FunctionMetaService.updateFunction**: Same pattern — unconditional 
schema lock for same-schema updates, dual-lock for cross-schema moves.
   - **ViewMetaService.updateView**: Same pattern.
   - **FilesetMetaService.updateFileset**: Add schema lock (previously had 
none). Inline the old `tryUpdateFileset` helper into `doMultipleWithCommit` 
with lock as the first step, and deduplicate `retryFilesetPO` construction (was 
built twice; now built once and shared by both lambdas).
   - **TopicMetaService.updateTopic**: Add schema lock (previously had none).
   - **ModelMetaService.updateModel**: Add schema lock (previously had none; 
only `insertModel` had it).
   
   New tests in `TestSchemaMetaService`:
   1. `testSchemaChildUpdateServicesWaitForConcurrentSchemaDelete` — runs 
cascade delete concurrently with each child type's update (table, view, 
fileset, function, model, topic) and asserts the schema and child entity are 
gone afterward.
   2. `testCascadeDeleteLeavesNoOrphanVersionRows` — runs cascade delete 
concurrently with table update, asserts no active `table_version_info` rows 
whose parent `table_meta` is deleted (skipped on H2 which lacks `FOR SHARE`; 
enforced on MySQL/PostgreSQL).
   
   ### Why are the changes needed?
   
   The insert paths (`insertTable`, `insertFunction`, `insertView`, etc.) 
already acquire a shared lock on the parent schema row before writing. However, 
the corresponding update paths did not consistently do so:
   
   - `updateTable`/`updateFunction`/`updateView`: only locked the schema when 
the entity moved to a different schema (`isSchemaChanged=true`); same-schema 
updates skipped the lock entirely.
   - `updateFileset`/`updateTopic`/`updateModel`: had no schema lock at all.
   
   As a result, a schema cascade delete could commit while an overlapping 
writer left an active row in a child or version table whose schema or parent 
entity had already been deleted (orphan row).
   
   Fix: #12406
   
   ### Does this PR introduce _any_ user-facing change?
   
   No. The fix is an internal concurrency-safety improvement to the relational 
storage layer. No public API, REST endpoint, or behavior contract changes.
   
   ### How was this patch tested?
   
   - `./gradlew :core:spotlessApply :core:compileJava :core:compileTestJava 
-PskipWeb=true`
   - `./gradlew :core:test --tests 
"org.apache.gravitino.storage.relational.service.TestSchemaMetaService" --tests 
"org.apache.gravitino.storage.relational.service.TestModelMetaService" --tests 
"org.apache.gravitino.storage.relational.service.TestFilesetMetaService" 
-PskipWeb=true -PskipDockerTests=true`
   
   All existing and new tests pass on H2. The no-orphan-row assertion in 
`testCascadeDeleteLeavesNoOrphanVersionRows` is gated to non-H2 backends 
because H2 lacks `FOR SHARE` (falls back to `FOR UPDATE`); MySQL and PostgreSQL 
coverage depends on CI with `dockerTest=true`.
   
   <!--
   1. Title: [#<issue>] <type>(<scope>): <subject>
      Examples:
        - "[#123] feat(operator): Support xxx"
        - "[#233] fix: Check null before access result in xxx"
        - "[MINOR] refactor: Fix typo in variable name"
        - "[MINOR] docs: Fix typo in README"
        - "[#255] test: Fix flaky test NameOfTheTest"
      Reference: https://www.conventionalcommits.org/en/v1.0.0/
   2. If the PR is unfinished, please mark this PR as draft.
   -->
   


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