-
Notifications
You must be signed in to change notification settings - Fork 24
feat(realtime): add primary-key in-memory support #224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
HaHaJeff
wants to merge
63
commits into
apache:main
Choose a base branch
from
HaHaJeff:jeff/pk-realtime-v1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
50d4207
feat(realtime): add primary-key in-memory writes
HaHaJeff 82949b3
feat(read): merge primary-key realtime memory with snapshots
HaHaJeff f8078a5
test(realtime): cover primary-key realtime lifecycle
HaHaJeff 949356a
refactor(realtime): consolidate PK state and validation
HaHaJeff 7f4b60b
fix(read): close PK realtime query readers
HaHaJeff 3dee339
fix(realtime): close rejected plugin readers
HaHaJeff b36b24f
fix(read): preserve PK reader metrics after close
HaHaJeff 20b834e
refactor(realtime): colocate PK realtime option validation
HaHaJeff b89a9fc
test(realtime): improve primary key coverage
HaHaJeff b3862d1
fix(realtime): prevent sequence reuse and align nested projections
HaHaJeff 3acae03
fix(realtime): align PK reads across schema changes
HaHaJeff 74d4fee
fix(realtime): align PK projections by field ID
HaHaJeff 2f7d228
refactor(mergetree): accept sorted key-value readers
HaHaJeff 3df2037
feat(realtime): adapt prepared primary-key batches
HaHaJeff 232d587
refactor(realtime): prepare primary-key batches in framework
HaHaJeff 62108e2
refactor(realtime): simplify primary-key write preparation
HaHaJeff b6bf461
test(mergetree): reuse reader failure mock
HaHaJeff 8c4c4c8
fix(realtime): preserve PK sequence across writer handoff
HaHaJeff aec0a2e
refactor(realtime): simplify primary key merge readers
HaHaJeff c248373
fix(realtime): validate PK reader contracts
HaHaJeff 1e1c7d2
refactor(realtime): simplify reader lifecycle cleanup
HaHaJeff 352ce21
fix(realtime): harden primary-key prepared batches
HaHaJeff d818466
refactor(realtime): simplify primary-key contracts
HaHaJeff ff0c7bd
fix(realtime): strengthen primary-key recovery coverage
HaHaJeff 83ff3cb
test(realtime): strengthen failure recovery coverage
HaHaJeff 5558182
refactor(realtime): simplify primary key state and tests
HaHaJeff e68ac16
test(realtime): simplify integration test setup
HaHaJeff f92fe6a
fix(realtime): reject PK read-optimized scans
HaHaJeff b187e07
fix(realtime): harden prepared store handling
HaHaJeff 5a6dcb6
refactor(realtime): simplify PK store boundary
HaHaJeff 808cc59
refactor(realtime): simplify PK offset coverage
HaHaJeff 7e59253
refactor(realtime): simplify stores around framework-owned PK offsets
HaHaJeff 7a59f9e
refactor(realtime): align PK query projection with store
HaHaJeff 884270f
refactor(realtime): address review feedback
HaHaJeff bf00d53
fix(realtime): tighten primary key framework boundaries
HaHaJeff 52ee6bd
fix(realtime): harden query schema alignment
HaHaJeff ace7e1d
fix(realtime): validate exact commit reader coverage
HaHaJeff 607cac7
fix(realtime): enforce store reader boundaries
HaHaJeff 86123e0
refactor(realtime): align primary key query projection
HaHaJeff 32844c1
refactor(realtime): centralize Arrow array memory retention
HaHaJeff 3476342
fix(realtime): refine primary key option validation
HaHaJeff 961aaaa
fix(realtime): validate plugin bitmap bounds
HaHaJeff 69d9693
fix(realtime): preserve primary keys in projected reads
HaHaJeff 09c53c9
fix(read): bound realtime merge fan-in
HaHaJeff 712b1e7
refactor(realtime): simplify primary key maintenance
HaHaJeff 3392f39
refactor(realtime): simplify primary key schema and reader setup
HaHaJeff dfb3329
refactor(realtime): remove duplicate offset validation
HaHaJeff e448f7a
refactor(realtime): localize primary-key split validation
HaHaJeff 0082544
fix(io): preserve merged reader initialization errors
HaHaJeff b4fb4d0
fix(realtime): validate prepared reader coverage
HaHaJeff 226cd85
fix(mergetree): transfer sorted reader ownership safely
HaHaJeff 3b65e10
refactor(realtime): simplify reader lifecycle
HaHaJeff e8a5b29
refactor(realtime): simplify prepared reader validation
HaHaJeff 87796a3
fix(read): close realtime readers on setup failure
HaHaJeff 982eb59
refactor(realtime): clarify primary-key reader contracts
HaHaJeff 9142758
Merge branch 'main' into jeff/pk-realtime-v1
lxy-9602 d4ebe09
fix(realtime): resolve CI failures
HaHaJeff 49f0ea7
test(realtime): remove redundant reader test code
HaHaJeff 813c644
test(realtime): streamline realtime test coverage
HaHaJeff e357418
fix(style): apply clang-format
HaHaJeff 020a14d
docs: preserve comments across refactoring
HaHaJeff a77b5f4
test(realtime): streamline primary key reader coverage
HaHaJeff a51b207
test(realtime): remove redundant close coverage
HaHaJeff File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the contribution. The code looks clear and well organized. Before diving into the detailed review, I would like to discuss two design points.
First, it seems that internal sequence-number assignment and per-batch primary-key sorting are currently handled inside the realtime store implementation. I suggest moving these responsibilities into the Paimon framework instead.
The framework could assign offsets and sequence numbers, append internal fields such as
_VALUE_KIND,_SEQUENCE_NUMBER, and_REALTIME_OFFSET, and physically sort each input Arrow batch before passing it to the store plugin. The plugin would then only manage storage concerns, without needing to understand PK sorting rules, sequence fields, or merge-engine semantics.Query and prepare-commit could convert these already sorted batches into
KeyValueRecordReaders and reuse the existingSortMergeReaderand merge functions. The flush path could also accept sorted readers directly, avoiding sequence reassignment and repeated per-batch sorting. This would make custom plugins easier to implement and allow realtime reads and writes to reuse the framework’s existing merge-engine and sequence-field behavior.I think this can be the first-stage solution. If profiling later shows that copying data to produce physically sorted Arrow batches is a real write-path bottleneck, we could introduce a shallow-copy mode based on sorted indices. That would require significantly more interface changes, so I suggest optimizing it only after it becomes an observed hotspot.
Second, the in-memory store could keep PK statistics for each batch, such as min/max values. Predicates on value fields may not be pushable, but
predicate_for_keysshould be applicable to these statistics so irrelevant in-memory batches can be pruned during reads. This optimization could also be implemented in a follow-up PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the detailed suggestion. I agree that sequence assignment, PK sorting, and merge semantics should belong to the Paimon framework rather than the real-time store plugin.
The current implementation assigns sequence numbers and performs PK sorting and in-memory merging inside the PK store. During prepare-commit, it converts the returned batches back into ordinary
RecordBatches and passes them throughWriteBuffer, which assigns sequence numbers and sorts the same data again. I plan to revise this design as follows.Framework-side batch preparation
Before calling
RealtimeStore::Write, the Paimon framework will:_REALTIME_OFFSETand_SEQUENCE_NUMBERatomically according to the original per-row write order;_VALUE_KIND,_SEQUENCE_NUMBER, and_REALTIME_OFFSET;All columns will be reordered with the same sort indices, so the value, row kind, sequence number, and real-time offset remain associated with the same mutation.
Sorting will not perform deduplication or early MOR. Every mutation will remain in the prepared batch. The progress counters will advance only after
RealtimeStore::Writesucceeds.RealtimeStore responsibility
RealtimeStorewill treat the internal fields as opaque Arrow columns and preserve the prepared batches through write, seal, read-view, query-reader, and commit-reader operations.It will no longer:
Each physically sorted input batch will represent one independent sorted run. A store may return multiple readers, and Paimon will merge those runs in the framework. The built-in and custom stores will therefore use the same path.
Query path
The framework will provide an adapter from the store's
BatchReadertoKeyValueRecordReader.For PK queries:
_REALTIME_OFFSETto remove memory rows already covered by the selected snapshot;KeyValueRecordReaders;SortMergeReadermerges the memory readers with disk readers;_SEQUENCE_NUMBERremains the row-version field used to resolve versions during disk-memory MOR.Prepare-commit path
RealtimeStoreandMergeTreeWriterwill not depend on each other directly. The framework-ownedRealtimePrimaryKeyWriterwill coordinate them:RealtimeStore::SealForCommitto obtain an immutable segment;RealtimeStore::CreateCommitReadersfor that segment;BatchReaders into sortedKeyValueRecordReaders;MergeTreeWriter::WriteSortedReaders;MergeTreeWriter::PrepareCommit;The resulting path will be:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your response! The current direction looks good to me. @zjw1111 , could you also take a look?
Also, the offset filtering for PK tables has now been moved to the framework layer, while for append tables it is still handled inside the plugin through the
offset_beginparameter inCreateQueryReaders. I plan to align the append-table path later as well, similar to PK tables, by moving the offset filtering into the framework layer. For this PR, I think it’s fine to keep the current interface for now and focus on implementing the PK-table part first.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the design guidance. The initial implementation placed sequence assignment, sorting, and in-memory MOR in the PK store, which made custom stores understand Paimon merge semantics and caused data to be sorted again during file writing. Commits 8d96153, df322c1, and 87e4548 moved sorted-reader writing, reader adaptation, transport-field materialization, and PK sorting into the framework. Commit ff44419 finalized the PK storage-only boundary by removing store-side PK merge dependencies. The framework allocates sequence and offsets under the V1 one-context/one-active-writer contract. PK statistics pruning remains follow-up work; predicate pruning before MOR stays disabled for correctness.