Skip to content

[Enhancement] Name shared-data vector index files by the segment's owning tablet id#75702

Merged
sevev merged 17 commits into
StarRocks:mainfrom
sevev:feat/sd-vi-owner-tablet-id
Jul 3, 2026
Merged

[Enhancement] Name shared-data vector index files by the segment's owning tablet id#75702
sevev merged 17 commits into
StarRocks:mainfrom
sevev:feat/sd-vi-owner-tablet-id

Conversation

@sevev

@sevev sevev commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Why I'm doing:

Follow-up to #75542, which added vector-index (.vi) support for shared-data bundle-file
segments. That PR names each .vi <segment_base>_<tablet_id>_<index_id>.vi, embedding the
tablet id to disambiguate segments that share one physical bundle file across tablets. It uses
the id of the tablet touching the segment, which is not reader-agnostic.

After a tablet split, a single segment is shared by multiple child tablets
(SegmentMetadataPB.shared, carried verbatim via CopyFrom). Each child reads the shared
segment with its own tablet id, so it derives a different .vi name than the one the writer
actually produced:

  • Read: the child looks up ..._<child_id>_<index_id>.vi, which does not exist → NotFound
    → silent fall back to brute-force vector search (results stay correct, but slow).
  • GC / vacuum: orphan protection and deletion also reconstruct the name from the local
    tablet id, so the real .vi (named after the writer) is neither protected nor collected under
    the name every referencing tablet computes — it can be deleted while still referenced, or
    leaked.

What I'm doing:

Record the writing tablet's id in a new persisted field
SegmentMetadataPB.vector_index_tablet_id and derive every .vi name from that recorded owner
instead of the local tablet id. Because the field is carried verbatim across split via
CopyFrom, every child that shares the segment resolves the exact same .vi the writer wrote.

  • The .vi filename format is unchanged (<segment_base>_<owner_tablet_id>_<index_id>.vi);
    only the source of the embedded id changes from "the tablet touching the segment" to "the
    recorded owner".
  • The owner is stamped at write time, in the same step that records vector_index_ids: the
    tablet writers (normal write and the deferred-async initial write) and the segment rewrite
    (partial-update / auto-increment). to_proto persists it and the publish apply carries it
    verbatim. From there it is threaded through FileInfo / SegmentReadOptions and consumed by
    the read path (segment_iterator), the async build (vector_index_build_task), and GC
    (vacuum / transactions).
  • Invariant, no fallback: a segment that records vector_index_ids always records this owner
    too, and every consumer reads the owner only for a vector-indexed segment and DCHECKs its
    presence — there is no fall back to the reading tablet id. A future write path that records ids
    but forgets the owner fails loudly in tests instead of silently degrading to brute-force reads
    and mis-named GC. This PR is a follow-up to [Enhancement] Build vector index for shared-data bundle segments #75542 (unreleased) and ships together with it, so
    no released version ever persisted a vector-indexed segment without the owner.
  • A split-shared .vi is named by the recorded owner, so it is one physical file referenced
    by every sibling tablet. It follows its segment's shared-file lifecycle in GC: routed through
    the shared-file deleter / retained while any sibling still references it, and delay-deleted like
    the shared segment. A bundle-only .vi stays per-tablet (the filename embeds the writer id)
    and keeps ordinary per-tablet deletion.

What type of PR is this:

  • BugFix
  • Feature
  • Enhancement
  • Refactor
  • UT
  • Doc
  • Tool

Does this PR entail a change in behavior?

  • Yes, this PR will result in a change in behavior.
  • No, this PR will not result in a change in behavior.

If yes, please specify the type of change:

  • Interface/UI changes: syntax, type conversion, expression evaluation, display information
  • Parameter changes: default values, similar parameters but with different default values
  • Policy changes: use new policy to replace old one, functionality automatically enabled
  • Feature removed
  • Miscellaneous: upgrade & downgrade compatibility, etc.

Checklist:

  • I have added test cases for my bug fix or my new feature
  • This pr needs user documentation (for new or modified features or behaviors)
    • I have added documentation for my new feature or new function
    • This pr needs auto generate documentation
  • This is a backport pr

