From 0a1c407d25609d366c9b25fed6cc8916900b7078 Mon Sep 17 00:00:00 2001 From: matkt Date: Thu, 13 Jul 2023 15:45:33 +0200 Subject: [PATCH] remove v0 version of the database (#5698) Signed-off-by: Karim TAAM --- CHANGELOG.md | 2 + .../backup/BackupRoundTripAcceptanceTest.java | 10 - .../DatabaseMigrationAcceptanceTest.java | 10 - .../database/version0/besu-db-archive.tar.gz | Bin 102404 -> 0 bytes .../operations/OperationBenchmarkHelper.java | 15 +- .../RocksDBKeyValuePrivacyStorageFactory.java | 4 +- .../RocksDBKeyValueStorageFactory.java | 19 +- .../configuration/DatabaseMetadata.java | 2 +- .../unsegmented/RocksDBKeyValueStorage.java | 223 ------------------ .../unsegmented/RocksDBTransaction.java | 112 --------- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 7 +- .../RocksDBKeyValueStorageFactoryTest.java | 8 +- ...nDBRocksDBColumnarKeyValueStorageTest.java | 18 ++ .../RocksDBColumnarKeyValueStorageTest.java | 100 ++++++++ .../segmented/RocksDBKeyValueStorageTest.java | 136 ----------- ...nDBRocksDBColumnarKeyValueStorageTest.java | 19 ++ 16 files changed, 164 insertions(+), 521 deletions(-) delete mode 100644 acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz delete mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java delete mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java delete mode 100644 plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a47fb3cd942..42e42706754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Breaking Changes +- Removed support for version 0 of the database as it is no longer used by any active node. + ### Additions and Improvements - EvmTool now executes the `execution-spec-tests` via the `t8n` and `b11r`. See the [README](ethereum/evmtool/README.md) in EvmTool for more instructions. - Improve lifecycle management of the transaction pool [#5634](https://github.com/hyperledger/besu/pull/5634) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java index d2afc2e6d39..5136cc64ab3 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/backup/BackupRoundTripAcceptanceTest.java @@ -80,16 +80,6 @@ public BackupRoundTripAcceptanceTest( public static Object[][] getParameters() { return new Object[][] { // First 10 blocks of ropsten - new Object[] { - "Before versioning was enabled", - "version0", - 0xA, - singletonList( - new AccountData( - "0xd1aeb42885a43b72b518182ef893125814811048", - BigInteger.valueOf(0xA), - Wei.fromHexString("0x2B5E3AF16B1880000"))), - }, new Object[] { "After versioning was enabled and using multiple RocksDB columns", "version1", diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java index d116a5cafcf..291506498ba 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/database/DatabaseMigrationAcceptanceTest.java @@ -56,16 +56,6 @@ public DatabaseMigrationAcceptanceTest( public static Object[][] getParameters() { return new Object[][] { // First 10 blocks of ropsten - new Object[] { - "Before versioning was enabled", - "version0", - 0xA, - singletonList( - new AccountData( - "0xd1aeb42885a43b72b518182ef893125814811048", - BigInteger.valueOf(0xA), - Wei.fromHexString("0x2B5E3AF16B1880000"))), - }, new Object[] { "After versioning was enabled and using multiple RocksDB columns", "version1", diff --git a/acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz b/acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz deleted file mode 100644 index 894c8e76a69bbbea528027e44a8320014b086e66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102404 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 z 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
  • 0C3ik2S_UZ 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

    ;~H9aI$6MoOjI@qw&$Zl5O_7-8Uy5Wv| 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 diff --git a/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java b/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java index 81796f89f29..a55ad27f20a 100644 --- a/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java +++ b/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/OperationBenchmarkHelper.java @@ -24,16 +24,19 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; -import org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented.RocksDBKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.OptimisticRocksDBColumnarKeyValueStorage; +import org.hyperledger.besu.services.kvstore.SnappableSegmentedKeyValueStorageAdapter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import com.google.common.io.MoreFiles; import com.google.common.io.RecursiveDeleteOption; @@ -58,12 +61,18 @@ private OperationBenchmarkHelper( public static OperationBenchmarkHelper create() throws IOException { final Path storageDirectory = Files.createTempDirectory("benchmark"); - final KeyValueStorage keyValueStorage = - new RocksDBKeyValueStorage( + final OptimisticRocksDBColumnarKeyValueStorage optimisticRocksDBColumnarKeyValueStorage = + new OptimisticRocksDBColumnarKeyValueStorage( new RocksDBConfigurationBuilder().databaseDir(storageDirectory).build(), + List.of(KeyValueSegmentIdentifier.BLOCKCHAIN), + emptyList(), new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + final KeyValueStorage keyValueStorage = + new SnappableSegmentedKeyValueStorageAdapter<>( + KeyValueSegmentIdentifier.BLOCKCHAIN, optimisticRocksDBColumnarKeyValueStorage); + final ExecutionContextTestFixture executionContext = ExecutionContextTestFixture.builder().blockchainKeyValueStorage(keyValueStorage).build(); final MutableBlockchain blockchain = executionContext.getBlockchain(); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java index ee20b85e968..042fdd15d3f 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactory.java @@ -38,7 +38,7 @@ public class RocksDBKeyValuePrivacyStorageFactory implements PrivacyKeyValueStor private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValuePrivacyStorageFactory.class); private static final int DEFAULT_VERSION = 1; - private static final Set SUPPORTED_VERSIONS = Set.of(0, 1); + private static final Set SUPPORTED_VERSIONS = Set.of(1); private static final String PRIVATE_DATABASE_PATH = "private"; private final RocksDBKeyValueStorageFactory publicFactory; @@ -96,7 +96,7 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr commonConfiguration.getStoragePath().resolve(PRIVATE_DATABASE_PATH).toFile().exists(); final int privacyDatabaseVersion; if (privacyDatabaseExists) { - privacyDatabaseVersion = DatabaseMetadata.lookUpFrom(dataDir).maybePrivacyVersion().orElse(0); + privacyDatabaseVersion = DatabaseMetadata.lookUpFrom(dataDir).maybePrivacyVersion().orElse(1); LOG.info( "Existing private database detected at {}. Version {}", dataDir, privacyDatabaseVersion); } else { diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java index 81aa1a37087..45eefc67182 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java @@ -30,7 +30,6 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.OptimisticRocksDBColumnarKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.TransactionDBRocksDBColumnarKeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented.RocksDBKeyValueStorage; import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; import org.hyperledger.besu.services.kvstore.SnappableSegmentedKeyValueStorageAdapter; @@ -50,7 +49,7 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValueStorageFactory.class); private static final int DEFAULT_VERSION = 1; - private static final Set SUPPORTED_VERSIONS = Set.of(0, 1, 2); + private static final Set SUPPORTED_VERSIONS = Set.of(1, 2); private static final String NAME = "rocksdb"; private final RocksDBMetricsFactory rocksDBMetricsFactory; @@ -58,7 +57,6 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private Integer databaseVersion; private Boolean isSegmentIsolationSupported; private RocksDBColumnarKeyValueStorage segmentedStorage; - private KeyValueStorage unsegmentedStorage; private RocksDBConfiguration rocksDBConfiguration; private final Supplier configuration; @@ -163,17 +161,7 @@ public KeyValueStorage create( // version. Introducing intermediate booleans that represent database properties and dispatching // creation logic based on them is error-prone. switch (databaseVersion) { - case 0 -> { - segmentedStorage = null; - if (unsegmentedStorage == null) { - unsegmentedStorage = - new RocksDBKeyValueStorage( - rocksDBConfiguration, metricsSystem, rocksDBMetricsFactory); - } - return unsegmentedStorage; - } case 1, 2 -> { - unsegmentedStorage = null; if (segmentedStorage == null) { final List segmentsForVersion = segments.stream() @@ -249,7 +237,7 @@ private void init(final BesuConfiguration commonConfiguration) { } private boolean requiresInit() { - return segmentedStorage == null && unsegmentedStorage == null; + return segmentedStorage == null; } private int readDatabaseVersion(final BesuConfiguration commonConfiguration) throws IOException { @@ -283,9 +271,6 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr @Override public void close() throws IOException { - if (unsegmentedStorage != null) { - unsegmentedStorage.close(); - } if (segmentedStorage != null) { segmentedStorage.close(); } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java index 49b54315b32..1faf610cdc9 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadata.java @@ -151,7 +151,7 @@ private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) try { databaseMetadata = MAPPER.readValue(metadataFile, DatabaseMetadata.class); } catch (FileNotFoundException fnfe) { - databaseMetadata = new DatabaseMetadata(0, 0); + databaseMetadata = new DatabaseMetadata(1, 1); } catch (JsonProcessingException jpe) { throw new IllegalStateException( String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java deleted file mode 100644 index 6f32bd89c19..00000000000 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.unsegmented; - -import static java.util.stream.Collectors.toUnmodifiableSet; - -import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbIterator; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbUtil; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.services.kvstore.KeyValueStorageTransactionTransitionValidatorDecorator; - -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.tuweni.bytes.Bytes; -import org.rocksdb.BlockBasedTableConfig; -import org.rocksdb.LRUCache; -import org.rocksdb.OptimisticTransactionDB; -import org.rocksdb.Options; -import org.rocksdb.ReadOptions; -import org.rocksdb.RocksDBException; -import org.rocksdb.RocksIterator; -import org.rocksdb.Statistics; -import org.rocksdb.Status; -import org.rocksdb.WriteOptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** The Rocks db key value storage. */ -public class RocksDBKeyValueStorage implements KeyValueStorage { - - static { - RocksDbUtil.loadNativeLibrary(); - } - - private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValueStorage.class); - - private final Options options; - private final OptimisticTransactionDB db; - private final AtomicBoolean closed = new AtomicBoolean(false); - private final RocksDBMetrics rocksDBMetrics; - private final WriteOptions tryDeleteOptions = - new WriteOptions().setNoSlowdown(true).setIgnoreMissingColumnFamilies(true); - private final ReadOptions readOptions = new ReadOptions().setVerifyChecksums(false); - - /** - * Instantiates a new Rocks db key value storage. - * - * @param configuration the configuration - * @param metricsSystem the metrics system - * @param rocksDBMetricsFactory the rocks db metrics factory - */ - public RocksDBKeyValueStorage( - final RocksDBConfiguration configuration, - final MetricsSystem metricsSystem, - final RocksDBMetricsFactory rocksDBMetricsFactory) { - - try { - final Statistics stats = new Statistics(); - options = - new Options() - .setCreateIfMissing(true) - .setMaxOpenFiles(configuration.getMaxOpenFiles()) - .setTableFormatConfig(createBlockBasedTableConfig(configuration)) - .setStatistics(stats); - options.getEnv().setBackgroundThreads(configuration.getBackgroundThreadCount()); - - db = OptimisticTransactionDB.open(options, configuration.getDatabaseDir().toString()); - rocksDBMetrics = rocksDBMetricsFactory.create(metricsSystem, configuration, db, stats); - } catch (final RocksDBException e) { - throw new StorageException(e); - } - } - - @Override - public void clear() throws StorageException { - throwIfClosed(); - - try (final RocksIterator rocksIterator = db.newIterator()) { - rocksIterator.seekToFirst(); - if (rocksIterator.isValid()) { - final byte[] firstKey = rocksIterator.key(); - rocksIterator.seekToLast(); - if (rocksIterator.isValid()) { - final byte[] lastKey = rocksIterator.key(); - db.deleteRange(firstKey, lastKey); - db.delete(lastKey); - } - } - } catch (final RocksDBException e) { - throw new StorageException(e); - } - } - - @Override - public boolean containsKey(final byte[] key) throws StorageException { - return get(key).isPresent(); - } - - @Override - public Optional get(final byte[] key) throws StorageException { - throwIfClosed(); - - try (final OperationTimer.TimingContext ignored = - rocksDBMetrics.getReadLatency().startTimer()) { - return Optional.ofNullable(db.get(readOptions, key)); - } catch (final RocksDBException e) { - throw new StorageException(e); - } - } - - @Override - public Set getAllKeysThat(final Predicate returnCondition) { - return stream() - .filter(pair -> returnCondition.test(pair.getKey())) - .map(Pair::getKey) - .collect(toUnmodifiableSet()); - } - - @Override - public Stream> stream() { - throwIfClosed(); - - final RocksIterator rocksIterator = db.newIterator(); - rocksIterator.seekToFirst(); - return RocksDbIterator.create(rocksIterator).toStream(); - } - - @Override - public Stream> streamFromKey(final byte[] startKey) { - return stream().filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); - } - - @Override - public Stream streamKeys() { - throwIfClosed(); - - final RocksIterator rocksIterator = db.newIterator(); - rocksIterator.seekToFirst(); - return RocksDbIterator.create(rocksIterator).toStreamKeys(); - } - - @Override - public Set getAllValuesFromKeysThat(final Predicate returnCondition) { - return stream() - .filter(pair -> returnCondition.test(pair.getKey())) - .map(Pair::getValue) - .collect(toUnmodifiableSet()); - } - - @Override - public boolean tryDelete(final byte[] key) { - throwIfClosed(); - try { - db.delete(tryDeleteOptions, key); - return true; - } catch (RocksDBException e) { - if (e.getStatus().getCode() == Status.Code.Incomplete) { - return false; - } else { - throw new StorageException(e); - } - } - } - - @Override - public KeyValueStorageTransaction startTransaction() throws StorageException { - throwIfClosed(); - final WriteOptions options = new WriteOptions(); - options.setIgnoreMissingColumnFamilies(true); - return new KeyValueStorageTransactionTransitionValidatorDecorator( - new RocksDBTransaction(db.beginTransaction(options), options, rocksDBMetrics)); - } - - @Override - public boolean isClosed() { - return closed.get(); - } - - @Override - public void close() { - if (closed.compareAndSet(false, true)) { - tryDeleteOptions.close(); - options.close(); - db.close(); - } - } - - private BlockBasedTableConfig createBlockBasedTableConfig(final RocksDBConfiguration config) { - final LRUCache cache = new LRUCache(config.getCacheCapacity()); - return new BlockBasedTableConfig().setBlockCache(cache); - } - - private void throwIfClosed() { - if (closed.get()) { - LOG.error("Attempting to use a closed RocksDBKeyValueStorage"); - throw new IllegalStateException("Storage has been closed"); - } - } -} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java deleted file mode 100644 index ffd5a1596f6..00000000000 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.unsegmented; - -import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; - -import org.rocksdb.RocksDBException; -import org.rocksdb.Transaction; -import org.rocksdb.WriteOptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** The RocksDb transaction. */ -public class RocksDBTransaction implements KeyValueStorageTransaction { - private static final Logger logger = LoggerFactory.getLogger(RocksDBTransaction.class); - private static final String NO_SPACE_LEFT_ON_DEVICE = "No space left on device"; - - private final RocksDBMetrics metrics; - private final Transaction innerTx; - private final WriteOptions options; - - /** - * Instantiates a new RocksDb transaction. - * - * @param innerTx the inner tx - * @param options the options - * @param metrics the metrics - */ - RocksDBTransaction( - final Transaction innerTx, final WriteOptions options, final RocksDBMetrics metrics) { - this.innerTx = innerTx; - this.options = options; - this.metrics = metrics; - } - - @Override - public void put(final byte[] key, final byte[] value) { - try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { - innerTx.put(key, value); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } - } - - @Override - public void remove(final byte[] key) { - try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { - innerTx.delete(key); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } - } - - @Override - public void commit() throws StorageException { - try (final OperationTimer.TimingContext ignored = metrics.getCommitLatency().startTimer()) { - innerTx.commit(); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } finally { - close(); - } - } - - @Override - public void rollback() { - try { - innerTx.rollback(); - metrics.getRollbackCount().inc(); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } finally { - close(); - } - } - - private void close() { - innerTx.close(); - options.close(); - } -} diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java index 7106b1ad4f4..19ee5c197ec 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValuePrivacyStorageFactoryTest.java @@ -48,7 +48,7 @@ public class RocksDBKeyValuePrivacyStorageFactoryTest { @Mock private SegmentIdentifier segment; @Test - public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception { + public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); final Path tempPrivateDatabaseDir = tempDatabaseDir.resolve("private"); @@ -69,9 +69,10 @@ public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isNotEmpty(); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(0); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()).isEqualTo(0); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()) + .isEqualTo(DEFAULT_VERSION); } @Test diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java index 000b5079c04..9a3fd3ade53 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactoryTest.java @@ -71,7 +71,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { } @Test - public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception { + public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); Files.createDirectories(tempDatabaseDir); @@ -85,7 +85,7 @@ public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isZero(); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); } @Test @@ -118,14 +118,14 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, segments, 1, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, 2, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); storageFactory.create(segment, commonConfiguration, metricsSystem); storageFactory.close(); final RocksDBKeyValueStorageFactory rolledbackStorageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, segments, 0, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, 1, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); rolledbackStorageFactory.create(segment, commonConfiguration, metricsSystem); } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java index 2c9fc86df13..ba65b62ff64 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; @@ -26,7 +27,10 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +@ExtendWith(MockitoExtension.class) public class OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest extends RocksDBColumnarKeyValueStorageTest { @@ -55,4 +59,18 @@ protected SegmentedKeyValueStorage createSegmentedStor new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); } + + @Override + protected SegmentedKeyValueStorage createSegmentedStore( + final Path path, + final MetricsSystem metricsSystem, + final List segments, + final List ignorableSegments) { + return new OptimisticRocksDBColumnarKeyValueStorage( + new RocksDBConfigurationBuilder().databaseDir(path).build(), + segments, + ignorableSegments, + metricsSystem, + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java index 98eaf034960..e342d6ddcb1 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java @@ -16,9 +16,21 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import org.hyperledger.besu.kvstore.AbstractKeyValueStorageTest; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; +import org.hyperledger.besu.plugin.services.metrics.Counter; +import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; @@ -33,13 +45,21 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import java.util.function.LongSupplier; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; public abstract class RocksDBColumnarKeyValueStorageTest extends AbstractKeyValueStorageTest { + @Mock private ObservableMetricsSystem metricsSystemMock; + @Mock private LabelledMetric labelledMetricOperationTimerMock; + @Mock private LabelledMetric labelledMetricCounterMock; + @Mock private OperationTimer operationTimerMock; + @TempDir public Path folder; @Test @@ -257,6 +277,80 @@ public void dbWillBeBackwardIncompatibleAfterExperimentalSegmentsAreAdded( } } + @Test + public void createStoreMustCreateMetrics() throws Exception { + // Prepare mocks + when(labelledMetricOperationTimerMock.labels(any())).thenReturn(operationTimerMock); + when(metricsSystemMock.createLabelledTimer( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) + .thenReturn(labelledMetricOperationTimerMock); + when(metricsSystemMock.createLabelledCounter( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) + .thenReturn(labelledMetricCounterMock); + // Prepare argument captors + final ArgumentCaptor labelledTimersMetricsNameArgs = + ArgumentCaptor.forClass(String.class); + final ArgumentCaptor labelledTimersHelpArgs = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor labelledCountersMetricsNameArgs = + ArgumentCaptor.forClass(String.class); + final ArgumentCaptor labelledCountersHelpArgs = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor longGaugesMetricsNameArgs = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor longGaugesHelpArgs = ArgumentCaptor.forClass(String.class); + + // Actual call + + final SegmentedKeyValueStorage store = + createSegmentedStore( + folder, metricsSystemMock, List.of(TestSegment.FOO), List.of(TestSegment.EXPERIMENTAL)); + + KeyValueStorage keyValueStorage = + new SnappableSegmentedKeyValueStorageAdapter<>(TestSegment.FOO, store); + + // Assertions + assertThat(keyValueStorage).isNotNull(); + verify(metricsSystemMock, times(4)) + .createLabelledTimer( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), + labelledTimersMetricsNameArgs.capture(), + labelledTimersHelpArgs.capture(), + any()); + assertThat(labelledTimersMetricsNameArgs.getAllValues()) + .containsExactly( + "read_latency_seconds", + "remove_latency_seconds", + "write_latency_seconds", + "commit_latency_seconds"); + assertThat(labelledTimersHelpArgs.getAllValues()) + .containsExactly( + "Latency for read from RocksDB.", + "Latency of remove requests from RocksDB.", + "Latency for write to RocksDB.", + "Latency for commits to RocksDB."); + + verify(metricsSystemMock, times(2)) + .createLongGauge( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), + longGaugesMetricsNameArgs.capture(), + longGaugesHelpArgs.capture(), + any(LongSupplier.class)); + assertThat(longGaugesMetricsNameArgs.getAllValues()) + .containsExactly("rocks_db_table_readers_memory_bytes", "rocks_db_files_size_bytes"); + assertThat(longGaugesHelpArgs.getAllValues()) + .containsExactly( + "Estimated memory used for RocksDB index and filter blocks in bytes", + "Estimated database size in bytes"); + + verify(metricsSystemMock) + .createLabelledCounter( + eq(BesuMetricCategory.KVSTORE_ROCKSDB), + labelledCountersMetricsNameArgs.capture(), + labelledCountersHelpArgs.capture(), + any()); + assertThat(labelledCountersMetricsNameArgs.getValue()).isEqualTo("rollback_count"); + assertThat(labelledCountersHelpArgs.getValue()) + .isEqualTo("Number of RocksDB transactions rolled back."); + } + public enum TestSegment implements SegmentIdentifier { FOO(new byte[] {1}), BAR(new byte[] {2}), @@ -302,6 +396,12 @@ protected abstract SegmentedKeyValueStorage createSegm final List segments, final List ignorableSegments); + protected abstract SegmentedKeyValueStorage createSegmentedStore( + final Path path, + final MetricsSystem metricsSystem, + final List segments, + final List ignorableSegments); + @Override protected KeyValueStorage createStore() throws Exception { return new SnappableSegmentedKeyValueStorageAdapter<>(TestSegment.FOO, createSegmentedStore()); diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java deleted file mode 100644 index 78968873ecf..00000000000 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright Hyperledger Besu Contributors. - * - * 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 static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.hyperledger.besu.kvstore.AbstractKeyValueStorageTest; -import org.hyperledger.besu.metrics.BesuMetricCategory; -import org.hyperledger.besu.metrics.ObservableMetricsSystem; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; -import org.hyperledger.besu.plugin.services.metrics.OperationTimer; -import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; -import org.hyperledger.besu.plugin.services.storage.rocksdb.unsegmented.RocksDBKeyValueStorage; - -import java.nio.file.Path; -import java.util.function.LongSupplier; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class RocksDBKeyValueStorageTest extends AbstractKeyValueStorageTest { - - @Mock private ObservableMetricsSystem metricsSystemMock; - @Mock private LabelledMetric labelledMetricOperationTimerMock; - @Mock private LabelledMetric labelledMetricCounterMock; - @Mock private OperationTimer operationTimerMock; - @TempDir static Path folder; - - @Override - protected KeyValueStorage createStore() throws Exception { - return new RocksDBKeyValueStorage( - config(), new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - } - - @Test - public void createStoreMustCreateMetrics() throws Exception { - // Prepare mocks - when(labelledMetricOperationTimerMock.labels(any())).thenReturn(operationTimerMock); - when(metricsSystemMock.createLabelledTimer( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) - .thenReturn(labelledMetricOperationTimerMock); - when(metricsSystemMock.createLabelledCounter( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), anyString(), anyString(), any())) - .thenReturn(labelledMetricCounterMock); - // Prepare argument captors - final ArgumentCaptor labelledTimersMetricsNameArgs = - ArgumentCaptor.forClass(String.class); - final ArgumentCaptor labelledTimersHelpArgs = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor labelledCountersMetricsNameArgs = - ArgumentCaptor.forClass(String.class); - final ArgumentCaptor labelledCountersHelpArgs = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor longGaugesMetricsNameArgs = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor longGaugesHelpArgs = ArgumentCaptor.forClass(String.class); - - // Actual call - final KeyValueStorage keyValueStorage = - new RocksDBKeyValueStorage( - config(), metricsSystemMock, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - - // Assertions - assertThat(keyValueStorage).isNotNull(); - verify(metricsSystemMock, times(4)) - .createLabelledTimer( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), - labelledTimersMetricsNameArgs.capture(), - labelledTimersHelpArgs.capture(), - any()); - assertThat(labelledTimersMetricsNameArgs.getAllValues()) - .containsExactly( - "read_latency_seconds", - "remove_latency_seconds", - "write_latency_seconds", - "commit_latency_seconds"); - assertThat(labelledTimersHelpArgs.getAllValues()) - .containsExactly( - "Latency for read from RocksDB.", - "Latency of remove requests from RocksDB.", - "Latency for write to RocksDB.", - "Latency for commits to RocksDB."); - - verify(metricsSystemMock, times(2)) - .createLongGauge( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), - longGaugesMetricsNameArgs.capture(), - longGaugesHelpArgs.capture(), - any(LongSupplier.class)); - assertThat(longGaugesMetricsNameArgs.getAllValues()) - .containsExactly("rocks_db_table_readers_memory_bytes", "rocks_db_files_size_bytes"); - assertThat(longGaugesHelpArgs.getAllValues()) - .containsExactly( - "Estimated memory used for RocksDB index and filter blocks in bytes", - "Estimated database size in bytes"); - - verify(metricsSystemMock) - .createLabelledCounter( - eq(BesuMetricCategory.KVSTORE_ROCKSDB), - labelledCountersMetricsNameArgs.capture(), - labelledCountersHelpArgs.capture(), - any()); - assertThat(labelledCountersMetricsNameArgs.getValue()).isEqualTo("rollback_count"); - assertThat(labelledCountersHelpArgs.getValue()) - .isEqualTo("Number of RocksDB transactions rolled back."); - } - - private RocksDBConfiguration config() throws Exception { - return new RocksDBConfigurationBuilder().databaseDir(getTempSubFolder(folder)).build(); - } -} diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java index d7d4e12da7d..5633de159d8 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; @@ -25,6 +26,10 @@ import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) public class TransactionDBRocksDBColumnarKeyValueStorageTest extends RocksDBColumnarKeyValueStorageTest { @@ -51,4 +56,18 @@ protected SegmentedKeyValueStorage createSegmentedStor new NoOpMetricsSystem(), RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); } + + @Override + protected SegmentedKeyValueStorage createSegmentedStore( + final Path path, + final MetricsSystem metricsSystem, + final List segments, + final List ignorableSegments) { + return new TransactionDBRocksDBColumnarKeyValueStorage( + new RocksDBConfigurationBuilder().databaseDir(path).build(), + segments, + ignorableSegments, + metricsSystem, + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + } }