Skip to content

Commit 51bb6c7

Browse files
siladumacfarla
andauthored
TrieLogPruner preload with 30 second timeout (#7365)
Also reduce pruning window from 30_000 to 5_000 --------- Signed-off-by: Simon Dudley <[email protected]> Co-authored-by: Sally MacFarlane <[email protected]>
1 parent a1efd21 commit 51bb6c7

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
- Add trie log pruner metrics [#7352](https://github.com/hyperledger/besu/pull/7352)
2727
- Force bonsai-limit-trie-logs-enabled=false when sync-mode=FULL instead of startup error [#7357](https://github.com/hyperledger/besu/pull/7357)
2828
- `--Xbonsai-parallel-tx-processing-enabled` option enables executing transactions in parallel during block processing for Bonsai nodes
29+
- Reduce default trie log pruning window size from 30,000 to 5,000 [#7365](https://github.com/hyperledger/besu/pull/7365)
2930
- Add option `--poa-discovery-retry-bootnodes` for PoA networks to always use bootnodes during peer refresh, not just on first start [#7314](https://github.com/hyperledger/besu/pull/7314)
3031

3132
### Bug fixes
3233
- Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323)
3334
- Prevent Besu from starting up with sync-mode=FULL and bonsai-limit-trie-logs-enabled=true for private networks [#7357](https://github.com/hyperledger/besu/pull/7357)
35+
- Add 30 second timeout to trie log pruner preload [#7365](https://github.com/hyperledger/besu/pull/7365)
3436
- Avoid executing pruner preload during trie log subcommands [#7366](https://github.com/hyperledger/besu/pull/7366)
3537

3638
## 24.7.0

Diff for: ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogPruner.java

+61-10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626

2727
import java.util.Comparator;
2828
import java.util.Optional;
29+
import java.util.concurrent.Executors;
30+
import java.util.concurrent.ScheduledExecutorService;
31+
import java.util.concurrent.ScheduledFuture;
32+
import java.util.concurrent.TimeUnit;
33+
import java.util.concurrent.TimeoutException;
34+
import java.util.concurrent.atomic.AtomicBoolean;
2935
import java.util.concurrent.atomic.AtomicLong;
3036
import java.util.function.Consumer;
3137
import java.util.stream.Stream;
@@ -40,6 +46,7 @@
4046
public class TrieLogPruner implements TrieLogEvent.TrieLogObserver {
4147

4248
private static final Logger LOG = LoggerFactory.getLogger(TrieLogPruner.class);
49+
private static final int PRELOAD_TIMEOUT_IN_SECONDS = 30;
4350

4451
private final int pruningLimit;
4552
private final int loadingLimit;
@@ -83,38 +90,82 @@ public TrieLogPruner(
8390
BesuMetricCategory.PRUNER, "trie_log_pruned_orphan", "trie log pruned orphan");
8491
}
8592

86-
public int initialize() {
87-
return preloadQueue();
93+
public void initialize() {
94+
preloadQueueWithTimeout();
8895
}
8996

90-
private int preloadQueue() {
97+
private void preloadQueueWithTimeout() {
98+
9199
LOG.atInfo()
92-
.setMessage("Loading first {} trie logs from database...")
100+
.setMessage("Attempting to load first {} trie logs from database...")
93101
.addArgument(loadingLimit)
94102
.log();
103+
104+
try (final ScheduledExecutorService preloadExecutor = Executors.newScheduledThreadPool(1)) {
105+
106+
final AtomicBoolean timeoutOccurred = new AtomicBoolean(false);
107+
final Runnable timeoutTask =
108+
() -> {
109+
timeoutOccurred.set(true);
110+
LOG.atWarn()
111+
.setMessage(
112+
"Timeout occurred while loading and processing {} trie logs from database")
113+
.addArgument(loadingLimit)
114+
.log();
115+
};
116+
117+
final ScheduledFuture<?> timeoutFuture =
118+
preloadExecutor.schedule(timeoutTask, PRELOAD_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
119+
LOG.atInfo()
120+
.setMessage(
121+
"Trie log pruning will timeout after {} seconds. If this is timing out, consider using `besu storage trie-log prune` subcommand, see https://besu.hyperledger.org/public-networks/how-to/bonsai-limit-trie-logs")
122+
.addArgument(PRELOAD_TIMEOUT_IN_SECONDS)
123+
.log();
124+
125+
preloadQueue(timeoutOccurred, timeoutFuture);
126+
}
127+
}
128+
129+
private void preloadQueue(
130+
final AtomicBoolean timeoutOccurred, final ScheduledFuture<?> timeoutFuture) {
131+
95132
try (final Stream<byte[]> trieLogKeys = rootWorldStateStorage.streamTrieLogKeys(loadingLimit)) {
96-
final AtomicLong count = new AtomicLong();
133+
134+
final AtomicLong addToPruneQueueCount = new AtomicLong();
97135
final AtomicLong orphansPruned = new AtomicLong();
98136
trieLogKeys.forEach(
99137
blockHashAsBytes -> {
138+
if (timeoutOccurred.get()) {
139+
throw new RuntimeException(
140+
new TimeoutException("Timeout occurred while preloading trie log prune queue"));
141+
}
100142
final Hash blockHash = Hash.wrap(Bytes32.wrap(blockHashAsBytes));
101143
final Optional<BlockHeader> header = blockchain.getBlockHeader(blockHash);
102144
if (header.isPresent()) {
103145
addToPruneQueue(header.get().getNumber(), blockHash);
104-
count.getAndIncrement();
146+
addToPruneQueueCount.getAndIncrement();
105147
} else {
106148
// prune orphaned blocks (sometimes created during block production)
107149
rootWorldStateStorage.pruneTrieLog(blockHash);
108150
orphansPruned.getAndIncrement();
109151
prunedOrphanCounter.inc();
110152
}
111153
});
154+
155+
timeoutFuture.cancel(true);
112156
LOG.atDebug().log("Pruned {} orphaned trie logs from database...", orphansPruned.intValue());
113-
LOG.atInfo().log("Loaded {} trie logs from database", count);
114-
return pruneFromQueue() + orphansPruned.intValue();
157+
LOG.atInfo().log(
158+
"Added {} trie logs to prune queue. Commencing pruning of eligible trie logs...",
159+
addToPruneQueueCount.intValue());
160+
int prunedCount = pruneFromQueue();
161+
LOG.atInfo().log("Pruned {} trie logs.", prunedCount);
115162
} catch (Exception e) {
116-
LOG.error("Error loading trie logs from database, nothing pruned", e);
117-
return 0;
163+
if (e.getCause() != null && e.getCause() instanceof TimeoutException) {
164+
int prunedCount = pruneFromQueue();
165+
LOG.atInfo().log("Operation timed out, but still pruned {} trie logs.", prunedCount);
166+
} else {
167+
LOG.error("Error loading trie logs from database, nothing pruned", e);
168+
}
118169
}
119170
}
120171

Diff for: ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public interface DataStorageConfiguration {
2525
long DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD = 512;
2626
boolean DEFAULT_BONSAI_LIMIT_TRIE_LOGS_ENABLED = true;
2727
long MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT = DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
28-
int DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE = 30_000;
28+
int DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE = 5_000;
2929
boolean DEFAULT_RECEIPT_COMPACTION_ENABLED = false;
3030

3131
DataStorageConfiguration DEFAULT_CONFIG =

0 commit comments

Comments
 (0)