SegmentedKeyValueStorage.java
/*
* 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;
import org.hyperledger.besu.plugin.services.exception.StorageException;
import java.io.Closeable;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.tuweni.bytes.Bytes;
/** Service provided by Besu to facilitate persistent data storage. */
public interface SegmentedKeyValueStorage extends Closeable {
/**
* Get the value from the associated segment and key.
*
* @param segment the segment
* @param key Index into persistent data repository.
* @return The value persisted at the key index.
* @throws StorageException the storage exception
*/
Optional<byte[]> get(SegmentIdentifier segment, byte[] key) throws StorageException;
/**
* Find the key and corresponding value "nearest to" the specified key. Nearest is defined as
* either matching the supplied key or the key lexicographically prior to it.
*
* @param segmentIdentifier segment to scan
* @param key key for which we are searching for the nearest match.
* @return Optional of NearestKeyValue-wrapped matched key and corresponding value.
* @throws StorageException the storage exception
*/
Optional<NearestKeyValue> getNearestTo(final SegmentIdentifier segmentIdentifier, Bytes key)
throws StorageException;
/**
* Contains key.
*
* @param segment the segment
* @param key the key
* @return the boolean
* @throws StorageException the storage exception
*/
default boolean containsKey(final SegmentIdentifier segment, final byte[] key)
throws StorageException {
return get(segment, key).isPresent();
}
/**
* Begins a transaction. Returns a transaction object that can be updated and committed.
*
* @return An object representing the transaction.
* @throws StorageException the storage exception
*/
SegmentedKeyValueStorageTransaction startTransaction() throws StorageException;
/**
* Returns a stream of all keys for the segment.
*
* @param segmentIdentifier The segment identifier whose keys we want to stream.
* @return A stream of all keys in the specified segment.
*/
Stream<Pair<byte[], byte[]>> stream(final SegmentIdentifier segmentIdentifier);
/**
* Returns a stream of key-value pairs starting from the specified key. This method is used to
* retrieve a stream of data from the storage, starting from the given key. If no data is
* available from the specified key onwards, an empty stream is returned.
*
* @param segmentIdentifier The segment identifier whose keys we want to stream.
* @param startKey The key from which the stream should start.
* @return A stream of key-value pairs starting from the specified key.
*/
Stream<Pair<byte[], byte[]>> streamFromKey(
final SegmentIdentifier segmentIdentifier, final byte[] startKey);
/**
* Returns a stream of key-value pairs starting from the specified key, ending at the specified
* key. This method is used to retrieve a stream of data from the storage, starting from the given
* key. If no data is available from the specified key onwards, an empty stream is returned.
*
* @param segmentIdentifier The segment identifier whose keys we want to stream.
* @param startKey The key from which the stream should start.
* @param endKey The key at which the stream should stop.
* @return A stream of key-value pairs starting from the specified key.
*/
Stream<Pair<byte[], byte[]>> streamFromKey(
final SegmentIdentifier segmentIdentifier, final byte[] startKey, final byte[] endKey);
/**
* Stream keys.
*
* @param segmentIdentifier the segment identifier
* @return the stream
*/
Stream<byte[]> streamKeys(final SegmentIdentifier segmentIdentifier);
/**
* Delete the value corresponding to the given key in the given segment if a write lock can be
* instantly acquired on the underlying storage. Do nothing otherwise.
*
* @param segmentIdentifier The segment identifier whose keys we want to stream.
* @param key The key to delete.
* @return false if the lock on the underlying storage could not be instantly acquired, true
* otherwise
* @throws StorageException any problem encountered during the deletion attempt.
*/
boolean tryDelete(SegmentIdentifier segmentIdentifier, byte[] key) throws StorageException;
/**
* Gets all keys that matches condition.
*
* @param segmentIdentifier the segment identifier
* @param returnCondition the return condition
* @return set of result
*/
Set<byte[]> getAllKeysThat(
SegmentIdentifier segmentIdentifier, Predicate<byte[]> returnCondition);
/**
* Gets all values from keys that matches condition.
*
* @param segmentIdentifier the segment identifier
* @param returnCondition the return condition
* @return the set of result
*/
Set<byte[]> getAllValuesFromKeysThat(
final SegmentIdentifier segmentIdentifier, Predicate<byte[]> returnCondition);
/**
* Clear.
*
* @param segmentIdentifier the segment identifier
*/
void clear(SegmentIdentifier segmentIdentifier);
/**
* Whether the underlying storage is closed.
*
* @return boolean indicating whether the underlying storage is closed.
*/
boolean isClosed();
/**
* record type used to wrap responses from getNearestTo, includes the matched key and the value.
*
* @param key the matched (nearest) key
* @param value the corresponding value
*/
record NearestKeyValue(Bytes key, Optional<byte[]> value) {
/**
* Convenience method to map the Optional value to Bytes.
*
* @return Optional of Bytes.
*/
public Optional<Bytes> wrapBytes() {
return value.map(Bytes::wrap);
}
}
}