Skip to content

[fix](routineload) Persist the current load definition - #66634

Open
0AyanamiRei wants to merge 13 commits into
apache:masterfrom
0AyanamiRei:feature/routine-load-definition-persistence
Open

[fix](routineload) Persist the current load definition#66634
0AyanamiRei wants to merge 13 commits into
apache:masterfrom
0AyanamiRei:feature/routine-load-definition-persistence

Conversation

@0AyanamiRei

@0AyanamiRei 0AyanamiRei commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: N/A

Related PR: #64878

Problem Summary:

This is the persistence and recovery prerequisite for future Routine Load ALTER work. It does not add target-table ALTER syntax or behavior.

Routine Load historically persisted the original CREATE statement in origStmt and reparsed it whenever an image was loaded. That statement is immutable, while ALTER ROUTINE LOAD changes the effective load clauses kept in RoutineLoadJob. After an ALTER followed by checkpoint/restart, reparsing the stale CREATE statement could therefore restore the original definition instead of the definition currently used to create tasks.

There are two independent persistence paths that must retain the same effective state:

  • Image/checkpoint: persist the canonical runtime fields used by Routine Load tasks directly, including partitions, column mappings, preceding/where/delete filters, separators, sequence column, merge type, execution memory limit, and memtable_on_sink_node.
  • ALTER journal: persist a nullable RoutineLoadDesc delta in AlterRoutineLoadJobOperationLog, apply properties and the load-clause delta under the job write lock on the leader, and apply them in the same order during follower replay.

The final design deliberately does not introduce a LoadDefinition wrapper or duplicate job/data-source property snapshots:

  • Existing RoutineLoadJob fields remain the effective state and receive stable Gson keys.
  • jobProperties remains authoritative for properties whose runtime caches are rebuilt after deserialization.
  • New-format images restore direct state without creating a SQL context, accessing the catalog, or validating CREATE SQL.
  • origStmt remains persisted for downgrade readability and for one-time migration of legacy images.
  • An image without the newly persisted merge type is treated as legacy. The new FE reparses origStmt once, restores the load clauses and exec_mem_limit, and the next checkpoint naturally writes the direct-state format.
  • Legacy memtable_on_sink_node cannot be reconstructed and retains its historical post-restart value of false.

The ALTER log stores only the changed RoutineLoadDesc clauses. Nullable fields preserve clauses not modified by that ALTER. Old logs do not contain this field and therefore leave the current definition unchanged during replay.

CSV ALTER properties are validated only on the leader before mutation. Replay trusts persisted journal values so that validation added by a newer FE cannot prevent replay of a journal written by an older FE. The cached enclose, escape, and empty_field_as_null values are kept in sync with jobProperties.

Because Routine Load converts legacy expressions back to SQL before building each Nereids task, the persisted expression graph must retain every field that affects SQL generation. This PR adds stable serialization for the relevant MatchPredicate, SlotRef, and TimeV2Literal fields and verifies SQL-equivalent Gson round trips.

Compatibility boundary:

  • Old image -> new FE: supported through one-time origStmt migration. ALTER load clauses that were never recorded by the old image or old journal are not recoverable; the original CREATE semantics are restored.
  • New image/log -> old FE: unknown JSON fields are structurally ignorable and origStmt is still available, but semantic downgrade is not guaranteed. An old FE may restore the original CREATE clauses and ignore new ALTER deltas.
  • Avoid ALTERing Routine Load load clauses until every FE has been upgraded. During a mixed-version rolling upgrade, an old follower can ignore the new journal delta, while a new follower cannot reconstruct a delta omitted by an old leader.
  • A checkpoint written by the new FE can therefore lose post-upgrade ALTER semantics if the cluster is rolled back to an older FE.

Out of scope:

  • Target-table ALTER.
  • Failed-ALTER atomicity refactoring.
  • Pause/cancel reason persistence, automatic-recovery backoff, state-transition timestamps, and other unrelated Routine Load lifecycle issues.

