You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by yu...@apache.org on 2026/06/17 01:12:11 UTC

(polaris) branch main updated: Fix: retry logic for table commits in CatalogHandlerUtils (#4748)

This is an automated email from the ASF dual-hosted git repository.

flyrain pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new 638247647c Fix: retry logic for table commits in CatalogHandlerUtils (#4748)
638247647c is described below

commit 638247647c27667697675df01d2163043121e656
Author: Ayush Saxena <ay...@apache.org>
AuthorDate: Wed Jun 17 06:42:07 2026 +0530

    Fix: retry logic for table commits in CatalogHandlerUtils (#4748)
---
 .../catalog/iceberg/CatalogHandlerUtils.java       |  1 +
 .../iceberg/AbstractLocalIcebergCatalogTest.java   | 39 ++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/CatalogHandlerUtils.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/CatalogHandlerUtils.java
index 1e7a602c3d..8aedda1925 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/CatalogHandlerUtils.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/CatalogHandlerUtils.java
@@ -420,6 +420,7 @@ public class CatalogHandlerUtils {
           .run(
               taskOps -> {
                 TableMetadata base = isRetry.get() ? taskOps.refresh() : taskOps.current();
+                isRetry.set(true);
 
                 TableMetadata.Builder metadataBuilder = TableMetadata.buildFrom(base);
                 TableMetadata newBase = base;
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogTest.java
index a7f36a943e..e0222dd3ec 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogTest.java
@@ -53,6 +53,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -858,6 +859,44 @@ public abstract class AbstractLocalIcebergCatalogTest extends CatalogTests<Local
     this.assertFiles(catalog.loadTable(TABLE), FILE_B);
   }
 
+  @Test
+  public void testCommitRetriesWithRefreshOnFailure() {
+    LocalIcebergCatalog catalog = this.catalog();
+    if (this.requiresNamespaceCreate()) {
+      catalog.createNamespace(NS);
+    }
+
+    catalog.buildTable(TABLE, SCHEMA).withPartitionSpec(SPEC).create();
+    catalog.loadTable(TABLE).newFastAppend().appendFile(FILE_A).commit();
+
+    TableOperations realOps = ((BaseTable) catalog.loadTable(TABLE)).operations();
+    List<MetadataUpdate> updates =
+        List.of(new MetadataUpdate.SetProperties(Map.of("test-key", "test-value")));
+    List<UpdateRequirement> requirements =
+        List.of(new UpdateRequirement.AssertTableUUID(realOps.current().uuid()));
+    UpdateTableRequest request = UpdateTableRequest.create(TABLE, requirements, updates);
+
+    TableOperations spyOps = spy(realOps);
+    AtomicBoolean firstCommit = new AtomicBoolean(true);
+    doAnswer(
+            invocation -> {
+              if (firstCommit.compareAndSet(true, false)) {
+                // Perform a real concurrent modification through the catalog
+                catalog.loadTable(TABLE).newFastAppend().appendFile(FILE_B).commit();
+                throw new CommitFailedException("concurrent modification detected");
+              }
+              return invocation.callRealMethod();
+            })
+        .when(spyOps)
+        .commit(any(), any());
+
+    CatalogHandlerUtils catalogHandlerUtils = new CatalogHandlerUtils(5, false);
+    TableMetadata result = catalogHandlerUtils.commit(spyOps, request);
+
+    Mockito.verify(spyOps, Mockito.atLeastOnce()).refresh();
+    Assertions.assertThat(result.properties()).containsEntry("test-key", "test-value");
+  }
+
   @Test
   public void testValidateNotificationWhenTableAndNamespacesDontExist() {
     Assumptions.assumeTrue(