This is an automated email from the ASF dual-hosted git repository.
amoghj pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new c6b252e97e Core: Skip unnecessary metadata refresh when producing
snapshot event after merge append (#14709)
c6b252e97e is described below
commit c6b252e97eace78cf31df1d72ff91e7e641049da
Author: gaborkaszab <[email protected]>
AuthorDate: Mon Feb 2 17:50:31 2026 +0100
Core: Skip unnecessary metadata refresh when producing snapshot event after
merge append (#14709)
---
.../apache/iceberg/MergingSnapshotProducer.java | 7 +++-
.../org/apache/iceberg/rest/RequestMatcher.java | 16 +++++++++
.../org/apache/iceberg/rest/TestRESTCatalog.java | 39 ++++++++++++++++++++--
3 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/apache/iceberg/MergingSnapshotProducer.java
b/core/src/main/java/org/apache/iceberg/MergingSnapshotProducer.java
index 51d17fbdd0..761f94a830 100644
--- a/core/src/main/java/org/apache/iceberg/MergingSnapshotProducer.java
+++ b/core/src/main/java/org/apache/iceberg/MergingSnapshotProducer.java
@@ -968,7 +968,12 @@ abstract class MergingSnapshotProducer<ThisT> extends
SnapshotProducer<ThisT> {
@Override
public Object updateEvent() {
long snapshotId = snapshotId();
- Snapshot justSaved = ops().refresh().snapshot(snapshotId);
+
+ Snapshot justSaved = ops().current().snapshot(snapshotId);
+ if (justSaved == null) {
+ justSaved = ops().refresh().snapshot(snapshotId);
+ }
+
long sequenceNumber = TableMetadata.INVALID_SEQUENCE_NUMBER;
Map<String, String> summary;
if (justSaved == null) {
diff --git a/core/src/test/java/org/apache/iceberg/rest/RequestMatcher.java
b/core/src/test/java/org/apache/iceberg/rest/RequestMatcher.java
index 18b66e7737..fb93b7c9da 100644
--- a/core/src/test/java/org/apache/iceberg/rest/RequestMatcher.java
+++ b/core/src/test/java/org/apache/iceberg/rest/RequestMatcher.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.argThat;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Predicate;
class RequestMatcher {
private RequestMatcher() {}
@@ -71,6 +72,21 @@ class RequestMatcher {
&& Objects.equals(req.body(), body));
}
+ static HTTPRequest matches(
+ HTTPRequest.HTTPMethod method,
+ String path,
+ Map<String, String> headers,
+ Map<String, String> parameters,
+ Predicate<Object> pred) {
+ return argThat(
+ req ->
+ req.method() == method
+ && req.path().equals(path)
+ && req.headers().equals(HTTPHeaders.of(headers))
+ && req.queryParameters().equals(parameters)
+ && pred.test(req.body()));
+ }
+
public static HTTPRequest containsHeaders(
HTTPRequest.HTTPMethod method, String path, Map<String, String> headers)
{
return argThat(
diff --git a/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
b/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
index ad5921c231..d03c5f9b88 100644
--- a/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
+++ b/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
@@ -86,6 +86,7 @@ import org.apache.iceberg.exceptions.ServiceFailureException;
import org.apache.iceberg.expressions.Expressions;
import org.apache.iceberg.inmemory.InMemoryCatalog;
import org.apache.iceberg.io.FileIO;
+import org.apache.iceberg.metrics.CommitReport;
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
@@ -99,6 +100,7 @@ import org.apache.iceberg.rest.auth.AuthSessionUtil;
import org.apache.iceberg.rest.auth.OAuth2Properties;
import org.apache.iceberg.rest.auth.OAuth2Util;
import org.apache.iceberg.rest.requests.CreateTableRequest;
+import org.apache.iceberg.rest.requests.ReportMetricsRequest;
import org.apache.iceberg.rest.requests.UpdateTableRequest;
import org.apache.iceberg.rest.responses.ConfigResponse;
import org.apache.iceberg.rest.responses.CreateNamespaceResponse;
@@ -3519,8 +3521,7 @@ public class TestRESTCatalog extends
CatalogTests<RESTCatalog> {
"parent",
RESTUtil.namespaceToQueryParam(parentNamespace,
expectedSeparator),
"pageToken",
- ""),
- null),
+ "")),
eq(ListNamespacesResponse.class),
any(),
any());
@@ -3648,6 +3649,40 @@ public class TestRESTCatalog extends
CatalogTests<RESTCatalog> {
.hasMessageContaining("No in-memory file found for location: " +
metadataFileLocation);
}
+ @Test
+ public void testNumLoadTableCallsForMergeAppend() {
+ RESTCatalogAdapter adapter = Mockito.spy(new
RESTCatalogAdapter(backendCatalog));
+ RESTCatalog catalog = catalog(adapter);
+
+ catalog.createNamespace(TABLE.namespace());
+ BaseTable table = (BaseTable) catalog.createTable(TABLE, SCHEMA);
+ table.newAppend().appendFile(FILE_A).commit();
+
+ // loadTable is executed once
+ Mockito.verify(adapter)
+ .execute(matches(HTTPMethod.GET, RESOURCE_PATHS.table(TABLE)), any(),
any(), any());
+
+ // CommitReport reflects the table state after the commit
+ Mockito.verify(adapter)
+ .execute(
+ matches(
+ HTTPMethod.POST,
+ RESOURCE_PATHS.metrics(TABLE),
+ Map.of(),
+ Map.of(),
+ requestObj ->
+ requestObj instanceof ReportMetricsRequest reportRequest
+ && reportRequest.report() instanceof CommitReport
commitReport
+ && commitReport.tableName().equals(table.name())
+ && commitReport.snapshotId() ==
table.currentSnapshot().snapshotId()
+ && commitReport.sequenceNumber() ==
table.currentSnapshot().sequenceNumber()
+ && commitReport.operation().equals("append")
+ &&
commitReport.commitMetrics().addedDataFiles().value() == 1),
+ any(),
+ any(),
+ any());
+ }
+
private RESTCatalog catalog(RESTCatalogAdapter adapter) {
RESTCatalog catalog =
new RESTCatalog(SessionCatalog.SessionContext.createEmpty(), (config)
-> adapter);