Tests added:

  • Direct Kafka/Kinesis image round trips with complete load clauses, non-default task properties, durable data-source state, and invalid origStmt to prove new images do not fall back to SQL parsing.
  • Empty load-definition image recovery without origStmt parsing.
  • Fixed image and ALTER-log fixtures generated by the real serializer at merge base a8928245, including provenance and explicit assertions for unrecoverable legacy state.
  • ALTER journal serialization/replay for all load-clause categories, CSV cache synchronization, legacy logs without RoutineLoadDesc, and leader/replay checkpoint parity.
  • Semantic expression round trips for analyzer selection, quoted slot labels/subpaths, and TIMEV2 literal values.
  • A three-FE Docker case covering leader ALTER, follower journal replay before checkpoint, leader failover, a subsequent ALTER on the new leader, checkpoint creation, and FE restart recovery.

Validation status for the final head:

  • git diff --check: passed.
  • FE unit tests and the Docker regression case were added but were not executed after the final changes.

Release note

Routine Load jobs now preserve the effective load clauses after ALTER across follower replay, leader failover, checkpoint, and FE restart.

During a rolling upgrade, do not ALTER Routine Load load clauses until all FEs are running the new version. Rolling back after a new-version checkpoint can restore the original CREATE clauses instead of post-upgrade ALTER semantics.

Check List (For Author)

  • Test

    • Regression test
      • Added a three-FE Routine Load journal replay, leader failover, checkpoint, and restart case.
      • Not executed after the final changes.
    • Unit Test
      • Added image, journal, legacy fixture, derived-state, CSV, and expression semantic coverage.
      • Not executed after the final changes.
    • Manual test
    • No need to test or manual test
  • Behavior changed:

    • No.
    • Yes. New images and ALTER journals retain the current effective Routine Load definition; legacy images migrate once from origStmt.
  • Does this need documentation?

    • No.
    • Yes. Rolling-upgrade and rollback limitations must be documented.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#64878

Problem Summary: Routine Load image recovery reparsed the immutable original CREATE statement, so CREATE semantics changed by ALTER were not represented in the image. Persist the current load definition, retain the original statement as the legacy-image fallback, journal altered load clauses, and validate failure-prone Kafka and Kinesis changes before mutating runtime state.

### Release note

Routine Load jobs now recover the current effective load definition after ALTER.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: Yes. Image recovery uses the current effective Routine Load definition while legacy images continue to use origStmt.
- 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?

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#64878

Problem Summary: Keep the original CREATE statement in new images so an older FE can ignore the new load definition field and use its existing recovery path. ALTERed load clauses are outside the downgrade compatibility guarantee and may not survive rollback.

### Release note

Document that Routine Load ALTER semantics are not guaranteed after rolling back to an older FE.

### Check List (For Author)

- Test: Not run (per request; compatibility coverage was added)
- Behavior changed: No. This records and tests the intended rollback compatibility boundary.
- Does this need documentation: Yes. The rollback limitation must be called out in the feature documentation.
@0AyanamiRei
0AyanamiRei marked this pull request as draft August 11, 2026 03:16
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#64878

Problem Summary: Routine Load now persists its effective load definition directly, but nested legacy Expr SQL-carrier fields also need stable serialization, legacy image/log fixtures must come from the merge base, and ALTER replay must not apply new leader-side CSV validation to historical journals. Complete those compatibility requirements and add three-FE failover coverage for leader journal write, follower replay, checkpoint, and restart recovery.

### Release note

Routine Load jobs preserve effective load clauses across ALTER, follower replay, checkpoint, and FE restart. Legacy images continue to migrate from the original CREATE statement; rollback to an older FE remains structurally readable but does not preserve new ALTER semantics.

### Check List (For Author)

- Test: Not run per requested handoff; FE unit and Docker regression coverage were added.
- Behavior changed: Yes. Routine Load persistence and ALTER replay retain the current effective definition.
- Does this need documentation: Yes. Document rolling-upgrade and rollback limitations.
@0AyanamiRei
0AyanamiRei marked this pull request as ready for review August 20, 2026 02:02
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#64878

Problem Summary: Directly persisting legacy Expr makes Routine Load metadata depend on complete Gson coverage for a broad and evolving expression graph. Keep origStmt as the durable load-definition carrier instead. ALTER logs persist the original ALTER SQL, leader and follower replay merge each delta into a canonical CREATE statement, and image recovery reparses that current effective statement.

