Skip to content

[fix](external catalog) Handle incomplete table ownership [branch-4.0] - #66600

Draft
Gabriel39 wants to merge 2 commits into
apache:branch-4.0from
Gabriel39:fix/external-table-database-reference-4.0
Draft

[fix](external catalog) Handle incomplete table ownership [branch-4.0]#66600
Gabriel39 wants to merge 2 commits into
apache:branch-4.0from
Gabriel39:fix/external-table-database-reference-4.0

Conversation

@Gabriel39

@Gabriel39 Gabriel39 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

This is the branch-4.0 backport of #66599.

Malformed external-table ownership metadata can cause optional materialized-view candidate collection to abort an otherwise valid query when BaseTableInfo is constructed.

Current image serialization does not persist external object caches. After an image round trip, lazy loading rebuilds tables with their catalog and database owners. The fix therefore keeps the recovery lifecycle unchanged and makes MTMV candidate collection skip only malformed table metadata.

Related issue: #58441

Test

  • Added an image round-trip and lazy-load test that verifies owner references are rebuilt before BaseTableInfo construction.
  • Added a unit test that verifies MTMV candidate collection does not fail a query when owner metadata is incomplete.
  • Ran ExternalDatabaseImageRestoreTest, ExternalEqualsTest, and CollectRelationTest: 3 tests passed, 0 failures.
  • FE Checkstyle passed as part of the FE unit-test build.

Release note

None.

Check List (For Author)

  • Test
    • Unit Test
  • Behavior changed
    • No.
  • Does this need documentation?
    • No.

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: this backport does not repair ownership on branch-4.0's actual recovery lifecycle.

Critical checkpoints:

  • Recovery/lifecycle: blocking. ExternalDatabase.registerTable is the HMS event-registration path, and its caller constructs a fresh table with the same catalog/database before entering it. Branch-4.0 image recovery instead rebuilds non-persistent external meta caches through buildDbForInit/buildTableForInit; it does not route a recovered table through these setters.
  • Publication, naming, and locking: verified for the HMS event path. The caller holds the database write lock and MetaCache.updateCache publishes the same already-owned object under the resolved local key.
  • MTMV fallback: the guard prevents BaseTableInfo from dereferencing a missing owner, but the review found no branch-4.0 production path that creates such an ownerless cached table. The conditional downstream concern was therefore dismissed rather than reported separately.
  • Compatibility/tests: the mixed test frameworks match module conventions and CheckStyle is green. FE UT and compile are still pending. No local build was run because this review runner forbids builds. The added tests manufacture the state and do not exercise checkpoint/follower recovery.
  • User focus: no additional focus was supplied; the complete four-file diff was reviewed.

Review converged after two complete rounds, including separate risk-focused scans. One inline blocking issue remains; all other candidates were verified, deduplicated, or dismissed with evidence.

String tableName = tableIf.getName();
T table = (T) tableIf;
// Replayed metadata may lose these non-persistent owner references, so restore them before publication.
table.setCatalog(extCatalog);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

registerTable is not the checkpoint/cache-recovery boundary described by this PR. Its only production external caller, CatalogMgr.registerExternalTableFromEvent, first calls buildTableForInit(..., hmsCatalog, db, false), whose constructor has already installed these exact owners (and nameMapping), so these assignments are no-ops there. Branch-4.0 recovery deliberately no longer persists external database/table maps: the external meta caches are rebuilt lazily through buildDbForInit/buildTableForInit, and no recovered table is routed through this method. A standalone deserialized ExternalTable would also have a null non-persistent nameMapping, which these two setters do not restore. Please put complete invariant reconstruction on the real recovery/cache-load path (and test that path), or demonstrate the production recovery caller that reaches this method; the current test only clears fields manually and invokes an event-only path.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 90.00% (9/10) 🎉
Increment coverage report
Complete coverage report

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: the defensive MTMV fallback is incomplete for the newly handled null-catalog state; see the inline issue.

Critical checkpoints:

  • Planner correctness/fallback: blocking. collectMTMVCandidates returns for a non-null database with a null catalog, but the same installed query/DML materialization hook later unconditionally collects partitions and dereferences that catalog through StatementContext.getTableId / TableIf.getFullQualifiers. A surviving scan can therefore still abort instead of using the original plan.
  • Recovery/lifecycle: verified. Branch-4.0 images omit external database/table meta caches, and lazy buildDbForInit / buildTableForInit reconstruct catalog, database, and name-mapping ownership. No production image, replay, cache reload, or event path was found that publishes a partially owned table. The superseded registerTable concern is absent from the current diff and was not duplicated.
  • State, locking, and concurrency: the null-database return occurs before candidate or related-table mutation; the original query table remains in normal statement state, and MTMV locks are released in finally. No distinct state or lock issue survived review.
  • Compatibility/tests: the image round trip meaningfully proves fresh lazy-loaded owner reconstruction, and the reflection test covers the null-database branch. It does not exercise the full post-rewrite hook or the null-catalog arm, which is why the blocking downstream failure is missed. CheckStyle is green; FE UT and compile are still pending. No local build was run because this review runner forbids builds.
  • Configuration, observability, and performance: no protocol/configuration change or material performance regression was found; the warning is limited to malformed metadata with an MV hook.
  • User focus: no additional focus was supplied; the complete three-file diff was reviewed.

Review converged after two complete rounds, including separate risk-focused scans. One distinct inline blocking issue remains; every other candidate was verified, deduplicated, or dismissed with code evidence.

if (shouldCollect) {
DatabaseIf database = table.getDatabase();
// MTMV rewrite is optional, so malformed ownership metadata must not abort the query.
if (database == null || database.getCatalog() == null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The database.getCatalog() == null arm does not actually provide the promised fallback. With the MV hook installed, InitMaterializationContextHook.afterRewrite() later runs QueryPartitionCollector; that visitor only skips a null database and then calls StatementContext.getTableId(table), which keys through table.getFullQualifiers() and dereferences database.getCatalog().getName(). A table handled by this new arm can therefore still abort the query during post-rewrite partition collection (the DML hook inherits the same path). Please make the downstream MV-hook work skip incomplete catalog ownership too, and cover this with a full planner regression using a non-null database whose catalog is null.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 20.00% (1/5) 🎉
Increment coverage report
Complete coverage report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants