-
Notifications
You must be signed in to change notification settings - Fork 3k
Core: Make sequence number conflicts retryable in concurrent commits #15126
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
44f6059
b14cbfe
5ace567
8732caf
0f65a65
24c66b4
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 |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
| package org.apache.iceberg; | ||
|
|
||
| import com.google.errorprone.annotations.FormatMethod; | ||
| import org.apache.iceberg.exceptions.ValidationException; | ||
|
|
||
| /** | ||
| * A {@link ValidationException} that indicates the client can retry with refreshed metadata. | ||
| * | ||
| * <p>This is used for validation failures caused by concurrent commits, such as sequence number | ||
| * conflicts. Server-side retry won't help since the conflict is in the request itself, but the | ||
| * client can retry after refreshing its metadata. | ||
| */ | ||
| public class RetryableValidationException extends ValidationException { | ||
agnes-xinyi-lu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @FormatMethod | ||
| public RetryableValidationException(String message, Object... args) { | ||
| super(message, args); | ||
| } | ||
|
|
||
| @FormatMethod | ||
| public RetryableValidationException(Throwable cause, String message, Object... args) { | ||
| super(cause, message, args); | ||
| } | ||
|
|
||
| @FormatMethod | ||
| public static void check(boolean test, String message, Object... args) { | ||
| if (!test) { | ||
| throw new RetryableValidationException(message, args); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1250,7 +1250,7 @@ public Builder addSnapshot(Snapshot snapshot) { | |
| "Snapshot already exists for id: %s", | ||
| snapshot.snapshotId()); | ||
|
|
||
| ValidationException.check( | ||
| RetryableValidationException.check( | ||
|
Contributor
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. The first row ID check also needs to be updated. |
||
| formatVersion == 1 | ||
| || snapshot.sequenceNumber() > lastSequenceNumber | ||
| || snapshot.parentId() == null, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,7 @@ | |
| import org.apache.iceberg.IncrementalAppendScan; | ||
| import org.apache.iceberg.MetadataUpdate.UpgradeFormatVersion; | ||
| import org.apache.iceberg.PartitionSpec; | ||
| import org.apache.iceberg.RetryableValidationException; | ||
| import org.apache.iceberg.Scan; | ||
| import org.apache.iceberg.Schema; | ||
| import org.apache.iceberg.SortOrder; | ||
|
|
@@ -634,7 +635,16 @@ static TableMetadata commit(TableOperations ops, UpdateTableRequest request) { | |
|
|
||
| // apply changes | ||
| TableMetadata.Builder metadataBuilder = TableMetadata.buildFrom(base); | ||
| request.updates().forEach(update -> update.applyTo(metadataBuilder)); | ||
| try { | ||
| request.updates().forEach(update -> update.applyTo(metadataBuilder)); | ||
| } catch (RetryableValidationException e) { | ||
| // Sequence number conflicts from concurrent commits are retryable by the client, | ||
| // but server-side retry won't help since the sequence number is in the request. | ||
agnes-xinyi-lu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Wrap in ValidationFailureException to skip server retry, return to client as | ||
| // CommitFailedException so the client can retry with refreshed metadata. | ||
| throw new ValidationFailureException( | ||
| new CommitFailedException(e, "Commit conflict: %s", e.getMessage())); | ||
|
Contributor
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. This should not rethrow a different exception. Instead, add Also, this commit message is incorrect. We are not throwing
Contributor
Author
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. @rdblue this exception is only retryable on the client side, server side retries will not help because snapshot is provided by the client side. |
||
| } | ||
|
|
||
| TableMetadata updated = metadataBuilder.build(); | ||
| if (updated.changes().isEmpty()) { | ||
|
|
||
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.
This is a bit too specific to the REST context because it mentions the client.
I think that this should focus on what the problem is: a validation failed but the commit can be fixed and retried. This is specifically not a conflict.