### Release note

Routine Load ALTER clauses are persisted by updating the stored CREATE statement and replaying ALTER SQL, avoiding a durable dependency on legacy Expr Gson serialization.

### Check List (For Author)

- Test: Unit Test
    - RoutineLoadJobPersistenceTest and KafkaRoutineLoadJobTest: 16 tests passed.
    - AlterRoutineLoadOperationLogTest and KinesisRoutineLoadJobTest: 13 tests passed in the preceding targeted run.
- Behavior changed: Yes. Routine Load load clauses use canonical origin SQL for image and journal recovery.
- Does this need documentation: Yes. Document ALTER recovery and rolling-upgrade compatibility.
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Routine Load cannot safely use the legacy Expr object graph as an image or journal compatibility surface. Keep the current effective load definition in origStmt, remove the duplicate execMemLimit JSON source, and cover all SQL-representable load clauses through CREATE image restore, ALTER merge, and a second image restore.

### Release note

Routine Load now persists ALTERed load clauses in the effective origin SQL used during FE recovery.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
    - Docker regression case added but not run locally
- Behavior changed: Yes, ALTERed Routine Load definitions survive journal replay and image recovery
- Does this need documentation: Yes, the existing design document and PR description must be updated
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Routine Load images already persist and replay origStmt. The persistence bug is that ALTER load clauses changed runtime fields without updating that statement. Keep the existing gsonPostProcess recovery path unchanged, persist the original ALTER SQL in the journal, and rewrite origStmt to a complete effective CREATE statement after leader and follower ALTER application. Remove direct-field persistence, cache hydration, CSV validation, and other adjacent changes from this PR.

### Release note

Routine Load now preserves ALTERed load clauses across follower replay, checkpoints, and FE restart by maintaining the effective CREATE statement.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.KinesisRoutineLoadJobTest
    - KafkaRoutineLoadJobTest and AlterRoutineLoadOperationLogTest passed in the combined targeted run
    - Docker regression case added but not run locally
- Behavior changed: Yes, ALTERed load clauses update the persisted origin statement
- Does this need documentation: Yes, document mixed-version ALTER limitations
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Treat the effective Routine Load fields as authoritative metadata instead of rewriting origStmt after ALTER. Persist the load-definition fields directly in images, persist RoutineLoadDesc deltas in ALTER journals, and use the original CREATE statement only when reading legacy images whose nullable effective fields are absent. Empty new definitions may also use the fallback safely because ALTER cannot unset all load clauses.

### Release note

Routine Load now preserves ALTERed load clauses across journal replay and FE restart through direct metadata persistence.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest,org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: Yes, image and ALTER journal persist effective Routine Load definitions directly
- Does this need documentation: Yes, document mixed-version ALTER limitations
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Metadata consumers now persist legacy Expr objects directly, but the existing Expr Gson test only checked subtype and JSON idempotence. Add stable serialization for SQL-relevant fields that were silently dropped, persist function ORDER BY metadata, require every Expr instance field to be serialized or explicitly classified as non-durable, and verify SQL output with and without table names for every concrete registered subtype. Add an analysis review guide for future Expr changes.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.analysis.ExprGsonSerializationTest
    - ./run-fe-ut.sh --run org.apache.doris.analysis.ExprGsonSerializationTest,org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: No user-facing SQL behavior; metadata Expr round trips now preserve SQL semantics
- Does this need documentation: No, contributor guidance is included in analysis/AGENTS.md
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: The first restoration of direct Routine Load persistence omitted parts of the previously reviewed design. Restore the exact persistence implementation from commit 4394fa3, including execMemLimit and memtableOnSinkNode image fields, jobProperties cache hydration, CSV ALTER cache synchronization, leader-only validation, legacy image migration, and the original Kafka/Kinesis persistence tests. Keep the separate Expr serde hardening on top.

### Release note

Routine Load persists its effective load definition and non-default task configuration directly across FE recovery.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.analysis.ExprGsonSerializationTest,org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest,org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: Yes, restore the complete direct-state image and ALTER journal persistence contract
- Does this need documentation: Yes, document mixed-version ALTER limitations
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