Add default _upsert_comparison_ts column for OFFLINE upsert - #19118
Add default _upsert_comparison_ts column for OFFLINE upsert#19118xiangfu0 wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #19118 +/- ##
==========================================
Coverage 65.62% 65.62%
Complexity 1423 1423
==========================================
Files 3439 3440 +1
Lines 218195 218309 +114
Branches 34669 34701 +32
==========================================
+ Hits 143198 143274 +76
- Misses 63443 63463 +20
- Partials 11554 11572 +18
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
b6d1812 to
847f27a
Compare
847f27a to
aec539c
Compare
aec539c to
a6e3050
Compare
f612d0f to
ace22f6
Compare
b05e99d to
329db43
Compare
There was a problem hiding this comment.
Pull request overview
Adds an implicit, stable comparison-time mechanism for OFFLINE FULL upsert tables that have neither configured comparison columns nor a time column, by introducing a reserved physical LONG column (_upsert_comparison_ts) that falls back to the source segment’s immutable index creation time. This prevents rebuilt/rewritten old segments from “winning” purely due to a newer artifact creation time, and makes the column visible via SELECT * and table-aware PinotSegmentRecordReader.
Changes:
- Introduce
_upsert_comparison_tsas the implicit comparison column for OFFLINE FULL upsert (schema augmentation + constant + TableConfig detection). - Ensure segment loading/preprocessing can materialize/fill the column based on source segment creation time, while upsert comparison falls back when values are null/unset.
- Add unit + integration tests covering schema caching, segment loading/record reading, and RefreshSegmentTask transactional replacement behavior.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pinot-spi/src/test/java/org/apache/pinot/spi/config/table/TableConfigTest.java | Adds tests for TableConfig.usesImplicitUpsertComparisonTime() behavior under different upsert/time-column configurations. |
| pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java | Introduces the reserved column name constant for the implicit upsert comparison-time column. |
| pinot-spi/src/main/java/org/apache/pinot/spi/config/table/TableConfig.java | Adds usesImplicitUpsertComparisonTime() helper to detect when implicit comparison-time should apply. |
| pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/ConcurrentMapTableUpsertMetadataManagerTest.java | Verifies implicit comparison-time injects comparison columns in upsert context and augments schema. |
| pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerTest.java | Adds regression test ensuring older physical comparison time beats newer rewritten segment creation time. |
| pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/loader/LoaderTest.java | Verifies implicit comparison-time column is materialized/readable via segment APIs and PinotSegmentRecordReader. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertUtils.java | Adds a comparison-column reader that can read/fallback for the implicit comparison-time column. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertComparisonTimeUtils.java | New utility encapsulating implicit comparison-time detection, schema augmentation, and physical datasource validation. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes.java | Uses createRecordInfoReader() to centralize record-reading behavior (including implicit comparison-time). |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManager.java | Uses createRecordInfoReader() to centralize record-reading behavior (including implicit comparison-time). |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/BaseTableUpsertMetadataManager.java | Wires implicit comparison-time into upsert context schema + comparison column selection for OFFLINE FULL upsert. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/BasePartitionUpsertMetadataManager.java | Adds implicit comparison-time reader path in createRecordInfoReader() for partition upsert managers. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/readers/PinotSegmentRecordReader.java | Adds table-aware init overload and ensures implicit comparison-time value fallback is visible in read rows. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/loader/IndexLoadingConfig.java | Ensures schema used during segment load includes the implicit comparison-time column when applicable. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/loader/defaultcolumn/BaseDefaultColumnHandler.java | Adjusts schema defaults so missing/auto-generated comparison-time values materialize from segment creation time. |
| pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/custom/RefreshSegmentUpsertMinionTest.java | New end-to-end integration test validating RefreshSegmentTask rewrite + transactional replacement preserves ordering. |
| pinot-common/src/test/java/org/apache/pinot/common/config/provider/StaticTableCacheTest.java | Tests that the effective cached schema includes the implicit comparison-time column. |
| pinot-common/src/main/java/org/apache/pinot/common/config/provider/ZkTableCache.java | Refreshes schema info on OFFLINE table-config add/remove so implicit comparison-time column presence stays consistent. |
| pinot-common/src/main/java/org/apache/pinot/common/config/provider/TableCache.java | Centralizes schema-info creation and injects implicit comparison-time column into cached schema when applicable. |
| pinot-common/src/main/java/org/apache/pinot/common/config/provider/StaticTableCache.java | Switches to using createSchemaInfo() and removes redundant schema bookkeeping. |
329db43 to
37710d5
Compare
Preserve source segment ordering when RefreshSegmentTask rebuilds an old segment. Without a stable physical comparison timestamp, transactional replacement can make stale rows win because the rebuilt artifact has a newer creation time.
37710d5 to
e9e638c
Compare
What changed
_upsert_comparison_tsas an automatic physical LONG column for OFFLINE FULL upsert tables with no configured comparison columns or table time column.SELECT *and table-awarePinotSegmentRecordReaderreads include it without broker virtual-column handling.RefreshSegmentTaskuse the effective schema and table-aware reader so its real output carries the source comparison time.How to reproduce
RefreshSegmentTaskand publish a rebuilt artifact through transactional segment replacement._upsert_comparison_ts, so the newer source row remains queryable.Compatibility and rollout
This is an additive SPI and user-visible schema change: qualifying tables reserve
_upsert_comparison_ts,SELECT *exposes it, and rewritten segments persist it. Because older servers do not consume this column, complete the broker/server upgrade for affected OFFLINE upsert tables before enabling Refresh or other segment-rewrite tasks; mixed-version replicas can otherwise use different ordering semantics.Validation
RefreshSegmentUpsertMinionTest: passed through the full 63-module reactor (956 Maven goals), covering actual Refresh materialization, transactional replacement, exact winning-row timestamps, andSELECT *visibility.test-compile: passed; no warnings in changed lines.RocksDB-backed upsert state handling remains a follow-up.