@ -16,6 +16,9 @@ package org.hyperledger.besu.cli.subcommands.storage;
import static com.google.common.base.Preconditions.checkArgument ;
import static com.google.common.base.Preconditions.checkNotNull ;
import static org.hyperledger.besu.cli.subcommands.storage.RocksDbHelper.formatOutputSize ;
import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH ;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_LOG_STORAGE ;
import org.hyperledger.besu.cli.util.VersionProvider ;
import org.hyperledger.besu.controller.BesuController ;
@ -31,10 +34,14 @@ import java.io.IOException;
import java.io.PrintWriter ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import java.util.Arrays ;
import java.util.List ;
import java.util.concurrent.atomic.AtomicLong ;
import org.apache.logging.log4j.Level ;
import org.apache.logging.log4j.core.config.Configurator ;
import org.rocksdb.RocksDBException ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import picocli.CommandLine ;
import picocli.CommandLine.Command ;
@ -54,6 +61,8 @@ import picocli.CommandLine.ParentCommand;
} )
public class TrieLogSubCommand implements Runnable {
private static final Logger LOG = LoggerFactory . getLogger ( TrieLogSubCommand . class ) ;
@SuppressWarnings ( "UnusedVariable" )
@ParentCommand
private static StorageSubCommand parentCommand ;
@ -124,12 +133,67 @@ public class TrieLogSubCommand implements Runnable {
final Path dataDirectoryPath =
Paths . get (
TrieLogSubCommand . parentCommand . parentCommand . dataDir ( ) . toAbsolutePath ( ) . toString ( ) ) ;
LOG . info ( "Estimating trie logs size before pruning..." ) ;
long sizeBefore = estimatedSizeOfTrieLogs ( ) ;
LOG . info ( "Estimated trie logs size before pruning: {}" , formatOutputSize ( sizeBefore ) ) ;
final TrieLogHelper trieLogHelper = new TrieLogHelper ( ) ;
boolean success =
trieLogHelper . prune (
context . config ( ) ,
context . rootWorldStateStorage ( ) ,
context . blockchain ( ) ,
dataDirectoryPath ) ;
if ( success ) {
LOG . info ( "Finished pruning. Re-estimating trie logs size..." ) ;
final long sizeAfter = estimatedSizeOfTrieLogs ( ) ;
LOG . info (
"Estimated trie logs size after pruning: {} (0 B estimate is normal when using default settings)" ,
formatOutputSize ( sizeAfter ) ) ;
long estimatedSaving = sizeBefore - sizeAfter ;
LOG . info (
"Prune ran successfully. We estimate you freed up {}! \uD83D\uDE80" ,
formatOutputSize ( estimatedSaving ) ) ;
spec . commandLine ( )
. getOut ( )
. printf (
"Prune ran successfully. We estimate you freed up %s! \uD83D\uDE80\n" ,
formatOutputSize ( estimatedSaving ) ) ;
}
}
private long estimatedSizeOfTrieLogs ( ) {
final String dbPath =
TrieLogSubCommand . parentCommand
. parentCommand
. dataDir ( )
. toString ( )
. concat ( "/" )
. concat ( DATABASE_PATH ) ;
AtomicLong estimatedSaving = new AtomicLong ( 0L ) ;
try {
RocksDbHelper . forEachColumnFamily (
dbPath ,
( rocksdb , cfHandle ) - > {
try {
if ( Arrays . equals ( cfHandle . getName ( ) , TRIE_LOG_STORAGE . getId ( ) ) ) {
estimatedSaving . set (
Long . parseLong (
rocksdb . getProperty ( cfHandle , "rocksdb.estimate-live-data-size" ) ) ) ;
}
} catch ( RocksDBException | NumberFormatException e ) {
throw new RuntimeException ( e ) ;
}
} ) ;
} catch ( Exception e ) {
LOG . warn ( "Error while estimating trie log size, returning 0 for estimate" , e ) ;
return 0L ;
}
return estimatedSaving . get ( ) ;
}
}