Skip to content

Commit

Permalink
core, ethdb, trie: mode dirty data to clean cache on flush (ethereum#…
Browse files Browse the repository at this point in the history
…19307)

This PR is a more advanced form of the dirty-to-clean cacher (ethereum#18995),
where we reuse previous database write batches as datasets to uncache,
saving a dirty-trie-iteration and a dirty-trie-rlp-reencoding per block.
  • Loading branch information
holiman authored and fjl committed Mar 26, 2019
1 parent df717ab commit 59e1953
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 67 deletions.
2 changes: 1 addition & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
defer bc.chainmu.Unlock()

// Rewind the header chain, deleting all block bodies until then
delFn := func(db ethdb.Deleter, hash common.Hash, num uint64) {
delFn := func(db ethdb.Writer, hash common.Hash, num uint64) {
rawdb.DeleteBody(db, hash, num)
}
bc.hc.SetHead(head, delFn)
Expand Down
2 changes: 1 addition & 1 deletion core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {

// DeleteCallback is a callback function that is called by SetHead before
// each header is deleted.
type DeleteCallback func(ethdb.Deleter, common.Hash, uint64)
type DeleteCallback func(ethdb.Writer, common.Hash, uint64)

// SetHead rewinds the local chain to a new head. Everything above the new head
// will be deleted and the new one set.
Expand Down
16 changes: 8 additions & 8 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func WriteCanonicalHash(db ethdb.Writer, hash common.Hash, number uint64) {
}

// DeleteCanonicalHash removes the number to hash canonical mapping.
func DeleteCanonicalHash(db ethdb.Deleter, number uint64) {
func DeleteCanonicalHash(db ethdb.Writer, number uint64) {
if err := db.Delete(headerHashKey(number)); err != nil {
log.Crit("Failed to delete number to hash mapping", "err", err)
}
Expand Down Expand Up @@ -180,7 +180,7 @@ func WriteHeader(db ethdb.Writer, header *types.Header) {
}

// DeleteHeader removes all block header data associated with a hash.
func DeleteHeader(db ethdb.Deleter, hash common.Hash, number uint64) {
func DeleteHeader(db ethdb.Writer, hash common.Hash, number uint64) {
deleteHeaderWithoutNumber(db, hash, number)
if err := db.Delete(headerNumberKey(hash)); err != nil {
log.Crit("Failed to delete hash to number mapping", "err", err)
Expand All @@ -189,7 +189,7 @@ func DeleteHeader(db ethdb.Deleter, hash common.Hash, number uint64) {

// deleteHeaderWithoutNumber removes only the block header but does not remove
// the hash to number mapping.
func deleteHeaderWithoutNumber(db ethdb.Deleter, hash common.Hash, number uint64) {
func deleteHeaderWithoutNumber(db ethdb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(headerKey(number, hash)); err != nil {
log.Crit("Failed to delete header", "err", err)
}
Expand Down Expand Up @@ -240,7 +240,7 @@ func WriteBody(db ethdb.Writer, hash common.Hash, number uint64, body *types.Bod
}

// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db ethdb.Deleter, hash common.Hash, number uint64) {
func DeleteBody(db ethdb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
Expand Down Expand Up @@ -278,7 +278,7 @@ func WriteTd(db ethdb.Writer, hash common.Hash, number uint64, td *big.Int) {
}

// DeleteTd removes all block total difficulty data associated with a hash.
func DeleteTd(db ethdb.Deleter, hash common.Hash, number uint64) {
func DeleteTd(db ethdb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(headerTDKey(number, hash)); err != nil {
log.Crit("Failed to delete block total difficulty", "err", err)
}
Expand Down Expand Up @@ -347,7 +347,7 @@ func WriteReceipts(db ethdb.Writer, hash common.Hash, number uint64, receipts ty
}

// DeleteReceipts removes all receipt data associated with a block hash.
func DeleteReceipts(db ethdb.Deleter, hash common.Hash, number uint64) {
func DeleteReceipts(db ethdb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(blockReceiptsKey(number, hash)); err != nil {
log.Crit("Failed to delete block receipts", "err", err)
}
Expand Down Expand Up @@ -378,7 +378,7 @@ func WriteBlock(db ethdb.Writer, block *types.Block) {
}

// DeleteBlock removes all block data associated with a hash.
func DeleteBlock(db ethdb.Deleter, hash common.Hash, number uint64) {
func DeleteBlock(db ethdb.Writer, hash common.Hash, number uint64) {
DeleteReceipts(db, hash, number)
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
Expand All @@ -387,7 +387,7 @@ func DeleteBlock(db ethdb.Deleter, hash common.Hash, number uint64) {

// deleteBlockWithoutNumber removes all block data associated with a hash, except
// the hash to number mapping.
func deleteBlockWithoutNumber(db ethdb.Deleter, hash common.Hash, number uint64) {
func deleteBlockWithoutNumber(db ethdb.Writer, hash common.Hash, number uint64) {
DeleteReceipts(db, hash, number)
deleteHeaderWithoutNumber(db, hash, number)
DeleteBody(db, hash, number)
Expand Down
2 changes: 1 addition & 1 deletion core/rawdb/accessors_indexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func WriteTxLookupEntries(db ethdb.Writer, block *types.Block) {
}

// DeleteTxLookupEntry removes all transaction data associated with a hash.
func DeleteTxLookupEntry(db ethdb.Deleter, hash common.Hash) {
func DeleteTxLookupEntry(db ethdb.Writer, hash common.Hash) {
db.Delete(txLookupKey(hash))
}

Expand Down
5 changes: 5 additions & 0 deletions core/rawdb/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,8 @@ func (b *tableBatch) Write() error {
func (b *tableBatch) Reset() {
b.batch.Reset()
}

// Replay replays the batch contents.
func (b *tableBatch) Replay(w ethdb.Writer) error {
return b.batch.Replay(w)
}
4 changes: 4 additions & 0 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ func (n *proofList) Put(key []byte, value []byte) error {
return nil
}

func (n *proofList) Delete(key []byte) error {
panic("not supported")
}

// StateDBs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
Expand Down
6 changes: 4 additions & 2 deletions ethdb/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ const IdealBatchSize = 100 * 1024
// when Write is called. A batch cannot be used concurrently.
type Batch interface {
Writer
Deleter

// ValueSize retrieves the amount of data queued up for writing.
ValueSize() int

// Write flushes any accumulated data to disk.
Write() error

// Reset resets the batch for reuse
// Reset resets the batch for reuse.
Reset()

// Replay replays the batch contents.
Replay(w Writer) error
}

// Batcher wraps the NewBatch method of a backing data store.
Expand Down
7 changes: 1 addition & 6 deletions ethdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package database defines the interfaces for an Ethereum data store.
// Package ethdb defines the interfaces for an Ethereum data store.
package ethdb

import "io"
Expand All @@ -32,10 +32,7 @@ type Reader interface {
type Writer interface {
// Put inserts the given value into the key-value data store.
Put(key []byte, value []byte) error
}

// Deleter wraps the Delete method of a backing data store.
type Deleter interface {
// Delete removes the key from the key-value data store.
Delete(key []byte) error
}
Expand Down Expand Up @@ -63,7 +60,6 @@ type Compacter interface {
type KeyValueStore interface {
Reader
Writer
Deleter
Batcher
Iteratee
Stater
Expand All @@ -76,7 +72,6 @@ type KeyValueStore interface {
type Database interface {
Reader
Writer
Deleter
Batcher
Iteratee
Stater
Expand Down
29 changes: 29 additions & 0 deletions ethdb/leveldb/leveldb.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,32 @@ func (b *batch) Reset() {
b.b.Reset()
b.size = 0
}

// Replay replays the batch contents.
func (b *batch) Replay(w ethdb.Writer) error {
return b.b.Replay(&replayer{writer: w})
}

// replayer is a small wrapper to implement the correct replay methods.
type replayer struct {
writer ethdb.Writer
failure error
}

// Put inserts the given value into the key-value data store.
func (r *replayer) Put(key, value []byte) {
// If the replay already failed, stop executing ops
if r.failure != nil {
return
}
r.failure = r.writer.Put(key, value)
}

// Delete removes the key from the key-value data store.
func (r *replayer) Delete(key []byte) {
// If the replay already failed, stop executing ops
if r.failure != nil {
return
}
r.failure = r.writer.Delete(key)
}
16 changes: 16 additions & 0 deletions ethdb/memorydb/memorydb.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,22 @@ func (b *batch) Reset() {
b.size = 0
}

// Replay replays the batch contents.
func (b *batch) Replay(w ethdb.Writer) error {
for _, keyvalue := range b.writes {
if keyvalue.delete {
if err := w.Delete(keyvalue.key); err != nil {
return err
}
continue
}
if err := w.Put(keyvalue.key, keyvalue.value); err != nil {
return err
}
}
return nil
}

// iterator can walk over the (potentially partial) keyspace of a memory key
// value store. Internally it is a deep copy of the entire iterated state,
// sorted by keys.
Expand Down
14 changes: 14 additions & 0 deletions light/nodeset.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ func (db *NodeSet) Put(key []byte, value []byte) error {
return nil
}

// Delete removes a node from the set
func (db *NodeSet) Delete(key []byte) error {
db.lock.Lock()
defer db.lock.Unlock()

delete(db.nodes, string(key))
return nil
}

// Get returns a stored node
func (db *NodeSet) Get(key []byte) ([]byte, error) {
db.lock.RLock()
Expand Down Expand Up @@ -138,6 +147,11 @@ func (n *NodeList) Put(key []byte, value []byte) error {
return nil
}

// Delete panics as there's no reason to remove a node from the list.
func (n *NodeList) Delete(key []byte) error {
panic("not supported")
}

// DataSize returns the aggregated data size of nodes in the list
func (n NodeList) DataSize() int {
var size int
Expand Down
Loading

0 comments on commit 59e1953

Please sign in to comment.