-
Notifications
You must be signed in to change notification settings - Fork 581
Add create-only split staging mode #6714
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -679,6 +679,7 @@ impl MetastoreService for PostgresqlMetastore { | |
| #[instrument(name = "metastore.postgres.stage_splits", skip_all, fields(split_ids))] | ||
| async fn stage_splits(&self, request: StageSplitsRequest) -> MetastoreResult<EmptyResponse> { | ||
| let index_uid: IndexUid = request.index_uid().clone(); | ||
| let create_only = request.create_only; | ||
| let splits_metadata = request.deserialize_splits_metadata()?; | ||
|
|
||
| if splits_metadata.is_empty() { | ||
|
|
@@ -745,7 +746,9 @@ impl MetastoreService for PostgresqlMetastore { | |
| node_id = excluded.node_id, | ||
| update_timestamp = CURRENT_TIMESTAMP, | ||
| create_timestamp = CURRENT_TIMESTAMP | ||
| WHERE splits.split_id = excluded.split_id AND splits.split_state = 'Staged' | ||
| WHERE splits.split_id = excluded.split_id | ||
| AND splits.split_state = 'Staged' | ||
| AND NOT $11 | ||
|
Comment on lines
+749
to
+751
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When concurrent create-only batches contain the same already-existing split IDs in different orders, this remains an Useful? React with 👍 / 👎. |
||
| RETURNING split_id; | ||
| "#) | ||
| .bind(&split_ids) | ||
|
|
@@ -758,11 +761,12 @@ impl MetastoreService for PostgresqlMetastore { | |
| .bind(&node_ids) | ||
| .bind(SplitState::Staged.as_str()) | ||
| .bind(&index_uid) | ||
| .bind(create_only) | ||
| .fetch_all(tx.as_mut()) | ||
| .await | ||
| .map_err(|sqlx_error| convert_sqlx_err(&index_uid.index_id, sqlx_error))?; | ||
|
|
||
| if upserted_split_ids.len() != split_ids.len() { | ||
| if !create_only && upserted_split_ids.len() != split_ids.len() { | ||
| let failed_split_ids: Vec<String> = split_ids | ||
| .into_iter() | ||
| .filter(|split_id| !upserted_split_ids.contains(split_id)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -388,6 +388,8 @@ message ListSplitsResponse { | |
| message StageSplitsRequest { | ||
| quickwit.common.IndexUid index_uid = 1; | ||
| string split_metadata_list_serialized_json = 2; | ||
| // Create-only mode: insert missing rows without upserting an existing split row. | ||
| bool create_only = 3; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
During a rolling or mixed-version deployment, an older metastore silently ignores unknown protobuf field 3 and executes the existing upsert path, so a new recovery client can overwrite the authoritative split row while receiving a successful response. This semantic mode needs a version-safe RPC or capability gate before callers can rely on it, or an explicitly enforced metastore-first upgrade procedure documented for this protocol change. AGENTS.md reference: AGENTS.md:L23-L24 Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| message PublishSplitsRequest { | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
When a file-backed create-only request contains only split IDs that already exist, this helper returns the same result as an insertion, and
stage_splitsconsequently returnsMutationOccurred::Yes. That makesmutaterewrite the entire index file viaput_indexfor a logical no-op, so repeated recovery retries incur unnecessary storage writes and can fail solely because storage is temporarily unavailable. Return whether an insertion occurred and aggregate that result so an all-skipped batch usesMutationOccurred::No.Useful? React with 👍 / 👎.