Bugfix cherry-pick branch check:

  • I have checked the version labels which the pr will be auto-backported to the target branch
    • 4.1
    • 4.0
    • 3.5

@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b0f8a18adb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread be/src/storage/lake/general_tablet_writer.cpp Outdated
Comment thread be/src/storage/lake/rowset_update_state.cpp Outdated
@sevev

sevev commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@sevev sevev force-pushed the feat/sd-vi-owner-tablet-id branch from c848776 to e7db02e Compare July 2, 2026 09:13
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7db02e821

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread be/src/storage/lake/vacuum.cpp Outdated
Comment thread be/src/storage/lake/rowset_update_state.cpp
@sevev sevev force-pushed the feat/sd-vi-owner-tablet-id branch 2 times, most recently from fd9414a to e6f3a96 Compare July 2, 2026 11:33
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: e6f3a96b76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sevev sevev enabled auto-merge (squash) July 2, 2026 12:36
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 061af1e782

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread be/src/storage/lake/filenames.h Outdated
Comment thread be/src/fs/fs.h Outdated
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@sevev sevev requested a review from xiangguangyxg July 3, 2026 03:46
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: c3ff3ac33f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

xiangguangyxg
xiangguangyxg previously approved these changes Jul 3, 2026
sevev and others added 5 commits July 3, 2026 15:25
…ning tablet id

Follow-up to StarRocks#75542, which added vector-index (.vi) support for shared-data
bundle-file segments and named each .vi <segment_base>_<tablet_id>_<index_id>.vi
using the id of the tablet touching the segment. That id is not reader-agnostic:
after a tablet split a segment is shared by multiple child tablets
(SegmentMetadataPB.shared, carried verbatim via CopyFrom), and each child derives
a different .vi name than the writer produced. On read this yields NotFound and a
silent fall back to brute-force search; in GC/vacuum the real .vi is neither
protected nor collected under the name every referencing tablet computes.

Record the writing tablet's id in the new persisted field
SegmentMetadataPB.vector_index_tablet_id (carried verbatim across split via
CopyFrom) and derive every .vi name from that recorded owner instead of the local
tablet id, falling back to the current tablet id for segments written before the
field existed. The .vi filename format is unchanged; only the source of the
embedded id changes. The owner id is stamped at write time (normal write,
partial-update rewrite, deferred async build), threaded through FileInfo /
SegmentReadOptions, and consumed by the read path, the async build task, and GC.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: sevev <qiangzh95@gmail.com>
Address review: VerticalGeneralTabletWriter::finish records vector_index_ids
directly rather than through record_segment_vector_index_ids, so it never
stamped vector_index_tablet_id; VerticalPkTabletWriter inherits that finish and
had the same gap. Set the owner id there too (the .vi is already named with
_tablet_id by fill_vector_index_file_paths, so the owner is _tablet_id), and
assert vector_index_tablet_id in the horizontal / horizontal-pk / vertical
tablet-writer tests.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review: rewrite_segment recorded vector_index_tablet_id only in the
copy-only async partial-update branch. Auto-increment rewrites and async partial
updates with vector-indexed unmodified columns also leave vector_index_ids in
file_info (via SegmentRewriter) but left the owner as -1, so MetaFileBuilder
persisted the ids with the owner cleared. A later tablet split would then derive
<segment>_<child_id>_<idx>.vi instead of the file written under the writer id.

Centralize the stamp in stamp_rewrite_vector_index_owner and call it before every
replace-segment assignment (the dest is always written by this tablet, so the .vi
owner is params.tablet->id()). Assert vector_index_tablet_id on the persisted
metadata across all rewrite-path tests in LakePartialUpdateVectorIndexTest.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e resolve helper

Write side: fill_missing_vector_index_owner() at every publish funnel (PK
apply_opwrite / set_final_rowset / apply_opcompaction; non-PK write /
compaction / schema-change apply) stamps the owner when a writer path recorded
vector_index_ids without it. Segments marked shared() (split cross-publish,
written by another tablet) and replication are deliberately skipped.

