From 67ff612efc60108cb906eeed66c17027197a4355 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 16 Jan 2024 13:47:11 +0100 Subject: [PATCH 01/13] WIP Signed-off-by: Fabio Di Fabio --- .../org/hyperledger/besu/cli/BesuCommand.java | 6 +- .../options/stable/DataStorageOptions.java | 2 +- .../storage/TrieLogSubCommand.java | 2 +- .../controller/BesuControllerBuilder.java | 2 +- .../hyperledger/besu/cli/BesuCommandTest.java | 2 +- .../stable/DataStorageOptionsTest.java | 2 +- .../storage/TrieLogHelperTest.java | 2 +- .../controller/BesuControllerBuilderTest.java | 2 +- .../MergeBesuControllerBuilderTest.java | 2 +- .../QbftBesuControllerBuilderTest.java | 2 +- .../besu/services/TraceServiceImplTest.java | 2 +- .../AbstractEthGraphQLHttpServiceTest.java | 2 +- .../AbstractJsonRpcHttpServiceTest.java | 2 +- .../DebugTraceJsonRpcHttpBySpecTest.java | 2 +- .../EthByzantiumJsonRpcHttpBySpecTest.java | 2 +- .../bonsai/TraceJsonRpcHttpBySpecTest.java | 2 +- .../DebugTraceJsonRpcHttpBySpecTest.java | 2 +- .../EthByzantiumJsonRpcHttpBySpecTest.java | 2 +- .../forest/TraceJsonRpcHttpBySpecTest.java | 2 +- .../filter/EthJsonRpcHttpServiceTest.java | 2 +- .../ethereum/storage/StorageProvider.java | 2 +- .../keyvalue/KeyValueSegmentIdentifier.java | 38 ++-- .../keyvalue/KeyValueStorageProvider.java | 2 +- .../BonsaiWorldStateKeyValueStorage.java | 2 +- .../ForestWorldStateKeyValueStorage.java | 2 +- .../worldstate/DataStorageConfiguration.java | 1 + .../worldstate/WorldStateStorage.java | 1 + .../ethereum/core/BlockchainSetupUtil.java | 2 +- .../core/InMemoryKeyValueStorageProvider.java | 2 +- .../trie/bonsai/AbstractIsolationTests.java | 8 +- .../bonsai/trielog/TrieLogFactoryTests.java | 2 +- .../WorldStateDownloaderBenchmark.java | 2 +- .../eth/sync/fastsync/FastSyncDownloader.java | 2 +- .../snapsync/SnapWorldStateDownloader.java | 2 +- .../eth/manager/EthProtocolManagerTest.java | 2 +- .../manager/EthProtocolManagerTestUtil.java | 2 +- .../ethtaskutils/AbstractMessageTaskTest.java | 2 +- .../task/SnapProtocolManagerTestUtil.java | 2 +- .../AbstractBlockPropagationManagerTest.java | 2 +- .../BonsaiBlockPropagationManagerTest.java | 2 +- .../eth/sync/ChainHeadTrackerTest.java | 2 +- .../eth/sync/DownloadHeadersStepTest.java | 2 +- .../ForestBlockPropagationManagerTest.java | 2 +- .../eth/sync/RangeHeadersFetcherTest.java | 2 +- .../CheckPointSyncChainDownloaderTest.java | 2 +- .../fastsync/DownloadReceiptsStepTest.java | 2 +- .../sync/fastsync/FastSyncActionsTest.java | 2 +- .../fastsync/FastSyncChainDownloaderTest.java | 2 +- .../sync/fastsync/FastSyncDownloaderTest.java | 2 +- .../fastsync/PivotBlockConfirmerTest.java | 2 +- .../fastsync/PivotBlockRetrieverTest.java | 2 +- .../FastWorldDownloadStateTest.java | 2 +- .../worldstate/PersistDataStepTest.java | 2 +- .../fullsync/FullSyncChainDownloaderTest.java | 2 +- ...DownloaderTotalTerminalDifficultyTest.java | 2 +- .../sync/fullsync/FullSyncDownloaderTest.java | 2 +- .../fullsync/FullSyncTargetManagerTest.java | 2 +- .../sync/snapsync/PersistDataStepTest.java | 2 +- .../snapsync/SnapWorldDownloadStateTest.java | 2 +- .../eth/sync/snapsync/TaskGenerator.java | 2 +- .../StorageTrieNodeHealingRequestTest.java | 2 +- .../eth/sync/tasks/PersistBlockTaskTest.java | 2 +- .../plugin/services/BesuConfiguration.java | 9 +- .../services/storage}/DataStorageFormat.java | 19 +- .../services/storage/SegmentIdentifier.java | 8 +- plugins/rocksdb/build.gradle | 1 + .../RocksDBKeyValuePrivacyStorageFactory.java | 9 +- .../RocksDBKeyValueStorageFactory.java | 135 +++++++------- .../configuration/DatabaseMetadata.java | 167 ++++++++++++------ .../configuration/VersionedStorageFormat.java | 61 +++++++ ...ksDBKeyValuePrivacyStorageFactoryTest.java | 11 +- .../RocksDBKeyValueStorageFactoryTest.java | 13 +- .../configuration/DatabaseMetadataTest.java | 17 +- 73 files changed, 368 insertions(+), 250 deletions(-) rename {ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate => plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage}/DataStorageFormat.java (64%) create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index d2fb5243313..6eab761e14d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -148,7 +148,7 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder; import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract; import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract; import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract; @@ -3386,8 +3386,8 @@ public Path getDataPath() { } @Override - public int getDatabaseVersion() { - return dataStorageOptions.toDomainObject().getDataStorageFormat().getDatabaseVersion(); + public DataStorageFormat getDatabaseFormat() { + return dataStorageOptions.toDomainObject().getDataStorageFormat(); } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java index e0b19735683..bfb674efc35 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java @@ -25,7 +25,7 @@ import org.hyperledger.besu.cli.options.CLIOptions; import org.hyperledger.besu.cli.util.CommandLineUtils; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import java.util.List; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java index bf75fd6eb9a..771778316f7 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java @@ -24,7 +24,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogPruner; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.io.PrintWriter; import java.nio.file.Path; diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 6bcfea3cad8..3ba72fb24dc 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -89,7 +89,7 @@ import org.hyperledger.besu.ethereum.trie.forest.pruner.Pruner; import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index dc56c34845d..aece743ebdf 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -39,7 +39,7 @@ import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.GOERLI_DISCOVERY_URL; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.MAINNET_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.MAINNET_DISCOVERY_URL; -import static org.hyperledger.besu.ethereum.worldstate.DataStorageFormat.BONSAI; +import static org.hyperledger.besu.plugin.services.storage.DataStorageFormat.BONSAI; import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER; import static org.junit.Assume.assumeThat; import static org.mockito.ArgumentMatchers.any; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java index 437053afd56..b4261e00544 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.junit.jupiter.api.Test; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelperTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelperTest.java index 82659701b1c..e3703104516 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelperTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelperTest.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.cli.subcommands.storage; -import static org.hyperledger.besu.ethereum.worldstate.DataStorageFormat.BONSAI; +import static org.hyperledger.besu.plugin.services.storage.DataStorageFormat.BONSAI; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java index dd9452e7806..cc23f2dfdf9 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -48,7 +48,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; diff --git a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java index 4368e831381..4d37889bf03 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java @@ -52,7 +52,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; diff --git a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java index 75fecf3f96e..d90a7a361b4 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java @@ -48,7 +48,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.internal.EvmConfiguration; diff --git a/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java index f7ae97cdf57..46954b2f41f 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java @@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.worldstate.WorldView; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java index 20b77eed839..1b002b0fd46 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.data.SyncStatus; import java.nio.file.Path; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index e43c39db4df..976887f6f42 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -45,7 +45,7 @@ import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.nat.NatService; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugTraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugTraceJsonRpcHttpBySpecTest.java index acfbcbaf492..37b2cedf7cf 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugTraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugTraceJsonRpcHttpBySpecTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java index a5f3ae0ab0c..358aeb15542 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthByzantiumJsonRpcHttpBySpecTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java index 127d7d3b696..a3bf6fc51db 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/TraceJsonRpcHttpBySpecTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugTraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugTraceJsonRpcHttpBySpecTest.java index 412a4958c3d..89b79c2af31 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugTraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugTraceJsonRpcHttpBySpecTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java index a98aa9b45e5..16392979923 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/EthByzantiumJsonRpcHttpBySpecTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java index 36b5b6f17e1..d71c28a2234 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/TraceJsonRpcHttpBySpecTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java index bdef98bb039..38dc9decc57 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.io.IOException; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java index 6cc9741cb22..f5459ae61fa 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.ethereum.chain.BlockchainStorage; import org.hyperledger.besu.ethereum.chain.VariablesStorage; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueSegmentIdentifier.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueSegmentIdentifier.java index 9cce0230cdb..ceb7a811295 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueSegmentIdentifier.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueSegmentIdentifier.java @@ -14,21 +14,27 @@ */ package org.hyperledger.besu.ethereum.storage.keyvalue; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.bouncycastle.util.Arrays; +import java.util.EnumSet; + +import static org.hyperledger.besu.plugin.services.storage.DataStorageFormat.BONSAI; +import static org.hyperledger.besu.plugin.services.storage.DataStorageFormat.FOREST; + public enum KeyValueSegmentIdentifier implements SegmentIdentifier { BLOCKCHAIN(new byte[] {1}, true), - WORLD_STATE(new byte[] {2}, new int[] {0, 1}), + WORLD_STATE(new byte[] {2}, EnumSet.of(FOREST)), PRIVATE_TRANSACTIONS(new byte[] {3}), PRIVATE_STATE(new byte[] {4}), - PRUNING_STATE(new byte[] {5}, new int[] {0, 1}), - ACCOUNT_INFO_STATE(new byte[] {6}, new int[] {2}), - CODE_STORAGE(new byte[] {7}, new int[] {2}), - ACCOUNT_STORAGE_STORAGE(new byte[] {8}, new int[] {2}), - TRIE_BRANCH_STORAGE(new byte[] {9}, new int[] {2}), - TRIE_LOG_STORAGE(new byte[] {10}, new int[] {2}), + PRUNING_STATE(new byte[] {5}, EnumSet.of(FOREST)), + ACCOUNT_INFO_STATE(new byte[] {6}, EnumSet.of(BONSAI)), + CODE_STORAGE(new byte[] {7}, EnumSet.of(BONSAI)), + ACCOUNT_STORAGE_STORAGE(new byte[] {8}, EnumSet.of(BONSAI)), + TRIE_BRANCH_STORAGE(new byte[] {9}, EnumSet.of(BONSAI)), + TRIE_LOG_STORAGE(new byte[] {10}, EnumSet.of(BONSAI)), VARIABLES(new byte[] {11}), // formerly GOQUORUM_PRIVATE_WORLD_STATE // previously supported GoQuorum private states @@ -43,25 +49,25 @@ public enum KeyValueSegmentIdentifier implements SegmentIdentifier { CHAIN_PRUNER_STATE(new byte[] {18}); private final byte[] id; - private final int[] versionList; + private final EnumSet formats; private final boolean containsStaticData; KeyValueSegmentIdentifier(final byte[] id) { - this(id, new int[] {0, 1, 2}); + this(id, EnumSet.allOf(DataStorageFormat.class)); } KeyValueSegmentIdentifier(final byte[] id, final boolean containsStaticData) { - this(id, new int[] {0, 1, 2}, containsStaticData); + this(id, EnumSet.allOf(DataStorageFormat.class), containsStaticData); } - KeyValueSegmentIdentifier(final byte[] id, final int[] versionList) { - this(id, versionList, false); + KeyValueSegmentIdentifier(final byte[] id, final EnumSet formats) { + this(id, formats, false); } KeyValueSegmentIdentifier( - final byte[] id, final int[] versionList, final boolean containsStaticData) { + final byte[] id, final EnumSet formats, final boolean containsStaticData) { this.id = id; - this.versionList = versionList; + this.formats = formats; this.containsStaticData = containsStaticData; } @@ -81,7 +87,7 @@ public boolean containsStaticData() { } @Override - public boolean includeInDatabaseVersion(final int version) { - return Arrays.contains(versionList, version); + public boolean includeInDatabaseFormat(final DataStorageFormat format) { + return formats.contains(format); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java index dea6b932c32..78ae097a856 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.ObservableMetricsSystem; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java index 97384fd6c12..6b22b967bb3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.flat.FlatDbStrategy; import org.hyperledger.besu.ethereum.trie.bonsai.storage.flat.FullFlatDbStrategy; import org.hyperledger.besu.ethereum.trie.bonsai.storage.flat.PartialFlatDbStrategy; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java index f53d3e53ce2..9fd8c483ee0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.trie.MerkleTrie; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java index a36b150337a..52d2c1cdb84 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.worldstate; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.immutables.value.Value; @Value.Immutable diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java index 3bb6a0dfe78..badb73aa934 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java @@ -24,6 +24,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; public interface WorldStateStorage { diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java index 5e43198e25e..f3d55874a5d 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java @@ -35,7 +35,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.util.RawBlockIterator; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java index 514c8821098..51f563ff61e 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java @@ -32,7 +32,7 @@ import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java index a77c51269d8..625272aa4c0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java @@ -68,7 +68,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogPruner; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.BesuConfiguration; @@ -188,7 +188,7 @@ protected StorageProvider createKeyValueStorageProvider() { 8388608 /*CACHE_CAPACITY*/, false), Arrays.asList(KeyValueSegmentIdentifier.values()), - 2, + DataStorageFormat.BONSAI, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS)) .withCommonConfiguration( new BesuConfiguration() { @@ -204,8 +204,8 @@ public Path getDataPath() { } @Override - public int getDatabaseVersion() { - return 2; + public DataStorageFormat getDatabaseFormat() { + return DataStorageFormat.BONSAI; } }) .withMetricsSystem(new NoOpMetricsSystem()) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogFactoryTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogFactoryTests.java index c74fc7e1805..5a940e752f8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogFactoryTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogFactoryTests.java @@ -24,7 +24,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLogFactory; diff --git a/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java b/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java index 5f7cbcdc8df..c20ddd281dd 100644 --- a/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java +++ b/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java @@ -38,7 +38,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.ObservableMetricsSystem; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java index b73daa28301..2332e3a05cb 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements; import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.services.tasks.TaskCollection; import org.hyperledger.besu.util.ExceptionUtils; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java index 313d5a3770f..f28fc6d15bd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 3b7178c365b..182ed3b3039 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -71,7 +71,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java index 5f970e44dc5..8f710c4757d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java @@ -35,7 +35,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.DefaultMessage; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.testutil.DeterministicEthScheduler; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index 1538ecc7278..a5f101ffa32 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -42,7 +42,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.testutil.DeterministicEthScheduler; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/SnapProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/SnapProtocolManagerTestUtil.java index 68bd4e4e5a1..6a62cb8adf4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/SnapProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/SnapProtocolManagerTestUtil.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import java.util.Collections; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index 25ff8ab4b46..e7559ae642b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -58,7 +58,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.testutil.TestClock; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/BonsaiBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/BonsaiBlockPropagationManagerTest.java index 7bd4d2bbbc4..eda0473147a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/BonsaiBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/BonsaiBlockPropagationManagerTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java index 4cde3fd7edc..ab28cbd861d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer.Responder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStepTest.java index b9d8eec0216..96896cf1c3d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStepTest.java @@ -30,7 +30,7 @@ import org.hyperledger.besu.ethereum.eth.sync.range.SyncTargetRange; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.ArrayList; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ForestBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ForestBlockPropagationManagerTest.java index 000958b1fac..9b2bd896203 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ForestBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ForestBlockPropagationManagerTest.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java index 0b18a0f64c6..828a844591f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java @@ -33,7 +33,7 @@ import org.hyperledger.besu.ethereum.eth.sync.range.RangeHeadersFetcher; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java index 62ef446503b..8fb18783f24 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java @@ -36,7 +36,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.ImmutableCheckpoint; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java index 0a775b130fa..6aa7d4e799a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java @@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.List; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java index a707228e92d..9bbdc9655da 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java @@ -40,7 +40,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java index d2c63a18a15..68ce8b1250b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java @@ -35,7 +35,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java index 632fed6ede1..afdd5f1dc9b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java @@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.NodeDataRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.services.tasks.TaskCollection; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java index 08ce7e9d37f..42582ea7350 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java @@ -32,7 +32,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.PivotBlockConfirmer.ContestedPivotBlockException; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java index 7e539c8a596..e7955b672a7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java @@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.util.ExceptionUtils; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java index 91c770d47be..87f8d6f09f5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadProcess; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java index e857648f7fc..08db38a4ddd 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.patricia.SimpleMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.services.tasks.Task; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java index b7588d1b4f9..b0bc3cc23ab 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java @@ -42,7 +42,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java index c86be6d6407..92b8354ef2f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java @@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java index aff0195db2d..75bbb880d47 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java @@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java index 790e17998a3..b627fcb65ef 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java @@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncTarget; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java index 69047bc6e50..b34571e040e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.services.tasks.Task; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java index a8dc4a9b083..76c15efe9fb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java @@ -40,7 +40,7 @@ import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadProcess; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java index 64bda37ae88..c8819907c7e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.services.tasks.Task; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java index 5295f4e3b5e..9bb86f37036 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java @@ -24,7 +24,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java index 5d02f398470..6621e0bb917 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTaskTest.java @@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java index 9f830162ecb..d2ff86db118 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.nio.file.Path; @@ -36,12 +37,12 @@ public interface BesuConfiguration extends BesuService { Path getDataPath(); /** - * Database version. This sets the list of segmentIdentifiers that should be initialized. + * Database format. This sets the list of segmentIdentifiers that should be initialized. * - * @return Database version. + * @return Database format. */ @Unstable - default int getDatabaseVersion() { - return 1; + default DataStorageFormat getDatabaseFormat() { + return DataStorageFormat.FOREST; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageFormat.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java similarity index 64% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageFormat.java rename to plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java index b97f79006ae..43d1c660572 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageFormat.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java @@ -14,19 +14,26 @@ * */ -package org.hyperledger.besu.ethereum.worldstate; +package org.hyperledger.besu.plugin.services.storage; + +import java.util.Arrays; public enum DataStorageFormat { FOREST(1), // Original format. Store all tries BONSAI(2); // New format. Store one trie, and trie logs to roll forward and backward. - private final int databaseVersion; + @Deprecated + private final int legacyVersion; + + DataStorageFormat(final int legacyVersion) { + this.legacyVersion = legacyVersion; + } - DataStorageFormat(final int databaseVersion) { - this.databaseVersion = databaseVersion; + public int getLegacyVersion() { + return legacyVersion; } - public int getDatabaseVersion() { - return databaseVersion; + public static DataStorageFormat fromLegacyVersion(final int i) { + return Arrays.stream(values()).filter(v -> v.legacyVersion == i).findFirst().orElseThrow(); } } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentIdentifier.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentIdentifier.java index c535966876f..992814820c8 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentIdentifier.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentIdentifier.java @@ -39,12 +39,12 @@ public interface SegmentIdentifier { /** * Not all segments are in all DB versions. This queries the segment to see if it is in the DB - * version. + * format. * - * @param version Version of the DB - * @return true if the segment is in that DB version + * @param format Version of the DB + * @return true if the segment is in that DB format */ - default boolean includeInDatabaseVersion(final int version) { + default boolean includeInDatabaseFormat(final DataStorageFormat format) { return true; } diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index f76e8d80ae0..6af582bf3b2 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -41,6 +41,7 @@ dependencies { implementation project(':util') implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8' implementation 'com.google.guava:guava' implementation 'info.picocli:picocli' implementation 'io.opentelemetry:opentelemetry-api' 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 355cc056924..24db0c0364c 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 @@ -27,8 +27,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.OptionalInt; import java.util.Set; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -122,15 +124,16 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr if (privacyDatabaseExists) { privacyDatabaseVersion = DatabaseMetadata.lookUpFrom(dataDir).maybePrivacyVersion().orElse(1); LOG.info( - "Existing private database detected at {}. Version {}", dataDir, privacyDatabaseVersion); + "Existing private database detected at {}. Metadata {}", dataDir, privacyDatabaseVersion); } else { privacyDatabaseVersion = DEFAULT_VERSION; LOG.info( - "No existing private database detected at {}. Using version {}", + "No existing private database detected at {}. Using metadata {}", dataDir, privacyDatabaseVersion); Files.createDirectories(dataDir); - new DatabaseMetadata(publicFactory.getDefaultVersion(), privacyDatabaseVersion) + final VersionedStorageFormat format = VersionedStorageFormat.fromFormat(commonConfiguration.getDatabaseFormat()); + new DatabaseMetadata(format.getFormat(), format.getVersion(), privacyDatabaseVersion) .writeToDirectory(dataDir); } 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 0f08e3c0f9b..65e41d9062b 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 @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; @@ -26,6 +26,7 @@ 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.configuration.RocksDBFactoryConfiguration; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat; 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; @@ -34,14 +35,18 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.EnumSet; import java.util.List; -import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat.BONSAI_ORIGINAL; +import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat.BONSAI_WITH_VARIABLES; +import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat.FOREST_WITH_VARIABLES; + /** * The Rocks db key value storage factory creates segmented storage and uses a adapter to support * unsegmented keyvalue storage. @@ -49,13 +54,11 @@ 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(1, 2); + private static final VersionedStorageFormat DEFAULT_VERSIONED_FORMAT = VersionedStorageFormat.FOREST_WITH_VARIABLES; + private static final EnumSet SUPPORTED_VERSIONED_FORMATS = EnumSet.of(FOREST_WITH_VARIABLES, BONSAI_WITH_VARIABLES); private static final String NAME = "rocksdb"; private final RocksDBMetricsFactory rocksDBMetricsFactory; - - private final int defaultVersion; - private Integer databaseVersion; + private VersionedStorageFormat versionedStorageFormat; private RocksDBColumnarKeyValueStorage segmentedStorage; private RocksDBConfiguration rocksDBConfiguration; @@ -69,20 +72,20 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { * @param configuration the configuration * @param configuredSegments the segments * @param ignorableSegments the ignorable segments - * @param defaultVersion the default version + * @param format the storage format * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, final List configuredSegments, final List ignorableSegments, - final int defaultVersion, + final DataStorageFormat format, final RocksDBMetricsFactory rocksDBMetricsFactory) { this.configuration = configuration; this.configuredSegments = configuredSegments; this.ignorableSegments = ignorableSegments; - this.defaultVersion = defaultVersion; this.rocksDBMetricsFactory = rocksDBMetricsFactory; + this.versionedStorageFormat = VersionedStorageFormat.fromFormat(format); } /** @@ -90,15 +93,15 @@ public RocksDBKeyValueStorageFactory( * * @param configuration the configuration * @param configuredSegments the segments - * @param defaultVersion the default version + * @param format the storage format * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, final List configuredSegments, - final int defaultVersion, + final DataStorageFormat format, final RocksDBMetricsFactory rocksDBMetricsFactory) { - this(configuration, configuredSegments, List.of(), defaultVersion, rocksDBMetricsFactory); + this(configuration, configuredSegments, List.of(), format, rocksDBMetricsFactory); } /** @@ -118,7 +121,7 @@ public RocksDBKeyValueStorageFactory( configuration, configuredSegments, ignorableSegments, - DEFAULT_VERSION, + DEFAULT_VERSIONED_FORMAT.getFormat(), rocksDBMetricsFactory); } @@ -133,16 +136,7 @@ public RocksDBKeyValueStorageFactory( final Supplier configuration, final List configuredSegments, final RocksDBMetricsFactory rocksDBMetricsFactory) { - this(configuration, configuredSegments, List.of(), DEFAULT_VERSION, rocksDBMetricsFactory); - } - - /** - * Gets default version. - * - * @return the default version - */ - int getDefaultVersion() { - return defaultVersion; + this(configuration, configuredSegments, List.of(), DEFAULT_VERSIONED_FORMAT.getFormat(), rocksDBMetricsFactory); } @Override @@ -166,8 +160,6 @@ public SegmentedKeyValueStorage create( final BesuConfiguration commonConfiguration, final MetricsSystem metricsSystem) throws StorageException { - final boolean isForestStorageFormat = - DataStorageFormat.FOREST.getDatabaseVersion() == commonConfiguration.getDatabaseVersion(); if (requiresInit()) { init(commonConfiguration); } @@ -182,44 +174,40 @@ public SegmentedKeyValueStorage create( .collect(Collectors.joining(", "))); } - // It's probably a good idea for the creation logic to be entirely dependent on the database - // version. Introducing intermediate booleans that represent database properties and dispatching - // creation logic based on them is error-prone. - switch (databaseVersion) { - case 1, 2 -> { - if (segmentedStorage == null) { - final List segmentsForVersion = + if (segmentedStorage == null) { + final List segmentsForFormat = configuredSegments.stream() - .filter(segmentId -> segmentId.includeInDatabaseVersion(databaseVersion)) - .collect(Collectors.toList()); - if (isForestStorageFormat) { - LOG.debug("FOREST mode detected, using TransactionDB."); - segmentedStorage = - new TransactionDBRocksDBColumnarKeyValueStorage( - rocksDBConfiguration, - segmentsForVersion, - ignorableSegments, - metricsSystem, - rocksDBMetricsFactory); - } else { - LOG.debug("Using OptimisticTransactionDB."); - segmentedStorage = - new OptimisticRocksDBColumnarKeyValueStorage( - rocksDBConfiguration, - segmentsForVersion, - ignorableSegments, - metricsSystem, - rocksDBMetricsFactory); - } + .filter(segmentId -> segmentId.includeInDatabaseFormat(versionedStorageFormat.getFormat())) + .toList(); + + // It's probably a good idea for the creation logic to be entirely dependent on the database + // version. Introducing intermediate booleans that represent database properties and dispatching + // creation logic based on them is error-prone. + switch (versionedStorageFormat.getFormat()) { + case FOREST -> { + LOG.debug("FOREST mode detected, using TransactionDB."); + segmentedStorage = + new TransactionDBRocksDBColumnarKeyValueStorage( + rocksDBConfiguration, + segmentsForFormat, + ignorableSegments, + metricsSystem, + rocksDBMetricsFactory); + } + case BONSAI -> { + LOG.debug("BONSAI mode detected, Using OptimisticTransactionDB."); + segmentedStorage = + new OptimisticRocksDBColumnarKeyValueStorage( + rocksDBConfiguration, + segmentsForFormat, + ignorableSegments, + metricsSystem, + rocksDBMetricsFactory); } - return segmentedStorage; } - default -> throw new IllegalStateException( - String.format( - "Developer error: A supported database version (%d) was detected but there is no associated creation logic.", - databaseVersion)); } - } + return segmentedStorage; +} /** * Storage path. @@ -233,7 +221,7 @@ protected Path storagePath(final BesuConfiguration commonConfiguration) { private void init(final BesuConfiguration commonConfiguration) { try { - databaseVersion = readDatabaseVersion(commonConfiguration); + versionedStorageFormat = readDatabaseMetadata(commonConfiguration); } catch (final IOException e) { final String message = "Failed to retrieve the RocksDB database meta version: " @@ -251,33 +239,36 @@ private boolean requiresInit() { return segmentedStorage == null; } - private int readDatabaseVersion(final BesuConfiguration commonConfiguration) throws IOException { + private VersionedStorageFormat readDatabaseMetadata(final BesuConfiguration commonConfiguration) throws IOException { final Path dataDir = commonConfiguration.getDataPath(); final boolean databaseExists = commonConfiguration.getStoragePath().toFile().exists(); final boolean dataDirExists = dataDir.toFile().exists(); - final int databaseVersion; + final DatabaseMetadata databaseMetadata; if (databaseExists) { - databaseVersion = DatabaseMetadata.lookUpFrom(dataDir).getVersion(); + databaseMetadata = DatabaseMetadata.lookUpFrom(dataDir); LOG.info( - "Existing database detected at {}. Version {}. Compacting database...", + "Existing database detected at {}. Metadata {}. Compacting database...", dataDir, - databaseVersion); + databaseMetadata); } else { - databaseVersion = commonConfiguration.getDatabaseVersion(); - LOG.info("No existing database detected at {}. Using version {}", dataDir, databaseVersion); + final VersionedStorageFormat format = VersionedStorageFormat.fromFormat(commonConfiguration.getDatabaseFormat()); + databaseMetadata = new DatabaseMetadata(format.getFormat(), format.getVersion()); + LOG.info("No existing database detected at {}. Using metadata {}", dataDir, databaseMetadata); if (!dataDirExists) { Files.createDirectories(dataDir); } - new DatabaseMetadata(databaseVersion).writeToDirectory(dataDir); + databaseMetadata.writeToDirectory(dataDir); } - if (!SUPPORTED_VERSIONS.contains(databaseVersion)) { - final String message = "Unsupported RocksDB Metadata version of: " + databaseVersion; + final VersionedStorageFormat versionedFormat = VersionedStorageFormat.fromMetadata(databaseMetadata); + + if(!SUPPORTED_VERSIONED_FORMATS.contains(versionedFormat)) { + final String message = "Unsupported RocksDB metadata: " + databaseMetadata; LOG.error(message); throw new StorageException(message); } - return databaseVersion; + return versionedFormat; } @Override 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 1faf610cdc9..bbd70e7621d 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 @@ -14,61 +14,88 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Optional; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DatabindException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; +import java.util.OptionalInt; + /** The Database metadata. */ public class DatabaseMetadata { private static final Logger LOG = LoggerFactory.getLogger(DatabaseMetadata.class); private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; - private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); + private final DataStorageFormat format; private final int version; - private Optional privacyVersion; + private final OptionalInt maybePrivacyVersion; +// +// /** +// * Instantiates a new Database metadata. +// * +// * @param version the version +// */ +// @JsonCreator +// public DatabaseMetadata(final DataStorageFormat format, @JsonProperty("version") final int version) { +// this(format, version, Optional.empty()); +// } /** * Instantiates a new Database metadata. * + * @param format the format * @param version the version */ - @JsonCreator - public DatabaseMetadata(@JsonProperty("version") final int version) { - this(version, Optional.empty()); + public DatabaseMetadata(final DataStorageFormat format, final int version) { + this(format, version, OptionalInt.empty()); } /** * Instantiates a new Database metadata. * + * @param format the format * @param version the version * @param privacyVersion the privacy version */ - public DatabaseMetadata(final int version, final Optional privacyVersion) { - this.version = version; - this.privacyVersion = privacyVersion; + public DatabaseMetadata(final DataStorageFormat format, final int version, final int privacyVersion) { + this(format, version, OptionalInt.of(privacyVersion)); } /** * Instantiates a new Database metadata. * + * @param format the format * @param version the version - * @param privacyVersion the privacy version + * @param maybePrivacyVersion the optional privacy version */ - public DatabaseMetadata(final int version, final int privacyVersion) { - this(version, Optional.of(privacyVersion)); + private DatabaseMetadata(final DataStorageFormat format, final int version, final OptionalInt maybePrivacyVersion) { + this.format = format; + this.version = version; + this.maybePrivacyVersion = maybePrivacyVersion; + } +// +// /** +// * Instantiates a new Database metadata. +// * +// * @param version the version +// * @param privacyVersion the privacy version +// */ +// public DatabaseMetadata(final DataStorageFormat format, final int version, final int privacyVersion) { +// this(format, version, Optional.of(privacyVersion)); +// } + + public DataStorageFormat getFormat() { + return format; } /** @@ -80,34 +107,13 @@ public int getVersion() { return version; } - /** - * Sets privacy version. - * - * @param privacyVersion the privacy version - */ - @JsonSetter("privacyVersion") - public void setPrivacyVersion(final int privacyVersion) { - this.privacyVersion = Optional.of(privacyVersion); - } - - /** - * Gets privacy version. - * - * @return the privacy version - */ - @JsonInclude(JsonInclude.Include.NON_NULL) - @JsonGetter("privacyVersion") - public Integer getPrivacyVersion() { - return privacyVersion.orElse(null); - } - /** * Maybe privacy version. * * @return the optional */ - public Optional maybePrivacyVersion() { - return privacyVersion; + public OptionalInt maybePrivacyVersion() { + return maybePrivacyVersion; } /** @@ -129,16 +135,11 @@ public static DatabaseMetadata lookUpFrom(final Path dataDir) throws IOException * @throws IOException the io exception */ public void writeToDirectory(final Path dataDir) throws IOException { - try { - final DatabaseMetadata currentMetadata = - MAPPER.readValue(getDefaultMetadataFile(dataDir), DatabaseMetadata.class); - if (currentMetadata.maybePrivacyVersion().isPresent()) { - setPrivacyVersion(currentMetadata.getPrivacyVersion()); - } - MAPPER.writeValue(getDefaultMetadataFile(dataDir), this); - } catch (FileNotFoundException fnfe) { - MAPPER.writeValue(getDefaultMetadataFile(dataDir), this); - } + writeToFile(getDefaultMetadataFile(dataDir)); + } + + private void writeToFile(final File file) throws IOException { + MAPPER.writeValue(file, new V2(new MetadataV2(format, version, maybePrivacyVersion))); } private static File getDefaultMetadataFile(final Path dataDir) { @@ -146,16 +147,66 @@ private static File getDefaultMetadataFile(final Path dataDir) { } private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) - throws IOException { + throws IOException { DatabaseMetadata databaseMetadata; try { - databaseMetadata = MAPPER.readValue(metadataFile, DatabaseMetadata.class); + try { + return tryReadAndMigrateV1(metadataFile); + } catch (DatabindException dbe) { + return tryReadV2(metadataFile); + } } catch (FileNotFoundException fnfe) { - databaseMetadata = new DatabaseMetadata(1, 1); + databaseMetadata = new DatabaseMetadata(DataStorageFormat.FOREST, 2); } catch (JsonProcessingException jpe) { throw new IllegalStateException( - String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); + String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); } return databaseMetadata; } + + private static DatabaseMetadata tryReadAndMigrateV1(final File metadataFile) throws IOException { + final V1 v1 = MAPPER.readValue(metadataFile, V1.class); + final DatabaseMetadata metadataV1 = new DatabaseMetadata(DataStorageFormat.fromLegacyVersion(v1.version), 2, v1.privacyVersion); + // writing the metadata will migrate to v2 + metadataV1.writeToFile(metadataFile); + return metadataV1; + } + + private static DatabaseMetadata tryReadV2(final File metadataFile) throws IOException { + final V2 v2 = MAPPER.readValue(metadataFile, V2.class); + return new DatabaseMetadata(v2.v2.format, v2.v2.version, v2.v2.privacyVersion); + } + + @Override + public String toString() { + return "format=" + format + + ", version=" + version + ((maybePrivacyVersion.isPresent()) ? ", privacyVersion=" + maybePrivacyVersion : ""); + } + + private static class V1 { + @JsonProperty + int version; + @JsonProperty + OptionalInt privacyVersion; + } + + private static class V2 { + private final MetadataV2 v2; + + public V2(final MetadataV2 v2) { + this.v2 = v2; + } + } + + private static class MetadataV2 { + private final DataStorageFormat format; + private final int version; + private final OptionalInt privacyVersion; + + public MetadataV2(final DataStorageFormat format, final int version, final OptionalInt privacyVersion) { + this.format = format; + this.version = version; + this.privacyVersion = privacyVersion; + } + } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java new file mode 100644 index 00000000000..44431954ab5 --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java @@ -0,0 +1,61 @@ +package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; + +import org.hyperledger.besu.plugin.services.exception.StorageException; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValueStorageFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; + +public enum VersionedStorageFormat { + FOREST_ORIGINAL(DataStorageFormat.FOREST, 1, 1), + FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2, 1), + BONSAI_ORIGINAL(DataStorageFormat.BONSAI,1, 1), + BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2, 1); + + private static final Logger LOG = LoggerFactory.getLogger(VersionedStorageFormat.class); + private final DataStorageFormat format; + private final int version; + private final int privacyVersion; + + VersionedStorageFormat(final DataStorageFormat format, final int version, final int privacyVersion) { + this.format = format; + this.version = version; + this.privacyVersion = privacyVersion; + } + + public static VersionedStorageFormat fromFormat(final DataStorageFormat format) { + return switch (format) { + case FOREST -> FOREST_WITH_VARIABLES; + case BONSAI -> BONSAI_WITH_VARIABLES; + }; + } + + public DataStorageFormat getFormat() { + return format; + } + + public int getVersion() { + return version; + } + + public int getPrivacyVersion() { + return privacyVersion; + } + + public static VersionedStorageFormat fromMetadata(final DatabaseMetadata metadata) { + return Arrays.stream(values()).filter(vsf -> + vsf.format.equals(metadata.getFormat()) + && vsf.version == metadata.getVersion() + && (metadata.maybePrivacyVersion().isPresent() + ? metadata.maybePrivacyVersion().getAsInt() == vsf.privacyVersion + : true) + ) + .findFirst().orElseThrow(() -> { + final String message = "Unsupported RocksDB metadata: " + metadata; + LOG.error(message); + throw new StorageException(message); + }); + } +} 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 e0ed3f7b396..d2510cad397 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 @@ -21,6 +21,7 @@ import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.BesuConfiguration; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; @@ -71,7 +72,7 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()) + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().getAsInt()) .isEqualTo(DEFAULT_VERSION); } @@ -81,7 +82,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); + when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); final RocksDBKeyValuePrivacyStorageFactory storageFactory = new RocksDBKeyValuePrivacyStorageFactory( @@ -97,7 +98,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()) + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().getAsInt()) .isEqualTo(DEFAULT_PRIVACY_VERSION); } @@ -107,7 +108,7 @@ public void shouldUpdateCorrectMetadataFileForLatestVersion() throws Exception { final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); + when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( @@ -126,7 +127,7 @@ public void shouldUpdateCorrectMetadataFileForLatestVersion() throws Exception { assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isNotEmpty(); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().get()) + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().getAsInt()) .isEqualTo(DEFAULT_PRIVACY_VERSION); } } 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 c3a8c32eb27..4bd6b09743b 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 @@ -23,6 +23,7 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.exception.StorageException; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; @@ -58,7 +59,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); + when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( @@ -95,7 +96,7 @@ public void shouldDetectCorrectVersionIfMetadataFileExists() throws Exception { Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); + when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( @@ -118,14 +119,14 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, segments, 2, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, DataStorageFormat.BONSAI, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); storageFactory.create(segment, commonConfiguration, metricsSystem); storageFactory.close(); final RocksDBKeyValueStorageFactory rolledbackStorageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, segments, 1, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, DataStorageFormat.FOREST, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); rolledbackStorageFactory.create(segment, commonConfiguration, metricsSystem); } @@ -137,7 +138,7 @@ public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - new DatabaseMetadata(-1).writeToDirectory(tempDataDir); + new DatabaseMetadata(DataStorageFormat.FOREST, 99).writeToDirectory(tempDataDir); assertThatThrownBy( () -> new RocksDBKeyValueStorageFactory( @@ -208,7 +209,7 @@ public void shouldCreateDBCorrectlyIfSymlink() throws Exception { final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempSymLinkDataDir); - when(commonConfiguration.getDatabaseVersion()).thenReturn(DEFAULT_VERSION); + when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java index 569819f8312..9d0504a652c 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java @@ -21,6 +21,7 @@ import java.nio.file.Files; import java.nio.file.Path; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -28,23 +29,15 @@ class DatabaseMetadataTest { @TempDir public Path temporaryFolder; @Test - void getVersion() { - final DatabaseMetadata databaseMetadata = new DatabaseMetadata(42); - assertThat(databaseMetadata).isNotNull(); - assertThat(databaseMetadata.getVersion()).isEqualTo(42); - } - - @Test - void metaFileShouldMayContain() throws Exception { + void readingMetadataV1() throws Exception { final Path tempDataDir = createAndWrite( - "data", "DATABASE_METADATA.json", "{\"version\":42 , \"privacyVersion\":55}"); + "data", "DATABASE_METADATA.json", "{\"version\":2 , \"privacyVersion\":1}"); final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); - assertThat(databaseMetadata).isNotNull(); - assertThat(databaseMetadata.getVersion()).isEqualTo(42); + assertThat(databaseMetadata.getFormat()).isEqualTo(DataStorageFormat.BONSAI); assertThat(databaseMetadata.maybePrivacyVersion()).isNotEmpty(); - assertThat(databaseMetadata.maybePrivacyVersion().get()).isEqualTo(55); + assertThat(databaseMetadata.maybePrivacyVersion().getAsInt()).isEqualTo(1); } @Test From a59c23311f4b3cc944f93f33196d2f23f795ddf0 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 25 Jan 2024 17:55:03 +0100 Subject: [PATCH 02/13] WIP Signed-off-by: Fabio Di Fabio --- .../services/storage/DataStorageFormat.java | 26 +-- .../RocksDBKeyValuePrivacyStorageFactory.java | 47 +++-- .../RocksDBKeyValueStorageFactory.java | 27 ++- .../configuration/DatabaseMetadata.java | 167 ++++++------------ .../PrivateDatabaseMetadata.java | 150 ++++++++++++++++ .../PrivateVersionedStorageFormat.java | 28 +++ .../configuration/VersionedStorageFormat.java | 52 +++--- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 16 +- .../RocksDBKeyValueStorageFactoryTest.java | 8 +- .../configuration/DatabaseMetadataTest.java | 19 +- 10 files changed, 326 insertions(+), 214 deletions(-) create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java index f115420cf6b..be7dd0b8d6f 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java @@ -19,20 +19,20 @@ import java.util.Arrays; public enum DataStorageFormat { - FOREST(1), // Original format. Store all tries - BONSAI(2); // New format. Store one trie, and trie logs to roll forward and backward. + FOREST, // Original format. Store all tries + BONSAI; // New format. Store one trie, and trie logs to roll forward and backward. - @Deprecated private final int legacyVersion; +// @Deprecated private final int legacyVersion; - DataStorageFormat(final int legacyVersion) { - this.legacyVersion = legacyVersion; - } +// DataStorageFormat(final int legacyVersion) { +// this.legacyVersion = legacyVersion; +// } - public int getLegacyVersion() { - return legacyVersion; - } - - public static DataStorageFormat fromLegacyVersion(final int i) { - return Arrays.stream(values()).filter(v -> v.legacyVersion == i).findFirst().orElseThrow(); - } +// public int getLegacyVersion() { +// return legacyVersion; +// } +// +// public static DataStorageFormat fromLegacyVersion(final int i) { +// return Arrays.stream(values()).filter(v -> v.legacyVersion == i).findFirst().orElseThrow(); +// } } 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 023ebf82a37..61095bdfdda 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 @@ -21,15 +21,16 @@ import org.hyperledger.besu.plugin.services.storage.PrivacyKeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateDatabaseMetadata; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.EnumSet; import java.util.List; import java.util.Set; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,12 +41,10 @@ public class RocksDBKeyValuePrivacyStorageFactory implements PrivacyKeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValuePrivacyStorageFactory.class); - private static final int DEFAULT_VERSION = 1; - private static final Set SUPPORTED_VERSIONS = Set.of(1); - + private static final Set SUPPORTED_VERSIONS = EnumSet.of(PrivateVersionedStorageFormat.ORIGINAL); private static final String PRIVATE_DATABASE_PATH = "private"; private final RocksDBKeyValueStorageFactory publicFactory; - private Integer databaseVersion; + private PrivateDatabaseMetadata databaseMetadata; /** * Instantiates a new RocksDb key value privacy storage factory. @@ -67,9 +66,9 @@ public KeyValueStorage create( final BesuConfiguration commonConfiguration, final MetricsSystem metricsSystem) throws StorageException { - if (databaseVersion == null) { + if (databaseMetadata == null) { try { - databaseVersion = readDatabaseVersion(commonConfiguration); + databaseMetadata = readDatabaseMetadata(commonConfiguration); } catch (final IOException e) { throw new StorageException("Failed to retrieve the RocksDB database meta version", e); } @@ -84,9 +83,9 @@ public SegmentedKeyValueStorage create( final BesuConfiguration commonConfiguration, final MetricsSystem metricsSystem) throws StorageException { - if (databaseVersion == null) { + if (databaseMetadata == null) { try { - databaseVersion = readDatabaseVersion(commonConfiguration); + databaseMetadata = readDatabaseMetadata(commonConfiguration); } catch (final IOException e) { throw new StorageException("Failed to retrieve the RocksDB database meta version", e); } @@ -115,39 +114,37 @@ public void close() throws IOException { * private database exists there may be a "privacyVersion" field in the metadata file otherwise * use the default version */ - private int readDatabaseVersion(final BesuConfiguration commonConfiguration) throws IOException { + private PrivateDatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) throws IOException { final Path dataDir = commonConfiguration.getDataPath(); final boolean privacyDatabaseExists = commonConfiguration.getStoragePath().resolve(PRIVATE_DATABASE_PATH).toFile().exists(); - final int privacyDatabaseVersion; + final PrivateDatabaseMetadata privateDatabaseMetadata; if (privacyDatabaseExists) { - privacyDatabaseVersion = DatabaseMetadata.lookUpFrom(dataDir).maybePrivacyVersion().orElse(1); + privateDatabaseMetadata = PrivateDatabaseMetadata.lookUpFrom(dataDir); LOG.info( - "Existing private database detected at {}. Metadata {}", dataDir, privacyDatabaseVersion); + "Existing private database detected at {}. Metadata {}", dataDir, privateDatabaseMetadata); } else { - privacyDatabaseVersion = DEFAULT_VERSION; + privateDatabaseMetadata = PrivateDatabaseMetadata.defaultForNewDb(); LOG.info( - "No existing private database detected at {}. Using metadata {}", + "No existing private database detected at {}. Using default metadata for new db {}", dataDir, - privacyDatabaseVersion); + privateDatabaseMetadata); Files.createDirectories(dataDir); - final VersionedStorageFormat format = - VersionedStorageFormat.fromFormat(commonConfiguration.getDatabaseFormat()); - new DatabaseMetadata(format.getFormat(), format.getVersion(), privacyDatabaseVersion) - .writeToDirectory(dataDir); + privateDatabaseMetadata + .writeToDirectory(dataDir); } - if (!SUPPORTED_VERSIONS.contains(privacyDatabaseVersion)) { - final String message = "Unsupported RocksDB Metadata version of: " + privacyDatabaseVersion; + if (!SUPPORTED_VERSIONS.contains(privateDatabaseMetadata.getPrivateVersionedStorageFormat())) { + final String message = "Unsupported RocksDB Metadata version of: " + privateDatabaseMetadata; LOG.error(message); throw new StorageException(message); } - return privacyDatabaseVersion; + return privateDatabaseMetadata; } @Override public int getVersion() { - return databaseVersion; + return databaseMetadata.getPrivateVersionedStorageFormat().getPrivacyVersion(); } } 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 a33d25430d2..751f3c0cf00 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 @@ -59,7 +59,7 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { EnumSet.of(FOREST_WITH_VARIABLES, BONSAI_WITH_VARIABLES); private static final String NAME = "rocksdb"; private final RocksDBMetricsFactory rocksDBMetricsFactory; - private VersionedStorageFormat versionedStorageFormat; + private DatabaseMetadata databaseMetadata; private RocksDBColumnarKeyValueStorage segmentedStorage; private RocksDBConfiguration rocksDBConfiguration; @@ -86,7 +86,7 @@ public RocksDBKeyValueStorageFactory( this.configuredSegments = configuredSegments; this.ignorableSegments = ignorableSegments; this.rocksDBMetricsFactory = rocksDBMetricsFactory; - this.versionedStorageFormat = VersionedStorageFormat.fromFormat(format); + this.databaseMetadata = DatabaseMetadata.defaultForNewDb(format); } /** @@ -185,14 +185,14 @@ public SegmentedKeyValueStorage create( configuredSegments.stream() .filter( segmentId -> - segmentId.includeInDatabaseFormat(versionedStorageFormat.getFormat())) + segmentId.includeInDatabaseFormat(databaseMetadata.getVersionedStorageFormat().getFormat())) .toList(); // It's probably a good idea for the creation logic to be entirely dependent on the database // version. Introducing intermediate booleans that represent database properties and // dispatching // creation logic based on them is error-prone. - switch (versionedStorageFormat.getFormat()) { + switch (databaseMetadata.getVersionedStorageFormat().getFormat()) { case FOREST -> { LOG.debug("FOREST mode detected, using TransactionDB."); segmentedStorage = @@ -230,7 +230,7 @@ protected Path storagePath(final BesuConfiguration commonConfiguration) { private void init(final BesuConfiguration commonConfiguration) { try { - versionedStorageFormat = readDatabaseMetadata(commonConfiguration); + databaseMetadata = readDatabaseMetadata(commonConfiguration); } catch (final IOException e) { final String message = "Failed to retrieve the RocksDB database meta version: " @@ -248,7 +248,7 @@ private boolean requiresInit() { return segmentedStorage == null; } - private VersionedStorageFormat readDatabaseMetadata(final BesuConfiguration commonConfiguration) + private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) throws IOException { final Path dataDir = commonConfiguration.getDataPath(); final boolean databaseExists = commonConfiguration.getStoragePath().toFile().exists(); @@ -257,30 +257,25 @@ private VersionedStorageFormat readDatabaseMetadata(final BesuConfiguration comm if (databaseExists) { databaseMetadata = DatabaseMetadata.lookUpFrom(dataDir); LOG.info( - "Existing database detected at {}. Metadata {}. Compacting database...", + "Existing database detected at {}. Metadata {}. Processing WAL...", dataDir, databaseMetadata); } else { - final VersionedStorageFormat format = - VersionedStorageFormat.fromFormat(commonConfiguration.getDatabaseFormat()); - databaseMetadata = new DatabaseMetadata(format.getFormat(), format.getVersion()); - LOG.info("No existing database detected at {}. Using metadata {}", dataDir, databaseMetadata); + databaseMetadata = DatabaseMetadata.defaultForNewDb(commonConfiguration.getDatabaseFormat()); + LOG.info("No existing database detected at {}. Using default metadata for new db {}", dataDir, databaseMetadata); if (!dataDirExists) { Files.createDirectories(dataDir); } databaseMetadata.writeToDirectory(dataDir); } - final VersionedStorageFormat versionedFormat = - VersionedStorageFormat.fromMetadata(databaseMetadata); - - if (!SUPPORTED_VERSIONED_FORMATS.contains(versionedFormat)) { + if (!SUPPORTED_VERSIONED_FORMATS.contains(databaseMetadata.getVersionedStorageFormat())) { final String message = "Unsupported RocksDB metadata: " + databaseMetadata; LOG.error(message); throw new StorageException(message); } - return versionedFormat; + return databaseMetadata; } @Override 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 82edec9d37b..4ee69f26898 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 @@ -14,15 +14,17 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Path; +import java.util.Arrays; import java.util.OptionalInt; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DatabindException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -36,95 +38,25 @@ public class DatabaseMetadata { private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); - private final DataStorageFormat format; - private final int version; - - private final OptionalInt maybePrivacyVersion; - // - // /** - // * Instantiates a new Database metadata. - // * - // * @param version the version - // */ - // @JsonCreator - // public DatabaseMetadata(final DataStorageFormat format, @JsonProperty("version") final int - // version) { - // this(format, version, Optional.empty()); - // } + private final VersionedStorageFormat versionedStorageFormat; - /** - * Instantiates a new Database metadata. - * - * @param format the format - * @param version the version - */ - public DatabaseMetadata(final DataStorageFormat format, final int version) { - this(format, version, OptionalInt.empty()); - } - - /** - * Instantiates a new Database metadata. - * - * @param format the format - * @param version the version - * @param privacyVersion the privacy version - */ - public DatabaseMetadata( - final DataStorageFormat format, final int version, final int privacyVersion) { - this(format, version, OptionalInt.of(privacyVersion)); - } - - /** - * Instantiates a new Database metadata. - * - * @param format the format - * @param version the version - * @param maybePrivacyVersion the optional privacy version - */ private DatabaseMetadata( - final DataStorageFormat format, final int version, final OptionalInt maybePrivacyVersion) { - this.format = format; - this.version = version; - this.maybePrivacyVersion = maybePrivacyVersion; - } - // - // /** - // * Instantiates a new Database metadata. - // * - // * @param version the version - // * @param privacyVersion the privacy version - // */ - // public DatabaseMetadata(final DataStorageFormat format, final int version, final int - // privacyVersion) { - // this(format, version, Optional.of(privacyVersion)); - // } - - public DataStorageFormat getFormat() { - return format; + final VersionedStorageFormat versionedStorageFormat) { + this.versionedStorageFormat = versionedStorageFormat; } - /** - * Gets version. - * - * @return the version - */ - public int getVersion() { - return version; + public static DatabaseMetadata defaultForNewDb(final DataStorageFormat dataStorageFormat) { + return new DatabaseMetadata(VersionedStorageFormat.defaultForNewDB(dataStorageFormat)); } - /** - * Maybe privacy version. - * - * @return the optional - */ - public OptionalInt maybePrivacyVersion() { - return maybePrivacyVersion; + public VersionedStorageFormat getVersionedStorageFormat() { + return versionedStorageFormat; } /** * Look up database metadata. * - * @param dataDir the data dir + * @param dataDir the data dir * @return the database metadata * @throws IOException the io exception */ @@ -144,7 +76,7 @@ public void writeToDirectory(final Path dataDir) throws IOException { } private void writeToFile(final File file) throws IOException { - MAPPER.writeValue(file, new V2(new MetadataV2(format, version, maybePrivacyVersion))); + MAPPER.writeValue(file, new V2(new MetadataV2(versionedStorageFormat.getFormat(), versionedStorageFormat.getVersion()))); } private static File getDefaultMetadataFile(final Path dataDir) { @@ -153,7 +85,6 @@ private static File getDefaultMetadataFile(final Path dataDir) { private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) throws IOException { - DatabaseMetadata databaseMetadata; try { try { return tryReadAndMigrateV1(metadataFile); @@ -161,60 +92,68 @@ private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) return tryReadV2(metadataFile); } } catch (FileNotFoundException fnfe) { - databaseMetadata = new DatabaseMetadata(DataStorageFormat.FOREST, 2); + throw new IllegalStateException("Database exists but metadata file " + metadataFile.toString() + " not found, without it there is no safe way to open the database"); } catch (JsonProcessingException jpe) { throw new IllegalStateException( String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); } - return databaseMetadata; } private static DatabaseMetadata tryReadAndMigrateV1(final File metadataFile) throws IOException { final V1 v1 = MAPPER.readValue(metadataFile, V1.class); - final DatabaseMetadata metadataV1 = - new DatabaseMetadata(DataStorageFormat.fromLegacyVersion(v1.version), 2, v1.privacyVersion); + // when migrating from v1, this version will automatically migrate the db to the variables storage, so we use the `_WITH_VARIABLES` variants + final var versionedStorageFormat = switch (v1.version()) { + case 1 -> VersionedStorageFormat.FOREST_WITH_VARIABLES; + case 2 -> VersionedStorageFormat.BONSAI_WITH_VARIABLES; + default -> throw new IllegalStateException("Unsupported db version: " + v1.version()); + }; + + final DatabaseMetadata metadataV2 = + new DatabaseMetadata(versionedStorageFormat); // writing the metadata will migrate to v2 - metadataV1.writeToFile(metadataFile); - return metadataV1; + metadataV2.writeToFile(metadataFile); + return metadataV2; } private static DatabaseMetadata tryReadV2(final File metadataFile) throws IOException { final V2 v2 = MAPPER.readValue(metadataFile, V2.class); - return new DatabaseMetadata(v2.v2.format, v2.v2.version, v2.v2.privacyVersion); + return new DatabaseMetadata(fromV2(v2.v2)); } - @Override - public String toString() { - return "format=" - + format - + ", version=" - + version - + ((maybePrivacyVersion.isPresent()) ? ", privacyVersion=" + maybePrivacyVersion : ""); + private static VersionedStorageFormat fromV2(final MetadataV2 metadataV2) { + return Arrays.stream(VersionedStorageFormat.values()) + .filter( + vsf -> + vsf.getFormat().equals(metadataV2.format()) + && vsf.getVersion() == metadataV2.version()) + .findFirst() + .orElseThrow( + () -> { + final String message = "Unsupported RocksDB metadata: " + metadataV2; + LOG.error(message); + throw new StorageException(message); + }); } - private static class V1 { - @JsonProperty int version; - @JsonProperty OptionalInt privacyVersion; + @Override + public String toString() { + return "versionedStorageFormat=" + + versionedStorageFormat; } - private static class V2 { - private final MetadataV2 v2; + @JsonSerialize + @SuppressWarnings("unused") + private record V1( + int version) + {}; - public V2(final MetadataV2 v2) { - this.v2 = v2; - } + @JsonSerialize + @SuppressWarnings("unused") + private record V2(MetadataV2 v2) { } - private static class MetadataV2 { - private final DataStorageFormat format; - private final int version; - private final OptionalInt privacyVersion; - - public MetadataV2( - final DataStorageFormat format, final int version, final OptionalInt privacyVersion) { - this.format = format; - this.version = version; - this.privacyVersion = privacyVersion; - } + @JsonSerialize + @SuppressWarnings("unused") + private record MetadataV2(DataStorageFormat format, int version) { } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java new file mode 100644 index 00000000000..6ba5865d240 --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java @@ -0,0 +1,150 @@ +/* + * 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.configuration; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; + +/** The Database metadata. */ +public class PrivateDatabaseMetadata { + private static final Logger LOG = LoggerFactory.getLogger(PrivateDatabaseMetadata.class); + + private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; + private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); + private final PrivateVersionedStorageFormat versionedStorageFormat; +// +// /** +// * Instantiates a new Database metadata. +// * +// * @param format the format +// * @param version the version +// */ +// public DatabaseMetadata(final DataStorageFormat format, final int version) { +// this(format, version, OptionalInt.empty()); +// } +// +// /** +// * Instantiates a new Database metadata. +// * +// * @param format the format +// * @param version the version +// * @param privacyVersion the privacy version +// */ +// public DatabaseMetadata( +// final DataStorageFormat format, final int version, final int privacyVersion) { +// this(format, version, OptionalInt.of(privacyVersion)); +// } +// +// /** +// * Instantiates a new Database metadata. +// * +// * @param format the format +// * @param version the version +// * @param maybePrivacyVersion the optional privacy version +// */ +// private DatabaseMetadata( +// final DataStorageFormat format, final int version, final OptionalInt maybePrivacyVersion) { +// this.format = format; +// this.version = version; +// this.maybePrivacyVersion = maybePrivacyVersion; +// } + + private PrivateDatabaseMetadata( + final PrivateVersionedStorageFormat versionedStorageFormat) { + this.versionedStorageFormat = versionedStorageFormat; + } + + public static PrivateDatabaseMetadata defaultForNewDb() { + return new PrivateDatabaseMetadata(PrivateVersionedStorageFormat.defaultForNewDB()); + } + + public PrivateVersionedStorageFormat getPrivateVersionedStorageFormat() { + return versionedStorageFormat; + } + + /** + * Look up database metadata. + * + * @param dataDir the data dir + * @return the database metadata + * @throws IOException the io exception + */ + public static PrivateDatabaseMetadata lookUpFrom(final Path dataDir) throws IOException { + LOG.info("Lookup private database metadata file in data directory: {}", dataDir.toString()); + return resolveDatabaseMetadata(getDefaultMetadataFile(dataDir)); + } + + /** + * Write to directory. + * + * @param dataDir the data dir + * @throws IOException the io exception + */ + public void writeToDirectory(final Path dataDir) throws IOException { + writeToFile(getDefaultMetadataFile(dataDir)); + } + + private void writeToFile(final File file) throws IOException { + MAPPER.writeValue(file, new V1(versionedStorageFormat.getPrivacyVersion())); + } + + private static File getDefaultMetadataFile(final Path dataDir) { + return dataDir.resolve(METADATA_FILENAME).toFile(); + } + + private static PrivateDatabaseMetadata resolveDatabaseMetadata(final File metadataFile) + throws IOException { + try { + return tryReadV1(metadataFile); + } catch (FileNotFoundException fnfe) { + throw new IllegalStateException("Private database exists but metadata file " + metadataFile.toString() + " not found, without it there is no safe way to open the private database"); + } catch (JsonProcessingException jpe) { + throw new IllegalStateException( + String.format("Invalid private database metadata file %s", metadataFile.getAbsolutePath()), jpe); + } + } + + private static PrivateDatabaseMetadata tryReadV1(final File metadataFile) throws IOException { + final V1 v1 = MAPPER.readValue(metadataFile, V1.class); + final var versionedStorageFormat = switch (v1.privacyVersion) { + case 1 -> PrivateVersionedStorageFormat.ORIGINAL; + default -> throw new IllegalStateException("Unsupported private database version: " + v1.privacyVersion); + }; + + return + new PrivateDatabaseMetadata(versionedStorageFormat); + } + + @Override + public String toString() { + return "privateVersionedStorageFormat=" + + versionedStorageFormat; + } + + @JsonSerialize + @SuppressWarnings("unused") + private record V1( + int privacyVersion) + {}; +} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java new file mode 100644 index 00000000000..653f7edfee0 --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java @@ -0,0 +1,28 @@ +package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; + +public enum PrivateVersionedStorageFormat { + ORIGINAL( 1); + + private final int privacyVersion; + + PrivateVersionedStorageFormat( + final int privacyVersion) { + this.privacyVersion = privacyVersion; + } + + public static PrivateVersionedStorageFormat defaultForNewDB() { + return ORIGINAL; + } + + public int getPrivacyVersion() { + return privacyVersion; + } + + + @Override + public String toString() { + return + "privacyVersion=" + privacyVersion + ; + } +} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java index 7e2059b5644..319a1e69de6 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java @@ -1,20 +1,14 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; -import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; -import java.util.Arrays; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public enum VersionedStorageFormat { FOREST_ORIGINAL(DataStorageFormat.FOREST, 1, 1), FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2, 1), BONSAI_ORIGINAL(DataStorageFormat.BONSAI, 1, 1), BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2, 1); - private static final Logger LOG = LoggerFactory.getLogger(VersionedStorageFormat.class); +// private static final Logger LOG = LoggerFactory.getLogger(VersionedStorageFormat.class); private final DataStorageFormat format; private final int version; private final int privacyVersion; @@ -26,7 +20,7 @@ public enum VersionedStorageFormat { this.privacyVersion = privacyVersion; } - public static VersionedStorageFormat fromFormat(final DataStorageFormat format) { + public static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { return switch (format) { case FOREST -> FOREST_WITH_VARIABLES; case BONSAI -> BONSAI_WITH_VARIABLES; @@ -45,21 +39,31 @@ public int getPrivacyVersion() { return privacyVersion; } - public static VersionedStorageFormat fromMetadata(final DatabaseMetadata metadata) { - return Arrays.stream(values()) - .filter( - vsf -> - vsf.format.equals(metadata.getFormat()) - && vsf.version == metadata.getVersion() - && (metadata.maybePrivacyVersion().isPresent() - ? metadata.maybePrivacyVersion().getAsInt() == vsf.privacyVersion - : true)) - .findFirst() - .orElseThrow( - () -> { - final String message = "Unsupported RocksDB metadata: " + metadata; - LOG.error(message); - throw new StorageException(message); - }); +// static VersionedStorageFormat fromMetadata(final DatabaseMetadata metadata) { +// return Arrays.stream(values()) +// .filter( +// vsf -> +// vsf.format.equals(metadata.getFormat()) +// && vsf.version == metadata.getVersion() +// && (metadata.maybePrivacyVersion().isPresent() +// ? metadata.maybePrivacyVersion().getAsInt() == vsf.privacyVersion +// : true)) +// .findFirst() +// .orElseThrow( +// () -> { +// final String message = "Unsupported RocksDB metadata: " + metadata; +// LOG.error(message); +// throw new StorageException(message); +// }); +// } + + + @Override + public String toString() { + return + "format=" + format + + ", version=" + version + + ", privacyVersion=" + privacyVersion + ; } } 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 e014dbaabce..52c18fb6192 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 @@ -24,6 +24,7 @@ import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; import java.nio.file.Files; @@ -94,12 +95,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { // Side effect is creation of the Metadata version file storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isNotEmpty(); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().getAsInt()) - .isEqualTo(DEFAULT_PRIVACY_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()).isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); } @Test @@ -116,18 +112,16 @@ public void shouldUpdateCorrectMetadataFileForLatestVersion() throws Exception { storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isEmpty(); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()).isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); final RocksDBKeyValuePrivacyStorageFactory privacyStorageFactory = new RocksDBKeyValuePrivacyStorageFactory(storageFactory); privacyStorageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isNotEmpty(); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).maybePrivacyVersion()).isNotEmpty(); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().getAsInt()) + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).maybePrivacyVersion().getAsInt()) .isEqualTo(DEFAULT_PRIVACY_VERSION); } } 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 f254052b7c8..21d3d248188 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 @@ -68,7 +68,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { // Side effect is creation of the Metadata version file storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).getVersion()).isEqualTo(DEFAULT_VERSION); } @Test @@ -86,7 +86,7 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).getVersion()).isEqualTo(DEFAULT_VERSION); } @Test @@ -104,7 +104,7 @@ public void shouldDetectCorrectVersionIfMetadataFileExists() throws Exception { storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).getVersion()).isEqualTo(DEFAULT_VERSION); assertThat(storageFactory.isSegmentIsolationSupported()).isTrue(); } @@ -224,7 +224,7 @@ public void shouldCreateDBCorrectlyIfSymlink() throws Exception { // Ensure that having created everything via a symlink data dir the DB meta-data has been // created correctly storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempRealDataDir).getVersion()) + assertThat(DatabaseMetadata.lookUpFrom(tempRealDataDir, commonConfiguration.getDatabaseFormat()).getVersion()) .isEqualTo(DEFAULT_VERSION); } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java index a232af7bd3c..f83ad4643e4 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java @@ -32,20 +32,25 @@ class DatabaseMetadataTest { @Test void readingMetadataV1() throws Exception { final Path tempDataDir = - createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":2 , \"privacyVersion\":1}"); + createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":2}"); final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); - assertThat(databaseMetadata.getFormat()).isEqualTo(DataStorageFormat.BONSAI); - assertThat(databaseMetadata.maybePrivacyVersion()).isNotEmpty(); - assertThat(databaseMetadata.maybePrivacyVersion().getAsInt()).isEqualTo(1); + assertThat(databaseMetadata.getVersionedStorageFormat()).isEqualTo(VersionedStorageFormat.BONSAI_WITH_VARIABLES); } @Test - void metaFileShouldBeSoughtIntoDataDirFirst() throws Exception { + void readingMetadataV2() throws Exception { + final Path tempDataDir = + createAndWrite("data", "DATABASE_METADATA.json", "{\"v2\":{\"format\":\"FOREST\",\"version\":2}}"); + + final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); + assertThat(databaseMetadata.getVersionedStorageFormat()).isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); + } + + @Test + void unsupportedMetadata() throws Exception { final Path tempDataDir = createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":42}"); final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); - assertThat(databaseMetadata).isNotNull(); - assertThat(databaseMetadata.getVersion()).isEqualTo(42); } private Path createAndWrite(final String dir, final String file, final String content) From 8cf7802fa340feb677b8ad178354f1d942589ad2 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 30 Jan 2024 19:48:40 +0100 Subject: [PATCH 03/13] WIP Signed-off-by: Fabio Di Fabio --- .../besu/ethereum/chain/GenesisState.java | 2 +- .../besu/ethereum/chain/GenesisStateTest.java | 2 +- .../services/storage/DataStorageFormat.java | 20 +--- .../RocksDBKeyValuePrivacyStorageFactory.java | 15 +-- .../RocksDBKeyValueStorageFactory.java | 8 +- .../configuration/DatabaseMetadata.java | 76 ++++++++-------- .../PrivateDatabaseMetadata.java | 91 ++++++------------- .../PrivateVersionedStorageFormat.java | 24 +++-- .../configuration/VersionedStorageFormat.java | 57 ++++-------- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 24 ++--- .../RocksDBKeyValueStorageFactoryTest.java | 19 ++-- .../configuration/DatabaseMetadataTest.java | 16 ++-- 12 files changed, 152 insertions(+), 202 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java index cc9240fd048..3e5f9ed5291 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.log.LogsBloomFilter; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.math.BigInteger; import java.util.HashMap; @@ -51,7 +52,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; public final class GenesisState { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java index 4a38153913b..8844c0b9c37 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.evm.account.Account; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.util.stream.Stream; @@ -33,7 +34,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; import org.bouncycastle.util.encoders.Hex; -import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java index be7dd0b8d6f..403541bbd95 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * 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 @@ -11,28 +11,10 @@ * specific language governing permissions and limitations under the License. * * SPDX-License-Identifier: Apache-2.0 - * */ - package org.hyperledger.besu.plugin.services.storage; -import java.util.Arrays; - public enum DataStorageFormat { FOREST, // Original format. Store all tries BONSAI; // New format. Store one trie, and trie logs to roll forward and backward. - -// @Deprecated private final int legacyVersion; - -// DataStorageFormat(final int legacyVersion) { -// this.legacyVersion = legacyVersion; -// } - -// public int getLegacyVersion() { -// return legacyVersion; -// } -// -// public static DataStorageFormat fromLegacyVersion(final int i) { -// return Arrays.stream(values()).filter(v -> v.legacyVersion == i).findFirst().orElseThrow(); -// } } 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 61095bdfdda..70894ad13e1 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 @@ -22,6 +22,7 @@ import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateDatabaseMetadata; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; import java.io.IOException; import java.nio.file.Files; @@ -30,7 +31,6 @@ import java.util.List; import java.util.Set; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,7 +41,8 @@ public class RocksDBKeyValuePrivacyStorageFactory implements PrivacyKeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValuePrivacyStorageFactory.class); - private static final Set SUPPORTED_VERSIONS = EnumSet.of(PrivateVersionedStorageFormat.ORIGINAL); + private static final Set SUPPORTED_VERSIONS = + EnumSet.of(PrivateVersionedStorageFormat.ORIGINAL); private static final String PRIVATE_DATABASE_PATH = "private"; private final RocksDBKeyValueStorageFactory publicFactory; private PrivateDatabaseMetadata databaseMetadata; @@ -114,7 +115,8 @@ public void close() throws IOException { * private database exists there may be a "privacyVersion" field in the metadata file otherwise * use the default version */ - private PrivateDatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) throws IOException { + private PrivateDatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) + throws IOException { final Path dataDir = commonConfiguration.getDataPath(); final boolean privacyDatabaseExists = commonConfiguration.getStoragePath().resolve(PRIVATE_DATABASE_PATH).toFile().exists(); @@ -122,7 +124,9 @@ private PrivateDatabaseMetadata readDatabaseMetadata(final BesuConfiguration com if (privacyDatabaseExists) { privateDatabaseMetadata = PrivateDatabaseMetadata.lookUpFrom(dataDir); LOG.info( - "Existing private database detected at {}. Metadata {}", dataDir, privateDatabaseMetadata); + "Existing private database detected at {}. Metadata {}", + dataDir, + privateDatabaseMetadata); } else { privateDatabaseMetadata = PrivateDatabaseMetadata.defaultForNewDb(); LOG.info( @@ -130,8 +134,7 @@ private PrivateDatabaseMetadata readDatabaseMetadata(final BesuConfiguration com dataDir, privateDatabaseMetadata); Files.createDirectories(dataDir); - privateDatabaseMetadata - .writeToDirectory(dataDir); + privateDatabaseMetadata.writeToDirectory(dataDir); } if (!SUPPORTED_VERSIONS.contains(privateDatabaseMetadata.getPrivateVersionedStorageFormat())) { 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 751f3c0cf00..68a9005e309 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 @@ -185,7 +185,8 @@ public SegmentedKeyValueStorage create( configuredSegments.stream() .filter( segmentId -> - segmentId.includeInDatabaseFormat(databaseMetadata.getVersionedStorageFormat().getFormat())) + segmentId.includeInDatabaseFormat( + databaseMetadata.getVersionedStorageFormat().getFormat())) .toList(); // It's probably a good idea for the creation logic to be entirely dependent on the database @@ -262,7 +263,10 @@ private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConf databaseMetadata); } else { databaseMetadata = DatabaseMetadata.defaultForNewDb(commonConfiguration.getDatabaseFormat()); - LOG.info("No existing database detected at {}. Using default metadata for new db {}", dataDir, databaseMetadata); + LOG.info( + "No existing database detected at {}. Using default metadata for new db {}", + dataDir, + databaseMetadata); if (!dataDirExists) { Files.createDirectories(dataDir); } 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 4ee69f26898..550c560bf7c 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 @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; @@ -23,11 +22,11 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Arrays; -import java.util.OptionalInt; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DatabindException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,9 +39,8 @@ public class DatabaseMetadata { private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); private final VersionedStorageFormat versionedStorageFormat; - private DatabaseMetadata( - final VersionedStorageFormat versionedStorageFormat) { - this.versionedStorageFormat = versionedStorageFormat; + private DatabaseMetadata(final VersionedStorageFormat versionedStorageFormat) { + this.versionedStorageFormat = versionedStorageFormat; } public static DatabaseMetadata defaultForNewDb(final DataStorageFormat dataStorageFormat) { @@ -56,7 +54,7 @@ public VersionedStorageFormat getVersionedStorageFormat() { /** * Look up database metadata. * - * @param dataDir the data dir + * @param dataDir the data dir * @return the database metadata * @throws IOException the io exception */ @@ -76,7 +74,11 @@ public void writeToDirectory(final Path dataDir) throws IOException { } private void writeToFile(final File file) throws IOException { - MAPPER.writeValue(file, new V2(new MetadataV2(versionedStorageFormat.getFormat(), versionedStorageFormat.getVersion()))); + MAPPER.writeValue( + file, + new V2( + new MetadataV2( + versionedStorageFormat.getFormat(), versionedStorageFormat.getVersion()))); } private static File getDefaultMetadataFile(final Path dataDir) { @@ -92,7 +94,10 @@ private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) return tryReadV2(metadataFile); } } catch (FileNotFoundException fnfe) { - throw new IllegalStateException("Database exists but metadata file " + metadataFile.toString() + " not found, without it there is no safe way to open the database"); + throw new IllegalStateException( + "Database exists but metadata file " + + metadataFile.toString() + + " not found, without it there is no safe way to open the database"); } catch (JsonProcessingException jpe) { throw new IllegalStateException( String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); @@ -101,15 +106,16 @@ private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) private static DatabaseMetadata tryReadAndMigrateV1(final File metadataFile) throws IOException { final V1 v1 = MAPPER.readValue(metadataFile, V1.class); - // when migrating from v1, this version will automatically migrate the db to the variables storage, so we use the `_WITH_VARIABLES` variants - final var versionedStorageFormat = switch (v1.version()) { - case 1 -> VersionedStorageFormat.FOREST_WITH_VARIABLES; - case 2 -> VersionedStorageFormat.BONSAI_WITH_VARIABLES; - default -> throw new IllegalStateException("Unsupported db version: " + v1.version()); - }; - - final DatabaseMetadata metadataV2 = - new DatabaseMetadata(versionedStorageFormat); + // when migrating from v1, this version will automatically migrate the db to the variables + // storage, so we use the `_WITH_VARIABLES` variants + final var versionedStorageFormat = + switch (v1.version()) { + case 1 -> VersionedStorageFormat.FOREST_WITH_VARIABLES; + case 2 -> VersionedStorageFormat.BONSAI_WITH_VARIABLES; + default -> throw new IllegalStateException("Unsupported db version: " + v1.version()); + }; + + final DatabaseMetadata metadataV2 = new DatabaseMetadata(versionedStorageFormat); // writing the metadata will migrate to v2 metadataV2.writeToFile(metadataFile); return metadataV2; @@ -122,38 +128,34 @@ private static DatabaseMetadata tryReadV2(final File metadataFile) throws IOExce private static VersionedStorageFormat fromV2(final MetadataV2 metadataV2) { return Arrays.stream(VersionedStorageFormat.values()) - .filter( - vsf -> - vsf.getFormat().equals(metadataV2.format()) - && vsf.getVersion() == metadataV2.version()) - .findFirst() - .orElseThrow( - () -> { - final String message = "Unsupported RocksDB metadata: " + metadataV2; - LOG.error(message); - throw new StorageException(message); - }); + .filter( + vsf -> + vsf.getFormat().equals(metadataV2.format()) + && vsf.getVersion() == metadataV2.version()) + .findFirst() + .orElseThrow( + () -> { + final String message = "Unsupported RocksDB metadata: " + metadataV2; + LOG.error(message); + throw new StorageException(message); + }); } @Override public String toString() { - return "versionedStorageFormat=" - + versionedStorageFormat; + return "versionedStorageFormat=" + versionedStorageFormat; } @JsonSerialize @SuppressWarnings("unused") - private record V1( - int version) - {}; + private record V1(int version) {} + ; @JsonSerialize @SuppressWarnings("unused") - private record V2(MetadataV2 v2) { - } + private record V2(MetadataV2 v2) {} @JsonSerialize @SuppressWarnings("unused") - private record MetadataV2(DataStorageFormat format, int version) { - } + private record MetadataV2(DataStorageFormat format, int version) {} } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java index 6ba5865d240..17866681f91 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * 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 @@ -14,6 +14,11 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb.configuration; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -21,11 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Path; - /** The Database metadata. */ public class PrivateDatabaseMetadata { private static final Logger LOG = LoggerFactory.getLogger(PrivateDatabaseMetadata.class); @@ -33,46 +33,9 @@ public class PrivateDatabaseMetadata { private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); private final PrivateVersionedStorageFormat versionedStorageFormat; -// -// /** -// * Instantiates a new Database metadata. -// * -// * @param format the format -// * @param version the version -// */ -// public DatabaseMetadata(final DataStorageFormat format, final int version) { -// this(format, version, OptionalInt.empty()); -// } -// -// /** -// * Instantiates a new Database metadata. -// * -// * @param format the format -// * @param version the version -// * @param privacyVersion the privacy version -// */ -// public DatabaseMetadata( -// final DataStorageFormat format, final int version, final int privacyVersion) { -// this(format, version, OptionalInt.of(privacyVersion)); -// } -// -// /** -// * Instantiates a new Database metadata. -// * -// * @param format the format -// * @param version the version -// * @param maybePrivacyVersion the optional privacy version -// */ -// private DatabaseMetadata( -// final DataStorageFormat format, final int version, final OptionalInt maybePrivacyVersion) { -// this.format = format; -// this.version = version; -// this.maybePrivacyVersion = maybePrivacyVersion; -// } - - private PrivateDatabaseMetadata( - final PrivateVersionedStorageFormat versionedStorageFormat) { - this.versionedStorageFormat = versionedStorageFormat; + + private PrivateDatabaseMetadata(final PrivateVersionedStorageFormat versionedStorageFormat) { + this.versionedStorageFormat = versionedStorageFormat; } public static PrivateDatabaseMetadata defaultForNewDb() { @@ -86,7 +49,7 @@ public PrivateVersionedStorageFormat getPrivateVersionedStorageFormat() { /** * Look up database metadata. * - * @param dataDir the data dir + * @param dataDir the data dir * @return the database metadata * @throws IOException the io exception */ @@ -116,35 +79,39 @@ private static File getDefaultMetadataFile(final Path dataDir) { private static PrivateDatabaseMetadata resolveDatabaseMetadata(final File metadataFile) throws IOException { try { - return tryReadV1(metadataFile); + return tryReadV1(metadataFile); } catch (FileNotFoundException fnfe) { - throw new IllegalStateException("Private database exists but metadata file " + metadataFile.toString() + " not found, without it there is no safe way to open the private database"); + throw new IllegalStateException( + "Private database exists but metadata file " + + metadataFile.toString() + + " not found, without it there is no safe way to open the private database"); } catch (JsonProcessingException jpe) { throw new IllegalStateException( - String.format("Invalid private database metadata file %s", metadataFile.getAbsolutePath()), jpe); + String.format( + "Invalid private database metadata file %s", metadataFile.getAbsolutePath()), + jpe); } } private static PrivateDatabaseMetadata tryReadV1(final File metadataFile) throws IOException { final V1 v1 = MAPPER.readValue(metadataFile, V1.class); - final var versionedStorageFormat = switch (v1.privacyVersion) { - case 1 -> PrivateVersionedStorageFormat.ORIGINAL; - default -> throw new IllegalStateException("Unsupported private database version: " + v1.privacyVersion); - }; - - return - new PrivateDatabaseMetadata(versionedStorageFormat); + final var versionedStorageFormat = + switch (v1.privacyVersion) { + case 1 -> PrivateVersionedStorageFormat.ORIGINAL; + default -> throw new IllegalStateException( + "Unsupported private database version: " + v1.privacyVersion); + }; + + return new PrivateDatabaseMetadata(versionedStorageFormat); } @Override public String toString() { - return "privateVersionedStorageFormat=" - + versionedStorageFormat; + return "privateVersionedStorageFormat=" + versionedStorageFormat; } @JsonSerialize @SuppressWarnings("unused") - private record V1( - int privacyVersion) - {}; + private record V1(int privacyVersion) {} + ; } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java index 653f7edfee0..b35ba86489f 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java @@ -1,12 +1,25 @@ +/* + * 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.configuration; public enum PrivateVersionedStorageFormat { - ORIGINAL( 1); + ORIGINAL(1); private final int privacyVersion; - PrivateVersionedStorageFormat( - final int privacyVersion) { + PrivateVersionedStorageFormat(final int privacyVersion) { this.privacyVersion = privacyVersion; } @@ -18,11 +31,8 @@ public int getPrivacyVersion() { return privacyVersion; } - @Override public String toString() { - return - "privacyVersion=" + privacyVersion - ; + return "privacyVersion=" + privacyVersion; } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java index 319a1e69de6..ded7fcb2fe2 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java @@ -1,23 +1,33 @@ +/* + * 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.configuration; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; public enum VersionedStorageFormat { - FOREST_ORIGINAL(DataStorageFormat.FOREST, 1, 1), - FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2, 1), - BONSAI_ORIGINAL(DataStorageFormat.BONSAI, 1, 1), - BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2, 1); + FOREST_ORIGINAL(DataStorageFormat.FOREST, 1), + FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2), + BONSAI_ORIGINAL(DataStorageFormat.BONSAI, 1), + BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2); -// private static final Logger LOG = LoggerFactory.getLogger(VersionedStorageFormat.class); private final DataStorageFormat format; private final int version; - private final int privacyVersion; - VersionedStorageFormat( - final DataStorageFormat format, final int version, final int privacyVersion) { + VersionedStorageFormat(final DataStorageFormat format, final int version) { this.format = format; this.version = version; - this.privacyVersion = privacyVersion; } public static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { @@ -35,35 +45,8 @@ public int getVersion() { return version; } - public int getPrivacyVersion() { - return privacyVersion; - } - -// static VersionedStorageFormat fromMetadata(final DatabaseMetadata metadata) { -// return Arrays.stream(values()) -// .filter( -// vsf -> -// vsf.format.equals(metadata.getFormat()) -// && vsf.version == metadata.getVersion() -// && (metadata.maybePrivacyVersion().isPresent() -// ? metadata.maybePrivacyVersion().getAsInt() == vsf.privacyVersion -// : true)) -// .findFirst() -// .orElseThrow( -// () -> { -// final String message = "Unsupported RocksDB metadata: " + metadata; -// LOG.error(message); -// throw new StorageException(message); -// }); -// } - - @Override public String toString() { - return - "format=" + format + - ", version=" + version + - ", privacyVersion=" + privacyVersion - ; + return "format=" + format + ", version=" + version; } } 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 52c18fb6192..dc9b0f826a2 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 @@ -24,6 +24,7 @@ import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateDatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; @@ -39,9 +40,6 @@ @ExtendWith(MockitoExtension.class) public class RocksDBKeyValuePrivacyStorageFactoryTest { - private static final int DEFAULT_VERSION = 1; - private static final int DEFAULT_PRIVACY_VERSION = 1; - @Mock private RocksDBFactoryConfiguration rocksDbConfiguration; @Mock private BesuConfiguration commonConfiguration; @TempDir private Path temporaryFolder; @@ -69,12 +67,8 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception // Side effect is creation of the Metadata version file storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion()).isNotEmpty(); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersion()).isEqualTo(DEFAULT_VERSION); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).maybePrivacyVersion().getAsInt()) - .isEqualTo(DEFAULT_VERSION); + assertThat(PrivateDatabaseMetadata.lookUpFrom(tempDataDir).getPrivateVersionedStorageFormat()) + .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); } @Test @@ -95,7 +89,8 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { // Side effect is creation of the Metadata version file storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()).isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); + assertThat(PrivateDatabaseMetadata.lookUpFrom(tempDataDir).getPrivateVersionedStorageFormat()) + .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); } @Test @@ -112,16 +107,15 @@ public void shouldUpdateCorrectMetadataFileForLatestVersion() throws Exception { storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()).isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); final RocksDBKeyValuePrivacyStorageFactory privacyStorageFactory = new RocksDBKeyValuePrivacyStorageFactory(storageFactory); privacyStorageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).maybePrivacyVersion()).isNotEmpty(); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).maybePrivacyVersion().getAsInt()) - .isEqualTo(DEFAULT_PRIVACY_VERSION); + assertThat(PrivateDatabaseMetadata.lookUpFrom(tempDataDir).getPrivateVersionedStorageFormat()) + .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); } } 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 21d3d248188..262c415ab49 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 @@ -27,6 +27,7 @@ import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorageTest.TestSegment; import java.nio.charset.Charset; @@ -44,7 +45,6 @@ public class RocksDBKeyValueStorageFactoryTest { private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; - private static final int DEFAULT_VERSION = 1; @Mock private RocksDBFactoryConfiguration rocksDbConfiguration; @Mock private BesuConfiguration commonConfiguration; @@ -68,7 +68,8 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { // Side effect is creation of the Metadata version file storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); } @Test @@ -86,7 +87,8 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); } @Test @@ -104,7 +106,8 @@ public void shouldDetectCorrectVersionIfMetadataFileExists() throws Exception { storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir, commonConfiguration.getDatabaseFormat()).getVersion()).isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); assertThat(storageFactory.isSegmentIsolationSupported()).isTrue(); } @@ -144,7 +147,9 @@ public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - new DatabaseMetadata(DataStorageFormat.FOREST, 99).writeToDirectory(tempDataDir); + final String badVersion = "{\"version\":99}"; + Files.write( + tempDataDir.resolve(METADATA_FILENAME), badVersion.getBytes(Charset.defaultCharset())); assertThatThrownBy( () -> new RocksDBKeyValueStorageFactory( @@ -224,7 +229,7 @@ public void shouldCreateDBCorrectlyIfSymlink() throws Exception { // Ensure that having created everything via a symlink data dir the DB meta-data has been // created correctly storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempRealDataDir, commonConfiguration.getDatabaseFormat()).getVersion()) - .isEqualTo(DEFAULT_VERSION); + assertThat(DatabaseMetadata.lookUpFrom(tempRealDataDir).getVersionedStorageFormat()) + .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java index f83ad4643e4..5a23826d119 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java @@ -17,8 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -31,26 +29,28 @@ class DatabaseMetadataTest { @Test void readingMetadataV1() throws Exception { - final Path tempDataDir = - createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":2}"); + final Path tempDataDir = createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":2}"); final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); - assertThat(databaseMetadata.getVersionedStorageFormat()).isEqualTo(VersionedStorageFormat.BONSAI_WITH_VARIABLES); + assertThat(databaseMetadata.getVersionedStorageFormat()) + .isEqualTo(VersionedStorageFormat.BONSAI_WITH_VARIABLES); } @Test void readingMetadataV2() throws Exception { final Path tempDataDir = - createAndWrite("data", "DATABASE_METADATA.json", "{\"v2\":{\"format\":\"FOREST\",\"version\":2}}"); + createAndWrite( + "data", "DATABASE_METADATA.json", "{\"v2\":{\"format\":\"FOREST\",\"version\":2}}"); final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); - assertThat(databaseMetadata.getVersionedStorageFormat()).isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); + assertThat(databaseMetadata.getVersionedStorageFormat()) + .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); } @Test void unsupportedMetadata() throws Exception { final Path tempDataDir = createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":42}"); - final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); + DatabaseMetadata.lookUpFrom(tempDataDir); } private Path createAndWrite(final String dir, final String file, final String content) From fd1f9cb050da915aef9eae337a7c63c8ac4104d2 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 31 Jan 2024 19:49:26 +0100 Subject: [PATCH 04/13] WIP Signed-off-by: Fabio Di Fabio --- .../RocksDBKeyValuePrivacyStorageFactory.java | 57 ++++++--- .../RocksDBKeyValueStorageFactory.java | 29 +++-- .../BaseVersionedStorageFormat.java | 61 +++++++++ .../configuration/DatabaseMetadata.java | 92 +++++++++++--- .../PrivacyVersionedStorageFormat.java | 67 ++++++++++ .../PrivateDatabaseMetadata.java | 117 ------------------ .../PrivateVersionedStorageFormat.java | 38 ------ .../configuration/VersionedStorageFormat.java | 34 +---- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 41 +++--- .../RocksDBKeyValueStorageFactoryTest.java | 109 ++++++++++------ .../services/storage/rocksdb/Utils.java | 69 +++++++++++ .../configuration/DatabaseMetadataTest.java | 35 +++++- 12 files changed, 464 insertions(+), 285 deletions(-) create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java delete mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java delete mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java create mode 100644 plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java 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 70894ad13e1..85e21044248 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 @@ -21,8 +21,8 @@ import org.hyperledger.besu.plugin.services.storage.PrivacyKeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateDatabaseMetadata; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivacyVersionedStorageFormat; import java.io.IOException; import java.nio.file.Files; @@ -41,11 +41,13 @@ public class RocksDBKeyValuePrivacyStorageFactory implements PrivacyKeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValuePrivacyStorageFactory.class); - private static final Set SUPPORTED_VERSIONS = - EnumSet.of(PrivateVersionedStorageFormat.ORIGINAL); + private static final Set SUPPORTED_VERSIONS = + EnumSet.of( + PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES, + PrivacyVersionedStorageFormat.BONSAI_WITH_VARIABLES); private static final String PRIVATE_DATABASE_PATH = "private"; private final RocksDBKeyValueStorageFactory publicFactory; - private PrivateDatabaseMetadata databaseMetadata; + private DatabaseMetadata databaseMetadata; /** * Instantiates a new RocksDb key value privacy storage factory. @@ -115,39 +117,54 @@ public void close() throws IOException { * private database exists there may be a "privacyVersion" field in the metadata file otherwise * use the default version */ - private PrivateDatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) + private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) throws IOException { final Path dataDir = commonConfiguration.getDataPath(); final boolean privacyDatabaseExists = commonConfiguration.getStoragePath().resolve(PRIVATE_DATABASE_PATH).toFile().exists(); - final PrivateDatabaseMetadata privateDatabaseMetadata; - if (privacyDatabaseExists) { - privateDatabaseMetadata = PrivateDatabaseMetadata.lookUpFrom(dataDir); - LOG.info( - "Existing private database detected at {}. Metadata {}", - dataDir, - privateDatabaseMetadata); + final boolean privacyDatabaseMetadataExists = DatabaseMetadata.isPresent(dataDir); + final DatabaseMetadata privacyDatabaseMetadata; + if (privacyDatabaseExists && !privacyDatabaseMetadataExists) { + throw new StorageException( + "Privacy database exists but metadata file not found, without it there is no safe way to open the database"); + } + if (privacyDatabaseMetadataExists) { + final var existingDatabaseMetadata = DatabaseMetadata.lookUpFrom(dataDir); + if (existingDatabaseMetadata.getVersionedStorageFormat().getPrivacyVersion().isEmpty()) { + privacyDatabaseMetadata = existingDatabaseMetadata.upgradeToPrivacy(); + privacyDatabaseMetadata.writeToDirectory(dataDir); + LOG.info( + "Upgraded existing database detected at {} to privacy database. Metadata {}", + dataDir, + existingDatabaseMetadata); + } else { + privacyDatabaseMetadata = existingDatabaseMetadata; + LOG.info( + "Existing privacy database detected at {}. Metadata {}", + dataDir, + privacyDatabaseMetadata); + } } else { - privateDatabaseMetadata = PrivateDatabaseMetadata.defaultForNewDb(); + privacyDatabaseMetadata = DatabaseMetadata.defaultForNewPrivateDb(); LOG.info( "No existing private database detected at {}. Using default metadata for new db {}", dataDir, - privateDatabaseMetadata); + privacyDatabaseMetadata); Files.createDirectories(dataDir); - privateDatabaseMetadata.writeToDirectory(dataDir); + privacyDatabaseMetadata.writeToDirectory(dataDir); } - if (!SUPPORTED_VERSIONS.contains(privateDatabaseMetadata.getPrivateVersionedStorageFormat())) { - final String message = "Unsupported RocksDB Metadata version of: " + privateDatabaseMetadata; + if (!SUPPORTED_VERSIONS.contains(privacyDatabaseMetadata.getVersionedStorageFormat())) { + final String message = "Unsupported RocksDB Metadata version of: " + privacyDatabaseMetadata; LOG.error(message); throw new StorageException(message); } - return privateDatabaseMetadata; + return privacyDatabaseMetadata; } @Override public int getVersion() { - return databaseMetadata.getPrivateVersionedStorageFormat().getPrivacyVersion(); + return databaseMetadata.getVersionedStorageFormat().getPrivacyVersion().getAsInt(); } } 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 68a9005e309..53094d429e9 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 @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.plugin.services.storage.rocksdb; -import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat.BONSAI_WITH_VARIABLES; -import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat.FOREST_WITH_VARIABLES; +import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.BaseVersionedStorageFormat.BONSAI_WITH_VARIABLES; +import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.BaseVersionedStorageFormat.FOREST_WITH_VARIABLES; import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -25,6 +25,7 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.BaseVersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; @@ -53,9 +54,8 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValueStorageFactory.class); - private static final VersionedStorageFormat DEFAULT_VERSIONED_FORMAT = - VersionedStorageFormat.FOREST_WITH_VARIABLES; - private static final EnumSet SUPPORTED_VERSIONED_FORMATS = + private static final VersionedStorageFormat DEFAULT_VERSIONED_FORMAT = FOREST_WITH_VARIABLES; + private static final EnumSet SUPPORTED_VERSIONED_FORMATS = EnumSet.of(FOREST_WITH_VARIABLES, BONSAI_WITH_VARIABLES); private static final String NAME = "rocksdb"; private final RocksDBMetricsFactory rocksDBMetricsFactory; @@ -252,10 +252,15 @@ private boolean requiresInit() { private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConfiguration) throws IOException { final Path dataDir = commonConfiguration.getDataPath(); - final boolean databaseExists = commonConfiguration.getStoragePath().toFile().exists(); final boolean dataDirExists = dataDir.toFile().exists(); + final boolean databaseExists = commonConfiguration.getStoragePath().toFile().exists(); + final boolean databaseMetadataExists = DatabaseMetadata.isPresent(dataDir); final DatabaseMetadata databaseMetadata; - if (databaseExists) { + if (databaseExists && !databaseMetadataExists) { + throw new StorageException( + "Database exists but metadata file not found, without it there is no safe way to open the database"); + } + if (databaseMetadataExists) { databaseMetadata = DatabaseMetadata.lookUpFrom(dataDir); LOG.info( "Existing database detected at {}. Metadata {}. Processing WAL...", @@ -273,7 +278,7 @@ private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConf databaseMetadata.writeToDirectory(dataDir); } - if (!SUPPORTED_VERSIONED_FORMATS.contains(databaseMetadata.getVersionedStorageFormat())) { + if (!isSupportedVersionedFormat(databaseMetadata.getVersionedStorageFormat())) { final String message = "Unsupported RocksDB metadata: " + databaseMetadata; LOG.error(message); throw new StorageException(message); @@ -282,6 +287,14 @@ private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConf return databaseMetadata; } + private boolean isSupportedVersionedFormat(final VersionedStorageFormat versionedStorageFormat) { + return SUPPORTED_VERSIONED_FORMATS.stream() + .anyMatch( + vsf -> + vsf.getFormat().equals(versionedStorageFormat.getFormat()) + && vsf.getVersion() == versionedStorageFormat.getVersion()); + } + @Override public void close() throws IOException { if (segmentedStorage != null) { diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java new file mode 100644 index 00000000000..2a7de3c9642 --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java @@ -0,0 +1,61 @@ +/* + * 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.configuration; + +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import java.util.OptionalInt; + +public enum BaseVersionedStorageFormat implements VersionedStorageFormat { + FOREST_ORIGINAL(DataStorageFormat.FOREST, 1), + FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2), + BONSAI_ORIGINAL(DataStorageFormat.BONSAI, 1), + BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2); + + private final DataStorageFormat format; + private final int version; + + BaseVersionedStorageFormat(final DataStorageFormat format, final int version) { + this.format = format; + this.version = version; + } + + static BaseVersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { + return switch (format) { + case FOREST -> FOREST_WITH_VARIABLES; + case BONSAI -> BONSAI_WITH_VARIABLES; + }; + } + + @Override + public DataStorageFormat getFormat() { + return format; + } + + @Override + public int getVersion() { + return version; + } + + @Override + public OptionalInt getPrivacyVersion() { + return OptionalInt.empty(); + } + + @Override + public String toString() { + return "BaseVersionedStorageFormat{" + "format=" + format + ", version=" + version + '}'; + } +} 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 550c560bf7c..182d3af905f 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 @@ -22,6 +22,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Arrays; +import java.util.OptionalInt; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DatabindException; @@ -39,12 +40,16 @@ public class DatabaseMetadata { private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); private final VersionedStorageFormat versionedStorageFormat; - private DatabaseMetadata(final VersionedStorageFormat versionedStorageFormat) { + protected DatabaseMetadata(final VersionedStorageFormat versionedStorageFormat) { this.versionedStorageFormat = versionedStorageFormat; } public static DatabaseMetadata defaultForNewDb(final DataStorageFormat dataStorageFormat) { - return new DatabaseMetadata(VersionedStorageFormat.defaultForNewDB(dataStorageFormat)); + return new DatabaseMetadata(BaseVersionedStorageFormat.defaultForNewDB(dataStorageFormat)); + } + + public static DatabaseMetadata defaultForNewPrivateDb() { + return new DatabaseMetadata(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); } public VersionedStorageFormat getVersionedStorageFormat() { @@ -63,6 +68,10 @@ public static DatabaseMetadata lookUpFrom(final Path dataDir) throws IOException return resolveDatabaseMetadata(getDefaultMetadataFile(dataDir)); } + public static boolean isPresent(final Path dataDir) throws IOException { + return getDefaultMetadataFile(dataDir).exists(); + } + /** * Write to directory. * @@ -78,7 +87,9 @@ private void writeToFile(final File file) throws IOException { file, new V2( new MetadataV2( - versionedStorageFormat.getFormat(), versionedStorageFormat.getVersion()))); + versionedStorageFormat.getFormat(), + versionedStorageFormat.getVersion(), + versionedStorageFormat.getPrivacyVersion()))); } private static File getDefaultMetadataFile(final Path dataDir) { @@ -94,10 +105,11 @@ private static DatabaseMetadata resolveDatabaseMetadata(final File metadataFile) return tryReadV2(metadataFile); } } catch (FileNotFoundException fnfe) { - throw new IllegalStateException( + throw new StorageException( "Database exists but metadata file " + metadataFile.toString() - + " not found, without it there is no safe way to open the database"); + + " not found, without it there is no safe way to open the database", + fnfe); } catch (JsonProcessingException jpe) { throw new IllegalStateException( String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); @@ -108,12 +120,26 @@ private static DatabaseMetadata tryReadAndMigrateV1(final File metadataFile) thr final V1 v1 = MAPPER.readValue(metadataFile, V1.class); // when migrating from v1, this version will automatically migrate the db to the variables // storage, so we use the `_WITH_VARIABLES` variants - final var versionedStorageFormat = - switch (v1.version()) { - case 1 -> VersionedStorageFormat.FOREST_WITH_VARIABLES; - case 2 -> VersionedStorageFormat.BONSAI_WITH_VARIABLES; - default -> throw new IllegalStateException("Unsupported db version: " + v1.version()); - }; + final VersionedStorageFormat versionedStorageFormat; + if (v1.privacyVersion().isEmpty()) { + versionedStorageFormat = + switch (v1.version()) { + case 1 -> BaseVersionedStorageFormat.FOREST_WITH_VARIABLES; + case 2 -> BaseVersionedStorageFormat.BONSAI_WITH_VARIABLES; + default -> throw new StorageException("Unsupported db version: " + v1.version()); + }; + } else { + versionedStorageFormat = + switch (v1.privacyVersion().getAsInt()) { + case 1 -> switch (v1.version()) { + case 1 -> PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES; + case 2 -> PrivacyVersionedStorageFormat.BONSAI_WITH_VARIABLES; + default -> throw new StorageException("Unsupported db version: " + v1.version()); + }; + default -> throw new StorageException( + "Unsupported db privacy version: " + v1.privacyVersion().getAsInt()); + }; + } final DatabaseMetadata metadataV2 = new DatabaseMetadata(versionedStorageFormat); // writing the metadata will migrate to v2 @@ -127,11 +153,26 @@ private static DatabaseMetadata tryReadV2(final File metadataFile) throws IOExce } private static VersionedStorageFormat fromV2(final MetadataV2 metadataV2) { - return Arrays.stream(VersionedStorageFormat.values()) + if (metadataV2.privacyVersion().isEmpty()) { + return Arrays.stream(BaseVersionedStorageFormat.values()) + .filter( + vsf -> + vsf.getFormat().equals(metadataV2.format()) + && vsf.getVersion() == metadataV2.version()) + .findFirst() + .orElseThrow( + () -> { + final String message = "Unsupported RocksDB metadata: " + metadataV2; + LOG.error(message); + throw new StorageException(message); + }); + } + return Arrays.stream(PrivacyVersionedStorageFormat.values()) .filter( vsf -> vsf.getFormat().equals(metadataV2.format()) - && vsf.getVersion() == metadataV2.version()) + && vsf.getVersion() == metadataV2.version() + && vsf.getPrivacyVersion().equals(metadataV2.privacyVersion())) .findFirst() .orElseThrow( () -> { @@ -141,6 +182,26 @@ private static VersionedStorageFormat fromV2(final MetadataV2 metadataV2) { }); } + public DatabaseMetadata upgradeToPrivacy() { + return new DatabaseMetadata( + switch (versionedStorageFormat.getFormat()) { + case FOREST -> switch (versionedStorageFormat.getVersion()) { + case 1 -> PrivacyVersionedStorageFormat.FOREST_ORIGINAL; + case 2 -> PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES; + default -> throw new StorageException( + "Unsupported database with format FOREST and version " + + versionedStorageFormat.getVersion()); + }; + case BONSAI -> switch (versionedStorageFormat.getVersion()) { + case 1 -> PrivacyVersionedStorageFormat.BONSAI_ORIGINAL; + case 2 -> PrivacyVersionedStorageFormat.BONSAI_WITH_VARIABLES; + default -> throw new StorageException( + "Unsupported database with format BONSAI and version " + + versionedStorageFormat.getVersion()); + }; + }); + } + @Override public String toString() { return "versionedStorageFormat=" + versionedStorageFormat; @@ -148,8 +209,7 @@ public String toString() { @JsonSerialize @SuppressWarnings("unused") - private record V1(int version) {} - ; + private record V1(int version, OptionalInt privacyVersion) {} @JsonSerialize @SuppressWarnings("unused") @@ -157,5 +217,5 @@ private record V2(MetadataV2 v2) {} @JsonSerialize @SuppressWarnings("unused") - private record MetadataV2(DataStorageFormat format, int version) {} + private record MetadataV2(DataStorageFormat format, int version, OptionalInt privacyVersion) {} } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java new file mode 100644 index 00000000000..ddbfe536519 --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java @@ -0,0 +1,67 @@ +/* + * 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.configuration; + +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import java.util.OptionalInt; + +public enum PrivacyVersionedStorageFormat implements VersionedStorageFormat { + FOREST_ORIGINAL(BaseVersionedStorageFormat.FOREST_ORIGINAL, 1), + FOREST_WITH_VARIABLES(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES, 1), + BONSAI_ORIGINAL(BaseVersionedStorageFormat.BONSAI_ORIGINAL, 1), + BONSAI_WITH_VARIABLES(BaseVersionedStorageFormat.BONSAI_WITH_VARIABLES, 1); + + private final VersionedStorageFormat baseVersionedStorageFormat; + private final OptionalInt privacyVersion; + + PrivacyVersionedStorageFormat( + final VersionedStorageFormat baseVersionedStorageFormat, final int privacyVersion) { + this.baseVersionedStorageFormat = baseVersionedStorageFormat; + this.privacyVersion = OptionalInt.of(privacyVersion); + } + + static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { + return switch (format) { + case FOREST -> FOREST_WITH_VARIABLES; + case BONSAI -> BONSAI_WITH_VARIABLES; + }; + } + + @Override + public DataStorageFormat getFormat() { + return baseVersionedStorageFormat.getFormat(); + } + + @Override + public int getVersion() { + return baseVersionedStorageFormat.getVersion(); + } + + @Override + public OptionalInt getPrivacyVersion() { + return privacyVersion; + } + + @Override + public String toString() { + return "PrivateVersionedStorageFormat{" + + "versionedStorageFormat=" + + baseVersionedStorageFormat + + ", privacyVersion=" + + privacyVersion + + '}'; + } +} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java deleted file mode 100644 index 17866681f91..00000000000 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateDatabaseMetadata.java +++ /dev/null @@ -1,117 +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.configuration; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Path; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** The Database metadata. */ -public class PrivateDatabaseMetadata { - private static final Logger LOG = LoggerFactory.getLogger(PrivateDatabaseMetadata.class); - - private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; - private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); - private final PrivateVersionedStorageFormat versionedStorageFormat; - - private PrivateDatabaseMetadata(final PrivateVersionedStorageFormat versionedStorageFormat) { - this.versionedStorageFormat = versionedStorageFormat; - } - - public static PrivateDatabaseMetadata defaultForNewDb() { - return new PrivateDatabaseMetadata(PrivateVersionedStorageFormat.defaultForNewDB()); - } - - public PrivateVersionedStorageFormat getPrivateVersionedStorageFormat() { - return versionedStorageFormat; - } - - /** - * Look up database metadata. - * - * @param dataDir the data dir - * @return the database metadata - * @throws IOException the io exception - */ - public static PrivateDatabaseMetadata lookUpFrom(final Path dataDir) throws IOException { - LOG.info("Lookup private database metadata file in data directory: {}", dataDir.toString()); - return resolveDatabaseMetadata(getDefaultMetadataFile(dataDir)); - } - - /** - * Write to directory. - * - * @param dataDir the data dir - * @throws IOException the io exception - */ - public void writeToDirectory(final Path dataDir) throws IOException { - writeToFile(getDefaultMetadataFile(dataDir)); - } - - private void writeToFile(final File file) throws IOException { - MAPPER.writeValue(file, new V1(versionedStorageFormat.getPrivacyVersion())); - } - - private static File getDefaultMetadataFile(final Path dataDir) { - return dataDir.resolve(METADATA_FILENAME).toFile(); - } - - private static PrivateDatabaseMetadata resolveDatabaseMetadata(final File metadataFile) - throws IOException { - try { - return tryReadV1(metadataFile); - } catch (FileNotFoundException fnfe) { - throw new IllegalStateException( - "Private database exists but metadata file " - + metadataFile.toString() - + " not found, without it there is no safe way to open the private database"); - } catch (JsonProcessingException jpe) { - throw new IllegalStateException( - String.format( - "Invalid private database metadata file %s", metadataFile.getAbsolutePath()), - jpe); - } - } - - private static PrivateDatabaseMetadata tryReadV1(final File metadataFile) throws IOException { - final V1 v1 = MAPPER.readValue(metadataFile, V1.class); - final var versionedStorageFormat = - switch (v1.privacyVersion) { - case 1 -> PrivateVersionedStorageFormat.ORIGINAL; - default -> throw new IllegalStateException( - "Unsupported private database version: " + v1.privacyVersion); - }; - - return new PrivateDatabaseMetadata(versionedStorageFormat); - } - - @Override - public String toString() { - return "privateVersionedStorageFormat=" + versionedStorageFormat; - } - - @JsonSerialize - @SuppressWarnings("unused") - private record V1(int privacyVersion) {} - ; -} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java deleted file mode 100644 index b35ba86489f..00000000000 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivateVersionedStorageFormat.java +++ /dev/null @@ -1,38 +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.configuration; - -public enum PrivateVersionedStorageFormat { - ORIGINAL(1); - - private final int privacyVersion; - - PrivateVersionedStorageFormat(final int privacyVersion) { - this.privacyVersion = privacyVersion; - } - - public static PrivateVersionedStorageFormat defaultForNewDB() { - return ORIGINAL; - } - - public int getPrivacyVersion() { - return privacyVersion; - } - - @Override - public String toString() { - return "privacyVersion=" + privacyVersion; - } -} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java index ded7fcb2fe2..34459d6ec56 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java @@ -16,37 +16,13 @@ import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; -public enum VersionedStorageFormat { - FOREST_ORIGINAL(DataStorageFormat.FOREST, 1), - FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2), - BONSAI_ORIGINAL(DataStorageFormat.BONSAI, 1), - BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2); +import java.util.OptionalInt; - private final DataStorageFormat format; - private final int version; +public interface VersionedStorageFormat { - VersionedStorageFormat(final DataStorageFormat format, final int version) { - this.format = format; - this.version = version; - } + DataStorageFormat getFormat(); - public static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { - return switch (format) { - case FOREST -> FOREST_WITH_VARIABLES; - case BONSAI -> BONSAI_WITH_VARIABLES; - }; - } + int getVersion(); - public DataStorageFormat getFormat() { - return format; - } - - public int getVersion() { - return version; - } - - @Override - public String toString() { - return "format=" + format + ", version=" + version; - } + OptionalInt getPrivacyVersion(); } 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 dc9b0f826a2..3ea3a595376 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 @@ -23,9 +23,9 @@ import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.BaseVersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateDatabaseMetadata; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivateVersionedStorageFormat; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivacyVersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; import java.nio.file.Files; @@ -48,7 +48,7 @@ public class RocksDBKeyValuePrivacyStorageFactoryTest { private final List segments = List.of(TestSegment.DEFAULT, segment); @Test - public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { + public void shouldDetectVersion1MetadataIfPresent() throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); final Path tempDatabaseDir = temporaryFolder.resolve("db"); final Path tempPrivateDatabaseDir = tempDatabaseDir.resolve("private"); @@ -57,6 +57,8 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); + Utils.createDatabaseMetadataV1Privacy(tempDataDir, 1, 1); + final RocksDBKeyValuePrivacyStorageFactory storageFactory = new RocksDBKeyValuePrivacyStorageFactory( new RocksDBKeyValueStorageFactory( @@ -65,10 +67,11 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception RocksDBMetricsFactory.PRIVATE_ROCKS_DB_METRICS)); // Side effect is creation of the Metadata version file - storageFactory.create(segment, commonConfiguration, metricsSystem); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { - assertThat(PrivateDatabaseMetadata.lookUpFrom(tempDataDir).getPrivateVersionedStorageFormat()) - .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); + } } @Test @@ -77,7 +80,6 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); final RocksDBKeyValuePrivacyStorageFactory storageFactory = new RocksDBKeyValuePrivacyStorageFactory( @@ -87,10 +89,10 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { RocksDBMetricsFactory.PRIVATE_ROCKS_DB_METRICS)); // Side effect is creation of the Metadata version file - storageFactory.create(segment, commonConfiguration, metricsSystem); - - assertThat(PrivateDatabaseMetadata.lookUpFrom(tempDataDir).getPrivateVersionedStorageFormat()) - .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); + } } @Test @@ -105,17 +107,22 @@ public void shouldUpdateCorrectMetadataFileForLatestVersion() throws Exception { new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PRIVATE_ROCKS_DB_METRICS); - storageFactory.create(segment, commonConfiguration, metricsSystem); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) - .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES); + } + storageFactory.close(); final RocksDBKeyValuePrivacyStorageFactory privacyStorageFactory = new RocksDBKeyValuePrivacyStorageFactory(storageFactory); - privacyStorageFactory.create(segment, commonConfiguration, metricsSystem); + try (final var storage = + privacyStorageFactory.create(segment, commonConfiguration, metricsSystem)) { - assertThat(PrivateDatabaseMetadata.lookUpFrom(tempDataDir).getPrivateVersionedStorageFormat()) - .isEqualTo(PrivateVersionedStorageFormat.ORIGINAL); + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); + } + privacyStorageFactory.close(); } } 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 262c415ab49..129ff965e5d 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 @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.when; import org.hyperledger.besu.metrics.ObservableMetricsSystem; @@ -25,17 +26,18 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.BaseVersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration; -import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorageTest.TestSegment; -import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; @@ -44,8 +46,6 @@ @ExtendWith(MockitoExtension.class) public class RocksDBKeyValueStorageFactoryTest { - private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; - @Mock private RocksDBFactoryConfiguration rocksDbConfiguration; @Mock private BesuConfiguration commonConfiguration; @TempDir public Path temporaryFolder; @@ -54,7 +54,7 @@ public class RocksDBKeyValueStorageFactoryTest { private final List segments = List.of(TestSegment.DEFAULT, segment); @Test - public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { + public void shouldCreateCorrectMetadataFileForLatestVersionForNewDb() throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); final Path tempDatabaseDir = temporaryFolder.resolve("db"); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); @@ -65,15 +65,15 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - // Side effect is creation of the Metadata version file - storageFactory.create(segment, commonConfiguration, metricsSystem); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) - .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { + // Side effect is creation of the Metadata version file + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES); + } } @Test - public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { + public void shouldFailIfDbExistsAndNoMetadataFileFound() throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); @@ -85,30 +85,35 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - storageFactory.create(segment, commonConfiguration, metricsSystem); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) - .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { + fail("Must fail if db is present but metadata is not"); + } catch (StorageException se) { + assertThat(se) + .hasMessage( + "Database exists but metadata file not found, without it there is no safe way to open the database"); + } } @Test - public void shouldDetectCorrectVersionIfMetadataFileExists() throws Exception { + public void shouldDetectCorrectMetadataV1() throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDataDir); + Files.createDirectories(tempDatabaseDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); + + Utils.createDatabaseMetadataV1(tempDataDir, 2); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - storageFactory.create(segment, commonConfiguration, metricsSystem); - - assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) - .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); - assertThat(storageFactory.isSegmentIsolationSupported()).isTrue(); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(BaseVersionedStorageFormat.BONSAI_WITH_VARIABLES); + assertThat(storageFactory.isSegmentIsolationSupported()).isTrue(); + } } @Test @@ -120,6 +125,8 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); + Utils.createDatabaseMetadataV1(tempDataDir, 2); + final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, @@ -137,6 +144,7 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { DataStorageFormat.FOREST, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); rolledbackStorageFactory.create(segment, commonConfiguration, metricsSystem); + rolledbackStorageFactory.close(); } @Test @@ -147,9 +155,8 @@ public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { Files.createDirectories(tempDataDir); when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - final String badVersion = "{\"version\":99}"; - Files.write( - tempDataDir.resolve(METADATA_FILENAME), badVersion.getBytes(Charset.defaultCharset())); + + Utils.createDatabaseMetadataV1(tempDataDir, 99); assertThatThrownBy( () -> new RocksDBKeyValueStorageFactory( @@ -161,7 +168,8 @@ public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { } @Test - public void shouldSetSegmentationFieldDuringCreation() throws Exception { + public void shouldDetectCorrectMetadataV2AndSetSegmentationFieldDuringCreation() + throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); @@ -169,11 +177,16 @@ public void shouldSetSegmentationFieldDuringCreation() throws Exception { when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); + Utils.createDatabaseMetadataV2(tempDataDir, DataStorageFormat.FOREST, 2); + final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThatCode(storageFactory::isSegmentIsolationSupported).doesNotThrowAnyException(); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { + assertThat(DatabaseMetadata.lookUpFrom(tempDataDir).getVersionedStorageFormat()) + .isEqualTo(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES); + assertThatCode(storageFactory::isSegmentIsolationSupported).doesNotThrowAnyException(); + } } @Test @@ -185,9 +198,7 @@ public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - final String badVersion = "{\"🦄\":1}"; - Files.write( - tempDataDir.resolve(METADATA_FILENAME), badVersion.getBytes(Charset.defaultCharset())); + Utils.createDatabaseMetadataRaw(tempDataDir, "{\"🦄\":1}"); assertThatThrownBy( () -> @@ -198,9 +209,7 @@ public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { .create(segment, commonConfiguration, metricsSystem)) .isInstanceOf(IllegalStateException.class); - final String badValue = "{\"version\":\"iomedae\"}"; - Files.write( - tempDatabaseDir.resolve(METADATA_FILENAME), badValue.getBytes(Charset.defaultCharset())); + Utils.createDatabaseMetadataRaw(tempDataDir, "{\"version\":\"iomedae\"}"); assertThatThrownBy( () -> @@ -213,6 +222,7 @@ public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { } @Test + @DisabledOnOs(OS.WINDOWS) public void shouldCreateDBCorrectlyIfSymlink() throws Exception { final Path tempRealDataDir = Files.createDirectories(temporaryFolder.resolve("real-data-dir")); final Path tempSymLinkDataDir = @@ -222,14 +232,39 @@ public void shouldCreateDBCorrectlyIfSymlink() throws Exception { when(commonConfiguration.getDataPath()).thenReturn(tempSymLinkDataDir); when(commonConfiguration.getDatabaseFormat()).thenReturn(DataStorageFormat.FOREST); + Utils.createDatabaseMetadataV2(tempSymLinkDataDir, DataStorageFormat.FOREST, 2); + final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); // Ensure that having created everything via a symlink data dir the DB meta-data has been // created correctly - storageFactory.create(segment, commonConfiguration, metricsSystem); - assertThat(DatabaseMetadata.lookUpFrom(tempRealDataDir).getVersionedStorageFormat()) - .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); + try (final var storage = storageFactory.create(segment, commonConfiguration, metricsSystem)) { + assertThat(DatabaseMetadata.lookUpFrom(tempRealDataDir).getVersionedStorageFormat()) + .isEqualTo(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES); + } } + + // private void createDatabaseMetadataV1(final Path tempDataDir, final int version) + // throws IOException { + // final String content = "{\"version\":" + version + "}"; + // Files.write(tempDataDir.resolve(METADATA_FILENAME), + // content.getBytes(Charset.defaultCharset())); + // } + // + // private void createDatabaseMetadataV2( + // final Path tempDataDir, final DataStorageFormat dataStorageFormat, final int version) + // throws IOException { + // final String content = + // "{\"v2\":{\"format\":\"" + dataStorageFormat + "\",\"version\":" + version + "}}"; + // Files.write(tempDataDir.resolve(METADATA_FILENAME), + // content.getBytes(Charset.defaultCharset())); + // } + // + // private void createDatabaseMetadataRaw(final Path tempDataDir, final String content) + // throws IOException { + // Files.write(tempDataDir.resolve(METADATA_FILENAME), + // content.getBytes(Charset.defaultCharset())); + // } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java new file mode 100644 index 00000000000..b5802f4bdf9 --- /dev/null +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java @@ -0,0 +1,69 @@ +/* + * 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; + +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Utils { + public static final String METADATA_FILENAME = "DATABASE_METADATA.json"; + + public static void createDatabaseMetadataV1(final Path tempDataDir, final int version) + throws IOException { + final String content = "{\"version\":" + version + "}"; + Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); + } + + public static void createDatabaseMetadataV1Privacy( + final Path tempDataDir, final int version, final int privacyVersion) throws IOException { + final String content = + "{\"version\":" + version + ",\"privacyVersion\":" + privacyVersion + "}"; + Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); + } + + public static void createDatabaseMetadataV2( + final Path tempDataDir, final DataStorageFormat dataStorageFormat, final int version) + throws IOException { + final String content = + "{\"v2\":{\"format\":\"" + dataStorageFormat + "\",\"version\":" + version + "}}"; + Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); + } + + public static void createDatabaseMetadataV2Privacy( + final Path tempDataDir, + final DataStorageFormat dataStorageFormat, + final int version, + final int privacyVersion) + throws IOException { + final String content = + "{\"v2\":{\"format\":\"" + + dataStorageFormat + + "\",\"version\":" + + version + + ",\"privacyVersion\":" + + privacyVersion + + "}}"; + Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); + } + + public static void createDatabaseMetadataRaw(final Path tempDataDir, final String content) + throws IOException { + Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); + } +} diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java index 5a23826d119..8ceea5b329f 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/DatabaseMetadataTest.java @@ -17,6 +17,8 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.hyperledger.besu.plugin.services.exception.StorageException; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -33,7 +35,17 @@ void readingMetadataV1() throws Exception { final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); assertThat(databaseMetadata.getVersionedStorageFormat()) - .isEqualTo(VersionedStorageFormat.BONSAI_WITH_VARIABLES); + .isEqualTo(BaseVersionedStorageFormat.BONSAI_WITH_VARIABLES); + } + + @Test + void readingMetadataV1Privacy() throws Exception { + final Path tempDataDir = + createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":1,\"privacyVersion\":1}"); + + final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); + assertThat(databaseMetadata.getVersionedStorageFormat()) + .isEqualTo(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); } @Test @@ -44,13 +56,30 @@ void readingMetadataV2() throws Exception { final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); assertThat(databaseMetadata.getVersionedStorageFormat()) - .isEqualTo(VersionedStorageFormat.FOREST_WITH_VARIABLES); + .isEqualTo(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES); + } + + @Test + void readingMetadataV2Privacy() throws Exception { + final Path tempDataDir = + createAndWrite( + "data", + "DATABASE_METADATA.json", + "{\"v2\":{\"format\":\"FOREST\",\"version\":2,\"privacyVersion\":1}}"); + + final DatabaseMetadata databaseMetadata = DatabaseMetadata.lookUpFrom(tempDataDir); + assertThat(databaseMetadata.getVersionedStorageFormat()) + .isEqualTo(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); } @Test void unsupportedMetadata() throws Exception { final Path tempDataDir = createAndWrite("data", "DATABASE_METADATA.json", "{\"version\":42}"); - DatabaseMetadata.lookUpFrom(tempDataDir); + try { + DatabaseMetadata.lookUpFrom(tempDataDir); + } catch (final StorageException se) { + assertThat(se).hasMessage("Unsupported db version: 42"); + } } private Path createAndWrite(final String dir, final String file, final String content) From 7bd6974b568e32713322d95a9465c5ee0b5c4e5f Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 31 Jan 2024 20:26:03 +0100 Subject: [PATCH 05/13] Update test Signed-off-by: Fabio Di Fabio --- .../RocksDBColumnarKeyValueStorageTest.java | 97 ++-- .../kvstore/AbstractKeyValueStorageTest.java | 507 +++++++++--------- 2 files changed, 297 insertions(+), 307 deletions(-) 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 80b9685b792..6f01dbce63d 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 @@ -308,58 +308,59 @@ public void createStoreMustCreateMetrics() throws Exception { // Actual call - final SegmentedKeyValueStorage store = + try (final SegmentedKeyValueStorage store = createSegmentedStore( folder, metricsSystemMock, List.of(TestSegment.DEFAULT, TestSegment.FOO), - List.of(TestSegment.EXPERIMENTAL)); - - KeyValueStorage keyValueStorage = new SegmentedKeyValueStorageAdapter(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."); + List.of(TestSegment.EXPERIMENTAL))) { + + KeyValueStorage keyValueStorage = new SegmentedKeyValueStorageAdapter(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 { diff --git a/testutil/src/main/java/org/hyperledger/besu/kvstore/AbstractKeyValueStorageTest.java b/testutil/src/main/java/org/hyperledger/besu/kvstore/AbstractKeyValueStorageTest.java index 60a66336765..2e0d9195e86 100644 --- a/testutil/src/main/java/org/hyperledger/besu/kvstore/AbstractKeyValueStorageTest.java +++ b/testutil/src/main/java/org/hyperledger/besu/kvstore/AbstractKeyValueStorageTest.java @@ -56,18 +56,20 @@ public abstract class AbstractKeyValueStorageTest { */ @Test public void twoStoresAreIndependent() throws Exception { - final KeyValueStorage store1 = createStore(); - final KeyValueStorage store2 = createStore(); + try (final KeyValueStorage store1 = createStore()) { + try (final KeyValueStorage store2 = createStore()) { - final KeyValueStorageTransaction tx = store1.startTransaction(); - final byte[] key = bytesFromHexString("0001"); - final byte[] value = bytesFromHexString("0FFF"); + final KeyValueStorageTransaction tx = store1.startTransaction(); + final byte[] key = bytesFromHexString("0001"); + final byte[] value = bytesFromHexString("0FFF"); - tx.put(key, value); - tx.commit(); + tx.put(key, value); + tx.commit(); - final Optional result = store2.get(key); - assertThat(result).isEmpty(); + final Optional result = store2.get(key); + assertThat(result).isEmpty(); + } + } } /** @@ -77,20 +79,21 @@ public void twoStoresAreIndependent() throws Exception { */ @Test public void put() throws Exception { - final KeyValueStorage store = createStore(); - final byte[] key = bytesFromHexString("0F"); - final byte[] firstValue = bytesFromHexString("0ABC"); - final byte[] secondValue = bytesFromHexString("0DEF"); - - KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(key, firstValue); - tx.commit(); - assertThat(store.get(key)).contains(firstValue); - - tx = store.startTransaction(); - tx.put(key, secondValue); - tx.commit(); - assertThat(store.get(key)).contains(secondValue); + try (final KeyValueStorage store = createStore()) { + final byte[] key = bytesFromHexString("0F"); + final byte[] firstValue = bytesFromHexString("0ABC"); + final byte[] secondValue = bytesFromHexString("0DEF"); + + KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(key, firstValue); + tx.commit(); + assertThat(store.get(key)).contains(firstValue); + + tx = store.startTransaction(); + tx.put(key, secondValue); + tx.commit(); + assertThat(store.get(key)).contains(secondValue); + } } /** @@ -100,16 +103,17 @@ public void put() throws Exception { */ @Test public void streamKeys() throws Exception { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - final List keys = - Stream.of("0F", "10", "11", "12") - .map(this::bytesFromHexString) - .collect(toUnmodifiableList()); - keys.forEach(key -> tx.put(key, bytesFromHexString("0ABC"))); - tx.commit(); - assertThat(store.stream().map(Pair::getKey).collect(toUnmodifiableSet())) - .containsExactlyInAnyOrder(keys.toArray(new byte[][] {})); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + final List keys = + Stream.of("0F", "10", "11", "12") + .map(this::bytesFromHexString) + .collect(toUnmodifiableList()); + keys.forEach(key -> tx.put(key, bytesFromHexString("0ABC"))); + tx.commit(); + assertThat(store.stream().map(Pair::getKey).collect(toUnmodifiableSet())) + .containsExactlyInAnyOrder(keys.toArray(new byte[][] {})); + } } /** @@ -119,18 +123,19 @@ public void streamKeys() throws Exception { */ @Test public void getAllKeysThat() throws Exception { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(bytesFromHexString("0F"), bytesFromHexString("0ABC")); - tx.put(bytesFromHexString("10"), bytesFromHexString("0ABC")); - tx.put(bytesFromHexString("11"), bytesFromHexString("0ABC")); - tx.put(bytesFromHexString("12"), bytesFromHexString("0ABC")); - tx.commit(); - Set keys = store.getAllKeysThat(bv -> Bytes.wrap(bv).toString().contains("1")); - assertThat(keys.size()).isEqualTo(3); - assertThat(keys) - .containsExactlyInAnyOrder( - bytesFromHexString("10"), bytesFromHexString("11"), bytesFromHexString("12")); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(bytesFromHexString("0F"), bytesFromHexString("0ABC")); + tx.put(bytesFromHexString("10"), bytesFromHexString("0ABC")); + tx.put(bytesFromHexString("11"), bytesFromHexString("0ABC")); + tx.put(bytesFromHexString("12"), bytesFromHexString("0ABC")); + tx.commit(); + Set keys = store.getAllKeysThat(bv -> Bytes.wrap(bv).toString().contains("1")); + assertThat(keys.size()).isEqualTo(3); + assertThat(keys) + .containsExactlyInAnyOrder( + bytesFromHexString("10"), bytesFromHexString("11"), bytesFromHexString("12")); + } } /** @@ -140,17 +145,18 @@ public void getAllKeysThat() throws Exception { */ @Test public void containsKey() throws Exception { - final KeyValueStorage store = createStore(); - final byte[] key = bytesFromHexString("ABCD"); - final byte[] value = bytesFromHexString("DEFF"); + try (final KeyValueStorage store = createStore()) { + final byte[] key = bytesFromHexString("ABCD"); + final byte[] value = bytesFromHexString("DEFF"); - assertThat(store.containsKey(key)).isFalse(); + assertThat(store.containsKey(key)).isFalse(); - final KeyValueStorageTransaction transaction = store.startTransaction(); - transaction.put(key, value); - transaction.commit(); + final KeyValueStorageTransaction transaction = store.startTransaction(); + transaction.put(key, value); + transaction.commit(); - assertThat(store.containsKey(key)).isTrue(); + assertThat(store.containsKey(key)).isTrue(); + } } /** @@ -160,18 +166,19 @@ public void containsKey() throws Exception { */ @Test public void removeExisting() throws Exception { - final KeyValueStorage store = createStore(); - final byte[] key = bytesFromHexString("0F"); - final byte[] value = bytesFromHexString("0ABC"); - - KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(key, value); - tx.commit(); - - tx = store.startTransaction(); - tx.remove(key); - tx.commit(); - assertThat(store.get(key)).isEmpty(); + try (final KeyValueStorage store = createStore()) { + final byte[] key = bytesFromHexString("0F"); + final byte[] value = bytesFromHexString("0ABC"); + + KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(key, value); + tx.commit(); + + tx = store.startTransaction(); + tx.remove(key); + tx.commit(); + assertThat(store.get(key)).isEmpty(); + } } /** @@ -181,15 +188,16 @@ public void removeExisting() throws Exception { */ @Test public void removeExistingSameTransaction() throws Exception { - final KeyValueStorage store = createStore(); - final byte[] key = bytesFromHexString("0F"); - final byte[] value = bytesFromHexString("0ABC"); - - KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(key, value); - tx.remove(key); - tx.commit(); - assertThat(store.get(key)).isEmpty(); + try (final KeyValueStorage store = createStore()) { + final byte[] key = bytesFromHexString("0F"); + final byte[] value = bytesFromHexString("0ABC"); + + KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(key, value); + tx.remove(key); + tx.commit(); + assertThat(store.get(key)).isEmpty(); + } } /** @@ -199,13 +207,14 @@ public void removeExistingSameTransaction() throws Exception { */ @Test public void removeNonExistent() throws Exception { - final KeyValueStorage store = createStore(); - final byte[] key = bytesFromHexString("0F"); + try (final KeyValueStorage store = createStore()) { + final byte[] key = bytesFromHexString("0F"); - KeyValueStorageTransaction tx = store.startTransaction(); - tx.remove(key); - tx.commit(); - assertThat(store.get(key)).isEmpty(); + KeyValueStorageTransaction tx = store.startTransaction(); + tx.remove(key); + tx.commit(); + assertThat(store.get(key)).isEmpty(); + } } /** @@ -216,39 +225,38 @@ public void removeNonExistent() throws Exception { @Test public void concurrentUpdate() throws Exception { final int keyCount = 1000; - final KeyValueStorage store = createStore(); - - final CountDownLatch finishedLatch = new CountDownLatch(2); - final Function updater = - (value) -> - new Thread( - () -> { - try { - for (int i = 0; i < keyCount; i++) { - KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(Bytes.minimalBytes(i).toArrayUnsafe(), value); - tx.commit(); + try (final KeyValueStorage store = createStore()) { + + final CountDownLatch finishedLatch = new CountDownLatch(2); + final Function updater = + (value) -> + new Thread( + () -> { + try { + for (int i = 0; i < keyCount; i++) { + KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(Bytes.minimalBytes(i).toArrayUnsafe(), value); + tx.commit(); + } + } finally { + finishedLatch.countDown(); } - } finally { - finishedLatch.countDown(); - } - }); + }); - // Run 2 concurrent transactions that write a bunch of values to the same keys - final byte[] a = Bytes.of(10).toArrayUnsafe(); - final byte[] b = Bytes.of(20).toArrayUnsafe(); - updater.apply(a).start(); - updater.apply(b).start(); + // Run 2 concurrent transactions that write a bunch of values to the same keys + final byte[] a = Bytes.of(10).toArrayUnsafe(); + final byte[] b = Bytes.of(20).toArrayUnsafe(); + updater.apply(a).start(); + updater.apply(b).start(); - finishedLatch.await(); + finishedLatch.await(); - for (int i = 0; i < keyCount; i++) { - final byte[] key = Bytes.minimalBytes(i).toArrayUnsafe(); - final byte[] actual = store.get(key).get(); - assertThat(Arrays.equals(actual, a) || Arrays.equals(actual, b)).isTrue(); + for (int i = 0; i < keyCount; i++) { + final byte[] key = Bytes.minimalBytes(i).toArrayUnsafe(); + final byte[] actual = store.get(key).get(); + assertThat(Arrays.equals(actual, a) || Arrays.equals(actual, b)).isTrue(); + } } - - store.close(); } /** @@ -258,34 +266,35 @@ public void concurrentUpdate() throws Exception { */ @Test public void transactionCommit() throws Exception { - final KeyValueStorage store = createStore(); - // Add some values - KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(bytesOf(1), bytesOf(1)); - tx.put(bytesOf(2), bytesOf(2)); - tx.put(bytesOf(3), bytesOf(3)); - tx.commit(); - - // Start transaction that adds, modifies, and removes some values - tx = store.startTransaction(); - tx.put(bytesOf(2), bytesOf(3)); - tx.put(bytesOf(2), bytesOf(4)); - tx.remove(bytesOf(3)); - tx.put(bytesOf(4), bytesOf(8)); - - // Check values before committing have not changed - assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); - assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); - assertThat(store.get(bytesOf(3))).contains(bytesOf(3)); - assertThat(store.get(bytesOf(4))).isEmpty(); - - tx.commit(); - - // Check that values have been updated after commit - assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); - assertThat(store.get(bytesOf(2))).contains(bytesOf(4)); - assertThat(store.get(bytesOf(3))).isEmpty(); - assertThat(store.get(bytesOf(4))).contains(bytesOf(8)); + try (final KeyValueStorage store = createStore()) { + // Add some values + KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(bytesOf(1), bytesOf(1)); + tx.put(bytesOf(2), bytesOf(2)); + tx.put(bytesOf(3), bytesOf(3)); + tx.commit(); + + // Start transaction that adds, modifies, and removes some values + tx = store.startTransaction(); + tx.put(bytesOf(2), bytesOf(3)); + tx.put(bytesOf(2), bytesOf(4)); + tx.remove(bytesOf(3)); + tx.put(bytesOf(4), bytesOf(8)); + + // Check values before committing have not changed + assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); + assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); + assertThat(store.get(bytesOf(3))).contains(bytesOf(3)); + assertThat(store.get(bytesOf(4))).isEmpty(); + + tx.commit(); + + // Check that values have been updated after commit + assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); + assertThat(store.get(bytesOf(2))).contains(bytesOf(4)); + assertThat(store.get(bytesOf(3))).isEmpty(); + assertThat(store.get(bytesOf(4))).contains(bytesOf(8)); + } } /** @@ -295,34 +304,35 @@ public void transactionCommit() throws Exception { */ @Test public void transactionRollback() throws Exception { - final KeyValueStorage store = createStore(); - // Add some values - KeyValueStorageTransaction tx = store.startTransaction(); - tx.put(bytesOf(1), bytesOf(1)); - tx.put(bytesOf(2), bytesOf(2)); - tx.put(bytesOf(3), bytesOf(3)); - tx.commit(); - - // Start transaction that adds, modifies, and removes some values - tx = store.startTransaction(); - tx.put(bytesOf(2), bytesOf(3)); - tx.put(bytesOf(2), bytesOf(4)); - tx.remove(bytesOf(3)); - tx.put(bytesOf(4), bytesOf(8)); - - // Check values before committing have not changed - assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); - assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); - assertThat(store.get(bytesOf(3))).contains(bytesOf(3)); - assertThat(store.get(bytesOf(4))).isEmpty(); - - tx.rollback(); - - // Check that values have not changed after rollback - assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); - assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); - assertThat(store.get(bytesOf(3))).contains(bytesOf(3)); - assertThat(store.get(bytesOf(4))).isEmpty(); + try (final KeyValueStorage store = createStore()) { + // Add some values + KeyValueStorageTransaction tx = store.startTransaction(); + tx.put(bytesOf(1), bytesOf(1)); + tx.put(bytesOf(2), bytesOf(2)); + tx.put(bytesOf(3), bytesOf(3)); + tx.commit(); + + // Start transaction that adds, modifies, and removes some values + tx = store.startTransaction(); + tx.put(bytesOf(2), bytesOf(3)); + tx.put(bytesOf(2), bytesOf(4)); + tx.remove(bytesOf(3)); + tx.put(bytesOf(4), bytesOf(8)); + + // Check values before committing have not changed + assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); + assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); + assertThat(store.get(bytesOf(3))).contains(bytesOf(3)); + assertThat(store.get(bytesOf(4))).isEmpty(); + + tx.rollback(); + + // Check that values have not changed after rollback + assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); + assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); + assertThat(store.get(bytesOf(3))).contains(bytesOf(3)); + assertThat(store.get(bytesOf(4))).isEmpty(); + } } /** @@ -332,9 +342,10 @@ public void transactionRollback() throws Exception { */ @Test public void transactionCommitEmpty() throws Exception { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.commit(); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.commit(); + } } /** @@ -344,143 +355,120 @@ public void transactionCommitEmpty() throws Exception { */ @Test public void transactionRollbackEmpty() throws Exception { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.rollback(); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.rollback(); + } } - /** - * Transaction put after commit. - * - * @throws Exception the exception - */ + /** Transaction put after commit. */ @Test - public void transactionPutAfterCommit() throws Exception { + public void transactionPutAfterCommit() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.commit(); - tx.put(bytesOf(1), bytesOf(1)); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.commit(); + tx.put(bytesOf(1), bytesOf(1)); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction remove after commit. - * - * @throws Exception the exception - */ + /** Transaction remove after commit. */ @Test - public void transactionRemoveAfterCommit() throws Exception { + public void transactionRemoveAfterCommit() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.commit(); - tx.remove(bytesOf(1)); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.commit(); + tx.remove(bytesOf(1)); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction put after rollback. - * - * @throws Exception the exception - */ + /** Transaction put after rollback. */ @Test - public void transactionPutAfterRollback() throws Exception { + public void transactionPutAfterRollback() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.rollback(); - tx.put(bytesOf(1), bytesOf(1)); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.rollback(); + tx.put(bytesOf(1), bytesOf(1)); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction remove after rollback. - * - * @throws Exception the exception - */ + /** Transaction remove after rollback. */ @Test - public void transactionRemoveAfterRollback() throws Exception { + public void transactionRemoveAfterRollback() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.rollback(); - tx.remove(bytesOf(1)); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.rollback(); + tx.remove(bytesOf(1)); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction commit after rollback. - * - * @throws Exception the exception - */ + /** Transaction commit after rollback. */ @Test - public void transactionCommitAfterRollback() throws Exception { + public void transactionCommitAfterRollback() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.rollback(); - tx.commit(); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.rollback(); + tx.commit(); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction commit twice. - * - * @throws Exception the exception - */ + /** Transaction commit twice. */ @Test - public void transactionCommitTwice() throws Exception { + public void transactionCommitTwice() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.commit(); - tx.commit(); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.commit(); + tx.commit(); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction rollback after commit. - * - * @throws Exception the exception - */ + /** Transaction rollback after commit. */ @Test - public void transactionRollbackAfterCommit() throws Exception { + public void transactionRollbackAfterCommit() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.commit(); - tx.rollback(); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.commit(); + tx.rollback(); + } }) .isInstanceOf(IllegalStateException.class); } - /** - * Transaction rollback twice. - * - * @throws Exception the exception - */ + /** Transaction rollback twice. */ @Test - public void transactionRollbackTwice() throws Exception { + public void transactionRollbackTwice() { Assertions.assertThatThrownBy( () -> { - final KeyValueStorage store = createStore(); - final KeyValueStorageTransaction tx = store.startTransaction(); - tx.rollback(); - tx.rollback(); + try (final KeyValueStorage store = createStore()) { + final KeyValueStorageTransaction tx = store.startTransaction(); + tx.rollback(); + tx.rollback(); + } }) .isInstanceOf(IllegalStateException.class); } @@ -492,19 +480,20 @@ public void transactionRollbackTwice() throws Exception { */ @Test public void twoTransactions() throws Exception { - final KeyValueStorage store = createStore(); + try (final KeyValueStorage store = createStore()) { - final KeyValueStorageTransaction tx1 = store.startTransaction(); - final KeyValueStorageTransaction tx2 = store.startTransaction(); + final KeyValueStorageTransaction tx1 = store.startTransaction(); + final KeyValueStorageTransaction tx2 = store.startTransaction(); - tx1.put(bytesOf(1), bytesOf(1)); - tx2.put(bytesOf(2), bytesOf(2)); + tx1.put(bytesOf(1), bytesOf(1)); + tx2.put(bytesOf(2), bytesOf(2)); - tx1.commit(); - tx2.commit(); + tx1.commit(); + tx2.commit(); - assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); - assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); + assertThat(store.get(bytesOf(1))).contains(bytesOf(1)); + assertThat(store.get(bytesOf(2))).contains(bytesOf(2)); + } } /** From 02fa76a78a797ad822eb4742ebf4ccc4b4a5b0c7 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 7 Feb 2024 16:47:48 +0100 Subject: [PATCH 06/13] Detect and handle db upgrades and downgrades Signed-off-by: Fabio Di Fabio --- .../RocksDBKeyValuePrivacyStorageFactory.java | 110 ++++++++++++--- .../RocksDBKeyValueStorageFactory.java | 125 ++++++++++++++---- .../BaseVersionedStorageFormat.java | 2 +- .../PrivacyVersionedStorageFormat.java | 2 +- 4 files changed, 188 insertions(+), 51 deletions(-) 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 85e21044248..bf5f92165f7 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 @@ -23,12 +23,14 @@ import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.DatabaseMetadata; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivacyVersionedStorageFormat; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.VersionedStorageFormat; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.EnumSet; import java.util.List; +import java.util.Optional; import java.util.Set; import org.slf4j.Logger; @@ -122,45 +124,109 @@ private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConf final Path dataDir = commonConfiguration.getDataPath(); final boolean privacyDatabaseExists = commonConfiguration.getStoragePath().resolve(PRIVATE_DATABASE_PATH).toFile().exists(); - final boolean privacyDatabaseMetadataExists = DatabaseMetadata.isPresent(dataDir); - final DatabaseMetadata privacyDatabaseMetadata; - if (privacyDatabaseExists && !privacyDatabaseMetadataExists) { + final boolean privacyMetadataExists = DatabaseMetadata.isPresent(dataDir); + DatabaseMetadata privacyMetadata; + if (privacyDatabaseExists && !privacyMetadataExists) { throw new StorageException( "Privacy database exists but metadata file not found, without it there is no safe way to open the database"); } - if (privacyDatabaseMetadataExists) { - final var existingDatabaseMetadata = DatabaseMetadata.lookUpFrom(dataDir); - if (existingDatabaseMetadata.getVersionedStorageFormat().getPrivacyVersion().isEmpty()) { - privacyDatabaseMetadata = existingDatabaseMetadata.upgradeToPrivacy(); - privacyDatabaseMetadata.writeToDirectory(dataDir); + if (privacyMetadataExists) { + final var existingPrivacyMetadata = DatabaseMetadata.lookUpFrom(dataDir); + final var maybeExistingPrivacyVersion = + existingPrivacyMetadata.getVersionedStorageFormat().getPrivacyVersion(); + if (maybeExistingPrivacyVersion.isEmpty()) { + privacyMetadata = existingPrivacyMetadata.upgradeToPrivacy(); + privacyMetadata.writeToDirectory(dataDir); LOG.info( - "Upgraded existing database detected at {} to privacy database. Metadata {}", + "Upgraded existing database at {} to privacy database. Metadata {}", dataDir, - existingDatabaseMetadata); + existingPrivacyMetadata); } else { - privacyDatabaseMetadata = existingDatabaseMetadata; - LOG.info( - "Existing privacy database detected at {}. Metadata {}", - dataDir, - privacyDatabaseMetadata); + privacyMetadata = existingPrivacyMetadata; + final int existingPrivacyVersion = maybeExistingPrivacyVersion.getAsInt(); + final var runtimeVersion = + PrivacyVersionedStorageFormat.defaultForNewDB(commonConfiguration.getDatabaseFormat()); + + if (existingPrivacyVersion > runtimeVersion.getPrivacyVersion().getAsInt()) { + final var maybeDowngradedMetadata = + handleVersionDowngrade(dataDir, privacyMetadata, runtimeVersion); + if (maybeDowngradedMetadata.isPresent()) { + privacyMetadata = maybeDowngradedMetadata.get(); + privacyMetadata.writeToDirectory(dataDir); + } + } else if (existingPrivacyVersion < runtimeVersion.getPrivacyVersion().getAsInt()) { + final var maybeUpgradedMetadata = + handleVersionUpgrade(dataDir, privacyMetadata, runtimeVersion); + if (maybeUpgradedMetadata.isPresent()) { + privacyMetadata = maybeUpgradedMetadata.get(); + privacyMetadata.writeToDirectory(dataDir); + } + } else { + LOG.info("Existing privacy database at {}. Metadata {}", dataDir, privacyMetadata); + } } } else { - privacyDatabaseMetadata = DatabaseMetadata.defaultForNewPrivateDb(); + privacyMetadata = DatabaseMetadata.defaultForNewPrivateDb(); LOG.info( - "No existing private database detected at {}. Using default metadata for new db {}", + "No existing private database at {}. Using default metadata for new db {}", dataDir, - privacyDatabaseMetadata); + privacyMetadata); Files.createDirectories(dataDir); - privacyDatabaseMetadata.writeToDirectory(dataDir); + privacyMetadata.writeToDirectory(dataDir); } - if (!SUPPORTED_VERSIONS.contains(privacyDatabaseMetadata.getVersionedStorageFormat())) { - final String message = "Unsupported RocksDB Metadata version of: " + privacyDatabaseMetadata; + if (!SUPPORTED_VERSIONS.contains(privacyMetadata.getVersionedStorageFormat())) { + final String message = "Unsupported RocksDB Metadata version of: " + privacyMetadata; LOG.error(message); throw new StorageException(message); } - return privacyDatabaseMetadata; + return privacyMetadata; + } + + private Optional handleVersionDowngrade( + final Path dataDir, + final DatabaseMetadata existingPrivacyMetadata, + final VersionedStorageFormat runtimeVersion) { + // here we put the code, or the messages, to perform an automated, or manual, downgrade of the + // database, if supported, otherwise we just prevent Besu from starting since it will not + // recognize the newer version. + // In case we do an automated downgrade, then we also need to update the metadata on disk to + // reflect the change to the runtime version, and return it. + + // for the moment there are supported automated downgrades, so we just fail. + String error = + String.format( + "Database unsafe downgrade detect: DB at %s is %s with version %s but version %s is expected. " + + "Please check your config and review release notes for supported downgrade procedures.", + dataDir, + existingPrivacyMetadata.getVersionedStorageFormat().getFormat().name(), + existingPrivacyMetadata.getVersionedStorageFormat().getVersion(), + runtimeVersion.getVersion()); + + throw new StorageException(error); + } + + private Optional handleVersionUpgrade( + final Path dataDir, + final DatabaseMetadata existingPrivacyMetadata, + final VersionedStorageFormat runtimeVersion) { + // here we put the code, or the messages, to perform an automated, or manual, upgrade of the + // database. + // In case we do an automated upgrade, then we also need to update the metadata on disk to + // reflect the change to the runtime version, and return it. + + // for the moment there are no planned automated upgrades, so we just fail. + String error = + String.format( + "Database unsafe upgrade detect: DB at %s is %s with version %s but version %s is expected. " + + "Please check your config and review release notes for supported upgrade procedures.", + dataDir, + existingPrivacyMetadata.getVersionedStorageFormat().getFormat().name(), + existingPrivacyMetadata.getVersionedStorageFormat().getVersion(), + runtimeVersion.getVersion()); + + throw new StorageException(error); } @Override 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 39fab3b1af6..31b64880e28 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 @@ -41,6 +41,7 @@ import java.nio.file.Path; import java.util.EnumSet; import java.util.List; +import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -254,51 +255,121 @@ private DatabaseMetadata readDatabaseMetadata(final BesuConfiguration commonConf final Path dataDir = commonConfiguration.getDataPath(); final boolean dataDirExists = dataDir.toFile().exists(); final boolean databaseExists = commonConfiguration.getStoragePath().toFile().exists(); - final boolean databaseMetadataExists = DatabaseMetadata.isPresent(dataDir); - final DatabaseMetadata databaseMetadata; - if (databaseExists && !databaseMetadataExists) { + final boolean metadataExists = DatabaseMetadata.isPresent(dataDir); + DatabaseMetadata metadata; + if (databaseExists && !metadataExists) { throw new StorageException( "Database exists but metadata file not found, without it there is no safe way to open the database"); } - if (databaseMetadataExists) { - databaseMetadata = DatabaseMetadata.lookUpFrom(dataDir); - if (!databaseMetadata + if (metadataExists) { + metadata = DatabaseMetadata.lookUpFrom(dataDir); + + if (!metadata .getVersionedStorageFormat() .getFormat() .equals(commonConfiguration.getDatabaseFormat())) { - String error = - String.format( - "Database format mismatch: DB at %s is %s but config expects %s. " - + "Please check your config.", - dataDir, - databaseMetadata.getVersionedStorageFormat().getFormat().name(), - commonConfiguration.getDatabaseFormat()); - - throw new StorageException(error); + handleFormatMismatch(commonConfiguration, dataDir, metadata); } - LOG.info( - "Existing database detected at {}. Metadata {}. Processing WAL...", - dataDir, - databaseMetadata); + + final var runtimeVersion = + BaseVersionedStorageFormat.defaultForNewDB(commonConfiguration.getDatabaseFormat()); + + if (metadata.getVersionedStorageFormat().getVersion() > runtimeVersion.getVersion()) { + final var maybeDowngradedMetadata = + handleVersionDowngrade(dataDir, metadata, runtimeVersion); + if (maybeDowngradedMetadata.isPresent()) { + metadata = maybeDowngradedMetadata.get(); + metadata.writeToDirectory(dataDir); + } + } + + if (metadata.getVersionedStorageFormat().getVersion() < runtimeVersion.getVersion()) { + final var maybeUpgradedMetadata = handleVersionUpgrade(dataDir, metadata, runtimeVersion); + if (maybeUpgradedMetadata.isPresent()) { + metadata = maybeUpgradedMetadata.get(); + metadata.writeToDirectory(dataDir); + } + } + + LOG.info("Existing database at {}. Metadata {}. Processing WAL...", dataDir, metadata); } else { - databaseMetadata = DatabaseMetadata.defaultForNewDb(commonConfiguration.getDatabaseFormat()); + + metadata = DatabaseMetadata.defaultForNewDb(commonConfiguration.getDatabaseFormat()); LOG.info( - "No existing database detected at {}. Using default metadata for new db {}", - dataDir, - databaseMetadata); + "No existing database at {}. Using default metadata for new db {}", dataDir, metadata); if (!dataDirExists) { Files.createDirectories(dataDir); } - databaseMetadata.writeToDirectory(dataDir); + metadata.writeToDirectory(dataDir); } - if (!isSupportedVersionedFormat(databaseMetadata.getVersionedStorageFormat())) { - final String message = "Unsupported RocksDB metadata: " + databaseMetadata; + if (!isSupportedVersionedFormat(metadata.getVersionedStorageFormat())) { + final String message = "Unsupported RocksDB metadata: " + metadata; LOG.error(message); throw new StorageException(message); } - return databaseMetadata; + return metadata; + } + + private static void handleFormatMismatch( + final BesuConfiguration commonConfiguration, + final Path dataDir, + final DatabaseMetadata existingMetadata) { + String error = + String.format( + "Database format mismatch: DB at %s is %s but config expects %s. " + + "Please check your config.", + dataDir, + existingMetadata.getVersionedStorageFormat().getFormat().name(), + commonConfiguration.getDatabaseFormat()); + + throw new StorageException(error); + } + + private Optional handleVersionDowngrade( + final Path dataDir, + final DatabaseMetadata existingMetadata, + final BaseVersionedStorageFormat runtimeVersion) { + // here we put the code, or the messages, to perform an automated, or manual, downgrade of the + // database, if supported, otherwise we just prevent Besu from starting since it will not + // recognize the newer version. + // In case we do an automated downgrade, then we also need to update the metadata on disk to + // reflect the change to the runtime version, and return it. + + // for the moment there are supported automated downgrades, so we just fail. + String error = + String.format( + "Database unsafe downgrade detect: DB at %s is %s with version %s but version %s is expected. " + + "Please check your config and review release notes for supported downgrade procedures.", + dataDir, + existingMetadata.getVersionedStorageFormat().getFormat().name(), + existingMetadata.getVersionedStorageFormat().getVersion(), + runtimeVersion.getVersion()); + + throw new StorageException(error); + } + + private Optional handleVersionUpgrade( + final Path dataDir, + final DatabaseMetadata existingMetadata, + final BaseVersionedStorageFormat runtimeVersion) { + // here we put the code, or the messages, to perform an automated, or manual, upgrade of the + // database. + // In case we do an automated upgrade, then we also need to update the metadata on disk to + // reflect the change to the runtime version, and return it. + + // for the moment there are no planned automated upgrades, so we just fail. + String error = + String.format( + "Database unsafe downgrade detect: DB at %s is %s with version %s but version %s is expected. " + + "Please check your config and review release notes for supported downgrade procedures.", + dataDir, + existingMetadata.getVersionedStorageFormat().getFormat().name(), + existingMetadata.getVersionedStorageFormat().getVersion(), + runtimeVersion.getVersion()); + + throw new StorageException(error); } private boolean isSupportedVersionedFormat(final VersionedStorageFormat versionedStorageFormat) { diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java index 2a7de3c9642..a9cbeaf579d 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java @@ -32,7 +32,7 @@ public enum BaseVersionedStorageFormat implements VersionedStorageFormat { this.version = version; } - static BaseVersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { + public static BaseVersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { return switch (format) { case FOREST -> FOREST_WITH_VARIABLES; case BONSAI -> BONSAI_WITH_VARIABLES; diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java index ddbfe536519..f5a05330652 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java @@ -33,7 +33,7 @@ public enum PrivacyVersionedStorageFormat implements VersionedStorageFormat { this.privacyVersion = OptionalInt.of(privacyVersion); } - static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { + public static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { return switch (format) { case FOREST -> FOREST_WITH_VARIABLES; case BONSAI -> BONSAI_WITH_VARIABLES; From 7220c483711280f082ede4c1071b9df4bb861c79 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 9 Feb 2024 12:33:24 +0100 Subject: [PATCH 07/13] Add tests Signed-off-by: Fabio Di Fabio --- .../trie/bonsai/AbstractIsolationTests.java | 1 - plugin-api/build.gradle | 2 +- .../RocksDBKeyValueStorageFactory.java | 49 +-------------- .../RocksDBKeyValueStorageFactoryTest.java | 61 +++++++++---------- 4 files changed, 32 insertions(+), 81 deletions(-) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java index 3a0fd12fd8b..4ef10a88051 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java @@ -187,7 +187,6 @@ protected StorageProvider createKeyValueStorageProvider() { 8388608 /*CACHE_CAPACITY*/, false), Arrays.asList(KeyValueSegmentIdentifier.values()), - DataStorageFormat.BONSAI, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS)) .withCommonConfiguration( new BesuConfiguration() { diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index ade07493c03..ebc533bd406 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = '3+WNtdl1idY70N/MwVBbopU2ZWyWiu12YV1qaYXprZ8=' + knownHash = 'zb0vFXnyTWFweXeIkzGoKBDcZ5HfYto12wmbmK0Px8Y=' } check.dependsOn('checkAPIChanges') 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 31b64880e28..eaf95e82a1e 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 @@ -20,7 +20,6 @@ import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; @@ -55,7 +54,6 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private static final Logger LOG = LoggerFactory.getLogger(RocksDBKeyValueStorageFactory.class); - private static final VersionedStorageFormat DEFAULT_VERSIONED_FORMAT = FOREST_WITH_VARIABLES; private static final EnumSet SUPPORTED_VERSIONED_FORMATS = EnumSet.of(FOREST_WITH_VARIABLES, BONSAI_WITH_VARIABLES); private static final String NAME = "rocksdb"; @@ -74,20 +72,17 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { * @param configuration the configuration * @param configuredSegments the segments * @param ignorableSegments the ignorable segments - * @param format the storage format * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, final List configuredSegments, final List ignorableSegments, - final DataStorageFormat format, final RocksDBMetricsFactory rocksDBMetricsFactory) { this.configuration = configuration; this.configuredSegments = configuredSegments; this.ignorableSegments = ignorableSegments; this.rocksDBMetricsFactory = rocksDBMetricsFactory; - this.databaseMetadata = DatabaseMetadata.defaultForNewDb(format); } /** @@ -95,55 +90,13 @@ public RocksDBKeyValueStorageFactory( * * @param configuration the configuration * @param configuredSegments the segments - * @param format the storage format * @param rocksDBMetricsFactory the rocks db metrics factory */ public RocksDBKeyValueStorageFactory( final Supplier configuration, final List configuredSegments, - final DataStorageFormat format, final RocksDBMetricsFactory rocksDBMetricsFactory) { - this(configuration, configuredSegments, List.of(), format, rocksDBMetricsFactory); - } - - /** - * Instantiates a new Rocks db key value storage factory. - * - * @param configuration the configuration - * @param configuredSegments the segments - * @param ignorableSegments the ignorable segments - * @param rocksDBMetricsFactory the rocks db metrics factory - */ - public RocksDBKeyValueStorageFactory( - final Supplier configuration, - final List configuredSegments, - final List ignorableSegments, - final RocksDBMetricsFactory rocksDBMetricsFactory) { - this( - configuration, - configuredSegments, - ignorableSegments, - DEFAULT_VERSIONED_FORMAT.getFormat(), - rocksDBMetricsFactory); - } - - /** - * Instantiates a new Rocks db key value storage factory. - * - * @param configuration the configuration - * @param configuredSegments the segments - * @param rocksDBMetricsFactory the rocks db metrics factory - */ - public RocksDBKeyValueStorageFactory( - final Supplier configuration, - final List configuredSegments, - final RocksDBMetricsFactory rocksDBMetricsFactory) { - this( - configuration, - configuredSegments, - List.of(), - DEFAULT_VERSIONED_FORMAT.getFormat(), - rocksDBMetricsFactory); + this(configuration, configuredSegments, List.of(), rocksDBMetricsFactory); } @Override 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 4e818a92129..22624e69e6e 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 @@ -73,13 +73,6 @@ public void shouldCreateCorrectMetadataFileForLatestVersionForNewDb() throws Exc } } - private void mockCommonConfiguration( - final Path tempDataDir, final Path tempDatabaseDir, final DataStorageFormat format) { - when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); - when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); - lenient().when(commonConfiguration.getDatabaseFormat()).thenReturn(format); - } - @Test public void shouldFailIfDbExistsAndNoMetadataFileFound() throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); @@ -122,7 +115,7 @@ public void shouldDetectCorrectMetadataV1() throws Exception { } @Test - public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { + public void shouldFailInCaseOfUnmanagedRollback() throws Exception { final Path tempDataDir = temporaryFolder.resolve("data"); final Path tempDatabaseDir = temporaryFolder.resolve("db"); Files.createDirectories(tempDatabaseDir); @@ -133,22 +126,20 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, - segments, - BONSAI, - RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); storageFactory.create(segment, commonConfiguration, metricsSystem); storageFactory.close(); + Utils.createDatabaseMetadataV2(tempDataDir, BONSAI, 1); + final RocksDBKeyValueStorageFactory rolledbackStorageFactory = new RocksDBKeyValueStorageFactory( - () -> rocksDbConfiguration, - segments, - FOREST, - RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); - rolledbackStorageFactory.create(segment, commonConfiguration, metricsSystem); - rolledbackStorageFactory.close(); + () -> rocksDbConfiguration, segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + assertThatThrownBy( + () -> rolledbackStorageFactory.create(segment, commonConfiguration, metricsSystem)) + .isInstanceOf(StorageException.class) + .hasMessageStartingWith("Database unsafe downgrade detect"); } @Test @@ -167,12 +158,12 @@ public void shouldThrowExceptionWhenVersionNumberIsInvalid() throws Exception { segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS) .create(segment, commonConfiguration, metricsSystem)) - .isInstanceOf(StorageException.class); + .isInstanceOf(StorageException.class) + .hasMessageStartingWith("Unsupported db version"); } @Test - public void shouldThrowExceptionWhenExistingDatabaseVersionDifferentFromConfig() - throws Exception { + public void shouldThrowExceptionWhenExistingDatabaseFormatDiffersFromConfig() throws Exception { final DataStorageFormat actualDatabaseFormat = FOREST; final DataStorageFormat expectedDatabaseFormat = BONSAI; @@ -185,12 +176,6 @@ public void shouldThrowExceptionWhenExistingDatabaseVersionDifferentFromConfig() Utils.createDatabaseMetadataV2(tempDataDir, FOREST, 2); - String exceptionMessage = - String.format( - "Database format mismatch: DB at %s is %s but config expects %s. " - + "Please check your config.", - tempDataDir.toAbsolutePath(), actualDatabaseFormat, expectedDatabaseFormat); - assertThatThrownBy( () -> new RocksDBKeyValueStorageFactory( @@ -199,7 +184,10 @@ public void shouldThrowExceptionWhenExistingDatabaseVersionDifferentFromConfig() RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS) .create(segment, commonConfiguration, metricsSystem)) .isInstanceOf(StorageException.class) - .hasMessage(exceptionMessage); + .hasMessage( + "Database format mismatch: DB at %s is %s but config expects %s. " + + "Please check your config.", + tempDataDir.toAbsolutePath(), actualDatabaseFormat, expectedDatabaseFormat); } @Test @@ -240,9 +228,11 @@ public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS) .create(segment, commonConfiguration, metricsSystem)) - .isInstanceOf(IllegalStateException.class); + .isInstanceOf(IllegalStateException.class) + .hasMessageStartingWith("Invalid metadata file"); + ; - Utils.createDatabaseMetadataRaw(tempDataDir, "{\"version\":\"iomedae\"}"); + Utils.createDatabaseMetadataRaw(tempDataDir, "{\"version\"=1}"); assertThatThrownBy( () -> @@ -251,7 +241,9 @@ public void shouldThrowExceptionWhenMetaDataFileIsCorrupted() throws Exception { segments, RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS) .create(segment, commonConfiguration, metricsSystem)) - .isInstanceOf(IllegalStateException.class); + .isInstanceOf(IllegalStateException.class) + .hasMessageStartingWith("Invalid metadata file"); + ; } @Test @@ -276,4 +268,11 @@ public void shouldCreateDBCorrectlyIfSymlink() throws Exception { .isEqualTo(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES); } } + + private void mockCommonConfiguration( + final Path tempDataDir, final Path tempDatabaseDir, final DataStorageFormat format) { + when(commonConfiguration.getStoragePath()).thenReturn(tempDatabaseDir); + when(commonConfiguration.getDataPath()).thenReturn(tempDataDir); + lenient().when(commonConfiguration.getDatabaseFormat()).thenReturn(format); + } } From 384d657d0a61dd04c650fe508d1dda96da20573e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 9 Feb 2024 16:55:14 +0100 Subject: [PATCH 08/13] Fix test Signed-off-by: Fabio Di Fabio --- besu/src/test/java/org/hyperledger/besu/RunnerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index c9e16baeecc..bdb9f9226db 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -163,7 +163,7 @@ private void syncFromGenesis(final SyncMode mode, final GenesisConfigFile genesi final Path dataDirAhead = Files.createTempDirectory(temp, "db-ahead"); final Path dbAhead = dataDirAhead.resolve("database"); final int blockCount = 500; - final NodeKey aheadDbNodeKey = NodeKeyUtils.createFrom(KeyPairUtil.loadKeyPair(dbAhead)); + final NodeKey aheadDbNodeKey = NodeKeyUtils.createFrom(KeyPairUtil.loadKeyPair(dataDirAhead)); final NodeKey behindDbNodeKey = NodeKeyUtils.generate(); final SynchronizerConfiguration syncConfigAhead = SynchronizerConfiguration.builder().syncMode(SyncMode.FULL).build(); From ed160b62787ae717561e6ac9b36d8e2a0b5bbbf1 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 13 Feb 2024 16:32:38 +0100 Subject: [PATCH 09/13] Add revert-metadata subcommand Signed-off-by: Fabio Di Fabio --- .../storage/RevertMetadataSubCommand.java | 129 ++++++++++++++++++ .../storage/StorageSubCommand.java | 3 +- 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java new file mode 100644 index 00000000000..8ced96d46d7 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java @@ -0,0 +1,129 @@ +/* + * 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.cli.subcommands.storage; + +import org.hyperledger.besu.cli.util.VersionProvider; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.OptionalInt; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.ParentCommand; + +/** The revert metadata to v1 subcommand. */ +@Command( + name = "revert-metadata", + description = "Revert database metadata to previous format", + mixinStandardHelpOptions = true, + versionProvider = VersionProvider.class, + subcommands = RevertMetadataSubCommand.v2ToV1.class) +public class RevertMetadataSubCommand implements Runnable { + private static final Logger LOG = LoggerFactory.getLogger(RevertMetadataSubCommand.class); + private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; + private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); + + @SuppressWarnings("unused") + @ParentCommand + private StorageSubCommand parentCommand; + + @SuppressWarnings("unused") + @CommandLine.Spec + private CommandLine.Model.CommandSpec spec; + + @Override + public void run() { + spec.commandLine().usage(System.out); + } + + @Command( + name = "v2-to-v1", + description = "Revert a database metadata v2 format to v1 format", + mixinStandardHelpOptions = true, + versionProvider = VersionProvider.class) + static class v2ToV1 implements Runnable { + + @SuppressWarnings("unused") + @CommandLine.Spec + private CommandLine.Model.CommandSpec spec; + + @SuppressWarnings("unused") + @ParentCommand + private RevertMetadataSubCommand parentCommand; + + @Override + public void run() { + + final Path dataDir = parentCommand.parentCommand.parentCommand.dataDir(); + + final File dbMetadata = dataDir.resolve(METADATA_FILENAME).toFile(); + if (!dbMetadata.exists()) { + String errMsg = + String.format( + "Could not find database metadata file %s, check your data dir %s", + dbMetadata, dataDir); + LOG.error(errMsg); + throw new IllegalArgumentException(errMsg); + } + try { + final var root = MAPPER.readTree(dbMetadata); + if (!root.has("v2")) { + String errMsg = + String.format("Database metadata file %s is not in v2 format", dbMetadata); + LOG.error(errMsg); + throw new IllegalArgumentException(errMsg); + } + + final var v2Obj = root.get("v2"); + if (!v2Obj.has("format")) { + String errMsg = + String.format( + "Database metadata file %s is malformed, \"format\" field not found", dbMetadata); + LOG.error(errMsg); + throw new IllegalArgumentException(errMsg); + } + + final var formatField = v2Obj.get("format").asText(); + final OptionalInt maybePrivacyVersion = + v2Obj.has("privacyVersion") + ? OptionalInt.of(v2Obj.get("privacyVersion").asInt()) + : OptionalInt.empty(); + + final DataStorageFormat dataStorageFormat = DataStorageFormat.valueOf(formatField); + final int v1Version = + switch (dataStorageFormat) { + case FOREST -> 1; + case BONSAI -> 2; + }; + + @JsonSerialize + record V1(int version, OptionalInt privacyVersion) {} + + MAPPER.writeValue(dbMetadata, new V1(v1Version, maybePrivacyVersion)); + LOG.info("Successfully reverted database metadata from v2 to v1 in {}", dbMetadata); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java index 0dbfa3d22c5..60a1250d69a 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java @@ -48,7 +48,8 @@ subcommands = { StorageSubCommand.RevertVariablesStorage.class, RocksDbSubCommand.class, - TrieLogSubCommand.class + TrieLogSubCommand.class, + RevertMetadataSubCommand.class }) public class StorageSubCommand implements Runnable { From 8fae465a5ea27c573ce4003fac823f4b6e6ad6fc Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 13 Feb 2024 20:06:10 +0100 Subject: [PATCH 10/13] Json pretty print and exclude empty optionals Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 13 ++++++++++++- .../storage/RevertMetadataSubCommand.java | 8 +++++++- .../rocksdb/configuration/DatabaseMetadata.java | 8 +++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e01d115b51a..273876f781b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 24.1.3-SNAPSHOT + +### Breaking Changes +- RocksDB database metadata format has changed to be more expressive, the migration of an existing metadata file to the new format is automatic at startup. Before prerforming a downgrade to a previous version then it is mandatory to revert to the original format using the subcommand `besu --data-path=/path/to/besu/datadir storage revert-metadata v2-to-v1`. + +### Deprecations + +### Additions and Improvements +- RocksDB database metadata refactoring [#6555](https://github.com/hyperledger/besu/pull/6555) + +### Bug fixes + ## 24.1.2-SNAPSHOT ### Breaking Changes @@ -9,7 +21,6 @@ - `--Xfilter-on-enr-fork-id` has been removed. To disable the feature use `--filter-on-enr-fork-id=false`. - `--engine-jwt-enabled` has been removed. Use `--engine-jwt-disabled` instead. [#6491](https://github.com/hyperledger/besu/pull/6491) - ### Deprecations - X_SNAP and X_CHECKPOINT are marked for deprecation and will be removed in 24.4.0 in favor of SNAP and CHECKPOINT [#6405](https://github.com/hyperledger/besu/pull/6405) - `--Xsnapsync-synchronizer-flat-db-healing-enabled` is deprecated (always enabled). [#6499](https://github.com/hyperledger/besu/pull/6499) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java index 8ced96d46d7..aa95452d90c 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RevertMetadataSubCommand.java @@ -22,7 +22,9 @@ import java.nio.file.Path; import java.util.OptionalInt; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import org.slf4j.Logger; @@ -41,7 +43,11 @@ public class RevertMetadataSubCommand implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(RevertMetadataSubCommand.class); private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; - private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); + private static final ObjectMapper MAPPER = + new ObjectMapper() + .registerModule(new Jdk8Module()) + .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) + .enable(SerializationFeature.INDENT_OUTPUT); @SuppressWarnings("unused") @ParentCommand 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 182d3af905f..db29d73c66d 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 @@ -24,9 +24,11 @@ import java.util.Arrays; import java.util.OptionalInt; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DatabindException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import org.slf4j.Logger; @@ -37,7 +39,11 @@ public class DatabaseMetadata { private static final Logger LOG = LoggerFactory.getLogger(DatabaseMetadata.class); private static final String METADATA_FILENAME = "DATABASE_METADATA.json"; - private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module()); + private static final ObjectMapper MAPPER = + new ObjectMapper() + .registerModule(new Jdk8Module()) + .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) + .enable(SerializationFeature.INDENT_OUTPUT); private final VersionedStorageFormat versionedStorageFormat; protected DatabaseMetadata(final VersionedStorageFormat versionedStorageFormat) { From 69961996276c1bc02524e649fb0eee0473e01dc1 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 15 Feb 2024 11:06:22 +0100 Subject: [PATCH 11/13] Update CHANGELOG.md Co-authored-by: Gabriel Fukushima Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 273876f781b..df9b7a837ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 24.1.3-SNAPSHOT ### Breaking Changes -- RocksDB database metadata format has changed to be more expressive, the migration of an existing metadata file to the new format is automatic at startup. Before prerforming a downgrade to a previous version then it is mandatory to revert to the original format using the subcommand `besu --data-path=/path/to/besu/datadir storage revert-metadata v2-to-v1`. +- RocksDB database metadata format has changed to be more expressive, the migration of an existing metadata file to the new format is automatic at startup. Before performing a downgrade to a previous version it is mandatory to revert to the original format using the subcommand `besu --data-path=/path/to/besu/datadir storage revert-metadata v2-to-v1`. ### Deprecations From 0ab629116d34270a17cf19a44a62ab6448e6d17e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 19 Feb 2024 11:24:23 +0100 Subject: [PATCH 12/13] Apply suggestion from code review Signed-off-by: Fabio Di Fabio --- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 3 ++- .../RocksDBKeyValueStorageFactoryTest.java | 4 ++-- .../services/storage/rocksdb/Utils.java | 22 +++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) 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 c3d518fcd65..003d640be8d 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 @@ -56,7 +56,8 @@ public void shouldDetectVersion1MetadataIfPresent() throws Exception { Files.createDirectories(tempDataDir); mockCommonConfiguration(tempDataDir, tempDatabaseDir); - Utils.createDatabaseMetadataV1Privacy(tempDataDir, 1, 1); + Utils.createDatabaseMetadataV1Privacy( + tempDataDir, PrivacyVersionedStorageFormat.FOREST_ORIGINAL); final RocksDBKeyValuePrivacyStorageFactory storageFactory = new RocksDBKeyValuePrivacyStorageFactory( 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 22624e69e6e..e2c56f0ac50 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 @@ -101,7 +101,7 @@ public void shouldDetectCorrectMetadataV1() throws Exception { Files.createDirectories(tempDataDir); mockCommonConfiguration(tempDataDir, tempDatabaseDir, BONSAI); - Utils.createDatabaseMetadataV1(tempDataDir, 2); + Utils.createDatabaseMetadataV1(tempDataDir, BONSAI); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( @@ -122,7 +122,7 @@ public void shouldFailInCaseOfUnmanagedRollback() throws Exception { Files.createDirectories(tempDataDir); mockCommonConfiguration(tempDataDir, tempDatabaseDir, BONSAI); - Utils.createDatabaseMetadataV1(tempDataDir, 2); + Utils.createDatabaseMetadataV1(tempDataDir, BONSAI); final RocksDBKeyValueStorageFactory storageFactory = new RocksDBKeyValueStorageFactory( diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java index b5802f4bdf9..4b18047413e 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/Utils.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.plugin.services.storage.rocksdb; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.PrivacyVersionedStorageFormat; import java.io.IOException; import java.nio.charset.Charset; @@ -24,12 +25,26 @@ public class Utils { public static final String METADATA_FILENAME = "DATABASE_METADATA.json"; + public static void createDatabaseMetadataV1( + final Path tempDataDir, final DataStorageFormat dataStorageFormat) throws IOException { + createDatabaseMetadataV1(tempDataDir, dataStorageFormatToV1(dataStorageFormat)); + } + public static void createDatabaseMetadataV1(final Path tempDataDir, final int version) throws IOException { final String content = "{\"version\":" + version + "}"; Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); } + public static void createDatabaseMetadataV1Privacy( + final Path tempDataDir, final PrivacyVersionedStorageFormat privacyVersionedStorageFormat) + throws IOException { + createDatabaseMetadataV1Privacy( + tempDataDir, + dataStorageFormatToV1(privacyVersionedStorageFormat.getFormat()), + privacyVersionedStorageFormat.getPrivacyVersion().getAsInt()); + } + public static void createDatabaseMetadataV1Privacy( final Path tempDataDir, final int version, final int privacyVersion) throws IOException { final String content = @@ -66,4 +81,11 @@ public static void createDatabaseMetadataRaw(final Path tempDataDir, final Strin throws IOException { Files.write(tempDataDir.resolve(METADATA_FILENAME), content.getBytes(Charset.defaultCharset())); } + + private static int dataStorageFormatToV1(final DataStorageFormat dataStorageFormat) { + return switch (dataStorageFormat) { + case FOREST -> 1; + case BONSAI -> 2; + }; + } } From 2a7c613f00f6d67a2140664c6649038f69dd7003 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 21 Feb 2024 16:11:39 +0100 Subject: [PATCH 13/13] javadoc Signed-off-by: Fabio Di Fabio --- plugin-api/build.gradle | 2 +- .../services/storage/DataStorageFormat.java | 7 +++-- .../BaseVersionedStorageFormat.java | 17 +++++++++++ .../configuration/DatabaseMetadata.java | 30 ++++++++++++++++++- .../PrivacyVersionedStorageFormat.java | 17 +++++++++++ .../configuration/VersionedStorageFormat.java | 17 ++++++++++- 6 files changed, 85 insertions(+), 5 deletions(-) diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index e314b8214a8..f9e2c936043 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = '2/ggfEtjHqgkV9wPZF3WNJLLAfs6XReazCIEUe2G8/4=' + knownHash = 'IPk6AtzTyEJknllOYlEf0GN+5Cyu/bwhkju29amNbds=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java index 403541bbd95..69df2717b3b 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/DataStorageFormat.java @@ -14,7 +14,10 @@ */ package org.hyperledger.besu.plugin.services.storage; +/** Supported database storage format */ public enum DataStorageFormat { - FOREST, // Original format. Store all tries - BONSAI; // New format. Store one trie, and trie logs to roll forward and backward. + /** Original format. Store all tries */ + FOREST, + /** New format. Store one trie, and trie logs to roll forward and backward */ + BONSAI; } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java index a9cbeaf579d..a18b907a6e7 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/BaseVersionedStorageFormat.java @@ -18,10 +18,21 @@ import java.util.OptionalInt; +/** Base versioned data storage format */ public enum BaseVersionedStorageFormat implements VersionedStorageFormat { + /** Original Forest version, not used since replace by FOREST_WITH_VARIABLES */ FOREST_ORIGINAL(DataStorageFormat.FOREST, 1), + /** + * Current Forest version, with blockchain variables in a dedicated column family, in order to + * make BlobDB more effective + */ FOREST_WITH_VARIABLES(DataStorageFormat.FOREST, 2), + /** Original Bonsai version, not used since replace by BONSAI_WITH_VARIABLES */ BONSAI_ORIGINAL(DataStorageFormat.BONSAI, 1), + /** + * Current Bonsai version, with blockchain variables in a dedicated column family, in order to + * make BlobDB more effective + */ BONSAI_WITH_VARIABLES(DataStorageFormat.BONSAI, 2); private final DataStorageFormat format; @@ -32,6 +43,12 @@ public enum BaseVersionedStorageFormat implements VersionedStorageFormat { this.version = version; } + /** + * Return the default version for new db for a specific format + * + * @param format data storage format + * @return the version to use for new db + */ public static BaseVersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { return switch (format) { case FOREST -> FOREST_WITH_VARIABLES; 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 db29d73c66d..4e18e35029c 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 @@ -46,18 +46,34 @@ public class DatabaseMetadata { .enable(SerializationFeature.INDENT_OUTPUT); private final VersionedStorageFormat versionedStorageFormat; - protected DatabaseMetadata(final VersionedStorageFormat versionedStorageFormat) { + private DatabaseMetadata(final VersionedStorageFormat versionedStorageFormat) { this.versionedStorageFormat = versionedStorageFormat; } + /** + * Return the default metadata for new db for a specific format + * + * @param dataStorageFormat data storage format + * @return the metadata to use for new db + */ public static DatabaseMetadata defaultForNewDb(final DataStorageFormat dataStorageFormat) { return new DatabaseMetadata(BaseVersionedStorageFormat.defaultForNewDB(dataStorageFormat)); } + /** + * Return the default metadata for new db when privacy feature is enabled + * + * @return the metadata to use for new db + */ public static DatabaseMetadata defaultForNewPrivateDb() { return new DatabaseMetadata(PrivacyVersionedStorageFormat.FOREST_WITH_VARIABLES); } + /** + * Return the version storage format contained in this metadata + * + * @return version storage format + */ public VersionedStorageFormat getVersionedStorageFormat() { return versionedStorageFormat; } @@ -74,6 +90,13 @@ public static DatabaseMetadata lookUpFrom(final Path dataDir) throws IOException return resolveDatabaseMetadata(getDefaultMetadataFile(dataDir)); } + /** + * Is the metadata file present in the specified data dir? + * + * @param dataDir the dir to search for the metadata file + * @return true is the metadata file exists, false otherwise + * @throws IOException if there is an error trying to access the metadata file + */ public static boolean isPresent(final Path dataDir) throws IOException { return getDefaultMetadataFile(dataDir).exists(); } @@ -188,6 +211,11 @@ private static VersionedStorageFormat fromV2(final MetadataV2 metadataV2) { }); } + /** + * Update an existing base storage to support privacy feature + * + * @return the update metadata with the privacy support + */ public DatabaseMetadata upgradeToPrivacy() { return new DatabaseMetadata( switch (versionedStorageFormat.getFormat()) { diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java index f5a05330652..9a86d6ec15d 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/PrivacyVersionedStorageFormat.java @@ -18,10 +18,21 @@ import java.util.OptionalInt; +/** Privacy enabled versioned data storage format */ public enum PrivacyVersionedStorageFormat implements VersionedStorageFormat { + /** Original Forest version, not used since replace by FOREST_WITH_VARIABLES */ FOREST_ORIGINAL(BaseVersionedStorageFormat.FOREST_ORIGINAL, 1), + /** + * Current Forest version, with blockchain variables in a dedicated column family, in order to + * make BlobDB more effective + */ FOREST_WITH_VARIABLES(BaseVersionedStorageFormat.FOREST_WITH_VARIABLES, 1), + /** Original Bonsai version, not used since replace by BONSAI_WITH_VARIABLES */ BONSAI_ORIGINAL(BaseVersionedStorageFormat.BONSAI_ORIGINAL, 1), + /** + * Current Bonsai version, with blockchain variables in a dedicated column family, in order to + * make BlobDB more effective + */ BONSAI_WITH_VARIABLES(BaseVersionedStorageFormat.BONSAI_WITH_VARIABLES, 1); private final VersionedStorageFormat baseVersionedStorageFormat; @@ -33,6 +44,12 @@ public enum PrivacyVersionedStorageFormat implements VersionedStorageFormat { this.privacyVersion = OptionalInt.of(privacyVersion); } + /** + * Return the default version for new db for a specific format + * + * @param format data storage format + * @return the version to use for new db + */ public static VersionedStorageFormat defaultForNewDB(final DataStorageFormat format) { return switch (format) { case FOREST -> FOREST_WITH_VARIABLES; diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java index 34459d6ec56..896438cc5ca 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/VersionedStorageFormat.java @@ -18,11 +18,26 @@ import java.util.OptionalInt; +/** Represent a specific version of a data storage format */ public interface VersionedStorageFormat { - + /** + * Get the data storage format + * + * @return the data storage format + */ DataStorageFormat getFormat(); + /** + * Get the version of the data storage format + * + * @return the version of the data storage format + */ int getVersion(); + /** + * Get the version of the privacy db, in case the privacy feature is enabled, or empty otherwise + * + * @return the optional privacy version + */ OptionalInt getPrivacyVersion(); }