Repository navigation
[fix](fe) Load FE images that carry Lance catalogs written by 4.1.4+ - #69575
morningman wants to merge 2 commits into
Conversation
### What problem does this PR solve? Issue Number: None Related PR: apache#65730, apache#68781 Problem Summary: branch-4.1 added the Lance catalog as fe-core classes in apache#65730, released in 4.1.4. 4.1.4, 4.1.4.1, 4.1.5 and branch-4.2 persist it in the image's datasource module under the GSON label LanceExternalCatalog (logType LANCE). master has no Lance classes and no compatible-subtype mapping for that label, so loading such an image fails with a JsonParseException and the FE does not start: a cluster with a Lance catalog cannot be upgraded to a master-based build. The upgrade fixtures on master were generated from 4.1.3, which predates Lance, so no test caught it. The only labels in the 4.1.4.1, 4.1.5 and 4.2.0-rc01 registries that master does not know are LanceExternalCatalog, LanceExternalDatabase and LanceExternalTable. The branch-4.x builds that carried the durable Lance index job framework (apache#67235, removed by apache#68781 before any release) also wrote edit-log op 500 (OP_LANCE_INDEX_JOB_UPSERT) and an image module named lanceIndexJobManager. master fails on both ("UNKNOWN Operation Type 500", "Unknown meta module"). Fix, following the other connectors migrated to plugins and apache#68781: - GsonUtils maps LanceExternalCatalog, LanceExternalDatabase and LanceExternalTable to PluginDrivenExternalCatalog, PluginDrivenExternalDatabase and PluginDrivenMvccExternalTable (LanceExternalTable implemented MvccTable). - InitCatalogLog.Type keeps LANCE, so the persisted logType still deserializes to itself. - op 500 is reserved as a tombstone: JournalEntity reads its Text-framed JSON and discards it, EditLog replays nothing; lanceIndexJobManager joins PersistMetaModules.DEPRECATED_MODULE_NAMES. Until a Lance connector plugin is installed, a migrated Lance catalog stays registered and fails only when used ("No ConnectorProvider found for plugin-driven catalog: <name>, type: lance"). Tests: golden fixtures emitted by 4.1.5-release bytecode under fe-core/src/test/resources/upgrade/415 (generator and PROVENANCE included), Legacy415LanceUpgradeTest and LanceGsonCompatReplayTest. ### Release note Fix: an FE upgraded from 4.1.4 or later (or 4.2) to this version loads an image that contains a Lance catalog. The catalog is kept but cannot be used until a Lance connector plugin is installed. ### Check List (For Author) - Test: Unit Test - Legacy415LanceUpgradeTest (9) and LanceGsonCompatReplayTest (4), with 17 related upgrade / GSON / journal suites: 127 tests pass - Behavior changed: Yes. An image with a Lance catalog loads instead of failing; a journal with op 500 and an image with the lanceIndexJobManager module are read instead of failing. - Does this need documentation: No Co-authored-by: kid <lucian1412@outlook.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
|
run buildall |
|
/review |
There was a problem hiding this comment.
Static review of PR #69575 at 7357266f189018a60ae86a39d5544df666390823: one low-priority finding in BDBJE inspection of retired op500 records. No verified P0/P1 findings or existing blocking comments. The inspected catalog migration, journal replay, and deprecated-image handling preserve forward metadata readability.
All 22 changed paths were reviewed. Both complete-scope reviewers and the separate risk reviewer completed the final unchanged-payload pass with NO_NEW_VALUABLE_FINDINGS. Review converged after 2 rounds; no unresolved candidate or uncovered changed file remains. No additional user focus was supplied.
| Required checkpoint | Conclusion |
|---|---|
| Goal and proving tests | Legacy Lance aliases restore catalog loading, preserve configuration, and defer missing-plugin failure to access. New 4.1.5 image/CREATE fixtures and focused unit-test source cover this contract. |
| Scope and reuse | Six production files use existing compatibility patterns; shared fixture helpers retain the 4.1.3 APIs and defaults. Generated-file license exemptions are narrow. |
| Concurrency and locks | No new threads, shared runtime state, locks, or lock-order changes. Existing synchronized initialization guards lazy provider creation; test manager installation/teardown and fresh JVMs isolate registry state. |
| Lifecycle and static initialization | Deserialization resets runtime flags without creating connector/JNI resources. Canonical GSON types precede read aliases; type backfill occurs before logType normalization. No new static dependency cycle. |
| Configuration | No configuration items added or changed. |
| Format and version compatibility | Legacy class/enum names remain readable, canonical write labels are unchanged, and historical op500 framing and image checksum behavior match the new readers. Runtime rolling-upgrade or downgrade behavior was not executed. |
| Thrift/protobuf IDs | No generated protocol definitions changed. |
| Parallel functional paths | Image and CREATE replay checked independently, including absent/present providers; cloud shares the external aliases. PluginDriven database rebuilding forces PLUGIN and preserves MVCC table routing. BDB and local journal cursors checked. |
| Special conditions and failures | Explicit tombstones intentionally discard retired state; malformed Text frames still fail. The missing base LANCE builder case is unreachable after the PluginDriven override. |
| Functional, negative, and unit coverage | Inspected tests cover subtype identity, property/state retention, missing-plugin diagnostics, provider handoff, CREATE replay, adjacent-record EOF, and module deprecation. The debug-consumer case in the inline finding is uncovered. |
| Changed expected results | No regression .out changes. Read-only checks verified exact binary framing/EOF, provenance hash, JSON equality, journal index completeness, and the three Lance-only label additions. |
| Observability | Missing-provider errors identify catalog/type. The inline P3 identifies a null payload that breaks journal inspection; no additional critical metrics path was introduced. |
| Persistence and failover | Both read and replay cases exist for the retired opcode; old image modules are skipped without changing the historical checksum. No current producer or durable metadata transition was added. |
| Data writes, atomicity, and crashes | No transaction/data-write algorithm changed. Committed-data visibility, visible-version, delete-bitmap, and BE memory-accounting paths are unaffected. |
| FE/BE variable propagation | No transmitted field or variable added. |
| Performance | Bounded registry additions and one Text-frame read on historical replay; no added hot-path scan, retained native resource, or redundant production copy. |
| Other issues and final sweep | Rechecked real historical constructors, inherited state, no-provider startup, cloud paths, opcode reservation, nonempty/last module skipping, helper callers, and all journal data consumers. Only the reported P3 remains. |
Validation was static inspection and read-only fixture-data analysis. No builds, unit/regression tests, fixture regeneration, cluster startup, or actual Lance connector execution were performed. Full-image skip behavior was checked against the historical writer and current offset/checksum logic, rather than executed. A future Lance plugin's query semantics are outside this compatibility patch.
Review converged after 2 round(s).
| } | ||
| case OperationType.OP_LANCE_INDEX_JOB_UPSERT: { | ||
| // Text-framed JSON of the removed branch-4.x Lance index job framework; consumed and ignored. | ||
| Text.readString(in); |
There was a problem hiding this comment.
[P3] Retain a printable payload for the retired journal record
When an operator enables enable_bdbje_debug_mode and inspects a historical op500 entry with SHOW PROC '/bdbje/<db>/<journalId>', this branch succeeds but leaves JournalEntity.data null. BDBDebugger.getJournalEntity() consequently returns a non-null entity, and BdbjeJournalDataProcNode.fetchResult() calls entity.entity.getData().toString(), so the inspection fails with NullPointerException. Retain the consumed JSON in an inert Text payload, or make the debug consumer handle tombstone payloads; replay can still ignore the record.
There was a problem hiding this comment.
Confirmed, and fixed in b0e09ae835e in the debug reader rather than in the tombstone. BdbjeJournalDataProcNode called getData().toString() without a null check, and master already has twelve retired operation types whose records are read without keeping a payload: the four PL/SQL ones that #58700 turned into Text.readString(in) (the form this PR copies for op 500, as branch-4.1/4.2 do) and eight external-catalog ones (329, 350–356) whose reader keeps no payload either. SHOW PROC '/bdbje/<db>/<journalId>' on any of those records already failed the same way. BDBTool, the other BDBJE inspection path, prints a missing payload as null; the proc node now does the same through String.valueOf, so op 500 and the existing tombstones are all printable, and the op 500 tombstone stays identical to #58700's and branch-4.x's. BdbjeJournalDataProcNodeTest reads an op 500 record and a retired PL/SQL record in their written form and checks the rows, and a live OP_SAVE_NEXTID record still shows its payload.
For scale: op 500 only exists in journals of unreleased branch-4.1/4.2 builds from between #67630 and #68781 on which the off-by-default enable_lance_index_mutation was turned on, and only until a checkpoint deletes those journals. The failure was limited to that one debug-mode statement; replay and checkpointing never read the payload. branch-4.1/4.2 have the same proc node and the same op 500 tombstone.
TPC-H: Total hot run time: 28051 ms |
TPC-DS: Total hot run time: 150692 ms |
ClickBench: Total hot run time: 25.26 s |
FE UT Coverage ReportIncrement line coverage |
FE Regression Coverage ReportIncrement line coverage |
…ebug view ### What problem does this PR solve? Issue Number: None Related PR: apache#69575 Problem Summary: In BDBJE debug mode (enable_bdbje_debug_mode), SHOW PROC '/bdbje/<db>/<journalId>' renders a record through BdbjeJournalDataProcNode, which called getData().toString() without a null check. The readers of retired operation types consume the payload without keeping it, so their data is null: the op 500 tombstone added by this PR, the four PL/SQL operation types retired by apache#58700 (the same Text.readString(in) form) and the payload-less external-catalog operation types. Viewing any of those records failed with a NullPointerException. For op 500 this is a regression of this PR: before it the record failed to read and the row showed "Not Found". BDBTool, the other BDBJE inspection path, already prints a missing payload as null. The proc node now prints the payload with String.valueOf, so such a record shows null as its data. The op 500 tombstone stays the same as apache#58700's and branch-4.x's. Replay and checkpointing never read these payloads and are unaffected. ### Release note None ### Check List (For Author) - Test: Unit Test - BdbjeJournalDataProcNodeTest: an op 500 record and a retired PL/SQL record, in their written form, show their journal ID, operation name, size and null data; a live OP_SAVE_NEXTID record still shows its payload - Legacy415LanceUpgradeTest, BDBDebuggerTest - Behavior changed: No (the debug view no longer fails on these records) - Does this need documentation: No Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Addressed the first review round in
New |
|
run buildall |
|
/review |
There was a problem hiding this comment.
Static review of all 24 changed paths at b0e09ae found no new actionable defects. The two complete-review agents and the independent risk reviewer each returned NO_NEW_VALUABLE_FINDINGS in round 1; both initial risk focuses were resolved with source evidence.
Existing P3 4367233851 is fixed: String.valueOf renders retired records without a payload safely, with tests retaining live-record display. It was not reposted. No supplied existing P0/P1 finding remains to carry forward. No additional user focus was supplied.
| Critical checkpoint | Conclusion |
|---|---|
| Goal and proving tests | Legacy Lance catalog labels now deserialize into plugin catalogs, preserving configuration and deferring a missing-provider error until access. Golden 4.1.5 fixtures and targeted JUnit cases cover image loading, replay, properties, aliases and debug display; inspected statically. |
| Scope and reuse | Small production changes reuse existing compatible-subtype, retired-opcode and deprecated-module mechanisms. Fixture readers share the existing release-root helpers. |
| Concurrency and locking | No new threads, lock acquisition/order or shared runtime mutation. Fresh journal entities and existing synchronized catalog initialization retain ownership guarantees. |
| Lifecycle and static initialization | Postprocessing resets initialized/objectCreated before lazy connector creation, including previously initialized images. Canonical plugin write labels remain unchanged; no new initialization cycle or resource lifetime is introduced. |
| Configuration | No configuration added or changed. |
| Format and upgrade compatibility | Historical op500 writers use the exact Text frame now consumed. Retired module load/save leave the checksum unchanged, so offset-based skipping preserves following modules and footer validation. No new persisted format is emitted by these compatibility additions. Runtime rolling upgrades were not exercised. |
| Thrift and protobuf IDs | Neither directory changes. |
| Parallel paths | Image and create-catalog replay, catalog/database/MVCC-table aliases, both journal cursors, both debug readers, and cloud/shared-nothing module placement were traced. |
| Conditional checks | Null-payload rendering matches the existing BDBTool behavior. Legacy initialization and empty/nonempty/final module cases have concrete, supported paths. |
| Test coverage | Covers S3/local/REST properties, identity/comment/time/auto-analyze state, absent and recording providers, exact target classes, op500 followed by a real record, no-op replay, module registration, and live/retired debug rows. A full nonempty historical image is not exercised by the added membership test; its offset/checksum contract was verified against the historical writer. |
| Test results and fixtures | No execution results are claimed. Binary frame lengths, opcode values, JSON payload identity, provenance hash, indexes and label inventories agree; the 4.1.3 helper roots remain intact. No regression result files are added. |
| Observability | Existing migration logs, skipped-module warnings, catalog-name/type errors and journal operation/size display cover these paths. |
| Persistence and failover | Catalog image and replay retain the persisted state; op500 is fully consumed and inert while replay advances normally. Checkpoints omit the retired module and use canonical plugin labels. No transaction persistence mode changes. |
| Data writes and crash atomicity | No data write or transaction mutation is added. Transaction visibility, partition visible versions and delete-bitmap invariants are unaffected; no BE allocation or memory-tracking change. |
| FE/BE variable propagation | No transmitted variable or send path changes. |
| Performance | Fixed registry additions and one retired-record dispatch introduce no material query hot-path work. No redundant scan or remote operation found. |
| Other issues and final recheck | Historical persistence boundaries exclude cached Lance database/table graphs; MVCC aliases and unknown legacy table-type normalization are consistent. No unresolved candidate or uncovered changed path remains. |
Review converged in one round. Validation was static only: no builds, tests, FE startup, fixture regeneration, live Lance connector queries or mixed-version deployment were run.
Review converged after 1 round(s).
TPC-H: Total hot run time: 28431 ms |
TPC-DS: Total hot run time: 150631 ms |
ClickBench: Total hot run time: 25.01 s |
FE Regression Coverage ReportIncrement line coverage |
What problem does this PR solve?
Issue Number: None
Related PR: #65730, #68781
Original author: @u70b3 (the op 500 and image-module tombstones follow branch-4.1 #68781; the commit carries Co-authored-by)
Problem Summary:
In short. This PR makes master read the metadata that branch-4.1's Lance catalog (#65730, released in 4.1.4) and its since-removed index job framework (tombstoned by #68781) wrote: an FE image written by 4.1.4 or later with a Lance catalog in it now loads. Before this PR the image failed to parse, so a cluster with a Lance catalog could not be upgraded from any released 4.1.4 / 4.1.4.1 / 4.1.5 build (or from 4.2) to a master-based build: the FE did not start. The Lance catalog's GSON labels are mapped to the plugin-driven classes, as the Iceberg, Paimon and LakeSoul labels already are, and the catalog stays registered, unusable until a Lance connector plugin is installed. The two pieces of metadata that only unreleased branch-4.x builds wrote (the Lance index job edit-log record and image module) are kept readable as tombstones, as branch-4.1 #68781 does.
Background. branch-4.1 added a Lance catalog as fe-core classes in #65730 (released in 4.1.4). Like every external catalog, it is persisted in the image's
datasourcemodule as GSON JSON whoseclazzfield names the class,LanceExternalCatalog, withlogTypeLANCE. master has no Lance classes: external catalogs are served by connector plugins, and the labels of the catalogs that used to be fe-core classes are redirected toPluginDrivenExternalCatalog/PluginDrivenExternalDatabase/PluginDrivenMvccExternalTablebyregisterCompatibleSubtypeinGsonUtils. A Lance connector plugin does not exist on master yet; it will be ported later.branch-4.1 also had, for a while, a durable Lance index job framework (#67235) that wrote edit-log op 500 (
OP_LANCE_INDEX_JOB_UPSERT) and an image module namedlanceIndexJobManager. #68781 removed it before any release. 4.1.5 and branch-4.2 keep op 500 as a tombstone that is read and discarded, and list the module as deprecated, so the journals and images of the builds in between stay readable.The upgrade fixtures on master (
upgrade/413) were generated from 4.1.3, before Lance existed, so no test caught this.The problem, and what it cost. Compared on master against fixtures emitted by real 4.1.5 bytecode:
datasourcemodule has a Lance catalog (every 4.1.4+ cluster with one)cannot deserialize interface org.apache.doris.datasource.CatalogIf subtype named LanceExternalCatalog; did you forget to register a subtype?; the FE cannot startPluginDrivenExternalCatalogof typelancewith all its properties, comment and auto-analyze policies; using it fails withNo ConnectorProvider found for plugin-driven catalog: <name>, type: lance. Ensure the connector plugin is installed.OP_CREATE_CATALOGof a Lance catalogUNKNOWN Operation Type 500lanceIndexJobManager(only from unreleased branch-4.x builds)Unknown meta module: lanceIndexJobManagerunlessignore_unknown_metadata_module = trueThe only labels in the GSON registries of 4.1.4.1, 4.1.5 and 4.2.0-rc01 that master does not know are
LanceExternalCatalog,LanceExternalDatabaseandLanceExternalTable.How this PR fixes it.
GsonUtils:LanceExternalCatalog→PluginDrivenExternalCatalog,LanceExternalDatabase→PluginDrivenExternalDatabase,LanceExternalTable→PluginDrivenMvccExternalTable(LanceExternalTableimplementedMvccTable). 4.1.x never persists an external database or table, so only the catalog label can actually appear; the other two complete the registry, as for the other migrated connectors.InitCatalogLog.TypekeepsLANCE, so thelogType4.1.4+ wrote still deserializes to itself. Nothing depends on it: a Lance catalog always persists itstypeproperty (no resource type creates one), andPluginDrivenExternalCatalog#gsonPostProcessrewrites the logType toPLUGIN.OperationType.OP_LANCE_INDEX_JOB_UPSERT = 500is reserved:JournalEntityreads its Text-framed JSON and discards it,EditLogreplays nothing.lanceIndexJobManagerjoinsPersistMetaModules.DEPRECATED_MODULE_NAMES. Both follow branch-4.1 branch-4.1: [refactor](lance) Remove the durable Lance index job framework (#66497) #68781.BdbjeJournalDataProcNode, which rendersSHOW PROC '/bdbje/<db>/<journalId>'in BDBJE debug mode, prints a record read without a payload asnull, asBDBToolalready does, instead of failing with aNullPointerException. This covers op 500 and the retired operation types already on master: the PL/SQL ones of [clean](plsql) remove plsql #58700 and the external-catalog ones whose reader keeps no payload.Until a Lance connector plugin is installed, an upgraded cluster lists its Lance catalogs and fails only when one is used; installing the plugin makes them work without any metadata change, since the catalog properties are handed to the connector unchanged.
Results.
fe/fe-core/src/test/resources/upgrade/415/, emitted by 4.1.5-release bytecode likeupgrade/413(generator andPROVENANCE.txtincluded, byte-deterministic): thedatasourcemodule with three Lance catalogs (filesystem on S3, filesystem onfile://, REST with bearer auth), theirOP_CREATE_CATALOGentries, and 4.1.5's label registries.Legacy415LanceUpgradeTest(9 tests): the image loads and every Lance catalog becomes aPluginDrivenExternalCatalogof typelancewith thePLUGINlogType; every persisted property, the comment,lastUpdateTimeand the auto-analyze policy survive; the persisted logType names still deserialize; without a plugin the catalog fails only when used, with the message above; a provider claiminglancereceives exactly the persisted properties, from the image and from the journal; the journal entries replay with and without a plugin; an op 500 record followed by a real 4.1.5 entry is consumed exactly, and replaying it needs noEnv;lanceIndexJobManagerstays deprecated.LanceGsonCompatReplayTest(4 tests): the three labels replay as the expected classes (the table as the MVCC variant), and they are the only labels 4.1.5 registered beyond 4.1.3.LANCE, theJournalEntitycase (UNKNOWN Operation Type 500), theEditLogcase (the replay ends inSystem.exit(-1), as on a real FE) or the deprecated-module entry.BdbjeJournalDataProcNodeTest(2 tests): an op 500 record and a retired PL/SQL record, in their written form, show their journal ID, operation name, size andnulldata in the debug view; a liveOP_SAVE_NEXTIDrecord still shows its payload. WithgetData().toString()back, the first test fails with aNullPointerException.Legacy413*,*GsonCompat*,CatalogMgrTest,ExternalCatalogTest,ConstraintPersistTest,BDBJEJournalTest, ...) pass; fe-core checkstyle passes. After the review fix,BdbjeJournalDataProcNodeTest,Legacy415LanceUpgradeTestandBDBDebuggerTest(12 tests) pass.Release note
Fix: an FE upgraded from 4.1.4 or later (or 4.2) to this version loads an image that contains a Lance catalog. The catalog is kept but cannot be used until a Lance connector plugin is installed.
Check List (For Author)
Test
Behavior changed:
An image with a Lance catalog loads instead of failing; journals with op 500 and images with the
lanceIndexJobManagermodule are read instead of failing. In BDBJE debug mode,SHOW PROC '/bdbje/<db>/<journalId>'shows a record kept without a payload (op 500, the retired PL/SQL and external-catalog operation types) withnulldata instead of failing.Does this need documentation?
Check List (For Reviewer who merge this PR)