diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index dd33a02b02a7..068520e736ee 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -1591,6 +1591,16 @@
If this is empty, no column families are compacted.
+
+ ozone.om.compaction.service.bottommostlevelcompaction
+ 0
+ OZONE, OM, PERFORMANCE
+
+ Bottommost level compaction type for compaction.
+ Invalid values will default to kSkip.
+ Valid values: 0 (kSkip), 1 (kIfHaveCompactionFilter), 2 (kForce), 3 (kForceOptimized).
+
+
ozone.om.snapshot.compact.non.snapshot.diff.tables
diff --git a/hadoop-ozone/common/pom.xml b/hadoop-ozone/common/pom.xml
index a5318a66f838..d3fe5875630d 100644
--- a/hadoop-ozone/common/pom.xml
+++ b/hadoop-ozone/common/pom.xml
@@ -105,6 +105,10 @@
org.apache.ozone
hdds-interface-client
+
+ org.apache.ozone
+ hdds-managed-rocksdb
+
org.apache.ozone
ozone-interface-client
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
index b1209b6a2135..168b411ce398 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
@@ -20,6 +20,7 @@
import java.util.concurrent.TimeUnit;
import org.apache.hadoop.hdds.client.ReplicationFactor;
import org.apache.hadoop.hdds.client.ReplicationType;
+import org.apache.hadoop.hdds.utils.db.managed.ManagedCompactRangeOptions;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.ratis.util.TimeDuration;
@@ -681,6 +682,18 @@ public final class OMConfigKeys {
public static final String OZONE_OM_COMPACTION_SERVICE_COLUMNFAMILIES_DEFAULT =
"keyTable,fileTable,directoryTable,deletedTable,deletedDirectoryTable,multipartInfoTable,multipartPartsTable";
+ /**
+ * Bottommost level compaction type for manual compaction.
+ * Invalid values will default to kSkip.
+ * Valid values: 0 (kSkip), 1 (kIfHaveCompactionFilter), 2 (kForce), 3 (kForceOptimized).
+ * Refer to {@code org.rocksdb.CompactRangeOptions.BottommostLevelCompaction}.
+ */
+ public static final String OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION =
+ "ozone.om.compaction.service.bottommostlevelcompaction";
+ public static final ManagedCompactRangeOptions.BottommostLevelCompaction
+ OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION_DEFAULT =
+ ManagedCompactRangeOptions.BottommostLevelCompaction.kSkip;
+
/**
* Configuration to enable/disable non-snapshot diff table compaction when snapshots are evicted from cache.
*/
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactDBUtil.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactDBUtil.java
index 73c54f2586db..d21a655cf9b9 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactDBUtil.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactDBUtil.java
@@ -20,9 +20,11 @@
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.utils.db.RDBStore;
import org.apache.hadoop.hdds.utils.db.RocksDatabase;
import org.apache.hadoop.hdds.utils.db.managed.ManagedCompactRangeOptions;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.util.Time;
import org.slf4j.Logger;
@@ -74,6 +76,23 @@ public static CompletableFuture compactTableAsync(OMMetadataManager metada
});
}
+ public static ManagedCompactRangeOptions.BottommostLevelCompaction getBottommostLevelCompaction(
+ OzoneConfiguration configuration) {
+ ManagedCompactRangeOptions.BottommostLevelCompaction blc =
+ OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION_DEFAULT;
+
+ try {
+ blc = configuration.getEnum(
+ OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION,
+ OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION_DEFAULT);
+ } catch (IllegalArgumentException e) {
+ LOG.warn("Invalid value for bottommost level compaction configuration '{}'",
+ configuration.get(OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION), e);
+ }
+
+ return blc;
+ }
+
/**
* Converts the given RocksDB id to a
* {@link ManagedCompactRangeOptions.BottommostLevelCompaction} enum value.
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactionService.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactionService.java
index 34c7a8ff8679..9c4653110c78 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactionService.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/CompactionService.java
@@ -54,6 +54,7 @@ public class CompactionService extends BackgroundService {
private final AtomicBoolean suspended;
// list of tables that can be compacted
private final List compactableTables;
+ private final ManagedCompactRangeOptions.BottommostLevelCompaction bottommostLevelCompaction;
public CompactionService(OzoneManager ozoneManager, TimeUnit unit, long interval, long timeout,
List tables) {
@@ -66,6 +67,7 @@ public CompactionService(OzoneManager ozoneManager, TimeUnit unit, long interval
this.numCompactions = new AtomicLong(0);
this.suspended = new AtomicBoolean(false);
this.compactableTables = validateTables(tables);
+ this.bottommostLevelCompaction = CompactDBUtil.getBottommostLevelCompaction(ozoneManager.getConfiguration());
}
private List validateTables(List tables) {
@@ -109,6 +111,11 @@ public List getCompactableTables() {
return compactableTables;
}
+ @VisibleForTesting
+ public ManagedCompactRangeOptions.BottommostLevelCompaction getBottommostLevelCompaction() {
+ return bottommostLevelCompaction;
+ }
+
/**
* Returns the number of manual compactions performed.
*
@@ -142,13 +149,11 @@ private boolean shouldRun() {
* @return CompletableFuture that completes when compaction finishes
*/
public CompletableFuture compactTableAsync(String tableName) {
- return CompactDBUtil.compactTableAsync(omMetadataManager, tableName,
- ManagedCompactRangeOptions.BottommostLevelCompaction.kForce);
+ return CompactDBUtil.compactTableAsync(omMetadataManager, tableName, bottommostLevelCompaction);
}
protected void compactFully(String tableName) throws IOException {
- CompactDBUtil.compactTable(omMetadataManager, tableName,
- ManagedCompactRangeOptions.BottommostLevelCompaction.kForce);
+ CompactDBUtil.compactTable(omMetadataManager, tableName, bottommostLevelCompaction);
}
private class CompactTask implements BackgroundTask {
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactDBUtil.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactDBUtil.java
new file mode 100644
index 000000000000..f757549c8ebe
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactDBUtil.java
@@ -0,0 +1,92 @@
+/*
+ * 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.hadoop.ozone.om.service;
+
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION_DEFAULT;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_DB_DIRS;
+import static org.apache.hadoop.ozone.om.service.CompactDBUtil.getBottommostLevelCompaction;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.utils.db.managed.ManagedCompactRangeOptions;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/**
+ * Tests for {@link CompactDBUtil}.
+ */
+class TestCompactDBUtil {
+
+ private OMMetadataManager omMetadataManager;
+
+ @BeforeEach
+ void setup(@TempDir File tempDir) throws Exception {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(OZONE_OM_DB_DIRS, tempDir.getAbsolutePath());
+ omMetadataManager = new OmMetadataManagerImpl(conf, null);
+ }
+
+ @ParameterizedTest
+ @EnumSource(ManagedCompactRangeOptions.BottommostLevelCompaction.class)
+ void testCompactionAlgorithms(ManagedCompactRangeOptions.BottommostLevelCompaction bottommostLevelCompaction) {
+ assertDoesNotThrow(() ->
+ CompactDBUtil.compactTable(omMetadataManager, "keyTable", bottommostLevelCompaction));
+ }
+
+ @Test
+ void testCompactInvalidColumnFamily() {
+ assertThrows(IOException.class, () ->
+ CompactDBUtil.compactTable(omMetadataManager, "nonExistentTable",
+ ManagedCompactRangeOptions.BottommostLevelCompaction.kSkip));
+ }
+
+ @Test
+ void testDefaultConfigValueMapsToKSkip() {
+ assertEquals(ManagedCompactRangeOptions.BottommostLevelCompaction.kSkip,
+ OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION_DEFAULT);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"", "kForceeee"})
+ void testDefaultConfigKeyIsReadFromOzoneConfiguration(String compactionType) {
+ // unset or invalid values should use the default value
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION, compactionType);
+ assertEquals(ManagedCompactRangeOptions.BottommostLevelCompaction.kSkip, getBottommostLevelCompaction(conf));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"kForce", " kForce", "kForce ", " kForce "})
+ void testConfigKeyIsReadFromOzoneConfiguration(String compactionType) {
+ // have trailing spaces in the config values to ensure they are trimmed and handled correctly
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION, compactionType);
+ assertEquals(ManagedCompactRangeOptions.BottommostLevelCompaction.kForce, getBottommostLevelCompaction(conf));
+ }
+}
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactionService.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactionService.java
index d25423156701..5fda4b4a0e35 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactionService.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestCompactionService.java
@@ -17,8 +17,10 @@
package org.apache.hadoop.ozone.om.service;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_ENABLED;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_COMPACTION_SERVICE_RUN_INTERVAL;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -39,6 +41,7 @@
import org.apache.hadoop.hdds.server.ServerUtils;
import org.apache.hadoop.hdds.utils.db.DBConfigFromFile;
import org.apache.hadoop.hdds.utils.db.TypedTable;
+import org.apache.hadoop.hdds.utils.db.managed.ManagedCompactRangeOptions;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OzoneManager;
@@ -74,6 +77,7 @@ void setup(@TempDir Path tempDir) {
ozoneManager = mock(OzoneManager.class);
OMMetadataManager metadataManager = mock(OMMetadataManager.class);
when(ozoneManager.getMetadataManager()).thenReturn(metadataManager);
+ when(ozoneManager.getConfiguration()).thenReturn(conf);
TypedTable table = mock(TypedTable.class);
Set tables = new HashSet<>();
@@ -159,6 +163,35 @@ public void testCompactFailure() {
() -> getCompactionService(compactTables));
}
+ @Test
+ public void testDefaultCompactionLevelIsKSkip() {
+ CompactionService compactionService = getCompactionService(Arrays.asList("keyTable", "fileTable"));
+ assertEquals(ManagedCompactRangeOptions.BottommostLevelCompaction.kSkip,
+ compactionService.getBottommostLevelCompaction());
+ }
+
+ @Test
+ public void testConfiguredCompactionLevelKForce() {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.setInt(OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION, 2);
+ when(ozoneManager.getConfiguration()).thenReturn(conf);
+
+ CompactionService compactionService = getCompactionService(Arrays.asList("keyTable", "fileTable"));
+ assertEquals(ManagedCompactRangeOptions.BottommostLevelCompaction.kForce,
+ compactionService.getBottommostLevelCompaction());
+ }
+
+ @Test
+ public void testInvalidCompactionLevelFallsBackToDefault() {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.setInt(OZONE_OM_COMPACTION_SERVICE_BOTTOMMOSTLEVELCOMPACTION, 99);
+ when(ozoneManager.getConfiguration()).thenReturn(conf);
+
+ CompactionService compactionService = getCompactionService(Arrays.asList("keyTable", "fileTable"));
+ assertEquals(ManagedCompactRangeOptions.BottommostLevelCompaction.kSkip,
+ compactionService.getBottommostLevelCompaction());
+ }
+
private CompactionService getCompactionService(List compactTables) {
CompactionService compactionService = new CompactionService(ozoneManager, TimeUnit.MILLISECONDS,
TimeUnit.SECONDS.toMillis(SERVICE_INTERVAL), TimeUnit.SECONDS.toMillis(60), compactTables) {