diff --git a/CHANGELOG.md b/CHANGELOG.md index f237b2d2ef2..9027b004c13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ### Breaking Changes - Version 22.4.x will be the last series to support Java 11. Version 22.7.0 will require Java 17 to build and run. +- In the Besu EVM Library all references to SHA3 have been renamed to the more accurate name Keccak256, including class names and comment. [#3749](https://github.com/hyperledger/besu/pull/3749) + +### Bug Fixes +- Fix nullpointer on snapsync [#3773](https://github.com/hyperledger/besu/pull/3773) +- Introduce RocksDbSegmentIdentifier to avoid changing the storage plugin [#3755](https://github.com/hyperledger/besu/pull/3755) ## 22.4.0-RC2 diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java index 2a28bffbf0a..a5c810f5cf4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java @@ -189,13 +189,8 @@ public synchronized void reloadHeal() { worldStateStorage.clearFlatDatabase(); pendingTrieNodeRequests.clearInternalQueues(); pendingCodeRequests.clearInternalQueue(); - enqueueRequest( - createAccountTrieNodeDataRequest( - snapSyncState.getPivotBlockHeader().orElseThrow().getStateRoot(), - Bytes.EMPTY, - inconsistentAccounts)); - requestComplete(true); - notifyTaskAvailable(); + snapSyncState.setHealStatus(false); + checkCompletion(snapSyncState.getPivotBlockHeader().orElseThrow()); } @Override 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 b0c5d14957e..010d49c8126 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 @@ -18,6 +18,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -236,4 +237,21 @@ public void shouldCancelOutstandingTasksWhenFutureIsCancelled() { verify(worldStateDownloadProcess).abort(); assertThat(downloadState.isDownloading()).isFalse(); } + + @Test + public void shouldRestartHealWhenNewPivotBlock() { + when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(mock(BlockHeader.class))); + when(snapSyncState.isHealInProgress()).thenReturn(false); + assertThat(downloadState.pendingTrieNodeRequests.isEmpty()).isTrue(); + // start heal + downloadState.checkCompletion(header); + verify(snapSyncState).setHealStatus(true); + assertThat(downloadState.pendingTrieNodeRequests.isEmpty()).isFalse(); + // reload the heal + downloadState.reloadHeal(); + verify(snapSyncState).setHealStatus(false); + spy(downloadState.pendingTrieNodeRequests).clearInternalQueues(); + spy(downloadState).checkCompletion(header); + assertThat(downloadState.pendingTrieNodeRequests.isEmpty()).isFalse(); + } } diff --git a/gradle.properties b/gradle.properties index d99aea58b56..d8b94a4fca7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=22.4.0-RC3-SNAPSHOT +version=22.4.0 # Workaround for Java 16 and spotless bug 834 https://github.com/diffplug/spotless/issues/834 org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDbSegmentIdentifier.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDbSegmentIdentifier.java new file mode 100644 index 00000000000..b1529244f4a --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDbSegmentIdentifier.java @@ -0,0 +1,75 @@ +/* + * 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.exception.StorageException; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +import org.rocksdb.ColumnFamilyDescriptor; +import org.rocksdb.ColumnFamilyHandle; +import org.rocksdb.RocksDBException; +import org.rocksdb.TransactionDB; + +public class RocksDbSegmentIdentifier { + + private final TransactionDB db; + private final AtomicReference reference; + + public RocksDbSegmentIdentifier( + final TransactionDB db, final ColumnFamilyHandle columnFamilyHandle) { + this.db = db; + this.reference = new AtomicReference<>(columnFamilyHandle); + } + + public void reset() { + reference.getAndUpdate( + oldHandle -> { + try { + ColumnFamilyDescriptor descriptor = + new ColumnFamilyDescriptor( + oldHandle.getName(), oldHandle.getDescriptor().getOptions()); + db.dropColumnFamily(oldHandle); + ColumnFamilyHandle newHandle = db.createColumnFamily(descriptor); + oldHandle.close(); + return newHandle; + } catch (final RocksDBException e) { + throw new StorageException(e); + } + }); + } + + public ColumnFamilyHandle get() { + return reference.get(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RocksDbSegmentIdentifier that = (RocksDbSegmentIdentifier) o; + return Objects.equals(reference.get(), that.reference.get()); + } + + @Override + public int hashCode() { + return reference.get().hashCode(); + } +} 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 0a37084da64..3d135b1a2c1 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 @@ -24,6 +24,7 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetrics; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbKeyIterator; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbUtil; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; @@ -36,7 +37,6 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -61,7 +61,7 @@ import org.slf4j.LoggerFactory; public class RocksDBColumnarKeyValueStorage - implements SegmentedKeyValueStorage { + implements SegmentedKeyValueStorage { private static final Logger LOG = LoggerFactory.getLogger(RocksDBColumnarKeyValueStorage.class); private static final String DEFAULT_COLUMN = "default"; @@ -75,7 +75,7 @@ public class RocksDBColumnarKeyValueStorage private final TransactionDBOptions txOptions; private final TransactionDB db; private final AtomicBoolean closed = new AtomicBoolean(false); - private final Map> columnHandlesByName; + private final Map columnHandlesByName; private final RocksDBMetrics metrics; private final WriteOptions tryDeleteOptions = new WriteOptions().setNoSlowdown(true); @@ -128,14 +128,13 @@ public RocksDBColumnarKeyValueStorage( Collectors.toMap( segment -> Bytes.wrap(segment.getId()), SegmentIdentifier::getName)); - final ImmutableMap.Builder> builder = - ImmutableMap.builder(); + final ImmutableMap.Builder builder = ImmutableMap.builder(); for (ColumnFamilyHandle columnHandle : columnHandles) { final String segmentName = requireNonNullElse( segmentsById.get(Bytes.wrap(columnHandle.getName())), DEFAULT_COLUMN); - builder.put(segmentName, new AtomicReference<>(columnHandle)); + builder.put(segmentName, new RocksDbSegmentIdentifier(db, columnHandle)); } columnHandlesByName = builder.build(); @@ -150,25 +149,24 @@ private BlockBasedTableConfig createBlockBasedTableConfig(final RocksDBConfigura } @Override - public AtomicReference getSegmentIdentifierByName( - final SegmentIdentifier segment) { + public RocksDbSegmentIdentifier getSegmentIdentifierByName(final SegmentIdentifier segment) { return columnHandlesByName.get(segment.getName()); } @Override - public Optional get(final ColumnFamilyHandle segment, final byte[] key) + public Optional get(final RocksDbSegmentIdentifier segment, final byte[] key) throws StorageException { throwIfClosed(); try (final OperationTimer.TimingContext ignored = metrics.getReadLatency().startTimer()) { - return Optional.ofNullable(db.get(segment, key)); + return Optional.ofNullable(db.get(segment.get(), key)); } catch (final RocksDBException e) { throw new StorageException(e); } } @Override - public Transaction startTransaction() throws StorageException { + public Transaction startTransaction() throws StorageException { throwIfClosed(); final WriteOptions writeOptions = new WriteOptions(); return new SegmentedKeyValueStorageTransactionTransitionValidatorDecorator<>( @@ -176,16 +174,16 @@ public Transaction startTransaction() throws StorageExceptio } @Override - public Stream streamKeys(final ColumnFamilyHandle segmentHandle) { - final RocksIterator rocksIterator = db.newIterator(segmentHandle); + public Stream streamKeys(final RocksDbSegmentIdentifier segmentHandle) { + final RocksIterator rocksIterator = db.newIterator(segmentHandle.get()); rocksIterator.seekToFirst(); return RocksDbKeyIterator.create(rocksIterator).toStream(); } @Override - public boolean tryDelete(final ColumnFamilyHandle segmentHandle, final byte[] key) { + public boolean tryDelete(final RocksDbSegmentIdentifier segmentHandle, final byte[] key) { try { - db.delete(segmentHandle, tryDeleteOptions, key); + db.delete(segmentHandle.get(), tryDeleteOptions, key); return true; } catch (RocksDBException e) { if (e.getStatus().getCode() == Status.Code.Incomplete) { @@ -198,33 +196,17 @@ public boolean tryDelete(final ColumnFamilyHandle segmentHandle, final byte[] ke @Override public Set getAllKeysThat( - final ColumnFamilyHandle segmentHandle, final Predicate returnCondition) { + final RocksDbSegmentIdentifier segmentHandle, final Predicate returnCondition) { return streamKeys(segmentHandle).filter(returnCondition).collect(toUnmodifiableSet()); } @Override - public void clear(final ColumnFamilyHandle segmentHandle) { - - var entry = - columnHandlesByName.values().stream().filter(e -> e.get().equals(segmentHandle)).findAny(); - - if (entry.isPresent()) { - AtomicReference segmentHandleRef = entry.get(); - segmentHandleRef.getAndUpdate( - oldHandle -> { - try { - ColumnFamilyDescriptor descriptor = - new ColumnFamilyDescriptor( - segmentHandle.getName(), segmentHandle.getDescriptor().getOptions()); - db.dropColumnFamily(oldHandle); - ColumnFamilyHandle newHandle = db.createColumnFamily(descriptor); - segmentHandle.close(); - return newHandle; - } catch (final RocksDBException e) { - throw new StorageException(e); - } - }); - } + public void clear(final RocksDbSegmentIdentifier segmentHandle) { + + columnHandlesByName.values().stream() + .filter(e -> e.equals(segmentHandle)) + .findAny() + .ifPresent(segmentIdentifier -> segmentIdentifier.reset()); } @Override @@ -234,7 +216,7 @@ public void close() { options.close(); tryDeleteOptions.close(); columnHandlesByName.values().stream() - .map(AtomicReference::get) + .map(RocksDbSegmentIdentifier::get) .forEach(ColumnFamilyHandle::close); db.close(); } @@ -247,7 +229,7 @@ private void throwIfClosed() { } } - private class RocksDbTransaction implements Transaction { + private class RocksDbTransaction implements Transaction { private final org.rocksdb.Transaction innerTx; private final WriteOptions options; @@ -258,9 +240,9 @@ private class RocksDbTransaction implements Transaction { } @Override - public void put(final ColumnFamilyHandle segment, final byte[] key, final byte[] value) { + public void put(final RocksDbSegmentIdentifier segment, final byte[] key, final byte[] value) { try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { - innerTx.put(segment, key, value); + innerTx.put(segment.get(), key, value); } catch (final RocksDBException e) { if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { LOG.error(e.getMessage()); @@ -271,9 +253,9 @@ public void put(final ColumnFamilyHandle segment, final byte[] key, final byte[] } @Override - public void remove(final ColumnFamilyHandle segment, final byte[] key) { + public void remove(final RocksDbSegmentIdentifier segment, final byte[] key) { try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { - innerTx.delete(segment, key); + innerTx.delete(segment.get(), key); } catch (final RocksDBException e) { if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { LOG.error(e.getMessage()); diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBColumnarKeyValueStorageTest.java index 95da9eda660..d1c0d7fe7e6 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBColumnarKeyValueStorageTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorage; import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; @@ -31,13 +32,11 @@ import java.util.Arrays; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.rocksdb.ColumnFamilyHandle; public class RocksDBColumnarKeyValueStorageTest extends AbstractKeyValueStorageTest { @@ -48,31 +47,31 @@ public void assertClear() throws Exception { final byte[] key = bytesFromHexString("0001"); final byte[] val1 = bytesFromHexString("0FFF"); final byte[] val2 = bytesFromHexString("1337"); - final SegmentedKeyValueStorage store = createSegmentedStore(); - AtomicReference segment = store.getSegmentIdentifierByName(TestSegment.FOO); + final SegmentedKeyValueStorage store = createSegmentedStore(); + RocksDbSegmentIdentifier segment = store.getSegmentIdentifierByName(TestSegment.FOO); KeyValueStorage duplicateSegmentRef = new SegmentedKeyValueStorageAdapter<>(TestSegment.FOO, store); final Consumer insert = value -> { - final Transaction tx = store.startTransaction(); - tx.put(segment.get(), key, value); + final Transaction tx = store.startTransaction(); + tx.put(segment, key, value); tx.commit(); }; // insert val: insert.accept(val1); - assertThat(store.get(segment.get(), key).orElse(null)).isEqualTo(val1); + assertThat(store.get(segment, key).orElse(null)).isEqualTo(val1); assertThat(duplicateSegmentRef.get(key).orElse(null)).isEqualTo(val1); // clear and assert empty: - store.clear(segment.get()); - assertThat(store.get(segment.get(), key)).isEmpty(); + store.clear(segment); + assertThat(store.get(segment, key)).isEmpty(); assertThat(duplicateSegmentRef.get(key)).isEmpty(); // insert into empty: insert.accept(val2); - assertThat(store.get(segment.get(), key).orElse(null)).isEqualTo(val2); + assertThat(store.get(segment, key).orElse(null)).isEqualTo(val2); assertThat(duplicateSegmentRef.get(key).orElse(null)).isEqualTo(val2); store.close(); @@ -80,18 +79,17 @@ public void assertClear() throws Exception { @Test public void twoSegmentsAreIndependent() throws Exception { - final SegmentedKeyValueStorage store = createSegmentedStore(); + final SegmentedKeyValueStorage store = createSegmentedStore(); - final Transaction tx = store.startTransaction(); + final Transaction tx = store.startTransaction(); tx.put( - store.getSegmentIdentifierByName(TestSegment.BAR).get(), + store.getSegmentIdentifierByName(TestSegment.BAR), bytesFromHexString("0001"), bytesFromHexString("0FFF")); tx.commit(); final Optional result = - store.get( - store.getSegmentIdentifierByName(TestSegment.FOO).get(), bytesFromHexString("0001")); + store.get(store.getSegmentIdentifierByName(TestSegment.FOO), bytesFromHexString("0001")); assertThat(result).isEmpty(); @@ -103,11 +101,11 @@ public void canRemoveThroughSegmentIteration() throws Exception { // we're looping this in order to catch intermittent failures when rocksdb objects are not close // properly for (int i = 0; i < 50; i++) { - final SegmentedKeyValueStorage store = createSegmentedStore(); - final ColumnFamilyHandle fooSegment = store.getSegmentIdentifierByName(TestSegment.FOO).get(); - final ColumnFamilyHandle barSegment = store.getSegmentIdentifierByName(TestSegment.BAR).get(); + final SegmentedKeyValueStorage store = createSegmentedStore(); + final RocksDbSegmentIdentifier fooSegment = store.getSegmentIdentifierByName(TestSegment.FOO); + final RocksDbSegmentIdentifier barSegment = store.getSegmentIdentifierByName(TestSegment.BAR); - final Transaction tx = store.startTransaction(); + final Transaction tx = store.startTransaction(); tx.put(fooSegment, bytesOf(1), bytesOf(1)); tx.put(fooSegment, bytesOf(2), bytesOf(2)); tx.put(fooSegment, bytesOf(3), bytesOf(3)); @@ -129,7 +127,7 @@ public void canRemoveThroughSegmentIteration() throws Exception { if (!Arrays.equals(key, bytesOf(4))) store.tryDelete(barSegment, key); }); - for (final ColumnFamilyHandle segment : Set.of(fooSegment, barSegment)) { + for (final RocksDbSegmentIdentifier segment : Set.of(fooSegment, barSegment)) { assertThat(store.streamKeys(segment).count()).isEqualTo(1); } @@ -147,11 +145,11 @@ public void canRemoveThroughSegmentIteration() throws Exception { @Test public void canGetThroughSegmentIteration() throws Exception { - final SegmentedKeyValueStorage store = createSegmentedStore(); - final ColumnFamilyHandle fooSegment = store.getSegmentIdentifierByName(TestSegment.FOO).get(); - final ColumnFamilyHandle barSegment = store.getSegmentIdentifierByName(TestSegment.BAR).get(); + final SegmentedKeyValueStorage store = createSegmentedStore(); + final RocksDbSegmentIdentifier fooSegment = store.getSegmentIdentifierByName(TestSegment.FOO); + final RocksDbSegmentIdentifier barSegment = store.getSegmentIdentifierByName(TestSegment.BAR); - final Transaction tx = store.startTransaction(); + final Transaction tx = store.startTransaction(); tx.put(fooSegment, bytesOf(1), bytesOf(1)); tx.put(fooSegment, bytesOf(2), bytesOf(2)); tx.put(fooSegment, bytesOf(3), bytesOf(3)); @@ -201,7 +199,8 @@ public byte[] getId() { } } - private SegmentedKeyValueStorage createSegmentedStore() throws Exception { + private SegmentedKeyValueStorage createSegmentedStore() + throws Exception { return new RocksDBColumnarKeyValueStorage( new RocksDBConfigurationBuilder().databaseDir(folder.newFolder().toPath()).build(), Arrays.asList(TestSegment.FOO, TestSegment.BAR), diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java index a09b1a8989e..38af4b6bf03 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorage.java @@ -20,18 +20,17 @@ import java.io.Closeable; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; import java.util.stream.Stream; /** - * Service provided by besu to facilitate persistent data storage. + * Service provided by Besu to facilitate persistent data storage. * * @param the segment identifier type */ public interface SegmentedKeyValueStorage extends Closeable { - AtomicReference getSegmentIdentifierByName(SegmentIdentifier segment); + S getSegmentIdentifierByName(SegmentIdentifier segment); /** * Get the value from the associated segment and key. diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java index 1fc65627808..236659c3d92 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java @@ -22,12 +22,11 @@ import java.io.IOException; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; import java.util.stream.Stream; public class SegmentedKeyValueStorageAdapter implements KeyValueStorage { - private final AtomicReference segmentHandle; + private final S segmentHandle; private final SegmentedKeyValueStorage storage; public SegmentedKeyValueStorageAdapter( @@ -38,32 +37,32 @@ public SegmentedKeyValueStorageAdapter( @Override public void clear() { - storage.clear(segmentHandle.get()); + storage.clear(segmentHandle); } @Override public boolean containsKey(final byte[] key) throws StorageException { - return storage.containsKey(segmentHandle.get(), key); + return storage.containsKey(segmentHandle, key); } @Override public Optional get(final byte[] key) throws StorageException { - return storage.get(segmentHandle.get(), key); + return storage.get(segmentHandle, key); } @Override public Set getAllKeysThat(final Predicate returnCondition) { - return storage.getAllKeysThat(segmentHandle.get(), returnCondition); + return storage.getAllKeysThat(segmentHandle, returnCondition); } @Override public Stream streamKeys() { - return storage.streamKeys(segmentHandle.get()); + return storage.streamKeys(segmentHandle); } @Override public boolean tryDelete(final byte[] key) { - return storage.tryDelete(segmentHandle.get(), key); + return storage.tryDelete(segmentHandle, key); } @Override @@ -78,12 +77,12 @@ public KeyValueStorageTransaction startTransaction() throws StorageException { @Override public void put(final byte[] key, final byte[] value) { - transaction.put(segmentHandle.get(), key, value); + transaction.put(segmentHandle, key, value); } @Override public void remove(final byte[] key) { - transaction.remove(segmentHandle.get(), key); + transaction.remove(segmentHandle, key); } @Override