diff --git a/agent_gradle_out.txt b/agent_gradle_out.txt new file mode 100644 index 00000000000..c77b00f0d89 Binary files /dev/null and b/agent_gradle_out.txt differ diff --git a/persistence/nosql/persistence/metastore-maintenance/src/test/java/org/apache/polaris/persistence/nosql/metastore/maintenance/TestCatalogMaintenance.java b/persistence/nosql/persistence/metastore-maintenance/src/test/java/org/apache/polaris/persistence/nosql/metastore/maintenance/TestCatalogMaintenance.java index bfe8ffd220a..2c914383976 100644 --- a/persistence/nosql/persistence/metastore-maintenance/src/test/java/org/apache/polaris/persistence/nosql/metastore/maintenance/TestCatalogMaintenance.java +++ b/persistence/nosql/persistence/metastore-maintenance/src/test/java/org/apache/polaris/persistence/nosql/metastore/maintenance/TestCatalogMaintenance.java @@ -569,8 +569,7 @@ private TestSetup bootstrapRealm() { var manager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); var session = metaStoreManagerFactory.getOrCreateSession(realmContext); - var metrics = metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); - var callCtx = new PolarisCallContext(realmContext, session, metrics, configurationSource); + var callCtx = new PolarisCallContext(realmContext, session, configurationSource); var persistence = realmPersistenceFactory.newBuilder().realmId(realmId).skipDecorators().build(); @@ -927,8 +926,7 @@ private void checkEntities(String step, List entities) { var manager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); var session = metaStoreManagerFactory.getOrCreateSession(realmContext); - var metrics = metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); - var callCtx = new PolarisCallContext(realmContext, session, metrics, configurationSource); + var callCtx = new PolarisCallContext(realmContext, session, configurationSource); for (var e : entities) { var result = diff --git a/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/NoSqlMetaStoreManagerFactory.java b/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/NoSqlMetaStoreManagerFactory.java index 63e30a4b7f6..0851b705726 100644 --- a/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/NoSqlMetaStoreManagerFactory.java +++ b/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/NoSqlMetaStoreManagerFactory.java @@ -283,11 +283,7 @@ private PrincipalSecretsResult bootstrapRealm( clock); PolarisCallContext ctx = - new PolarisCallContext( - () -> realmId, - metaStore, - NO_OP_METRICS_PERSISTENCE, - RealmConfigurationSource.EMPTY_CONFIG); + new PolarisCallContext(() -> realmId, metaStore, RealmConfigurationSource.EMPTY_CONFIG); var secretsResult = createPolarisPrincipalForRealm(metaStoreManager, ctx); realmManagement.update( diff --git a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java index 98d3fb40aa6..9949ac40670 100644 --- a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java +++ b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java @@ -105,9 +105,8 @@ protected PolarisTestMetaStoreManager createPolarisTestMetaStoreManager() { var manager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); var session = metaStoreManagerFactory.getOrCreateSession(realmContext); - var metrics = metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); - var callCtx = new PolarisCallContext(realmContext, session, metrics, configurationSource); + var callCtx = new PolarisCallContext(realmContext, session, configurationSource); return new PolarisTestMetaStoreManager(manager, callCtx, startTime, false); } diff --git a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlResolver.java b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlResolver.java index 27c99e211d8..2b6e29b319a 100644 --- a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlResolver.java +++ b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlResolver.java @@ -72,8 +72,7 @@ protected PolarisCallContext callCtx() { metaStoreManager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); var session = metaStoreManagerFactory.getOrCreateSession(realmContext); - var metrics = metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); - callCtx = new PolarisCallContext(realmContext, session, metrics, configurationSource); + callCtx = new PolarisCallContext(realmContext, session, configurationSource); tm = new PolarisTestMetaStoreManager(metaStoreManager, callCtx, startTime, false); } diff --git a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestIndexedContainerAccess.java b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestIndexedContainerAccess.java index 4e9012d44ea..1a780d476ce 100644 --- a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestIndexedContainerAccess.java +++ b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestIndexedContainerAccess.java @@ -97,9 +97,7 @@ public void setup(TestInfo testInfo) { var realmContext = (RealmContext) () -> realmId; callContext = new PolarisCallContext( - realmContext, - metaStoreManagerFactory.getOrCreateSession(realmContext), - metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext)); + realmContext, metaStoreManagerFactory.getOrCreateSession(realmContext)); metaStoreManager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); } diff --git a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestMemoizedIndexAccess.java b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestMemoizedIndexAccess.java index 77698876242..fc8319b32be 100644 --- a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestMemoizedIndexAccess.java +++ b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/indexaccess/TestMemoizedIndexAccess.java @@ -92,9 +92,7 @@ public void setup(TestInfo testInfo) { var realmContext = (RealmContext) () -> realmId; callContext = new PolarisCallContext( - realmContext, - metaStoreManagerFactory.getOrCreateSession(realmContext), - metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext)); + realmContext, metaStoreManagerFactory.getOrCreateSession(realmContext)); metaStoreManager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); memoized = MemoizedIndexedAccess.newMemoizedIndexedAccess(persistence); diff --git a/polaris-core/src/main/java/org/apache/polaris/core/PolarisCallContext.java b/polaris-core/src/main/java/org/apache/polaris/core/PolarisCallContext.java index 394f8180dd3..3379390f626 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/PolarisCallContext.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/PolarisCallContext.java @@ -25,31 +25,29 @@ import org.apache.polaris.core.context.CallContext; import org.apache.polaris.core.context.RealmContext; import org.apache.polaris.core.persistence.BasePersistence; -import org.apache.polaris.core.persistence.metrics.MetricsPersistence; import org.jspecify.annotations.NonNull; /** * The Call context is allocated each time a new REST request is processed. It contains instances of * low-level services required to process that request. * - *

{@link BasePersistence} continues to carry the bulk of the metastore SPI surface (and still - * extends {@code PolicyMappingPersistence} / acts as the {@code IntegrationPersistence} via a - * runtime cast for now). {@link MetricsPersistence} is intentionally decoupled and supplied - * separately so callers that only need metrics persistence do not have to depend on {@link - * BasePersistence}. + *

{@link BasePersistence} carries the bulk of the metastore SPI surface (and still extends + * {@code PolicyMappingPersistence} / acts as the {@code IntegrationPersistence} via a runtime cast + * for now). {@link org.apache.polaris.core.persistence.metrics.MetricsPersistence} is intentionally + * kept out of this context; service code that needs metrics persistence should depend on that SPI + * directly. */ public class PolarisCallContext implements CallContext { // meta store which is used to persist Polaris entity metadata private final BasePersistence metaStore; - private final MetricsPersistence metricsPersistence; private final RealmConfigurationSource configurationSource; private final RealmContext realmContext; private final RealmConfig realmConfig; /** * @deprecated Use {@link PolarisCallContext#PolarisCallContext(RealmContext, BasePersistence, - * MetricsPersistence, RealmConfigurationSource)}. + * RealmConfigurationSource)}. */ @SuppressWarnings("removal") @Deprecated(forRemoval = true) @@ -57,61 +55,29 @@ public PolarisCallContext( @NonNull RealmContext realmContext, @NonNull BasePersistence metaStore, @NonNull PolarisConfigurationStore configurationStore) { - this( - realmContext, metaStore, new MetricsPersistence() {}, configurationStore::getConfiguration); + this(realmContext, metaStore, configurationStore::getConfiguration); } - /** - * Convenience constructor for backends whose {@link BasePersistence} implementation also - * implements {@link MetricsPersistence} (the common in-tree case). Callers that need to wire a - * distinct metrics implementation should use {@link #PolarisCallContext(RealmContext, - * BasePersistence, MetricsPersistence, RealmConfigurationSource)}. - */ - public

PolarisCallContext( - @NonNull RealmContext realmContext, - @NonNull P metaStore, - @NonNull RealmConfigurationSource configurationSource) { - this(realmContext, metaStore, metaStore, configurationSource); - } - - /** Primary constructor — {@link MetricsPersistence} is supplied separately from the metastore. */ public PolarisCallContext( @NonNull RealmContext realmContext, @NonNull BasePersistence metaStore, - @NonNull MetricsPersistence metricsPersistence, @NonNull RealmConfigurationSource configurationSource) { this.realmContext = realmContext; this.metaStore = metaStore; - this.metricsPersistence = metricsPersistence; this.configurationSource = configurationSource; this.realmConfig = new RealmConfigImpl(this.configurationSource, this.realmContext); } /** Convenience constructor that defaults to {@link RealmConfigurationSource#EMPTY_CONFIG}. */ public PolarisCallContext( - @NonNull RealmContext realmContext, - @NonNull BasePersistence metaStore, - @NonNull MetricsPersistence metricsPersistence) { - this(realmContext, metaStore, metricsPersistence, RealmConfigurationSource.EMPTY_CONFIG); - } - - /** - * Convenience constructor for callers whose persistence type satisfies both SPIs and who do not - * have a {@link RealmConfigurationSource}. - */ - public

PolarisCallContext( - @NonNull RealmContext realmContext, @NonNull P metaStore) { - this(realmContext, metaStore, metaStore, RealmConfigurationSource.EMPTY_CONFIG); + @NonNull RealmContext realmContext, @NonNull BasePersistence metaStore) { + this(realmContext, metaStore, RealmConfigurationSource.EMPTY_CONFIG); } public BasePersistence getMetaStore() { return metaStore; } - public MetricsPersistence getMetricsPersistence() { - return metricsPersistence; - } - @Override public RealmContext getRealmContext() { return realmContext; @@ -136,7 +102,6 @@ public PolarisCallContext copy() { // copy of the RealmContext to ensure the access during the task executor. String realmId = this.realmContext.getRealmIdentifier(); RealmContext realmContext = () -> realmId; - return new PolarisCallContext( - realmContext, this.metaStore, this.metricsPersistence, this.configurationSource); + return new PolarisCallContext(realmContext, this.metaStore, this.configurationSource); } } diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisMetaStoreManager.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisMetaStoreManager.java index 35c8c72221c..939d1f76258 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisMetaStoreManager.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisMetaStoreManager.java @@ -48,7 +48,6 @@ import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntitiesResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; -import org.apache.polaris.core.persistence.metrics.PolarisMetricsManager; import org.apache.polaris.core.persistence.pagination.Page; import org.apache.polaris.core.persistence.pagination.PageToken; import org.apache.polaris.core.policy.PolarisPolicyMappingManager; @@ -63,8 +62,7 @@ public interface PolarisMetaStoreManager extends PolarisSecretsManager, PolarisGrantManager, PolarisPolicyMappingManager, - PolarisEventManager, - PolarisMetricsManager { + PolarisEventManager { /** * Bootstrap the Polaris service, creating the root catalog, root principal, and associated diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/MetricsPersistence.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/MetricsPersistence.java index bec34a97a12..881fa5b8ba8 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/MetricsPersistence.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/MetricsPersistence.java @@ -42,8 +42,6 @@ * *

Note: This SPI is currently experimental and not yet implemented in all persistence * backends. The API may change in future releases. - * - * @see PolarisMetricsManager */ @Beta public interface MetricsPersistence { diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/PolarisMetricsManager.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/PolarisMetricsManager.java deleted file mode 100644 index 1d2885d0d94..00000000000 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/metrics/PolarisMetricsManager.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.polaris.core.persistence.metrics; - -import org.apache.polaris.core.PolarisCallContext; -import org.jspecify.annotations.NonNull; - -/** - * Interface for managing Iceberg metrics persistence through the metastore manager layer. - * - *

This follows the same pattern as {@link org.apache.polaris.core.entity.PolarisEventManager}, - * providing a high-level interface that delegates to the underlying persistence layer. - * - *

The service layer should interact with this interface (via {@link - * org.apache.polaris.core.persistence.PolarisMetaStoreManager}) rather than directly accessing - * persistence implementations. - * - *

Request context (principal name, request ID, OTEL trace/span IDs) should be populated in the - * record by the caller before invoking these methods. This keeps the SPI simple with a single - * method parameter containing all the data needed for persistence. - * - *

Since {@link org.apache.polaris.core.persistence.BasePersistence} now extends {@link - * MetricsPersistence} with default no-op implementations, all persistence backends automatically - * support this interface. Backends that want actual metrics persistence (e.g., JDBC) override the - * methods; others use the default no-op behavior. - */ -public interface PolarisMetricsManager { - - /** - * Writes a scan metrics record to the persistence layer. - * - *

Delegates to the underlying {@link MetricsPersistence#writeScanReport} method. If the - * persistence backend doesn't override the default implementation, this is a no-op. - * - *

The record should contain all request context fields (principalName, requestId, otelTraceId, - * otelSpanId) populated by the caller. - * - * @param callCtx the call context containing the persistence layer - * @param record the scan metrics record to persist (including request context) - */ - default void writeScanMetrics( - @NonNull PolarisCallContext callCtx, @NonNull ScanMetricsRecord record) { - callCtx.getMetricsPersistence().writeScanReport(record); - } - - /** - * Writes a commit metrics record to the persistence layer. - * - *

Delegates to the underlying {@link MetricsPersistence#writeCommitReport} method. If the - * persistence backend doesn't override the default implementation, this is a no-op. - * - *

The record should contain all request context fields (principalName, requestId, otelTraceId, - * otelSpanId) populated by the caller. - * - * @param callCtx the call context containing the persistence layer - * @param record the commit metrics record to persist (including request context) - */ - default void writeCommitMetrics( - @NonNull PolarisCallContext callCtx, @NonNull CommitMetricsRecord record) { - callCtx.getMetricsPersistence().writeCommitReport(record); - } -} diff --git a/polaris-core/src/test/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManagerRefreshTest.java b/polaris-core/src/test/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManagerRefreshTest.java index 189d0d2f7bc..d19d47c9397 100644 --- a/polaris-core/src/test/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManagerRefreshTest.java +++ b/polaris-core/src/test/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManagerRefreshTest.java @@ -36,7 +36,6 @@ import org.apache.polaris.core.entity.PolarisEntityType; import org.apache.polaris.core.persistence.dao.entity.BaseResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; -import org.apache.polaris.core.persistence.metrics.MetricsPersistence; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -58,7 +57,7 @@ public class AtomicOperationMetaStoreManagerRefreshTest { public void setUp() { diagnostics = new PolarisDefaultDiagServiceImpl(); metaStore = Mockito.mock(BasePersistence.class); - callCtx = new PolarisCallContext(() -> "testRealm", metaStore, new MetricsPersistence() {}); + callCtx = new PolarisCallContext(() -> "testRealm", metaStore); manager = new AtomicOperationMetaStoreManager(Clock.systemUTC(), diagnostics); } diff --git a/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java b/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java index ebf57e67fd4..54bbdf4975b 100644 --- a/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java +++ b/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java @@ -140,13 +140,14 @@ public CallContext polarisCallContext( RealmConfigurationSource configurationSource, MetaStoreManagerFactory metaStoreManagerFactory) { BasePersistence metaStore = metaStoreManagerFactory.getOrCreateSession(realmContext); - // When the backend implements both SPIs on the same instance (e.g. JDBC, in-memory), reuse the - // session instead of building a second persistence instance per request. - MetricsPersistence metricsPersistence = - (metaStore instanceof MetricsPersistence mp) - ? mp - : metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); - return new PolarisCallContext(realmContext, metaStore, metricsPersistence, configurationSource); + return new PolarisCallContext(realmContext, metaStore, configurationSource); + } + + @Produces + @RequestScoped + public MetricsPersistence metricsPersistence( + RealmContext realmContext, MetaStoreManagerFactory metaStoreManagerFactory) { + return metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); } @Produces diff --git a/runtime/service/src/main/java/org/apache/polaris/service/events/listeners/inmemory/InMemoryBufferEventListener.java b/runtime/service/src/main/java/org/apache/polaris/service/events/listeners/inmemory/InMemoryBufferEventListener.java index 8a6aee707a6..f626b1b45ac 100644 --- a/runtime/service/src/main/java/org/apache/polaris/service/events/listeners/inmemory/InMemoryBufferEventListener.java +++ b/runtime/service/src/main/java/org/apache/polaris/service/events/listeners/inmemory/InMemoryBufferEventListener.java @@ -109,8 +109,7 @@ protected void flush(String realmId, List events) { RealmContext realmContext = () -> realmId; var metaStoreManager = metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); var basePersistence = metaStoreManagerFactory.getOrCreateSession(realmContext); - var metricsPersistence = metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext); - var callContext = new PolarisCallContext(realmContext, basePersistence, metricsPersistence); + var callContext = new PolarisCallContext(realmContext, basePersistence); metaStoreManager.writeEvents(callContext, events); } diff --git a/runtime/service/src/main/java/org/apache/polaris/service/reporting/PersistingMetricsReporter.java b/runtime/service/src/main/java/org/apache/polaris/service/reporting/PersistingMetricsReporter.java index 8703d3b8db5..8925213819e 100644 --- a/runtime/service/src/main/java/org/apache/polaris/service/reporting/PersistingMetricsReporter.java +++ b/runtime/service/src/main/java/org/apache/polaris/service/reporting/PersistingMetricsReporter.java @@ -30,32 +30,29 @@ import org.apache.iceberg.metrics.MetricsReport; import org.apache.iceberg.metrics.ScanReport; import org.apache.polaris.core.auth.PolarisPrincipal; -import org.apache.polaris.core.context.CallContext; import org.apache.polaris.core.context.RequestIdSupplier; import org.apache.polaris.core.metrics.iceberg.MetricsRecordConverter; -import org.apache.polaris.core.persistence.PolarisMetaStoreManager; import org.apache.polaris.core.persistence.metrics.CommitMetricsRecord; +import org.apache.polaris.core.persistence.metrics.MetricsPersistence; import org.apache.polaris.core.persistence.metrics.ScanMetricsRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Implementation of {@link PolarisMetricsReporter} that persists metrics using the {@link - * PolarisMetaStoreManager} from the current {@link CallContext}. + * Implementation of {@link PolarisMetricsReporter} that persists metrics via the request-scoped + * {@link MetricsPersistence} backend. * *

This reporter is selected when {@code polaris.iceberg-metrics.reporting.type} is set to {@code * "persisting"}. * - *

The reporter uses {@link PolarisMetaStoreManager} to persist metrics, following the same - * abstraction pattern as other Polaris operations. If the underlying persistence does not support - * metrics, they are silently discarded. + *

If the underlying persistence does not support metrics, they are silently discarded. * *

The reporter receives catalog and table IDs from the caller (already resolved during * authorization), avoiding redundant entity lookups. It uses {@link MetricsRecordConverter} to * convert Iceberg metrics reports to SPI records before persisting them. * * @see PolarisMetricsReporter - * @see PolarisMetaStoreManager + * @see MetricsPersistence * @see MetricsRecordConverter */ @RequestScoped @@ -63,19 +60,16 @@ public class PersistingMetricsReporter implements PolarisMetricsReporter { private static final Logger LOGGER = LoggerFactory.getLogger(PersistingMetricsReporter.class); - private final CallContext callContext; - private final PolarisMetaStoreManager metaStoreManager; + private final MetricsPersistence metricsPersistence; private final Instance polarisPrincipal; private final Instance requestIdSupplier; @Inject public PersistingMetricsReporter( - CallContext callContext, - PolarisMetaStoreManager metaStoreManager, + MetricsPersistence metricsPersistence, Instance polarisPrincipal, Instance requestIdSupplier) { - this.callContext = callContext; - this.metaStoreManager = metaStoreManager; + this.metricsPersistence = metricsPersistence; this.polarisPrincipal = polarisPrincipal; this.requestIdSupplier = requestIdSupplier; } @@ -113,7 +107,7 @@ public void reportMetric( .otelTraceId(otelTraceId) .otelSpanId(otelSpanId) .build(); - metaStoreManager.writeScanMetrics(callContext.getPolarisCallContext(), record); + metricsPersistence.writeScanReport(record); LOGGER.debug( "Persisted scan metrics for {}.{} (reportId={})", catalogName, table, record.reportId()); } else if (metricsReport instanceof CommitReport commitReport) { @@ -127,7 +121,7 @@ public void reportMetric( .otelTraceId(otelTraceId) .otelSpanId(otelSpanId) .build(); - metaStoreManager.writeCommitMetrics(callContext.getPolarisCallContext(), record); + metricsPersistence.writeCommitReport(record); LOGGER.debug( "Persisted commit metrics for {}.{} (reportId={})", catalogName, diff --git a/runtime/service/src/test/java/org/apache/polaris/service/reporting/PersistingMetricsReporterTest.java b/runtime/service/src/test/java/org/apache/polaris/service/reporting/PersistingMetricsReporterTest.java index 88face5b245..ac76f8dcc1d 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/reporting/PersistingMetricsReporterTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/reporting/PersistingMetricsReporterTest.java @@ -40,12 +40,10 @@ import org.apache.iceberg.metrics.ScanMetrics; import org.apache.iceberg.metrics.ScanMetricsResult; import org.apache.iceberg.metrics.ScanReport; -import org.apache.polaris.core.PolarisCallContext; import org.apache.polaris.core.auth.PolarisPrincipal; -import org.apache.polaris.core.context.CallContext; import org.apache.polaris.core.context.RequestIdSupplier; -import org.apache.polaris.core.persistence.PolarisMetaStoreManager; import org.apache.polaris.core.persistence.metrics.CommitMetricsRecord; +import org.apache.polaris.core.persistence.metrics.MetricsPersistence; import org.apache.polaris.core.persistence.metrics.ScanMetricsRecord; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -56,7 +54,7 @@ * *

Note: The reporter now receives catalogId and tableId directly from the caller (already * resolved during authorization in IcebergCatalogHandler), so there's no need to mock entity - * lookups. The reporter uses {@link PolarisMetaStoreManager} to persist metrics. + * lookups. The reporter uses {@link MetricsPersistence} to persist metrics. */ public class PersistingMetricsReporterTest { @@ -67,20 +65,13 @@ public class PersistingMetricsReporterTest { private static final TableIdentifier TABLE_IDENTIFIER = TableIdentifier.of(Namespace.of("db", "schema"), TABLE_NAME); - private PolarisMetaStoreManager metaStoreManager; - private PolarisCallContext polarisCallContext; + private MetricsPersistence metricsPersistence; private PersistingMetricsReporter reporter; @SuppressWarnings("unchecked") @BeforeEach void setUp() { - // Mock PolarisMetaStoreManager - metaStoreManager = mock(PolarisMetaStoreManager.class); - - // Mock CallContext - CallContext callContext = mock(CallContext.class); - polarisCallContext = mock(PolarisCallContext.class); - when(callContext.getPolarisCallContext()).thenReturn(polarisCallContext); + metricsPersistence = mock(MetricsPersistence.class); // Mock Instance beans (not resolvable in test context) Instance principalInstance = mock(Instance.class); @@ -90,8 +81,7 @@ void setUp() { when(requestIdInstance.isResolvable()).thenReturn(false); reporter = - new PersistingMetricsReporter( - callContext, metaStoreManager, principalInstance, requestIdInstance); + new PersistingMetricsReporter(metricsPersistence, principalInstance, requestIdInstance); } @Test @@ -103,9 +93,9 @@ void testReportScanMetrics() { reporter.reportMetric( CATALOG_NAME, CATALOG_ID, TABLE_IDENTIFIER, TABLE_ID, scanReport, Instant.now()); - // Verify metaStoreManager was called with correct record + // Verify metricsPersistence was called with correct record ArgumentCaptor captor = ArgumentCaptor.forClass(ScanMetricsRecord.class); - verify(metaStoreManager).writeScanMetrics(any(PolarisCallContext.class), captor.capture()); + verify(metricsPersistence).writeScanReport(captor.capture()); ScanMetricsRecord record = captor.getValue(); assertThat(record.catalogId()).isEqualTo(CATALOG_ID); @@ -122,9 +112,9 @@ void testReportCommitMetrics() { reporter.reportMetric( CATALOG_NAME, CATALOG_ID, TABLE_IDENTIFIER, TABLE_ID, commitReport, Instant.now()); - // Verify metaStoreManager was called with correct record + // Verify metricsPersistence was called with correct record ArgumentCaptor captor = ArgumentCaptor.forClass(CommitMetricsRecord.class); - verify(metaStoreManager).writeCommitMetrics(any(PolarisCallContext.class), captor.capture()); + verify(metricsPersistence).writeCommitReport(captor.capture()); CommitMetricsRecord record = captor.getValue(); assertThat(record.catalogId()).isEqualTo(CATALOG_ID); @@ -141,9 +131,9 @@ void testUnknownReportType() { reporter.reportMetric( CATALOG_NAME, CATALOG_ID, TABLE_IDENTIFIER, TABLE_ID, unknownReport, Instant.now()); - // Verify metaStoreManager was NOT called since report type is unknown - verify(metaStoreManager, never()).writeScanMetrics(any(), any()); - verify(metaStoreManager, never()).writeCommitMetrics(any(), any()); + // Verify metricsPersistence was NOT called since report type is unknown + verify(metricsPersistence, never()).writeScanReport(any()); + verify(metricsPersistence, never()).writeCommitReport(any()); } private ScanReport createScanReport() { diff --git a/runtime/service/src/test/java/org/apache/polaris/service/test/PolarisIntegrationTestFixture.java b/runtime/service/src/test/java/org/apache/polaris/service/test/PolarisIntegrationTestFixture.java index 74240efcb13..a987ab3efb8 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/test/PolarisIntegrationTestFixture.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/test/PolarisIntegrationTestFixture.java @@ -107,7 +107,6 @@ private PolarisPrincipalSecrets fetchAdminSecrets() { new PolarisCallContext( realmContext, helper.metaStoreManagerFactory.getOrCreateSession(realmContext), - helper.metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext), helper.configurationSource); PolarisMetaStoreManager metaStoreManager = helper.metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext); diff --git a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java index ce52a212023..bb4779eedf7 100644 --- a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java +++ b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java @@ -232,7 +232,6 @@ public TestServices build() { new PolarisCallContext( realmContext, metaStoreManagerFactory.getOrCreateSession(realmContext), - metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext), configurationSource); PolarisMetaStoreManager metaStoreManager = @@ -471,7 +470,6 @@ public PolarisCallContext newCallContext() { return new PolarisCallContext( realmContext, metaStoreManagerFactory.getOrCreateSession(realmContext), - metaStoreManagerFactory.getOrCreateMetricsPersistence(realmContext), configurationSource); } }