Read side: collapse the ten owner-or-fallback ternaries into
resolve_vector_index_owner_tablet_id / gen_vector_index_filename_for_segment
in filenames.h, so the fallback rule lives in one place.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sevev and others added 9 commits July 3, 2026 15:26
gen_vector_index_filename / gen_vector_index_path_from_segment_path are plain
string formatters and carry no owner semantics; restore their original
tablet_id parameter and comments. The owner rule lives in
resolve_vector_index_owner_tablet_id and the SegmentMetadataPB field comment.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Concentrate the write-side logic: writers no longer carry or set
vector_index_tablet_id (drop the FileInfo field, the writer/rewrite stamps and
the to_proto copy). fill_missing_vector_index_owner at the publish funnels
becomes the sole producer — there the publishing tablet is the writing tablet
for every non-shared segment, so the stamped value always matches the id
embedded in the .vi filenames on disk. Consumers are unchanged.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Writers record vector_index_tablet_id into FileInfo alongside vector_index_ids
(tablet writers and stamp_rewrite_vector_index_owner for segment rewrites);
to_proto persists it and the publish apply carries it verbatim — the
apply-funnel stamping is removed and txn_log_applier reverts to main. Carry
the owner through VectorIndexBuildTask via FileInfo so build_segment keeps its
original signature; fill SegmentReadOptions only in Rowset::read(), the sole
entry point serving ANN queries.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A split-shared segment's .vi is named by the recorded owner, so it is the same
file every sibling tablet references. Give it the same shared-file lifecycle as
its segment: route deletion through the shared-file deleter (or retain when the
segment is retained) in delete_rowset_vi_files; delay-delete alive shared .vi in
collect_alive_shared_files; and carry src_seg_meta.shared() onto the orphaned
source .vi in rewrite_segment. A bundle-only segment's .vi stays per-tablet
(the filename embeds the writer id) and keeps ordinary deletion.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ded owner

Every persisted vector-indexed segment records its owner at write time (the
tablet writers and the segment rewrite stamp it; ADD VECTOR INDEX rewrites
through the tablet writer, never the no-rewrite fast path), so the shared-data
vector index has no owner-less on-disk state. Drop the "recorded owner or local
tablet id" fallback: vector_index_owner_tablet_id(segment_meta) returns the
recorded owner and DCHECKs its presence, and its callers (read / GC / build /
rewrite) lose the fallback_tablet_id argument; segment_iterator DCHECKs the
option is set instead of defaulting to the reading tablet. A future write path
that forgets to stamp now fails loudly in tests rather than silently degrading
to brute-force reads and mis-named GC.

Test metadata that modeled the old fallback (vector_index_ids without an owner)
now records the owner, matching the .vi files each test creates.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…allback invariant

The final design DCHECKs the recorded owner instead of falling back to the
reading tablet id, but the SegmentMetadataPB.vector_index_tablet_id comment still
described the removed fallback. Reword it: the owner is always stamped in the same
step that records vector_index_ids, and consumers (read / GC / async build) DCHECK
its presence for vector-indexed segments with no fallback.

Signed-off-by: sevev <qiangzh95@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The vector-index build tests hand-build TabletMetadataPB but omitted
vector_index_tablet_id, which the production write path always stamps
alongside vector_index_ids. Under release builds the guarding DCHECK in
vector_index_owner_tablet_id() is compiled out, so the build named the
.vi with owner=0 while the assertions expected owner=kTabletId, failing
LakeServiceVectorIndexBuildTest.test_build_vector_index_full_path and
test_build_vector_index_partial_failure.

Set vector_index_tablet_id in the test metadata to mirror the write path.

Signed-off-by: sevev <qiangzh95@gmail.com>
vector_index_ids and vector_index_tablet_id are per-segment attributes but
sat on the generic FileInfo, and SegmentFileInfo already shadowed
vector_index_ids -- a latent footgun where writes and reads could target
different copies. Move both fields down to SegmentFileInfo (the only copy now)
and thread SegmentFileInfo through the lake rewrite/apply/build-task paths and
the replace_segments maps.

