Skip to content

Commit

Permalink
core/rawdb, cmd, ethdb, eth: implement freezer tail deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
rjl493456442 authored and unkonwn-coder committed Nov 25, 2021
1 parent ad7c90c commit 91e6c0e
Show file tree
Hide file tree
Showing 17 changed files with 791 additions and 157 deletions.
4 changes: 2 additions & 2 deletions cmd/geth/dbcmd.go
Expand Up @@ -517,9 +517,9 @@ func freezerInspect(ctx *cli.Context) error {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
kind := ctx.Args().Get(0)
if noSnap, ok := rawdb.FreezerNoSnappy[kind]; !ok {
if noSnap, ok := rawdb.ChainFreezerNoSnappy[kind]; !ok {
var options []string
for opt := range rawdb.FreezerNoSnappy {
for opt := range rawdb.ChainFreezerNoSnappy {
options = append(options, opt)
}
sort.Strings(options)
Expand Down
18 changes: 9 additions & 9 deletions core/blockchain.go
Expand Up @@ -274,7 +274,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
rawdb.InitDatabaseFromFreezer(bc.db)
// If ancient database is not empty, reconstruct all missing
// indices in the background.
frozen, _ := bc.db.Ancients()
frozen, _ := bc.db.Ancients(rawdb.ChainFreezer)
if frozen > 0 {
txIndexBlock = frozen
}
Expand Down Expand Up @@ -313,7 +313,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
}

// Ensure that a previous crash in SetHead doesn't leave extra ancients
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
if frozen, err := bc.db.Ancients(rawdb.ChainFreezer); err == nil && frozen > 0 {
var (
needRewind bool
low uint64
Expand Down Expand Up @@ -506,7 +506,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
// Retrieve the last pivot block to short circuit rollbacks beyond it and the
// current freezer limit to start nuking id underflown
pivot := rawdb.ReadLastPivotNumber(bc.db)
frozen, _ := bc.db.Ancients()
frozen, _ := bc.db.Ancients(rawdb.ChainFreezer)

updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (uint64, bool) {
// Rewind the blockchain, ensuring we don't end up with a stateless head
Expand Down Expand Up @@ -590,11 +590,11 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
// Rewind the header chain, deleting all block bodies until then
delFn := func(db ethdb.KeyValueWriter, hash common.Hash, num uint64) {
// Ignore the error here since light client won't hit this path
frozen, _ := bc.db.Ancients()
frozen, _ := bc.db.Ancients(rawdb.ChainFreezer)
if num+1 <= frozen {
// Truncate all relative data(header, total difficulty, body, receipt
// and canonical hash) from ancient store.
if err := bc.db.TruncateAncients(num); err != nil {
if err := bc.db.TruncateHead(rawdb.ChainFreezer, num); err != nil {
log.Crit("Failed to truncate ancient data", "number", num, "err", err)
}
// Remove the hash <-> number mapping from the active store.
Expand Down Expand Up @@ -949,7 +949,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [

// Ensure genesis is in ancients.
if first.NumberU64() == 1 {
if frozen, _ := bc.db.Ancients(); frozen == 0 {
if frozen, _ := bc.db.Ancients(rawdb.ChainFreezer); frozen == 0 {
b := bc.genesisBlock
td := bc.genesisBlock.Difficulty()
writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{b}, []types.Receipts{nil}, td)
Expand Down Expand Up @@ -1004,14 +1004,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// The tx index data could not be written.
// Roll back the ancient store update.
fastBlock := bc.CurrentFastBlock().NumberU64()
if err := bc.db.TruncateAncients(fastBlock + 1); err != nil {
if err := bc.db.TruncateHead(rawdb.ChainFreezer, fastBlock+1); err != nil {
log.Error("Can't truncate ancient store after failed insert", "err", err)
}
return 0, err
}

// Sync the ancient store explicitly to ensure all data has been flushed to disk.
if err := bc.db.Sync(); err != nil {
if err := bc.db.Sync(rawdb.ChainFreezer); err != nil {
return 0, err
}

Expand All @@ -1020,7 +1020,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
if !updateHead(blockChain[len(blockChain)-1]) {
// We end up here if the header chain has reorg'ed, and the blocks/receipts
// don't match the canonical chain.
if err := bc.db.TruncateAncients(previousFastBlock + 1); err != nil {
if err := bc.db.TruncateHead(rawdb.ChainFreezer, previousFastBlock+1); err != nil {
log.Error("Can't truncate ancient store after failed insert", "err", err)
}
return 0, errSideChainReceipts
Expand Down
4 changes: 2 additions & 2 deletions core/blockchain_repair_test.go
Expand Up @@ -1818,7 +1818,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
// Force run a freeze cycle
type freezer interface {
Freeze(threshold uint64) error
Ancients() (uint64, error)
Ancients(typ string) (uint64, error)
}
db.(freezer).Freeze(tt.freezeThreshold)

Expand Down Expand Up @@ -1857,7 +1857,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
}
if frozen, err := db.(freezer).Ancients(); err != nil {
if frozen, err := db.(freezer).Ancients(rawdb.ChainFreezer); err != nil {
t.Errorf("Failed to retrieve ancient count: %v\n", err)
} else if int(frozen) != tt.expFrozen {
t.Errorf("Frozen block count mismatch: have %d, want %d", frozen, tt.expFrozen)
Expand Down
4 changes: 2 additions & 2 deletions core/blockchain_sethead_test.go
Expand Up @@ -2024,7 +2024,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
// Force run a freeze cycle
type freezer interface {
Freeze(threshold uint64) error
Ancients() (uint64, error)
Ancients(typ string) (uint64, error)
}
db.(freezer).Freeze(tt.freezeThreshold)

Expand All @@ -2050,7 +2050,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
}
if frozen, err := db.(freezer).Ancients(); err != nil {
if frozen, err := db.(freezer).Ancients(rawdb.ChainFreezer); err != nil {
t.Errorf("Failed to retrieve ancient count: %v\n", err)
} else if int(frozen) != tt.expFrozen {
t.Errorf("Frozen block count mismatch: have %d, want %d", frozen, tt.expFrozen)
Expand Down
6 changes: 3 additions & 3 deletions core/blockchain_test.go
Expand Up @@ -836,7 +836,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
ancient.SetHead(remove - 1)
assert(t, "ancient", ancient, 0, 0, 0)

if frozen, err := ancientDb.Ancients(); err != nil || frozen != 1 {
if frozen, err := ancientDb.Ancients(rawdb.ChainFreezer); err != nil || frozen != 1 {
t.Fatalf("failed to truncate ancient store, want %v, have %v", 1, frozen)
}
// Import the chain as a light node and ensure all pointers are updated
Expand Down Expand Up @@ -1723,7 +1723,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
if ancientChain.CurrentFastBlock().NumberU64() != 0 {
t.Fatalf("failed to rollback ancient data, want %d, have %d", 0, ancientChain.CurrentFastBlock().NumberU64())
}
if frozen, err := ancientChain.db.Ancients(); err != nil || frozen != 1 {
if frozen, err := ancientChain.db.Ancients(rawdb.ChainFreezer); err != nil || frozen != 1 {
t.Fatalf("failed to truncate ancient data, frozen index is %d", frozen)
}

Expand All @@ -1735,7 +1735,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
if ancientChain.CurrentFastBlock().NumberU64() != canonblocks[len(canonblocks)-1].NumberU64() {
t.Fatalf("failed to insert ancient recept chain after rollback")
}
if frozen, _ := ancientChain.db.Ancients(); frozen != uint64(len(canonblocks))+1 {
if frozen, _ := ancientChain.db.Ancients(rawdb.ChainFreezer); frozen != uint64(len(canonblocks))+1 {
t.Fatalf("wrong ancients count %d", frozen)
}
}
Expand Down
40 changes: 25 additions & 15 deletions core/rawdb/accessors_chain.go
Expand Up @@ -36,7 +36,7 @@ import (
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash {
var data []byte
db.ReadAncients(func(reader ethdb.AncientReader) error {
db.ReadAncients(ChainFreezer, func(reader ethdb.AncientReadOp) error {
data, _ = reader.Ancient(freezerHashTable, number)
if len(data) == 0 {
// Get it by hash from leveldb
Expand Down Expand Up @@ -83,8 +83,8 @@ type NumberHash struct {
Hash common.Hash
}

// ReadAllHashes retrieves all the hashes assigned to blocks at a certain heights,
// both canonical and reorged forks included.
// ReadAllHashesInRange retrieves all the hashes assigned to blocks at a certain
// heights, both canonical and reorged forks included.
// This method considers both limits to be _inclusive_.
func ReadAllHashesInRange(db ethdb.Iteratee, first, last uint64) []*NumberHash {
var (
Expand Down Expand Up @@ -300,7 +300,7 @@ func WriteFastTxLookupLimit(db ethdb.KeyValueWriter, number uint64) {
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte
db.ReadAncients(func(reader ethdb.AncientReader) error {
db.ReadAncients(ChainFreezer, func(reader ethdb.AncientReadOp) error {
// First try to look up the data in ancient database. Extra hash
// comparison is necessary since ancient database only maintains
// the canonical data.
Expand Down Expand Up @@ -377,25 +377,35 @@ func deleteHeaderWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
}
}

// isCanon is an internal utility method, to check whether the given number/hash
// isCanonOp is an internal utility method, to check whether the given number/hash
// is part of the ancient (canon) set.
func isCanon(reader ethdb.AncientReader, number uint64, hash common.Hash) bool {
func isCanonOp(reader ethdb.AncientReadOp, number uint64, hash common.Hash) bool {
h, err := reader.Ancient(freezerHashTable, number)
if err != nil {
return false
}
return bytes.Equal(h, hash[:])
}

// isCanonOp is an internal utility method, to check whether the given number/hash
// is part of the ancient (canon) set.
func isCanon(reader ethdb.AncientReader, number uint64, hash common.Hash) bool {
h, err := reader.Ancient(ChainFreezer, freezerHashTable, number)
if err != nil {
return false
}
return bytes.Equal(h, hash[:])
}

// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
// First try to look up the data in ancient database. Extra hash
// comparison is necessary since ancient database only maintains
// the canonical data.
var data []byte
db.ReadAncients(func(reader ethdb.AncientReader) error {
db.ReadAncients(ChainFreezer, func(reader ethdb.AncientReadOp) error {
// Check if the data is in ancients
if isCanon(reader, number, hash) {
if isCanonOp(reader, number, hash) {
data, _ = reader.Ancient(freezerBodiesTable, number)
return nil
}
Expand All @@ -410,7 +420,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue
// block at number, in RLP encoding.
func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue {
var data []byte
db.ReadAncients(func(reader ethdb.AncientReader) error {
db.ReadAncients(ChainFreezer, func(reader ethdb.AncientReadOp) error {
data, _ = reader.Ancient(freezerBodiesTable, number)
if len(data) > 0 {
return nil
Expand Down Expand Up @@ -473,9 +483,9 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding.
func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte
db.ReadAncients(func(reader ethdb.AncientReader) error {
db.ReadAncients(ChainFreezer, func(reader ethdb.AncientReadOp) error {
// Check if the data is in ancients
if isCanon(reader, number, hash) {
if isCanonOp(reader, number, hash) {
data, _ = reader.Ancient(freezerDifficultyTable, number)
return nil
}
Expand Down Expand Up @@ -533,9 +543,9 @@ func HasReceipts(db ethdb.Reader, hash common.Hash, number uint64) bool {
// ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding.
func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte
db.ReadAncients(func(reader ethdb.AncientReader) error {
db.ReadAncients(ChainFreezer, func(reader ethdb.AncientReadOp) error {
// Check if the data is in ancients
if isCanon(reader, number, hash) {
if isCanonOp(reader, number, hash) {
data, _ = reader.Ancient(freezerReceiptTable, number)
return nil
}
Expand Down Expand Up @@ -741,13 +751,13 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
WriteHeader(db, block.Header())
}

// WriteAncientBlock writes entire block data into ancient store and returns the total written size.
// WriteAncientBlocks writes entire block data into ancient store and returns the total written size.
func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts []types.Receipts, td *big.Int) (int64, error) {
var (
tdSum = new(big.Int).Set(td)
stReceipts []*types.ReceiptForStorage
)
return db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
return db.ModifyAncients(ChainFreezer, func(op ethdb.AncientWriteOp) error {
for i, block := range blocks {
// Convert receipts to storage format and sum up total difficulty.
stReceipts = stReceipts[:0]
Expand Down
4 changes: 2 additions & 2 deletions core/rawdb/chain_iterator.go
Expand Up @@ -34,7 +34,7 @@ import (
// injects into the database the block hash->number mappings.
func InitDatabaseFromFreezer(db ethdb.Database) {
// If we can't access the freezer or it's empty, abort
frozen, err := db.Ancients()
frozen, err := db.Ancients(ChainFreezer)
if err != nil || frozen == 0 {
return
}
Expand All @@ -50,7 +50,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
if i+count > frozen {
count = frozen - i
}
data, err := db.AncientRange(freezerHashTable, i, count, 32*count)
data, err := db.AncientRange(ChainFreezer, freezerHashTable, i, count, 32*count)
if err != nil {
log.Crit("Failed to init database from freezer", "err", err)
}
Expand Down

0 comments on commit 91e6c0e

Please sign in to comment.