diff --git a/CHANGELOG.md b/CHANGELOG.md index 495a89b1af..8d378d847c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ at locations that better optimize for object storage. - The Helm chart now supports Pod Disruption Budgets (PDBs) for Polaris components. This allows users to define the minimum number of pods that must be available during voluntary disruptions, such as node maintenance. +- Feature configuration `PURGE_VIEW_METADATA_ON_DROP` was added to allow dropping views without purging their metadata files. + ### Changes - Polaris Management API clients must be prepared to deal with new attributes in `AwsStorageConfigInfo` objects. diff --git a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisRestCatalogIntegrationBase.java b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisRestCatalogIntegrationBase.java index ff0d9b7f11..4a4ab6bbf4 100644 --- a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisRestCatalogIntegrationBase.java +++ b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisRestCatalogIntegrationBase.java @@ -1199,6 +1199,32 @@ public void testDropViewStatus() { } } + @Test + public void testDropViewWithPurge() { + restCatalog.createNamespace(Namespace.of("ns1")); + TableIdentifier id = TableIdentifier.of(Namespace.of("ns1"), "view1"); + restCatalog + .buildView(id) + .withSchema(SCHEMA) + .withDefaultNamespace(Namespace.of("ns1")) + .withQuery("spark", VIEW_QUERY) + .create(); + + Catalog catalog = managementApi.getCatalog(currentCatalogName); + Map catalogProps = new HashMap<>(catalog.getProperties().toMap()); + catalogProps.put(FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "false"); + catalogProps.put(FeatureConfiguration.PURGE_VIEW_METADATA_ON_DROP.catalogConfig(), "true"); + managementApi.updateCatalog(catalog, catalogProps); + + assertThatThrownBy(() -> restCatalog.dropView(id)).isInstanceOf(ForbiddenException.class); + + catalog = managementApi.getCatalog(currentCatalogName); + catalogProps.put(FeatureConfiguration.PURGE_VIEW_METADATA_ON_DROP.catalogConfig(), "false"); + managementApi.updateCatalog(catalog, catalogProps); + + assertThatCode(() -> restCatalog.dropView(id)).doesNotThrowAnyException(); + } + @Test public void testRenameViewStatus() { String tableName = "tbl1"; diff --git a/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java b/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java index fe5d6bc6a8..e01e065a1c 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java @@ -191,6 +191,15 @@ public static void enforceFeatureEnabledOrThrow( .defaultValue(false) .buildFeatureConfiguration(); + public static final FeatureConfiguration PURGE_VIEW_METADATA_ON_DROP = + PolarisConfiguration.builder() + .key("PURGE_VIEW_METADATA_ON_DROP") + .catalogConfig("polaris.config.purge-view-metadata-on-drop") + .description( + "If set to true, Polaris will attempt to delete view metadata files when a view is dropped.") + .defaultValue(true) + .buildFeatureConfiguration(); + public static final FeatureConfiguration STORAGE_CREDENTIAL_DURATION_SECONDS = PolarisConfiguration.builder() .key("STORAGE_CREDENTIAL_DURATION_SECONDS") diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java index 7eec03595f..8102a80309 100644 --- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java +++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java @@ -801,7 +801,13 @@ protected ViewOperations newViewOps(TableIdentifier identifier) { @Override public boolean dropView(TableIdentifier identifier) { - return dropTableLike(PolarisEntitySubType.ICEBERG_VIEW, identifier, Map.of(), true).isSuccess(); + boolean purge = + callContext + .getRealmConfig() + .getConfig(FeatureConfiguration.PURGE_VIEW_METADATA_ON_DROP, catalogEntity); + + return dropTableLike(PolarisEntitySubType.ICEBERG_VIEW, identifier, Map.of(), purge) + .isSuccess(); } @Override