Skip to content

Commit 08d49f4

Browse files
lintingbinclaude
andauthored
[AMORO-4163][ams] Fix Version-N-already-exists race in newTableOperations for legacy mixed-iceberg (#4185)
When AMS saves a new legacy mixed-iceberg table to the database, a background table-explorer thread can concurrently pick up the same table and call newTableOperations(), which now commits the mixed-format properties to the Iceberg metadata (introduced by the AMORO-4163 fix). If the background thread wins the race and writes v2.metadata.json before the onTableCreated() path attempts the same commit, HadoopTableOperations throws CommitFailedException: "Version 2 already exists", aborting the createTableMeta RPC. Fix: catch CommitFailedException in the commit block, refresh to obtain the latest on-disk metadata, and proceed if a concurrent writer already committed the correct properties. Re-throw only when the properties still differ after refresh, indicating a genuine commit conflict. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ec2a448 commit 08d49f4

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

amoro-ams/src/main/java/org/apache/amoro/server/table/internal/InternalMixedIcebergHandler.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.hadoop.fs.Path;
3333
import org.apache.iceberg.TableOperations;
3434
import org.apache.iceberg.catalog.TableIdentifier;
35+
import org.apache.iceberg.exceptions.CommitFailedException;
3536

3637
import java.util.Map;
3738

@@ -81,7 +82,18 @@ private TableOperations newTableOperations(boolean changeStore) {
8182
org.apache.iceberg.TableMetadata legacyCurrent = legacyTableMetadata(current, changeStore);
8283
if (!current.equals(legacyCurrent)) {
8384
// add rest based mixed-format table properties
84-
ops.commit(current, legacyCurrent);
85+
try {
86+
ops.commit(current, legacyCurrent);
87+
} catch (CommitFailedException e) {
88+
// A concurrent caller (e.g. background table-explorer racing with onTableCreated) may
89+
// have already committed the same property update. Refresh to get the latest metadata;
90+
// if properties are now up-to-date, proceed normally. Otherwise re-throw.
91+
current = ops.refresh();
92+
legacyCurrent = legacyTableMetadata(current, changeStore);
93+
if (!current.equals(legacyCurrent)) {
94+
throw e;
95+
}
96+
}
8597
}
8698
return ops;
8799
}

0 commit comments

Comments
 (0)