From 8274fe3b811be354cc46febfd82fc0fa9b6d7f78 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 30 Aug 2023 16:39:12 -0700 Subject: [PATCH 1/5] parse rocksdb error for unprintable column family id's Signed-off-by: garyschulte --- .../RocksDBColumnarKeyValueStorage.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 567b3f623b9..ce9b13a0377 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -16,6 +16,9 @@ import static java.util.stream.Collectors.toUnmodifiableSet; +import com.google.common.base.Splitter; +import com.google.common.collect.Streams; +import org.apache.tuweni.bytes.Bytes; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -31,6 +34,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -161,7 +165,42 @@ public RocksDBColumnarKeyValueStorage( txOptions = new TransactionDBOptions(); columnHandles = new ArrayList<>(columnDescriptors.size()); } catch (RocksDBException e) { - throw new StorageException(e); + List knownSegments = Streams.concat( + defaultSegments.stream(), + ignorableSegments.stream()) + .distinct() + .toList(); + throw parseRocksDBException(e, knownSegments); + } + } + + private static StorageException parseRocksDBException( + final RocksDBException ex, + final List knownSegments) { + String message = ex.getMessage(); + + // parse out unprintable segment names for a more useful exception: + String columnExceptionMessagePrefix = "Column families not opened: "; + if (message.contains(columnExceptionMessagePrefix)) { + String substring = message.substring(message.indexOf(": ") + 2); + + List unHandledSegments = new ArrayList<>(); + Splitter.on(", ").splitToStream(substring) + .forEach(part -> { + byte[] bytes = part.getBytes(StandardCharsets.UTF_8); + unHandledSegments.add( + knownSegments.stream().filter(seg -> Arrays.equals(seg.getId(), bytes)) + .findFirst() + .map(SegmentIdentifier::getName) + .orElse("unknown segment:{" + Bytes.of(bytes).toHexString() + "}")); + + }); + + return new StorageException( + "RocksDBException: Unhandled column families: [" + + unHandledSegments.stream().collect(Collectors.joining(", ")) + "]"); + } else { + return new StorageException(ex); } } From aa31df6304389a9285faabf8e916e54fdcdbfadf Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 30 Aug 2023 16:46:40 -0700 Subject: [PATCH 2/5] spotless Signed-off-by: garyschulte --- .../RocksDBColumnarKeyValueStorage.java | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index ce9b13a0377..5ef091c9c3a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -16,9 +16,6 @@ import static java.util.stream.Collectors.toUnmodifiableSet; -import com.google.common.base.Splitter; -import com.google.common.collect.Streams; -import org.apache.tuweni.bytes.Bytes; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -34,7 +31,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -44,7 +40,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.google.common.base.Splitter; +import com.google.common.collect.Streams; import org.apache.commons.lang3.tuple.Pair; +import org.apache.tuweni.bytes.Bytes; import org.rocksdb.BlockBasedTableConfig; import org.rocksdb.BloomFilter; import org.rocksdb.ColumnFamilyDescriptor; @@ -165,18 +164,14 @@ public RocksDBColumnarKeyValueStorage( txOptions = new TransactionDBOptions(); columnHandles = new ArrayList<>(columnDescriptors.size()); } catch (RocksDBException e) { - List knownSegments = Streams.concat( - defaultSegments.stream(), - ignorableSegments.stream()) - .distinct() - .toList(); + List knownSegments = + Streams.concat(defaultSegments.stream(), ignorableSegments.stream()).distinct().toList(); throw parseRocksDBException(e, knownSegments); } } private static StorageException parseRocksDBException( - final RocksDBException ex, - final List knownSegments) { + final RocksDBException ex, final List knownSegments) { String message = ex.getMessage(); // parse out unprintable segment names for a more useful exception: @@ -185,20 +180,23 @@ private static StorageException parseRocksDBException( String substring = message.substring(message.indexOf(": ") + 2); List unHandledSegments = new ArrayList<>(); - Splitter.on(", ").splitToStream(substring) - .forEach(part -> { - byte[] bytes = part.getBytes(StandardCharsets.UTF_8); - unHandledSegments.add( - knownSegments.stream().filter(seg -> Arrays.equals(seg.getId(), bytes)) - .findFirst() - .map(SegmentIdentifier::getName) - .orElse("unknown segment:{" + Bytes.of(bytes).toHexString() + "}")); - - }); + Splitter.on(", ") + .splitToStream(substring) + .forEach( + part -> { + byte[] bytes = part.getBytes(StandardCharsets.UTF_8); + unHandledSegments.add( + knownSegments.stream() + .filter(seg -> Arrays.equals(seg.getId(), bytes)) + .findFirst() + .map(SegmentIdentifier::getName) + .orElse("unknown segment:{" + Bytes.of(bytes).toHexString() + "}")); + }); return new StorageException( - "RocksDBException: Unhandled column families: [" + - unHandledSegments.stream().collect(Collectors.joining(", ")) + "]"); + "RocksDBException: Unhandled column families: [" + + unHandledSegments.stream().collect(Collectors.joining(", ")) + + "]"); } else { return new StorageException(ex); } From de88169583081544f368ac1539ff046d99dfe393 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 30 Aug 2023 21:45:23 -0700 Subject: [PATCH 3/5] fix the bug that creates the ignorable chain pruner segment, add rocks exception parsing to RocksDBColumnarKeyValueStorage subclasses Signed-off-by: garyschulte --- .../org/hyperledger/besu/cli/BesuCommand.java | 2 +- .../storage/StorageSubCommand.java | 2 ++ ...imisticRocksDBColumnarKeyValueStorage.java | 2 +- .../RocksDBColumnarKeyValueStorage.java | 23 +++++++++++++------ ...ctionDBRocksDBColumnarKeyValueStorage.java | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) 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 e0330170b7f..651d04738ad 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -3489,7 +3489,7 @@ private void setMergeConfigOptions() { getActualGenesisConfigOptions().getTerminalTotalDifficulty().isPresent()); } - private void setIgnorableStorageSegments() { + public void setIgnorableStorageSegments() { if (!unstableChainPruningOptions.getChainDataPruningEnabled()) { rocksDBPlugin.addIgnorableSegmentIdentifier(KeyValueSegmentIdentifier.CHAIN_PRUNER_STATE); } 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 f7a1a6eca11..bd40a42a431 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 @@ -99,6 +99,8 @@ public void run() { } private StorageProvider getStorageProvider() { + // init collection of ignorable segments + parentCommand.parentCommand.setIgnorableStorageSegments(); return parentCommand.parentCommand.getStorageProvider(); } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java index 13f50da388e..fa5786e6b9a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java @@ -63,7 +63,7 @@ public OptimisticRocksDBColumnarKeyValueStorage( initColumnHandles(); } catch (final RocksDBException e) { - throw new StorageException(e); + throw parseRocksDBException(e, segments, ignorableSegments); } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 5ef091c9c3a..2c82825fe1e 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -164,15 +164,17 @@ public RocksDBColumnarKeyValueStorage( txOptions = new TransactionDBOptions(); columnHandles = new ArrayList<>(columnDescriptors.size()); } catch (RocksDBException e) { - List knownSegments = - Streams.concat(defaultSegments.stream(), ignorableSegments.stream()).distinct().toList(); - throw parseRocksDBException(e, knownSegments); + throw parseRocksDBException(e, defaultSegments, ignorableSegments); } } - private static StorageException parseRocksDBException( - final RocksDBException ex, final List knownSegments) { + protected static StorageException parseRocksDBException( + final RocksDBException ex, + final List defaultSegments, + final List ignorableSegments) { String message = ex.getMessage(); + List knownSegments = + Streams.concat(defaultSegments.stream(), ignorableSegments.stream()).distinct().toList(); // parse out unprintable segment names for a more useful exception: String columnExceptionMessagePrefix = "Column families not opened: "; @@ -189,8 +191,9 @@ private static StorageException parseRocksDBException( knownSegments.stream() .filter(seg -> Arrays.equals(seg.getId(), bytes)) .findFirst() - .map(SegmentIdentifier::getName) - .orElse("unknown segment:{" + Bytes.of(bytes).toHexString() + "}")); + .map(seg -> new SegmentRecord(seg.getName(), seg.getId())) + .orElse(new SegmentRecord(part, bytes)) + .forDisplay()); }); return new StorageException( @@ -393,4 +396,10 @@ void throwIfClosed() { } abstract RocksDB getDB(); + + record SegmentRecord(String name, byte[] id) { + public String forDisplay() { + return String.format("'%s'(%s)", name, Bytes.of(id).toHexString()); + } + } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java index 6825a05063a..4825154561a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java @@ -66,7 +66,7 @@ public TransactionDBRocksDBColumnarKeyValueStorage( initColumnHandles(); } catch (final RocksDBException e) { - throw new StorageException(e); + throw parseRocksDBException(e, segments, ignorableSegments); } } From 550d39b025824bbddcbdfa55f7249aadbccb190c Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 31 Aug 2023 00:10:58 -0700 Subject: [PATCH 4/5] javadoc and unit test exception message assertions Signed-off-by: garyschulte --- .../main/java/org/hyperledger/besu/cli/BesuCommand.java | 1 + .../rocksdb/segmented/RocksDBColumnarKeyValueStorage.java | 8 ++++++++ .../segmented/RocksDBColumnarKeyValueStorageTest.java | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) 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 651d04738ad..9ccf10df966 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -3489,6 +3489,7 @@ private void setMergeConfigOptions() { getActualGenesisConfigOptions().getTerminalTotalDifficulty().isPresent()); } + /** Set ignorable segments in RocksDB Storage Provider plugin. */ public void setIgnorableStorageSegments() { if (!unstableChainPruningOptions.getChainDataPruningEnabled()) { rocksDBPlugin.addIgnorableSegmentIdentifier(KeyValueSegmentIdentifier.CHAIN_PRUNER_STATE); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 2c82825fe1e..3d98be37523 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -168,6 +168,14 @@ public RocksDBColumnarKeyValueStorage( } } + /** + * Parse RocksDBException and wrap in StorageException + * + * @param ex RocksDBException + * @param defaultSegments segments requested to open + * @param ignorableSegments segments which are ignorable if not present + * @return StorageException wrapping the RocksDB Exception + */ protected static StorageException parseRocksDBException( final RocksDBException ex, final List defaultSegments, 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 827b18eb0c1..5462d239b91 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 @@ -222,7 +222,7 @@ public void dbShouldNotIgnoreExperimentalSegmentsIfExisted(@TempDir final Path t createSegmentedStore(testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR), List.of()); fail("DB without knowledge of experimental column family should fail"); } catch (StorageException e) { - assertThat(e.getMessage()).contains("Column families not opened"); + assertThat(e.getMessage()).contains("Unhandled column families"); } // Even if the column family is marked as ignored, as long as it exists, it will not be ignored @@ -265,7 +265,7 @@ public void dbWillBeBackwardIncompatibleAfterExperimentalSegmentsAreAdded( createSegmentedStore(testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR), List.of()); fail("DB without knowledge of experimental column family should fail"); } catch (StorageException e) { - assertThat(e.getMessage()).contains("Column families not opened"); + assertThat(e.getMessage()).contains("Unhandled column families"); } } From 05e5d7a05c3fe35ab73cdb0fa5008029edd88d1f Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 31 Aug 2023 08:10:41 -0700 Subject: [PATCH 5/5] update changelog Signed-off-by: garyschulte --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09280d05a3b..ccca9652cf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 23.7.3 +### Additions and Improvements + +### Breaking Changes +- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) + +### Additions and Improvements + +### Bug Fixes +- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) + +### Download Links + + ## 23.7.2 ### Additions and Improvements @@ -30,7 +44,6 @@ ### Breaking Changes - Removed deprecated GoQuorum permissioning interop [#5607](https://github.com/hyperledger/besu/pull/5607) - Removed support for version 0 of the database as it is no longer used by any active node. [#5698](https://github.com/hyperledger/besu/pull/5698) -- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) ### Additions and Improvements - `evmtool` launcher binaries now ship as part of the standard distribution. [#5701](https://github.com/hyperledger/besu/pull/5701)