Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise the approach for setting level_compaction_dynamic_level_bytes #8037

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public OptimisticRocksDBColumnarKeyValueStorage(
try {

db =
OptimisticTransactionDB.open(
RocksDBOpener.openOptimisticTransactionDBWithWarning(
options, configuration.getDatabaseDir().toString(), columnDescriptors, columnHandles);
initMetrics();
initColumnHandles();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@
import org.rocksdb.ColumnFamilyHandle;
import org.rocksdb.ColumnFamilyOptions;
import org.rocksdb.CompressionType;
import org.rocksdb.ConfigOptions;
import org.rocksdb.DBOptions;
import org.rocksdb.Env;
import org.rocksdb.LRUCache;
import org.rocksdb.Options;
import org.rocksdb.OptionsUtil;
import org.rocksdb.ReadOptions;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
Expand All @@ -76,9 +78,6 @@ public abstract class RocksDBColumnarKeyValueStorage implements SegmentedKeyValu
/** RocksDb blockcache size when using the high spec option */
protected static final long ROCKSDB_BLOCKCACHE_SIZE_HIGH_SPEC = 1_073_741_824L;

/** RocksDb memtable size when using the high spec option */
protected static final long ROCKSDB_MEMTABLE_SIZE_HIGH_SPEC = 536_870_912L;

/** Max total size of all WAL file, after which a flush is triggered */
protected static final long WAL_MAX_TOTAL_SIZE = 1_073_741_824L;

Expand Down Expand Up @@ -186,15 +185,47 @@ public RocksDBColumnarKeyValueStorage(
*/
private ColumnFamilyDescriptor createColumnDescriptor(
final SegmentIdentifier segment, final RocksDBConfiguration configuration) {

boolean dynamicLevelBytes = true;
try {
ConfigOptions configOptions = new ConfigOptions();
DBOptions dbOptions = new DBOptions();
List<ColumnFamilyDescriptor> cfDescriptors = new ArrayList<>();

String latestOptionsFileName =
OptionsUtil.getLatestOptionsFileName(
configuration.getDatabaseDir().toString(), Env.getDefault());
LOG.trace("Latest OPTIONS file detected: " + latestOptionsFileName);

String optionsFilePath =
configuration.getDatabaseDir().toString() + "/" + latestOptionsFileName;
OptionsUtil.loadOptionsFromFile(configOptions, optionsFilePath, dbOptions, cfDescriptors);
ahamlat marked this conversation as resolved.
Show resolved Hide resolved

LOG.trace("RocksDB options loaded successfully from: " + optionsFilePath);

if (!cfDescriptors.isEmpty()) {
Optional<ColumnFamilyOptions> matchedCfOptions = Optional.empty();
for (ColumnFamilyDescriptor descriptor : cfDescriptors) {
if (Arrays.equals(descriptor.getName(), segment.getId())) {
matchedCfOptions = Optional.of(descriptor.getOptions());
break;
}
}
if (matchedCfOptions.isPresent()) {
dynamicLevelBytes = matchedCfOptions.get().levelCompactionDynamicLevelBytes();
LOG.trace("dynamicLevelBytes is set to an existing value : " + dynamicLevelBytes);
}
}
} catch (RocksDBException ex) {
// Options file is not found in the database
}
BlockBasedTableConfig basedTableConfig = createBlockBasedTableConfig(segment, configuration);

final var options =
new ColumnFamilyOptions()
.setTtl(0)
.setCompressionType(CompressionType.LZ4_COMPRESSION)
.setTableFormatConfig(basedTableConfig);

.setTableFormatConfig(basedTableConfig)
.setLevelCompactionDynamicLevelBytes(dynamicLevelBytes);
if (segment.containsStaticData()) {
options
.setEnableBlobFiles(true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Copyright contributors to Besu.
*
* Licensed 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented;

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.rocksdb.ColumnFamilyDescriptor;
import org.rocksdb.ColumnFamilyHandle;
import org.rocksdb.DBOptions;
import org.rocksdb.OptimisticTransactionDB;
import org.rocksdb.RocksDBException;
import org.rocksdb.TransactionDB;
import org.rocksdb.TransactionDBOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Utility class for opening RocksDB instances with a warning mechanism.
*
* <p>This class provides methods to open RocksDB databases ({@link OptimisticTransactionDB} and
* {@link TransactionDB}) while monitoring the operation's duration. If the database takes longer
* than a predefined delay (default: 60 seconds) to open, a warning message is logged. This warning
* helps identify potential delays caused by factors such as RocksDB compaction.
*/
public class RocksDBOpener {

/**
* Default delay (in seconds) after which a warning is logged if the database opening operation
* has not completed.
*/
public static final int DEFAULT_DELAY = 60;

/**
* Warning message logged when the database opening operation takes longer than the predefined
* delay.
*/
public static final String WARN_MESSAGE =
"Opening RocksDB database is taking longer than 60 seconds... "
+ "This may be due to prolonged RocksDB compaction. Please wait until the end of the compaction. "
+ "No action is needed from the user.";

private static final Logger LOG = LoggerFactory.getLogger(RocksDBOpener.class);

/**
* Default constructor.
*
* <p>This is a utility class and is not meant to be instantiated directly.
*/
private RocksDBOpener() {
// Default constructor for RocksDBOpener
}

/**
* Opens an {@link OptimisticTransactionDB} instance with a warning mechanism.
*
* <p>If the database opening operation takes longer than {@link #DEFAULT_DELAY} seconds, a
* warning message is logged indicating a possible delay caused by compaction.
*
* @param options the {@link DBOptions} instance used to configure the database.
* @param dbPath the file path to the RocksDB database directory.
* @param columnDescriptors a list of {@link ColumnFamilyDescriptor} objects for the column
* families to open.
* @param columnHandles a list of {@link ColumnFamilyHandle} objects to be populated with the
* opened column families.
* @return an instance of {@link OptimisticTransactionDB}.
* @throws RocksDBException if the database cannot be opened.
*/
public static OptimisticTransactionDB openOptimisticTransactionDBWithWarning(
final DBOptions options,
final String dbPath,
final List<ColumnFamilyDescriptor> columnDescriptors,
final List<ColumnFamilyHandle> columnHandles)
throws RocksDBException {
return openDBWithWarning(
() -> OptimisticTransactionDB.open(options, dbPath, columnDescriptors, columnHandles));
}

/**
* Opens a {@link TransactionDB} instance with a warning mechanism.
*
* <p>If the database opening operation takes longer than {@link #DEFAULT_DELAY} seconds, a
* warning message is logged indicating a possible delay caused by compaction.
*
* @param options the {@link DBOptions} instance used to configure the database.
* @param transactionDBOptions the {@link TransactionDBOptions} for transaction-specific
* configuration.
* @param dbPath the file path to the RocksDB database directory.
* @param columnDescriptors a list of {@link ColumnFamilyDescriptor} objects for the column
* families to open.
* @param columnHandles a list of {@link ColumnFamilyHandle} objects to be populated with the
* opened column families.
* @return an instance of {@link TransactionDB}.
* @throws RocksDBException if the database cannot be opened.
*/
public static TransactionDB openTransactionDBWithWarning(
final DBOptions options,
final TransactionDBOptions transactionDBOptions,
final String dbPath,
final List<ColumnFamilyDescriptor> columnDescriptors,
final List<ColumnFamilyHandle> columnHandles)
throws RocksDBException {
return openDBWithWarning(
() ->
TransactionDB.open(
options, transactionDBOptions, dbPath, columnDescriptors, columnHandles));
}

/**
* A generic method to open a RocksDB database with a warning mechanism.
*
* <p>If the operation takes longer than {@link #DEFAULT_DELAY} seconds, a warning message is
* logged.
*
* @param dbOperation a lambda or method reference representing the database opening logic.
* @param <T> the type of the database being opened (e.g., {@link OptimisticTransactionDB} or
* {@link TransactionDB}).
* @return an instance of the database being opened.
* @throws RocksDBException if the database cannot be opened.
*/
private static <T> T openDBWithWarning(final DBOperation<T> dbOperation) throws RocksDBException {
AtomicBoolean operationCompleted = new AtomicBoolean(false);
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(
() -> {
if (!operationCompleted.get()) {
LOG.warn(WARN_MESSAGE);
}
},
DEFAULT_DELAY,
TimeUnit.SECONDS);

try {
T db = dbOperation.open();
operationCompleted.set(true);
return db;
} finally {
scheduler.shutdown();
}
}

/**
* Functional interface representing a database opening operation.
*
* @param <T> the type of the database being opened.
*/
@FunctionalInterface
private interface DBOperation<T> {
/**
* Opens the database.
*
* @return the opened database instance.
* @throws RocksDBException if an error occurs while opening the database.
*/
T open() throws RocksDBException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public TransactionDBRocksDBColumnarKeyValueStorage(
try {

db =
TransactionDB.open(
RocksDBOpener.openTransactionDBWithWarning(
options,
txOptions,
configuration.getDatabaseDir().toString(),
Expand Down
Loading