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

(polaris) branch main updated: Avoid re-reading view metadata from storage after a commit (#5238)

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

dimas-b 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 0ead1daed4 Avoid re-reading view metadata from storage after a commit (#5238)
0ead1daed4 is described below

commit 0ead1daed4fe722c74c6132de45b48b3555e1332
Author: Ayush Saxena <ay...@apache.org>
AuthorDate: Thu Aug 13 04:18:59 2026 +0530

    Avoid re-reading view metadata from storage after a commit (#5238)
---
 .../core/config/BehaviorChangeConfiguration.java   | 11 +++++
 .../catalog/iceberg/LocalIcebergCatalog.java       | 20 ++++++++-
 .../iceberg/AbstractLocalIcebergCatalogTest.java   | 48 ++++++++++++++++++++++
 .../flags-polaris_behavior_changes.md              |  9 ++++
 4 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/polaris-core/src/main/java/org/apache/polaris/core/config/BehaviorChangeConfiguration.java b/polaris-core/src/main/java/org/apache/polaris/core/config/BehaviorChangeConfiguration.java
index 0a9e5bde3b..a4171236f1 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/config/BehaviorChangeConfiguration.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/config/BehaviorChangeConfiguration.java
@@ -75,6 +75,17 @@ public class BehaviorChangeConfiguration<T> extends PolarisConfiguration<T> {
               .defaultValue(true)
               .buildBehaviorChangeConfiguration();
 
+  public static final BehaviorChangeConfiguration<Boolean>
+      VIEW_OPERATIONS_MAKE_METADATA_CURRENT_ON_COMMIT =
+          PolarisConfiguration.<Boolean>builder()
+              .key("VIEW_OPERATIONS_MAKE_METADATA_CURRENT_ON_COMMIT")
+              .description(
+                  "If true, BasePolarisViewOperations should mark the metadata that is passed into"
+                      + " `commit` as current, and reuse it to skip a trip to object storage to re-construct"
+                      + " the committed metadata again.")
+              .defaultValue(true)
+              .buildBehaviorChangeConfiguration();
+
   public static final BehaviorChangeConfiguration<Boolean> ALLOW_NAMESPACE_CUSTOM_LOCATION =
       PolarisConfiguration.<Boolean>builder()
           .key("ALLOW_NAMESPACE_CUSTOM_LOCATION")
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java
index 1cea9890c3..2f3d998879 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java
@@ -1023,9 +1023,17 @@ public class LocalIcebergCatalog extends BaseMetastoreViewCatalog
   }
 
   @VisibleForTesting
+  public ViewOperations newViewOps(
+      TableIdentifier identifier, boolean makeMetadataCurrentOnCommit) {
+    return new BasePolarisViewOperations(catalogFileIO, identifier, makeMetadataCurrentOnCommit);
+  }
+
   @Override
   protected ViewOperations newViewOps(TableIdentifier identifier) {
-    return new BasePolarisViewOperations(catalogFileIO, identifier);
+    boolean makeMetadataCurrentOnCommit =
+        realmConfig.getConfig(
+            BehaviorChangeConfiguration.VIEW_OPERATIONS_MAKE_METADATA_CURRENT_ON_COMMIT);
+    return newViewOps(identifier, makeMetadataCurrentOnCommit);
   }
 
   /**
@@ -2218,12 +2226,15 @@ public class LocalIcebergCatalog extends BaseMetastoreViewCatalog
       implements ViewOperations {
     private final TableIdentifier identifier;
     private final String fullViewName;
+    private final boolean makeMetadataCurrentOnCommit;
     private FileIO viewFileIO;
 
-    BasePolarisViewOperations(FileIO defaultFileIO, TableIdentifier identifier) {
+    BasePolarisViewOperations(
+        FileIO defaultFileIO, TableIdentifier identifier, boolean makeMetadataCurrentOnCommit) {
       this.viewFileIO = defaultFileIO;
       this.identifier = identifier;
       this.fullViewName = ViewUtil.fullViewName(catalogName, identifier);
+      this.makeMetadataCurrentOnCommit = makeMetadataCurrentOnCommit;
     }
 
     @Override
@@ -2459,6 +2470,11 @@ public class LocalIcebergCatalog extends BaseMetastoreViewCatalog
         } else {
           updateTableLike(identifier, entity, true);
         }
+        if (makeMetadataCurrentOnCommit) {
+          currentMetadata =
+              ViewMetadata.buildFrom(metadata).setMetadataLocation(newLocation).build();
+          currentMetadataLocation = newLocation;
+        }
         writeSucceeded = true;
       } finally {
         if (!writeSucceeded && writeResult.written()) {
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 8da58c833c..d5ec17e1f9 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
@@ -102,6 +102,7 @@ import org.apache.iceberg.exceptions.ValidationException;
 import org.apache.iceberg.inmemory.InMemoryFileIO;
 import org.apache.iceberg.io.CloseableIterable;
 import org.apache.iceberg.io.FileIO;
+import org.apache.iceberg.io.InputFile;
 import org.apache.iceberg.rest.requests.UpdateTableRequest;
 import org.apache.iceberg.types.Types;
 import org.apache.iceberg.util.CharSequenceSet;
@@ -110,6 +111,7 @@ import org.apache.iceberg.view.ImmutableSQLViewRepresentation;
 import org.apache.iceberg.view.ImmutableViewVersion;
 import org.apache.iceberg.view.ViewMetadata;
 import org.apache.iceberg.view.ViewMetadataParser;
+import org.apache.iceberg.view.ViewOperations;
 import org.apache.polaris.core.PolarisCallContext;
 import org.apache.polaris.core.PolarisDiagnostics;
 import org.apache.polaris.core.admin.model.AwsStorageConfigInfo;
@@ -3053,6 +3055,52 @@ public abstract class AbstractLocalIcebergCatalogTest extends CatalogTests<Local
     }
   }
 
+  @ParameterizedTest
+  @ValueSource(booleans = {false, true})
+  public void testViewOperationsDoesNotRefreshAfterCommit(boolean updateMetadataOnCommit) {
+    Assumptions.assumeTrue(
+        requiresNamespaceCreate(),
+        "Only applicable if namespaces must be created before adding children");
+
+    catalog.createNamespace(NS);
+    catalog
+        .buildView(TABLE)
+        .withSchema(SCHEMA)
+        .withDefaultNamespace(NS)
+        .withQuery("spark", VIEW_QUERY)
+        .create();
+
+    ViewOperations ops = catalog.newViewOps(TABLE, updateMetadataOnCommit);
+
+    try (MockedStatic<ViewMetadataParser> mocked =
+        Mockito.mockStatic(ViewMetadataParser.class, Mockito.CALLS_REAL_METHODS)) {
+      ViewMetadata base1 = ops.current();
+      mocked.verify(() -> ViewMetadataParser.read(Mockito.any(InputFile.class)), Mockito.times(1));
+
+      ViewMetadata base2 = ops.refresh();
+      mocked.verify(() -> ViewMetadataParser.read(Mockito.any(InputFile.class)), Mockito.times(1));
+
+      Assertions.assertThat(base1.metadataFileLocation()).isEqualTo(base2.metadataFileLocation());
+
+      ViewMetadata newMetadata =
+          ViewMetadata.buildFrom(base2).setProperties(Map.of("new_prop", "new_value")).build();
+      ops.commit(base2, newMetadata);
+      mocked.verify(() -> ViewMetadataParser.read(Mockito.any(InputFile.class)), Mockito.times(1));
+
+      ops.current();
+      int expectedReads = updateMetadataOnCommit ? 1 : 2;
+      mocked.verify(
+          () -> ViewMetadataParser.read(Mockito.any(InputFile.class)),
+          Mockito.times(expectedReads));
+      ops.refresh();
+      mocked.verify(
+          () -> ViewMetadataParser.read(Mockito.any(InputFile.class)),
+          Mockito.times(expectedReads));
+    } finally {
+      catalog.dropView(TABLE);
+    }
+  }
+
   private boolean metadataFileExists(String location) {
     try {
       return fileIO.newInputFile(location).exists();
diff --git a/site/content/in-dev/unreleased/configuration/config-sections/flags-polaris_behavior_changes.md b/site/content/in-dev/unreleased/configuration/config-sections/flags-polaris_behavior_changes.md
index b25475e8b8..68c1b177d9 100644
--- a/site/content/in-dev/unreleased/configuration/config-sections/flags-polaris_behavior_changes.md
+++ b/site/content/in-dev/unreleased/configuration/config-sections/flags-polaris_behavior_changes.md
@@ -79,3 +79,12 @@ If true, validate that view locations don't overlap when views are created
 - **Default:** `true`
 
 ---
+
+##### `polaris.behavior-changes."VIEW_OPERATIONS_MAKE_METADATA_CURRENT_ON_COMMIT"`
+
+If true, BasePolarisViewOperations should mark the metadata that is passed into `commit` as current, and reuse it to skip a trip to object storage to re-construct the committed metadata again.
+
+- **Type:** `Boolean`
+- **Default:** `true`
+
+---