diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 98ed348d8c..591f3c4839 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -775,17 +775,45 @@ func pruneHistory(ctx *cli.Context) error { log.Info("Starting history pruning", "head", currentHeader.Number, "target", targetBlock, "targetHash", targetBlockHash.Hex()) start := time.Now() - rawdb.PruneTransactionIndex(chaindb, targetBlock) + sizeBefore := prunableFreezerSize(chaindb) + txIndexBytes := rawdb.PruneTransactionIndex(chaindb, targetBlock) if _, err := chaindb.TruncateTail(targetBlock); err != nil { return fmt.Errorf("failed to truncate ancient data: %v", err) } - log.Info("History pruning completed", "tail", targetBlock, "elapsed", common.PrettyDuration(time.Since(start))) + sizeAfter := prunableFreezerSize(chaindb) + var cleared common.StorageSize + if sizeBefore > sizeAfter { + cleared = common.StorageSize(sizeBefore - sizeAfter) + } + // Include the tx index entries pruned from the KV store; without this the + // reported figure only covers the body/receipt freezer delta and ignores + // the index work above. + cleared += common.StorageSize(txIndexBytes) + log.Info("History pruning completed", "tail", targetBlock, "elapsed", common.PrettyDuration(time.Since(start)), "cleared", cleared) // TODO(s1na): what if there is a crash between the two prune operations? return nil } +// prunableFreezerSize returns the total on-disk size of the chain freezer +// tables that prune-history truncates (bodies and receipts). The header and +// hash tables are retained long-term and are not measured here. +func prunableFreezerSize(db ethdb.Database) uint64 { + var total uint64 + for _, table := range []string{rawdb.ChainFreezerBodiesTable, rawdb.ChainFreezerReceiptTable} { + size, err := db.AncientSize(table) + if err != nil { + // If we can't read the size of any prunable table, the delta would + // be misleading. Return 0 so the caller logs "cleared=0.00 B" rather + // than a partial figure. + return 0 + } + total += size + } + return total +} + // downloadEra is the era1 file downloader tool. func downloadEra(ctx *cli.Context) error { flags.CheckExclusive(ctx, eraBlockFlag, eraEpochFlag, eraAllFlag) diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index afa1aa7a4c..8965e4fc20 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -377,8 +377,11 @@ func unindexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, in unindexTransactions(db, from, to, interrupt, hook, false) } -// PruneTransactionIndex removes all tx index entries below a certain block number. -func PruneTransactionIndex(db ethdb.Database, pruneBlock uint64) { +// PruneTransactionIndex removes all tx index entries below a certain block number +// and returns the approximate number of bytes freed (sum of key + value lengths +// for each deleted entry). The figure is logical (uncompacted) but is the only +// per-prefix size signal the KV store exposes without forcing a full compaction. +func PruneTransactionIndex(db ethdb.Database, pruneBlock uint64) (removedBytes uint64) { tail := ReadTxIndexTail(db) if tail == nil || *tail > pruneBlock { return // no index, or index ends above pruneBlock @@ -386,6 +389,7 @@ func PruneTransactionIndex(db ethdb.Database, pruneBlock uint64) { // There are blocks below pruneBlock in the index. Iterate the entire index to remove // their entries. Note if this fails, the index is messed up, but tail still points to // the old tail. + keyLen := uint64(len(txLookupPrefix) + common.HashLength) var count, removed int DeleteAllTxLookupEntries(db, func(txhash common.Hash, v []byte) bool { count++ @@ -399,11 +403,13 @@ func PruneTransactionIndex(db ethdb.Database, pruneBlock uint64) { bn := decodeNumber(v) if bn < pruneBlock { removed++ + removedBytes += keyLen + uint64(len(v)) return true } return false }) WriteTxIndexTail(db, pruneBlock) + return } func decodeNumber(b []byte) uint64 {