The shared SegmentRewriter keeps its FileInfo* dest (still used by the
shared-nothing storage engine) and instead returns the recorded ids through a
new optional out_vector_index_ids parameter, so no downcast and no behavior
change for either engine.

Signed-off-by: sevev <qiangzh95@gmail.com>
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e262cc57f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread be/src/storage/lake/vacuum.cpp Outdated
sevev and others added 3 commits July 3, 2026 15:54
After rebasing onto StarRocks#75588 (which added shared-.vi vacuum protection using
the old tablet-id-based .vi name), the owner-based .vi handling only ran for
segment_meta.shared(), missing bundled split segments (is_shared_segment but
not shared()). A parent/sibling vacuum could then delete the owner-named .vi
while a child still referenced the bundled segment, dropping its index.

Make .vi handling mirror the segment it belongs to in every vacuum path:
- collect_alive_shared_files: delay-delete the owner-named .vi for every
  is_shared_segment (bundle or shared), not just shared(); drop the stale
  old-name delay and the redundant shared()-only block.
- split-metadata GC: delete the owner-named .vi under the same
  !is_shared_segment || allow_delete_shared_files guard as the segment, and
  drop the duplicate delete_rowset_vi_files call that used a different
  (refcount) retention policy than the segment's skip-to-retain.

Signed-off-by: sevev <qiangzh95@gmail.com>
The field/param named ...tablet_id read as "the current tablet", but its
role is a per-segment unique key that disambiguates a segment's .vi
filenames (so bundle-file segments shared across tablets get distinct .vi,
and the name stays reader-agnostic across tablet split). Its value happens
to be the writing tablet's id, used purely as a unique key.

Name it by that role, value-agnostically:
- SegmentMetadataPB.vector_index_tablet_id -> segment_vector_index_uid
  (field ordinal 13 kept -> wire compatible)
- SegmentFileInfo / SegmentReadOptions members likewise
- helper vector_index_owner_tablet_id() -> resolve_segment_vector_index_uid()
  (distinct from the raw getter segment_vector_index_uid())
- reword comments to lead with the role; note the value is the writer id

The low-level gen_vector_index_filename(..., tablet_id, ...) formatter param
is left unchanged (it is a generic string formatter with no owner semantics).
Pure rename, no behavior change.

Signed-off-by: sevev <qiangzh95@gmail.com>
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: a4efb7fefb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

[Java-Extensions Incremental Coverage Report]

pass : 0 / 0 (0%)

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

[FE Incremental Coverage Report]

pass : 0 / 0 (0%)

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

[BE Incremental Coverage Report]

pass : 54 / 60 (90.00%)

file detail

path covered_line new_line coverage not_covered_line_detail
🔵 be/src/storage/rowset/segment_iterator.cpp 0 3 00.00% [1115, 1117, 1118]
🔵 be/src/storage/lake/vacuum.cpp 3 4 75.00% [390]
🔵 be/src/storage/lake/meta_file.cpp 7 8 87.50% [1287]
🔵 be/src/storage/lake/rowset_update_state.cpp 13 14 92.86% [621]
🔵 be/src/storage/lake/filenames.h 5 5 100.00% []
🔵 be/src/storage/lake/update_manager.cpp 2 2 100.00% []
🔵 be/src/storage/rowset/segment_file_info.cpp 2 2 100.00% []
🔵 be/src/storage/rowset/segment_rewriter.cpp 5 5 100.00% []
🔵 be/src/storage/lake/general_tablet_writer.cpp 4 4 100.00% []
🔵 be/src/storage/lake/rowset.cpp 3 3 100.00% []
🔵 be/src/storage/lake/vector_index_build_task.cpp 8 8 100.00% []
🔵 be/src/storage/lake/transactions.cpp 2 2 100.00% []

@sevev sevev merged commit fa08e4f into StarRocks:main Jul 3, 2026
60 of 61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants