mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-08 20:47:59 -05:00
Revise the approach for setting level_compaction_dynamic_level_bytes (#8037)
* Create a RocksDB opener that display a warning if it takes too much time to open the database * Change the strategy levelCompactionDynamicLevelBytes is set Signed-off-by: Ameziane H. <ameziane.hamlat@consensys.net>
This commit is contained in:
@@ -57,7 +57,7 @@ public class OptimisticRocksDBColumnarKeyValueStorage extends RocksDBColumnarKey
|
||||
try {
|
||||
|
||||
db =
|
||||
OptimisticTransactionDB.open(
|
||||
RocksDBOpener.openOptimisticTransactionDBWithWarning(
|
||||
options, configuration.getDatabaseDir().toString(), columnDescriptors, columnHandles);
|
||||
initMetrics();
|
||||
initColumnHandles();
|
||||
|
||||
@@ -51,10 +51,12 @@ import org.rocksdb.ColumnFamilyDescriptor;
|
||||
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;
|
||||
@@ -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;
|
||||
|
||||
@@ -186,15 +185,47 @@ public abstract class RocksDBColumnarKeyValueStorage implements SegmentedKeyValu
|
||||
*/
|
||||
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);
|
||||
|
||||
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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class TransactionDBRocksDBColumnarKeyValueStorage extends RocksDBColumnar
|
||||
try {
|
||||
|
||||
db =
|
||||
TransactionDB.open(
|
||||
RocksDBOpener.openTransactionDBWithWarning(
|
||||
options,
|
||||
txOptions,
|
||||
configuration.getDatabaseDir().toString(),
|
||||
|
||||
Reference in New Issue
Block a user