Skip to content

[Tracking][Catalog] Catalog SPI migration — decouple built-in connectors from FE core into loadable plugins #65185

Description

@morningman

Development branch: branch-catalog-spi — all migration PRs target this branch; it merges to master through #64304.

Background

Today Apache Doris FE hard-codes every external data source (hive, iceberg, paimon,
hudi, trino-connector, maxcompute, jdbc, es, …) inside fe/fe-core/.../datasource/,
wired into the catalog and planner layers through switch-case and
instanceof *ExternalTable checks. Adding or changing a connector means touching FE
core.

This tracking issue covers the effort to decouple each concrete connector into an
independent, loadable plugin module under fe/fe-connector/*
, leaving only generic
infrastructure and a stable catalog SPI bridge in fe-core.

End state: each connector ships as a self-contained plugin zip; fe-core has no
compile-time knowledge of any specific connector; the runtime discovers and loads
connectors through the catalog SPI (PluginDrivenExternalCatalog / …Table /
…ScanNode).

In scope: FE-side connector code under
datasource/{hive,iceberg,paimon,hudi,trinoconnector,maxcompute,jdbc,es,…}, plus the
reverse couplings (instanceof *ExternalTable, connector-specific sinks / scan-nodes)
scattered across nereids / planner / tablefunction / alter.

Out of scope: BE-side readers; fe-fs-spi file-system plugin work (separate
workstream); extension-spi; kafka / kinesis / odbc / Doris-to-Doris federation
(tracked separately). RemoteDoris stays an engine built-in catalog type; the
deprecated lakesoul type was removed rather than migrated (#65736).

Where the framework is documented

Prose docs now live in the tree and are the authoritative reference (they replaced the
branch's plan-doc/ corpus in #66251):

  • fe/fe-connector/README.md — architecture, module map, how a connector runs
    (startup / CREATE CATALOG routing / per-statement metadata / classloading /
    packaging), how to read the API, and a step-by-step "adding a new connector" guide.
  • fe/fe-connector/AGENTS.md — build & test recipes, the machine-checked obligations,
    and the invariants that no gate can express.

Design invariants (acceptance criteria)

These invariants must hold at every step:

  1. One-way dependency fe-connector → fe-core. No connector module may
    import org.apache.doris.{catalog,common,datasource,qe,analysis,nereids,planner}.
    Enforced in the validate phase by build-support/check-fe-connector-imports.sh
    (self-test under build-support/tests/).
  2. Single metadata entry point. Inside fe-core, only PluginDrivenMetadata may
    call Connector#getMetadata; exempt call sites carry an explicit marker and
    deleting a marker auto-tightens the gate. Enforced by
    build-support/check-fe-core-metadata-funnel.sh ([perf](catalog) fe-connector-iceberg hot-path caching + fe-core per-statement metadata funnel, with session=user cache isolation #65785).
  3. Metadata backward compatibility. Old FE images holding GSON types such as
    IcebergExternalCatalog / PaimonExternalDatabase must deserialize and migrate
    transparently to PluginDrivenExternalCatalog. Verified by a unit-test suite whose
    fixtures are generated from real 4.1.3 bytecode ([test](catalog) verify 4.1.3 catalogs survive the connector-SPI cutover, with fixtures generated by real 4.1.3 bytecode #66214).
  4. No user-visible behavior regression. SHOW CREATE CATALOG, SHOW TABLE STATUS,
    information_schema.tables, EXPLAIN output, error messages, and catalog type /
    engine names are all preserved.

Progress — phases

Each phase lands as one or more PRs against branch-catalog-spi.

Supporting refactor & post-migration hardening (landed alongside / after the phases above):

Connector status

Connector Target module Status Landed in
jdbc fe-connector-jdbc ✅ Done (SPI baseline / reference) pre-existing
es fe-connector-es ✅ Done (SPI baseline / reference) pre-existing
trino-connector fe-connector-trino ✅ Done P2 (#64096)
maxcompute fe-connector-maxcompute ✅ Done P4 (#64253, #64256)
paimon fe-connector-paimon ✅ Done P5 (#64446, #64653)
hudi fe-connector-hudi ✅ Done P3 (#64143), P7 (#65473)
iceberg fe-connector-iceberg ✅ Done P6 (#64688)
hive (+HMS) fe-connector-hive / fe-connector-hms ✅ Done P7 (#65473)

Shared modules added for them (see the README's module map): fe-connector-metastore-api
/ -spi / -hms / -iceberg / -paimon (so a connector never hand-parses metastore
endpoint properties), fe-connector-cache, fe-connector-hms-hive-shade,
fe-connector-paimon-hive-shade, plus fe-kerberos and fe-trino-connector-common
outside this directory.

Upstream re-ports

The branch is rebased onto master continuously, and every upstream change to an
already-migrated datasource is re-ported onto the SPI rather than merged textually
(a textual merge would silently resurrect fe-core-side code paths that no longer run).
Re-ported so far: #63068, #64966, #65094, #65262, #65329, #65332, #65365, #65548,
#65676, #65782, #65784, #65834, #65870, #65904, #65955, #65984, #65991, #66004, #66008,
#66112.

User-visible changes at merge time

  • External catalogs are served by connector plugins, shipped as zips under
    fe/plugins/connector/ (Config.connector_plugin_root). Existing catalogs keep
    working across upgrade; no DDL change is required.
  • trino_connector_plugin_dir default moves from plugins/connectors to
    plugins/trino_plugins; the old directory is still read as a fallback.
  • The deprecated lakesoul catalog type is removed — creating or replaying one fails
    with Lakesoul catalog is no longer supported.

Remaining before #64304 can merge


This is an umbrella tracking issue; individual PRs reference it for detailed
per-phase design and review.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions