Skip to content

Commit

Permalink
Add FlatDbStrategy (hyperledger#5901)
Browse files Browse the repository at this point in the history
* move FlatDbReader to FlatDbStrategy (including writes), add getNearestTo

Signed-off-by: garyschulte <[email protected]>
  • Loading branch information
garyschulte authored Sep 22, 2023
1 parent 9d7ee2b commit d81e1f3
Show file tree
Hide file tree
Showing 19 changed files with 389 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public BonsaiSnapshotWorldStateKeyValueStorage(
final ObservableMetricsSystem metricsSystem) {
super(
parentWorldStateStorage.flatDbMode,
parentWorldStateStorage.flatDbReaderStrategy,
parentWorldStateStorage.flatDbStrategy,
segmentedWorldStateStorage,
trieLogStorage,
metricsSystem);
Expand Down Expand Up @@ -77,7 +77,8 @@ private boolean isClosedGet() {
public BonsaiUpdater updater() {
return new Updater(
((SnappedKeyValueStorage) composedWorldStateStorage).getSnapshotTransaction(),
trieLogStorage.startTransaction());
trieLogStorage.startTransaction(),
flatDbStrategy);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@

import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.bonsai.storage.flat.FlatDbReaderStrategy;
import org.hyperledger.besu.ethereum.bonsai.storage.flat.FullFlatDbReaderStrategy;
import org.hyperledger.besu.ethereum.bonsai.storage.flat.PartialFlatDbReaderStrategy;
import org.hyperledger.besu.ethereum.bonsai.storage.flat.FlatDbStrategy;
import org.hyperledger.besu.ethereum.bonsai.storage.flat.FullFlatDbStrategy;
import org.hyperledger.besu.ethereum.bonsai.storage.flat.PartialFlatDbStrategy;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.MerkleTrie;
Expand Down Expand Up @@ -67,7 +67,7 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC
public static final byte[] FLAT_DB_MODE = "flatDbStatus".getBytes(StandardCharsets.UTF_8);

protected FlatDbMode flatDbMode;
protected FlatDbReaderStrategy flatDbReaderStrategy;
protected FlatDbStrategy flatDbStrategy;

protected final SegmentedKeyValueStorage composedWorldStateStorage;
protected final KeyValueStorage trieLogStorage;
Expand All @@ -94,33 +94,49 @@ public BonsaiWorldStateKeyValueStorage(

public BonsaiWorldStateKeyValueStorage(
final FlatDbMode flatDbMode,
final FlatDbReaderStrategy flatDbReaderStrategy,
final FlatDbStrategy flatDbStrategy,
final SegmentedKeyValueStorage composedWorldStateStorage,
final KeyValueStorage trieLogStorage,
final ObservableMetricsSystem metricsSystem) {
this.flatDbMode = flatDbMode;
this.flatDbReaderStrategy = flatDbReaderStrategy;
this.flatDbStrategy = flatDbStrategy;
this.composedWorldStateStorage = composedWorldStateStorage;
this.trieLogStorage = trieLogStorage;
this.metricsSystem = metricsSystem;
}

public void loadFlatDbStrategy() {
this.flatDbMode =
private void loadFlatDbStrategy() {
// derive our flatdb strategy from db or default:
var newFlatDbMode = deriveFlatDbStrategy();

// if flatDbMode is not loaded or has changed, reload flatDbStrategy
if (this.flatDbMode == null || !this.flatDbMode.equals(newFlatDbMode)) {
this.flatDbMode = newFlatDbMode;
if (flatDbMode == FlatDbMode.FULL) {
this.flatDbStrategy = new FullFlatDbStrategy(metricsSystem);
} else {
this.flatDbStrategy = new PartialFlatDbStrategy(metricsSystem);
}
}
}

public FlatDbMode deriveFlatDbStrategy() {
var flatDbMode =
FlatDbMode.fromVersion(
composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, FLAT_DB_MODE)
.map(Bytes::wrap)
.orElse(
FlatDbMode.PARTIAL
.getVersion())); // for backward compatibility we use partial as
// default
.orElse(FlatDbMode.PARTIAL.getVersion()));
LOG.info("Bonsai flat db mode found {}", flatDbMode);
if (flatDbMode == FlatDbMode.FULL) {
this.flatDbReaderStrategy = new FullFlatDbReaderStrategy(metricsSystem);
} else {
this.flatDbReaderStrategy = new PartialFlatDbReaderStrategy(metricsSystem);

return flatDbMode;
}

public FlatDbStrategy getFlatDbStrategy() {
if (flatDbStrategy == null) {
loadFlatDbStrategy();
}
return flatDbStrategy;
}

@Override
Expand All @@ -133,22 +149,18 @@ public FlatDbMode getFlatDbMode() {
return flatDbMode;
}

public FlatDbReaderStrategy getFlatDbReaderStrategy() {
return flatDbReaderStrategy;
}

@Override
public Optional<Bytes> getCode(final Bytes32 codeHash, final Hash accountHash) {
if (codeHash.equals(Hash.EMPTY)) {
return Optional.of(Bytes.EMPTY);
} else {
return getFlatDbReaderStrategy().getCode(codeHash, accountHash, composedWorldStateStorage);
return getFlatDbStrategy().getFlatCode(codeHash, accountHash, composedWorldStateStorage);
}
}

public Optional<Bytes> getAccount(final Hash accountHash) {
return getFlatDbReaderStrategy()
.getAccount(
return getFlatDbStrategy()
.getFlatAccount(
this::getWorldStateRootHash,
this::getAccountStateTrieNode,
accountHash,
Expand Down Expand Up @@ -226,8 +238,8 @@ public Optional<Bytes> getStorageValueByStorageSlotKey(
final Supplier<Optional<Hash>> storageRootSupplier,
final Hash accountHash,
final StorageSlotKey storageSlotKey) {
return getFlatDbReaderStrategy()
.getStorageValueByStorageSlotKey(
return getFlatDbStrategy()
.getFlatStorageValueByStorageSlotKey(
this::getWorldStateRootHash,
storageRootSupplier,
(location, hash) -> getAccountStorageTrieNode(accountHash, location, hash),
Expand All @@ -239,14 +251,14 @@ public Optional<Bytes> getStorageValueByStorageSlotKey(
@Override
public Map<Bytes32, Bytes> streamFlatAccounts(
final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return getFlatDbReaderStrategy()
return getFlatDbStrategy()
.streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max);
}

@Override
public Map<Bytes32, Bytes> streamFlatStorages(
final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return getFlatDbReaderStrategy()
return getFlatDbStrategy()
.streamStorageFlatDatabase(
composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max);
}
Expand All @@ -273,6 +285,7 @@ public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHas
public void upgradeToFullFlatDbMode() {
final SegmentedKeyValueStorageTransaction transaction =
composedWorldStateStorage.startTransaction();
// TODO: consider ARCHIVE mode
transaction.put(
TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.FULL.getVersion().toArrayUnsafe());
transaction.commit();
Expand All @@ -291,7 +304,7 @@ public void downgradeToPartialFlatDbMode() {
@Override
public void clear() {
subscribers.forEach(BonsaiStorageSubscriber::onClearStorage);
getFlatDbReaderStrategy().clearAll(composedWorldStateStorage);
getFlatDbStrategy().clearAll(composedWorldStateStorage);
composedWorldStateStorage.clear(TRIE_BRANCH_STORAGE);
trieLogStorage.clear();
loadFlatDbStrategy(); // force reload of flat db reader strategy
Expand All @@ -306,13 +319,15 @@ public void clearTrieLog() {
@Override
public void clearFlatDatabase() {
subscribers.forEach(BonsaiStorageSubscriber::onClearFlatDatabaseStorage);
getFlatDbReaderStrategy().resetOnResync(composedWorldStateStorage);
getFlatDbStrategy().resetOnResync(composedWorldStateStorage);
}

@Override
public BonsaiUpdater updater() {
return new Updater(
composedWorldStateStorage.startTransaction(), trieLogStorage.startTransaction());
composedWorldStateStorage.startTransaction(),
trieLogStorage.startTransaction(),
flatDbStrategy);
}

@Override
Expand Down Expand Up @@ -351,18 +366,21 @@ public static class Updater implements BonsaiUpdater {

private final SegmentedKeyValueStorageTransaction composedWorldStateTransaction;
private final KeyValueStorageTransaction trieLogStorageTransaction;
private final FlatDbStrategy flatDbStrategy;

public Updater(
final SegmentedKeyValueStorageTransaction composedWorldStateTransaction,
final KeyValueStorageTransaction trieLogStorageTransaction) {
final KeyValueStorageTransaction trieLogStorageTransaction,
final FlatDbStrategy flatDbStrategy) {

this.composedWorldStateTransaction = composedWorldStateTransaction;
this.trieLogStorageTransaction = trieLogStorageTransaction;
this.flatDbStrategy = flatDbStrategy;
}

@Override
public BonsaiUpdater removeCode(final Hash accountHash) {
composedWorldStateTransaction.remove(CODE_STORAGE, accountHash.toArrayUnsafe());
flatDbStrategy.removeFlatCode(composedWorldStateTransaction, accountHash);
return this;
}

Expand All @@ -372,14 +390,13 @@ public BonsaiUpdater putCode(final Hash accountHash, final Bytes32 codeHash, fin
// Don't save empty values
return this;
}
composedWorldStateTransaction.put(
CODE_STORAGE, accountHash.toArrayUnsafe(), code.toArrayUnsafe());
flatDbStrategy.putFlatCode(composedWorldStateTransaction, accountHash, codeHash, code);
return this;
}

@Override
public BonsaiUpdater removeAccountInfoState(final Hash accountHash) {
composedWorldStateTransaction.remove(ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe());
flatDbStrategy.removeFlatAccount(composedWorldStateTransaction, accountHash);
return this;
}

Expand All @@ -389,8 +406,7 @@ public BonsaiUpdater putAccountInfoState(final Hash accountHash, final Bytes acc
// Don't save empty values
return this;
}
composedWorldStateTransaction.put(
ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe(), accountValue.toArrayUnsafe());
flatDbStrategy.putFlatAccount(composedWorldStateTransaction, accountHash, accountValue);
return this;
}

Expand Down Expand Up @@ -441,18 +457,16 @@ public synchronized BonsaiUpdater putAccountStorageTrieNode(
@Override
public synchronized BonsaiUpdater putStorageValueBySlotHash(
final Hash accountHash, final Hash slotHash, final Bytes storage) {
composedWorldStateTransaction.put(
ACCOUNT_STORAGE_STORAGE,
Bytes.concatenate(accountHash, slotHash).toArrayUnsafe(),
storage.toArrayUnsafe());
flatDbStrategy.putFlatAccountStorageValueByStorageSlotHash(
composedWorldStateTransaction, accountHash, slotHash, storage);
return this;
}

@Override
public synchronized void removeStorageValueBySlotHash(
final Hash accountHash, final Hash slotHash) {
composedWorldStateTransaction.remove(
ACCOUNT_STORAGE_STORAGE, Bytes.concatenate(accountHash, slotHash).toArrayUnsafe());
flatDbStrategy.removeFlatAccountStorageValueByStorageSlotHash(
composedWorldStateTransaction, accountHash, slotHash);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;

import java.util.Map;
import java.util.Optional;
Expand All @@ -40,11 +41,11 @@
import org.apache.tuweni.rlp.RLP;

/**
* This class represents a FlatDbReaderStrategy, which is responsible for reading data from flat
* databases. It implements various methods for retrieving account data, code data, and storage data
* from the corresponding KeyValueStorage.
* This class represents a FlatDbReaderStrategy, which is responsible for reading and writing data
* from flat databases. It implements various methods for storing and retrieving account data, code
* data, and storage data from the corresponding KeyValueStorage.
*/
public abstract class FlatDbReaderStrategy {
public abstract class FlatDbStrategy {

protected final MetricsSystem metricsSystem;
protected final Counter getAccountCounter;
Expand All @@ -53,7 +54,7 @@ public abstract class FlatDbReaderStrategy {
protected final Counter getStorageValueCounter;
protected final Counter getStorageValueFlatDatabaseCounter;

public FlatDbReaderStrategy(final MetricsSystem metricsSystem) {
public FlatDbStrategy(final MetricsSystem metricsSystem) {
this.metricsSystem = metricsSystem;

getAccountCounter =
Expand Down Expand Up @@ -84,7 +85,7 @@ public FlatDbReaderStrategy(final MetricsSystem metricsSystem) {
/*
* Retrieves the account data for the given account hash, using the world state root hash supplier and node loader.
*/
public abstract Optional<Bytes> getAccount(
public abstract Optional<Bytes> getFlatAccount(
Supplier<Optional<Bytes>> worldStateRootHashSupplier,
NodeLoader nodeLoader,
Hash accountHash,
Expand All @@ -94,7 +95,7 @@ public abstract Optional<Bytes> getAccount(
* Retrieves the storage value for the given account hash and storage slot key, using the world state root hash supplier, storage root supplier, and node loader.
*/

public abstract Optional<Bytes> getStorageValueByStorageSlotKey(
public abstract Optional<Bytes> getFlatStorageValueByStorageSlotKey(
Supplier<Optional<Bytes>> worldStateRootHashSupplier,
Supplier<Optional<Hash>> storageRootSupplier,
NodeLoader nodeLoader,
Expand All @@ -105,7 +106,7 @@ public abstract Optional<Bytes> getStorageValueByStorageSlotKey(
/*
* Retrieves the code data for the given code hash and account hash.
*/
public Optional<Bytes> getCode(
public Optional<Bytes> getFlatCode(
final Bytes32 codeHash, final Hash accountHash, final SegmentedKeyValueStorage storage) {
if (codeHash.equals(Hash.EMPTY)) {
return Optional.of(Bytes.EMPTY);
Expand All @@ -117,6 +118,65 @@ public Optional<Bytes> getCode(
}
}

/*
* Puts the account data for the given account hash, using the world state root hash supplier and node loader.
*/
public void putFlatAccount(
final SegmentedKeyValueStorageTransaction transaction,
final Hash accountHash,
final Bytes accountValue) {
transaction.put(ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe(), accountValue.toArrayUnsafe());
}

public void removeFlatAccount(
final SegmentedKeyValueStorageTransaction transaction, final Hash accountHash) {
transaction.remove(ACCOUNT_INFO_STATE, accountHash.toArrayUnsafe());
}

/*
* Puts the storage value for the given account hash and storage slot key, using the world state root hash supplier, storage root supplier, and node loader.
*/
public void putFlatAccountStorageValueByStorageSlotHash(
final SegmentedKeyValueStorageTransaction transaction,
final Hash accountHash,
final Hash slotHash,
final Bytes storage) {
transaction.put(
ACCOUNT_STORAGE_STORAGE,
Bytes.concatenate(accountHash, slotHash).toArrayUnsafe(),
storage.toArrayUnsafe());
}

/*
* Removes the storage value for the given account hash and storage slot key, using the world state root hash supplier, storage root supplier, and node loader.
*/
public void removeFlatAccountStorageValueByStorageSlotHash(
final SegmentedKeyValueStorageTransaction transaction,
final Hash accountHash,
final Hash slotHash) {
transaction.remove(
ACCOUNT_STORAGE_STORAGE, Bytes.concatenate(accountHash, slotHash).toArrayUnsafe());
}

/*
* Removes code for the given account hash.
*/
public void removeFlatCode(
final SegmentedKeyValueStorageTransaction transaction, final Hash accountHash) {
transaction.remove(CODE_STORAGE, accountHash.toArrayUnsafe());
}

/*
* Puts the code data for the given code hash and account hash.
*/
public void putFlatCode(
final SegmentedKeyValueStorageTransaction transaction,
final Hash accountHash,
final Bytes32 codeHash,
final Bytes code) {
transaction.put(CODE_STORAGE, accountHash.toArrayUnsafe(), code.toArrayUnsafe());
}

public void clearAll(final SegmentedKeyValueStorage storage) {
storage.clear(ACCOUNT_INFO_STATE);
storage.clear(ACCOUNT_STORAGE_STORAGE);
Expand Down
Loading

0 comments on commit d81e1f3

Please sign in to comment.