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) {