You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hudi.apache.org by "nsivabalan (via GitHub)" <gi...@apache.org> on 2026/10/16 15:10:40 UTC
[PR] feat(spark)!: truncate table as a replacecommit and scope the streaming sink checkpoint identifier to the checkpoint location [hudi]
nsivabalan opened a new pull request, #20378:
URL: https://github.com/apache/hudi/pull/20378
### Describe the issue this Pull Request addresses
**WIP / RFC-112 groundwork.** While validating Spark 4.1 Declarative Pipelines against Hudi (see the review on #19997), two existing behaviours combined into a data-safety problem:
1. Full-table `TRUNCATE TABLE` deletes the base path and re-initializes `hoodie.properties` (`TruncateHoodieTableCommand`). History, savepoints, the metadata table and every incremental/streaming reader offset are gone, and the operation is a non-transactional filesystem delete.
2. `HoodieStreamingSink` records its last committed batch id in commit metadata under `hoodie.datasource.write.streaming.checkpoint.identifier` (default `default_single_writer`) and skips any incoming batch id ≤ that value. The only reason this did not lose data after SDP's `--full-refresh` (fresh Structured Streaming checkpoint → batch ids restart at 0) was that (1) wiped the timeline first. The moment truncate stops destroying history, the sink silently skips every batch until the old high-water mark is passed.
The two therefore have to change together.
### Summary and Changelog
- `TRUNCATE TABLE t` (no partition spec) now issues a single `replacecommit` (`insert_overwrite_table` of an empty dataset) that replaces every file group. Timeline, savepoints, MDT and reader offsets stay valid; the truncation is visible as an instant. `TRUNCATE TABLE t PARTITION (...)` is unchanged (already a `delete_partition` replacecommit).
- New advanced config `hoodie.sql.truncate.purge.enabled` (default `false`) restores the previous delete-and-reinit behaviour for users who want a hard reset.
- `HoodieStreamingSink` scopes the default checkpoint identifier to the query's `checkpointLocation` (`default_single_writer@<checkpointLocation>`) when no explicit identifier is configured. A stream resumed from the same checkpoint keeps deduplicating replayed batches; a stream started from a fresh checkpoint is no longer matched against another stream's high-water mark. An explicit identifier behaves exactly as before. Logic lives in `HoodieStreamingSink.resolveCheckpointIdentifier`. The sink also forwards the resolved identifier in the write options, because the bulk-insert row-writer path does not go through the sink's pre-commit hook and builds the checkpoint entry on its own in `DataSourceUtils.getExtraMetadata` (found by `testStructuredStreamingWithBulkInsert`).
- Tests: `TestTruncateTable` (timeline retained + trailing replacecommit + writes after truncate, for COW/MOR × partitioned/non-partitioned; purge mode resets the timeline) and `TestStructuredStreaming` (dedup scoped to checkpoint location; resolver unit cases; existing default-identifier test adapted).
Validated end to end against stock Spark 4.1.1 `spark-pipelines` (Connect) with a Kafka → Hudi streaming table: `--full-refresh` now yields `N commits + replacecommit + N commits`, batch ids 0..N re-land under the new identifier, row counts identical before/after.
### Impact
- User-facing behaviour change for `TRUNCATE TABLE`: history is retained instead of purged, and the table directory is not removed. Readers see one more instant; storage is reclaimed by the cleaner instead of immediately. Opt back in with `hoodie.sql.truncate.purge.enabled=true`.
- Commit metadata: the `_hudi_streaming_sink_checkpoint` map key changes for streams that rely on the default identifier. Existing tables keep their old entries; after upgrade the first restart of such a stream will not find a matching entry and will not deduplicate a batch that was committed to Hudi but not yet acknowledged in the Spark checkpoint at the moment of upgrade (a crash exactly at the upgrade boundary; upserts are idempotent, inserts would duplicate that one batch). Open question below.
- No storage format, timeline schema or public API changes.
### Risk Level
medium. Truncate now goes through the regular write path (`insert_overwrite_table` with an empty input) for COW and MOR; covered by the new tests plus the SDP end-to-end run. The identifier change is covered by tests; the upgrade-boundary window is documented above.
### Open questions for reviewers
- Should the sink also write the legacy `default_single_writer` entry for one release to close the upgrade-boundary window, at the cost of re-introducing the skip after a checkpoint reset on tables that have only legacy entries?
- `hoodie.sql.truncate.purge.enabled` is read from the session conf only; should it also be accepted as a table/SQL option?
- Title carries `!` because `TRUNCATE` semantics change; happy to drop it if we consider "history retained" non-breaking.
- Truncate on a table with pending compaction/clustering now inherits whatever `INSERT OVERWRITE TABLE` does today for those file groups; worth confirming that is acceptable (it was not a question when truncate was a filesystem delete).
- Still to add before un-drafting: tests for truncating an empty table and truncating twice in a row.
### Documentation Update
- New config `hoodie.sql.truncate.purge.enabled` (description in `DataSourceWriteOptions`).
- SQL DDL page: note that `TRUNCATE TABLE` is a replacecommit and how to opt into purge.
### Contributor's checklist
- [x] Read through [contributor's guide](https://hudi.apache.org/contribute/how-to-contribute)
- [x] Enough context is provided in the sections above
- [x] Adequate tests were added if applicable
cc @danny0405 @cshuo
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
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: commits-unsubscribe@hudi.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] feat(spark)!: truncate table as a replacecommit and scope the streaming sink checkpoint identifier to the checkpoint location [hudi]
Posted by "nsivabalan (via GitHub)" <gi...@apache.org>.
nsivabalan commented on PR #20378:
URL: https://github.com/apache/hudi/pull/20378#issuecomment-6218670060
CC @danny0405 : we might need this for the SDP support
--
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: commits-unsubscribe@hudi.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] feat(spark)!: truncate table as a replacecommit and scope the streaming sink checkpoint identifier to the checkpoint location [hudi]
Posted by "codecov-commenter (via GitHub)" <gi...@apache.org>.
codecov-commenter commented on PR #20378:
URL: https://github.com/apache/hudi/pull/20378#issuecomment-6219022909
## [Codecov](https://app.codecov.io/gh/apache/hudi/pull/20378?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
:white_check_mark: All modified and coverable lines are covered by tests.
:white_check_mark: Project coverage is 80.44%. Comparing base ([`4f4c357`](https://app.codecov.io/gh/apache/hudi/commit/4f4c3571bfdce29753d455fed2e93b0ac95f1334?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`0eb10cb`](https://app.codecov.io/gh/apache/hudi/commit/0eb10cb1f09be944384c9532fd4b5319e58339c9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
:warning: Report is 37 commits behind head on master.
<details><summary>Additional details and impacted files</summary>
```diff
@@ Coverage Diff @@
## master #20378 +/- ##
============================================
- Coverage 80.62% 80.44% -0.18%
- Complexity 35056 35233 +177
============================================
Files 2552 2552
Lines 143390 144444 +1054
Branches 17450 17608 +158
============================================
+ Hits 115606 116202 +596
- Misses 19868 20274 +406
- Partials 7916 7968 +52
```
| [Components](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=components&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
|---|---|---|
| [hudi-common](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `83.43% <ø> (-0.73%)` | :arrow_down: |
| [hudi-client](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `83.80% <ø> (-0.01%)` | :arrow_down: |
| [hudi-flink](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `85.97% <ø> (ø)` | |
| [hudi-spark-datasource](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `74.05% <ø> (-0.01%)` | :arrow_down: |
| [hudi-utilities](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `78.18% <ø> (ø)` | |
| [hudi-cli](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `70.80% <ø> (ø)` | |
| [hudi-hadoop](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `70.88% <ø> (-0.25%)` | :arrow_down: |
| [hudi-sync](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `76.25% <ø> (ø)` | |
| [hudi-io](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `81.79% <ø> (+0.36%)` | :arrow_up: |
| [hudi-timeline-service](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `82.91% <ø> (-0.15%)` | :arrow_down: |
| [hudi-cloud](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `81.00% <ø> (ø)` | |
| [hudi-kafka-connect](https://app.codecov.io/gh/apache/hudi/pull/20378/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `53.20% <ø> (ø)` | |
| [Flag](https://app.codecov.io/gh/apache/hudi/pull/20378/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
|---|---|---|
| [hadoop-mr-java-client](https://app.codecov.io/gh/apache/hudi/pull/20378/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `43.94% <ø> (-0.03%)` | :arrow_down: |
Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
| [Files with missing lines](https://app.codecov.io/gh/apache/hudi/pull/20378?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
|---|---|---|
| [...main/scala/org/apache/hudi/DataSourceOptions.scala](https://app.codecov.io/gh/apache/hudi/pull/20378?src=pr&el=tree&filepath=hudi-spark-datasource%2Fhudi-spark-common%2Fsrc%2Fmain%2Fscala%2Forg%2Fapache%2Fhudi%2FDataSourceOptions.scala&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-aHVkaS1zcGFyay1kYXRhc291cmNlL2h1ZGktc3BhcmstY29tbW9uL3NyYy9tYWluL3NjYWxhL29yZy9hcGFjaGUvaHVkaS9EYXRhU291cmNlT3B0aW9ucy5zY2FsYQ==) | `95.25% <ø> (ø)` | |
| [...in/scala/org/apache/hudi/HoodieStreamingSink.scala](https://app.codecov.io/gh/apache/hudi/pull/20378?src=pr&el=tree&filepath=hudi-spark-datasource%2Fhudi-spark-common%2Fsrc%2Fmain%2Fscala%2Forg%2Fapache%2Fhudi%2FHoodieStreamingSink.scala&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-aHVkaS1zcGFyay1kYXRhc291cmNlL2h1ZGktc3BhcmstY29tbW9uL3NyYy9tYWluL3NjYWxhL29yZy9hcGFjaGUvaHVkaS9Ib29kaWVTdHJlYW1pbmdTaW5rLnNjYWxh) | `68.94% <ø> (-0.76%)` | :arrow_down: |
| [.../sql/hudi/command/TruncateHoodieTableCommand.scala](https://app.codecov.io/gh/apache/hudi/pull/20378?src=pr&el=tree&filepath=hudi-spark-datasource%2Fhudi-spark-common%2Fsrc%2Fmain%2Fscala%2Forg%2Fapache%2Fspark%2Fsql%2Fhudi%2Fcommand%2FTruncateHoodieTableCommand.scala&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-aHVkaS1zcGFyay1kYXRhc291cmNlL2h1ZGktc3BhcmstY29tbW9uL3NyYy9tYWluL3NjYWxhL29yZy9hcGFjaGUvc3Bhcmsvc3FsL2h1ZGkvY29tbWFuZC9UcnVuY2F0ZUhvb2RpZVRhYmxlQ29tbWFuZC5zY2FsYQ==) | `76.08% <ø> (-0.51%)` | :arrow_down: |
... and [17 files with indirect coverage changes](https://app.codecov.io/gh/apache/hudi/pull/20378/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
</details>
<details><summary> :rocket: New features to boost your workflow: </summary>
- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
--
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: commits-unsubscribe@hudi.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org