github.com/theQRL/go-zond@v0.1.1/trie/triedb/pathdb/difflayer.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package pathdb
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  
    23  	"github.com/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/log"
    25  	"github.com/theQRL/go-zond/trie/trienode"
    26  	"github.com/theQRL/go-zond/trie/triestate"
    27  )
    28  
    29  // diffLayer represents a collection of modifications made to the in-memory tries
    30  // along with associated state changes after running a block on top.
    31  //
    32  // The goal of a diff layer is to act as a journal, tracking recent modifications
    33  // made to the state, that have not yet graduated into a semi-immutable state.
    34  type diffLayer struct {
    35  	// Immutables
    36  	root   common.Hash                               // Root hash to which this layer diff belongs to
    37  	id     uint64                                    // Corresponding state id
    38  	block  uint64                                    // Associated block number
    39  	nodes  map[common.Hash]map[string]*trienode.Node // Cached trie nodes indexed by owner and path
    40  	states *triestate.Set                            // Associated state change set for building history
    41  	memory uint64                                    // Approximate guess as to how much memory we use
    42  
    43  	parent layer        // Parent layer modified by this one, never nil, **can be changed**
    44  	lock   sync.RWMutex // Lock used to protect parent
    45  }
    46  
    47  // newDiffLayer creates a new diff layer on top of an existing layer.
    48  func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer {
    49  	var (
    50  		size  int64
    51  		count int
    52  	)
    53  	dl := &diffLayer{
    54  		root:   root,
    55  		id:     id,
    56  		block:  block,
    57  		nodes:  nodes,
    58  		states: states,
    59  		parent: parent,
    60  	}
    61  	for _, subset := range nodes {
    62  		for path, n := range subset {
    63  			dl.memory += uint64(n.Size() + len(path))
    64  			size += int64(len(n.Blob) + len(path))
    65  		}
    66  		count += len(subset)
    67  	}
    68  	if states != nil {
    69  		dl.memory += uint64(states.Size())
    70  	}
    71  	dirtyWriteMeter.Mark(size)
    72  	diffLayerNodesMeter.Mark(int64(count))
    73  	diffLayerBytesMeter.Mark(int64(dl.memory))
    74  	log.Debug("Created new diff layer", "id", id, "block", block, "nodes", count, "size", common.StorageSize(dl.memory))
    75  	return dl
    76  }
    77  
    78  // rootHash implements the layer interface, returning the root hash of
    79  // corresponding state.
    80  func (dl *diffLayer) rootHash() common.Hash {
    81  	return dl.root
    82  }
    83  
    84  // stateID implements the layer interface, returning the state id of the layer.
    85  func (dl *diffLayer) stateID() uint64 {
    86  	return dl.id
    87  }
    88  
    89  // parentLayer implements the layer interface, returning the subsequent
    90  // layer of the diff layer.
    91  func (dl *diffLayer) parentLayer() layer {
    92  	dl.lock.RLock()
    93  	defer dl.lock.RUnlock()
    94  
    95  	return dl.parent
    96  }
    97  
    98  // node retrieves the node with provided node information. It's the internal
    99  // version of Node function with additional accessed layer tracked. No error
   100  // will be returned if node is not found.
   101  func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, depth int) ([]byte, error) {
   102  	// Hold the lock, ensure the parent won't be changed during the
   103  	// state accessing.
   104  	dl.lock.RLock()
   105  	defer dl.lock.RUnlock()
   106  
   107  	// If the trie node is known locally, return it
   108  	subset, ok := dl.nodes[owner]
   109  	if ok {
   110  		n, ok := subset[string(path)]
   111  		if ok {
   112  			// If the trie node is not hash matched, or marked as removed,
   113  			// bubble up an error here. It shouldn't happen at all.
   114  			if n.Hash != hash {
   115  				dirtyFalseMeter.Mark(1)
   116  				log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
   117  				return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path)
   118  			}
   119  			dirtyHitMeter.Mark(1)
   120  			dirtyNodeHitDepthHist.Update(int64(depth))
   121  			dirtyReadMeter.Mark(int64(len(n.Blob)))
   122  			return n.Blob, nil
   123  		}
   124  	}
   125  	// Trie node unknown to this layer, resolve from parent
   126  	if diff, ok := dl.parent.(*diffLayer); ok {
   127  		return diff.node(owner, path, hash, depth+1)
   128  	}
   129  	// Failed to resolve through diff layers, fallback to disk layer
   130  	return dl.parent.Node(owner, path, hash)
   131  }
   132  
   133  // Node implements the layer interface, retrieving the trie node blob with the
   134  // provided node information. No error will be returned if the node is not found.
   135  func (dl *diffLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
   136  	return dl.node(owner, path, hash, 0)
   137  }
   138  
   139  // update implements the layer interface, creating a new layer on top of the
   140  // existing layer tree with the specified data items.
   141  func (dl *diffLayer) update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer {
   142  	return newDiffLayer(dl, root, id, block, nodes, states)
   143  }
   144  
   145  // persist flushes the diff layer and all its parent layers to disk layer.
   146  func (dl *diffLayer) persist(force bool) (layer, error) {
   147  	if parent, ok := dl.parentLayer().(*diffLayer); ok {
   148  		// Hold the lock to prevent any read operation until the new
   149  		// parent is linked correctly.
   150  		dl.lock.Lock()
   151  
   152  		// The merging of diff layers starts at the bottom-most layer,
   153  		// therefore we recurse down here, flattening on the way up
   154  		// (diffToDisk).
   155  		result, err := parent.persist(force)
   156  		if err != nil {
   157  			dl.lock.Unlock()
   158  			return nil, err
   159  		}
   160  		dl.parent = result
   161  		dl.lock.Unlock()
   162  	}
   163  	return diffToDisk(dl, force)
   164  }
   165  
   166  // diffToDisk merges a bottom-most diff into the persistent disk layer underneath
   167  // it. The method will panic if called onto a non-bottom-most diff layer.
   168  func diffToDisk(layer *diffLayer, force bool) (layer, error) {
   169  	disk, ok := layer.parentLayer().(*diskLayer)
   170  	if !ok {
   171  		panic(fmt.Sprintf("unknown layer type: %T", layer.parentLayer()))
   172  	}
   173  	return disk.commit(layer, force)
   174  }