flyrain commented on code in PR #14320:
URL: https://github.com/apache/iceberg/pull/14320#discussion_r2433926747


##########
core/src/main/java/org/apache/iceberg/rest/RESTTableOperations.java:
##########
@@ -155,20 +157,86 @@ public void commit(TableMetadata base, TableMetadata 
metadata) {
     // the error handler will throw necessary exceptions like 
CommitFailedException and
     // UnknownCommitStateException
     // TODO: ensure that the HTTP client lib passes HTTP client errors to the 
error handler
-    LoadTableResponse response =
-        client.post(path, request, LoadTableResponse.class, headers, 
errorHandler);
+    LoadTableResponse response;
+    try {
+      response = client.post(path, request, LoadTableResponse.class, headers, 
errorHandler);
+    } catch (CommitStateUnknownException e) {
+      // Lightweight reconciliation for snapshot-add-only updates on transient 
unknown commit state
+      if (updateType == UpdateType.SIMPLE && reconcileOnSimpleUpdate(updates, 
e)) {
+        return;
+      }
+
+      throw e;
+    }
 
     // all future commits should be simple commits
     this.updateType = UpdateType.SIMPLE;
 
     updateCurrentMetadata(response);
   }
 
+  /**
+   * Attempt best-effort reconciliation for SIMPLE updates that only add a 
snapshot.
+   *
+   * <p>Returns true if the expected snapshot is observed in the refreshed 
table state. Returns
+   * false if the expected snapshot cannot be determined, is not present after 
refresh, or if the
+   * refresh fails. In case of refresh failure, the failure is recorded as 
suppressed on the
+   * provided {@code original} exception to aid diagnostics.
+   */
+  private boolean reconcileOnSimpleUpdate(
+      List<MetadataUpdate> updates, CommitStateUnknownException original) {
+    Long expectedSnapshotId = expectedSnapshotIdIfSnapshotAddOnly(updates);
+    if (expectedSnapshotId == null) {
+      return false;
+    }
+
+    try {
+      TableMetadata refreshed = refresh();
+      return refreshed != null && refreshed.snapshot(expectedSnapshotId) != 
null;
+    } catch (RuntimeException reconEx) {
+      original.addSuppressed(reconEx);
+      return false;
+    }
+  }
+
   @Override
   public FileIO io() {
     return io;
   }
 
+  private static Long expectedSnapshotIdIfSnapshotAddOnly(List<MetadataUpdate> 
updates) {
+    Long addedSnapshotId = null;
+    Long mainRefSnapshotId = null;
+
+    for (MetadataUpdate update : updates) {
+      if (update instanceof MetadataUpdate.AddSnapshot) {
+        if (addedSnapshotId != null) {
+          return null; // multiple snapshot adds -> not safe
+        }
+        addedSnapshotId = ((MetadataUpdate.AddSnapshot) 
update).snapshot().snapshotId();
+      } else if (update instanceof MetadataUpdate.SetSnapshotRef) {
+        MetadataUpdate.SetSnapshotRef setRef = (MetadataUpdate.SetSnapshotRef) 
update;
+        if (!SnapshotRef.MAIN_BRANCH.equals(setRef.name())) {
+          return null; // only allow main ref update
+        }
+        mainRefSnapshotId = setRef.snapshotId();
+      } else {
+        // any other update type makes this not a pure snapshot-add
+        return null;
+      }
+    }
+
+    if (addedSnapshotId == null) {
+      return null;
+    }
+
+    if (mainRefSnapshotId != null && 
!addedSnapshotId.equals(mainRefSnapshotId)) {

Review Comment:
   Nit: add a comment to explain why this check needed?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to