github.com/ledgerwatch/erigon-lib@v1.0.0/kv/kvcache/cache.go (about)

     1  /*
     2  Copyright 2021 Erigon contributors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  package kvcache
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"hash"
    24  	"sort"
    25  	"sync"
    26  	"sync/atomic"
    27  	"time"
    28  
    29  	"github.com/VictoriaMetrics/metrics"
    30  	"github.com/c2h5oh/datasize"
    31  	btree2 "github.com/tidwall/btree"
    32  	"golang.org/x/crypto/sha3"
    33  
    34  	"github.com/ledgerwatch/erigon-lib/common"
    35  	"github.com/ledgerwatch/erigon-lib/gointerfaces"
    36  	"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
    37  	"github.com/ledgerwatch/erigon-lib/kv"
    38  )
    39  
    40  type CacheValidationResult struct {
    41  	RequestCancelled   bool
    42  	Enabled            bool
    43  	LatestStateBehind  bool
    44  	CacheCleared       bool
    45  	LatestStateID      uint64
    46  	StateKeysOutOfSync [][]byte
    47  	CodeKeysOutOfSync  [][]byte
    48  }
    49  
    50  type Cache interface {
    51  	// View - returns CacheView consistent with givent kv.Tx
    52  	View(ctx context.Context, tx kv.Tx) (CacheView, error)
    53  	OnNewBlock(sc *remote.StateChangeBatch)
    54  	Len() int
    55  	ValidateCurrentRoot(ctx context.Context, tx kv.Tx) (*CacheValidationResult, error)
    56  }
    57  type CacheView interface {
    58  	Get(k []byte) ([]byte, error)
    59  	GetCode(k []byte) ([]byte, error)
    60  }
    61  
    62  // Coherent works on top of Database Transaction and pair Coherent+ReadTransaction must
    63  // provide "Serializable Isolation Level" semantic: all data form consistent db view at moment
    64  // when read transaction started, read data are immutable until end of read transaction, reader can't see newer updates
    65  //
    66  // Every time a new state change comes, we do the following:
    67  // - Check that prevBlockHeight and prevBlockHash match what is the top values we have, and if they don't we
    68  // invalidate the cache, because we missed some messages and cannot consider the cache coherent anymore.
    69  // - Clone the cache pointer (such that the previous pointer is still accessible, but new one shared the content with it),
    70  // apply state updates to the cloned cache pointer and save under the new identified made from blockHeight and blockHash.
    71  // - If there is a conditional variable corresponding to the identifier, remove it from the map and notify conditional
    72  // variable, waking up the read-only transaction waiting on it.
    73  //
    74  // On the other hand, whenever we have a cache miss (by looking at the top cache), we do the following:
    75  // - Once read the current block height and block hash (canonical) from underlying db transaction
    76  // - Construct the identifier from the current block height and block hash
    77  // - Look for the constructed identifier in the cache. If the identifier is found, use the corresponding
    78  // cache in conjunction with this read-only transaction (it will be consistent with it). If the identifier is
    79  // not found, it means that the transaction has been committed in Erigon, but the state update has not
    80  // arrived yet (as shown in the picture on the right). Insert conditional variable for this identifier and wait on
    81  // it until either cache with the given identifier appears, or timeout (indicating that the cache update
    82  // mechanism is broken and cache is likely invalidated).
    83  //
    84  
    85  // Pair.Value == nil - is a marker of absense key in db
    86  
    87  // Coherent
    88  // High-level guaranties:
    89  // - Keys/Values returned by cache are valid/immutable until end of db transaction
    90  // - CacheView is always coherent with given db transaction -
    91  //
    92  // Rules of set view.isCanonical value:
    93  //   - method View can't parent.Clone() - because parent view is not coherent with current kv.Tx
    94  //   - only OnNewBlock method may do parent.Clone() and apply StateChanges to create coherent view of kv.Tx
    95  //   - parent.Clone() can't be caled if parent.isCanonical=false
    96  //   - only OnNewBlock method can set view.isCanonical=true
    97  //
    98  // Rules of filling cache.stateEvict:
    99  //   - changes in Canonical View SHOULD reflect in stateEvict
   100  //   - changes in Non-Canonical View SHOULD NOT reflect in stateEvict
   101  type Coherent struct {
   102  	hasher               hash.Hash
   103  	codeEvictLen         *metrics.Counter
   104  	codeKeys             *metrics.Counter
   105  	keys                 *metrics.Counter
   106  	evict                *metrics.Counter
   107  	latestStateView      *CoherentRoot
   108  	codeMiss             *metrics.Counter
   109  	timeout              *metrics.Counter
   110  	hits                 *metrics.Counter
   111  	codeHits             *metrics.Counter
   112  	roots                map[uint64]*CoherentRoot
   113  	stateEvict           *ThreadSafeEvictionList
   114  	codeEvict            *ThreadSafeEvictionList
   115  	miss                 *metrics.Counter
   116  	cfg                  CoherentConfig
   117  	latestStateVersionID uint64
   118  	lock                 sync.Mutex
   119  	waitExceededCount    atomic.Int32 // used as a circuit breaker to stop the cache waiting for new blocks
   120  }
   121  
   122  type CoherentRoot struct {
   123  	cache           *btree2.BTreeG[*Element]
   124  	codeCache       *btree2.BTreeG[*Element]
   125  	ready           chan struct{} // close when ready
   126  	readyChanClosed atomic.Bool   // protecting `ready` field from double-close (on unwind). Consumers don't need check this field.
   127  
   128  	// Views marked as `Canonical` if it received onNewBlock message
   129  	// we may drop `Non-Canonical` views even if they had fresh keys
   130  	// keys added to `Non-Canonical` views SHOULD NOT be added to stateEvict
   131  	// cache.latestStateView is always `Canonical`
   132  	isCanonical bool
   133  }
   134  
   135  // CoherentView - dumb object, which proxy all requests to Coherent object.
   136  // It's thread-safe, because immutable
   137  type CoherentView struct {
   138  	tx             kv.Tx
   139  	cache          *Coherent
   140  	stateVersionID uint64
   141  }
   142  
   143  func (c *CoherentView) Get(k []byte) ([]byte, error) { return c.cache.Get(k, c.tx, c.stateVersionID) }
   144  func (c *CoherentView) GetCode(k []byte) ([]byte, error) {
   145  	return c.cache.GetCode(k, c.tx, c.stateVersionID)
   146  }
   147  
   148  var _ Cache = (*Coherent)(nil)         // compile-time interface check
   149  var _ CacheView = (*CoherentView)(nil) // compile-time interface check
   150  
   151  const (
   152  	DEGREE    = 32
   153  	MAX_WAITS = 100
   154  )
   155  
   156  type CoherentConfig struct {
   157  	CacheSize       datasize.ByteSize
   158  	CodeCacheSize   datasize.ByteSize
   159  	WaitForNewBlock bool // should we wait 10ms for a new block message to arrive when calling View?
   160  	WithStorage     bool
   161  	MetricsLabel    string
   162  	NewBlockWait    time.Duration // how long wait
   163  	KeepViews       uint64        // keep in memory up to this amount of views, evict older
   164  }
   165  
   166  var DefaultCoherentConfig = CoherentConfig{
   167  	KeepViews:       5,
   168  	NewBlockWait:    5 * time.Millisecond,
   169  	CacheSize:       2 * datasize.GB,
   170  	CodeCacheSize:   2 * datasize.GB,
   171  	MetricsLabel:    "default",
   172  	WithStorage:     true,
   173  	WaitForNewBlock: true,
   174  }
   175  
   176  func New(cfg CoherentConfig) *Coherent {
   177  	if cfg.KeepViews == 0 {
   178  		panic("empty config passed")
   179  	}
   180  
   181  	return &Coherent{
   182  		roots:        map[uint64]*CoherentRoot{},
   183  		stateEvict:   &ThreadSafeEvictionList{l: NewList()},
   184  		codeEvict:    &ThreadSafeEvictionList{l: NewList()},
   185  		hasher:       sha3.NewLegacyKeccak256(),
   186  		cfg:          cfg,
   187  		miss:         metrics.GetOrCreateCounter(fmt.Sprintf(`cache_total{result="miss",name="%s"}`, cfg.MetricsLabel)),
   188  		hits:         metrics.GetOrCreateCounter(fmt.Sprintf(`cache_total{result="hit",name="%s"}`, cfg.MetricsLabel)),
   189  		timeout:      metrics.GetOrCreateCounter(fmt.Sprintf(`cache_timeout_total{name="%s"}`, cfg.MetricsLabel)),
   190  		keys:         metrics.GetOrCreateCounter(fmt.Sprintf(`cache_keys_total{name="%s"}`, cfg.MetricsLabel)),
   191  		evict:        metrics.GetOrCreateCounter(fmt.Sprintf(`cache_list_total{name="%s"}`, cfg.MetricsLabel)),
   192  		codeMiss:     metrics.GetOrCreateCounter(fmt.Sprintf(`cache_code_total{result="miss",name="%s"}`, cfg.MetricsLabel)),
   193  		codeHits:     metrics.GetOrCreateCounter(fmt.Sprintf(`cache_code_total{result="hit",name="%s"}`, cfg.MetricsLabel)),
   194  		codeKeys:     metrics.GetOrCreateCounter(fmt.Sprintf(`cache_code_keys_total{name="%s"}`, cfg.MetricsLabel)),
   195  		codeEvictLen: metrics.GetOrCreateCounter(fmt.Sprintf(`cache_code_list_total{name="%s"}`, cfg.MetricsLabel)),
   196  	}
   197  }
   198  
   199  // selectOrCreateRoot - used for usual getting root
   200  func (c *Coherent) selectOrCreateRoot(versionID uint64) *CoherentRoot {
   201  	c.lock.Lock()
   202  	defer c.lock.Unlock()
   203  	r, ok := c.roots[versionID]
   204  	if ok {
   205  		return r
   206  	}
   207  
   208  	r = &CoherentRoot{
   209  		ready:     make(chan struct{}),
   210  		cache:     btree2.NewBTreeG[*Element](Less),
   211  		codeCache: btree2.NewBTreeG[*Element](Less),
   212  	}
   213  	c.roots[versionID] = r
   214  	return r
   215  }
   216  
   217  // advanceRoot - used for advancing root onNewBlock
   218  func (c *Coherent) advanceRoot(stateVersionID uint64) (r *CoherentRoot) {
   219  	r, rootExists := c.roots[stateVersionID]
   220  
   221  	// if nothing has progressed just return the existing root
   222  	if c.latestStateVersionID == stateVersionID && rootExists {
   223  		return r
   224  	}
   225  
   226  	if !rootExists {
   227  		r = &CoherentRoot{ready: make(chan struct{})}
   228  		c.roots[stateVersionID] = r
   229  	}
   230  
   231  	if prevView, ok := c.roots[stateVersionID-1]; ok && prevView.isCanonical {
   232  		//log.Info("advance: clone", "from", viewID-1, "to", viewID)
   233  		r.cache = prevView.cache.Copy()
   234  		r.codeCache = prevView.codeCache.Copy()
   235  	} else {
   236  		c.stateEvict.Init()
   237  		c.codeEvict.Init()
   238  		if r.cache == nil {
   239  			//log.Info("advance: new", "to", viewID)
   240  			r.cache = btree2.NewBTreeG[*Element](Less)
   241  			r.codeCache = btree2.NewBTreeG[*Element](Less)
   242  		} else {
   243  			r.cache.Walk(func(items []*Element) bool {
   244  				for _, i := range items {
   245  					c.stateEvict.PushFront(i)
   246  				}
   247  				return true
   248  			})
   249  			r.codeCache.Walk(func(items []*Element) bool {
   250  				for _, i := range items {
   251  					c.codeEvict.PushFront(i)
   252  				}
   253  				return true
   254  			})
   255  		}
   256  	}
   257  	r.isCanonical = true
   258  
   259  	c.evictRoots()
   260  	c.latestStateVersionID = stateVersionID
   261  	c.latestStateView = r
   262  
   263  	c.keys.Set(uint64(c.latestStateView.cache.Len()))
   264  	c.codeKeys.Set(uint64(c.latestStateView.codeCache.Len()))
   265  	c.evict.Set(uint64(c.stateEvict.Len()))
   266  	c.codeEvictLen.Set(uint64(c.codeEvict.Len()))
   267  	return r
   268  }
   269  
   270  func (c *Coherent) OnNewBlock(stateChanges *remote.StateChangeBatch) {
   271  	c.lock.Lock()
   272  	defer c.lock.Unlock()
   273  	c.waitExceededCount.Store(0) // reset the circuit breaker
   274  	id := stateChanges.StateVersionId
   275  	r := c.advanceRoot(id)
   276  	for _, sc := range stateChanges.ChangeBatch {
   277  		for i := range sc.Changes {
   278  			switch sc.Changes[i].Action {
   279  			case remote.Action_UPSERT:
   280  				addr := gointerfaces.ConvertH160toAddress(sc.Changes[i].Address)
   281  				v := sc.Changes[i].Data
   282  				//fmt.Printf("set: %x,%x\n", addr, v)
   283  				c.add(addr[:], v, r, id)
   284  			case remote.Action_UPSERT_CODE:
   285  				addr := gointerfaces.ConvertH160toAddress(sc.Changes[i].Address)
   286  				v := sc.Changes[i].Data
   287  				c.add(addr[:], v, r, id)
   288  				c.hasher.Reset()
   289  				c.hasher.Write(sc.Changes[i].Code)
   290  				k := make([]byte, 32)
   291  				c.hasher.Sum(k)
   292  				c.addCode(k, sc.Changes[i].Code, r, id)
   293  			case remote.Action_REMOVE:
   294  				addr := gointerfaces.ConvertH160toAddress(sc.Changes[i].Address)
   295  				c.add(addr[:], nil, r, id)
   296  			case remote.Action_STORAGE:
   297  				//skip, will check later
   298  			case remote.Action_CODE:
   299  				c.hasher.Reset()
   300  				c.hasher.Write(sc.Changes[i].Code)
   301  				k := make([]byte, 32)
   302  				c.hasher.Sum(k)
   303  				c.addCode(k, sc.Changes[i].Code, r, id)
   304  			default:
   305  				panic("not implemented yet")
   306  			}
   307  			if c.cfg.WithStorage && len(sc.Changes[i].StorageChanges) > 0 {
   308  				addr := gointerfaces.ConvertH160toAddress(sc.Changes[i].Address)
   309  				for _, change := range sc.Changes[i].StorageChanges {
   310  					loc := gointerfaces.ConvertH256ToHash(change.Location)
   311  					k := make([]byte, 20+8+32)
   312  					copy(k, addr[:])
   313  					binary.BigEndian.PutUint64(k[20:], sc.Changes[i].Incarnation)
   314  					copy(k[20+8:], loc[:])
   315  					c.add(k, change.Data, r, id)
   316  				}
   317  			}
   318  		}
   319  	}
   320  
   321  	switched := r.readyChanClosed.CompareAndSwap(false, true)
   322  	if switched {
   323  		close(r.ready) //broadcast
   324  	}
   325  	//log.Info("on new block handled", "viewID", stateChanges.StateVersionID)
   326  }
   327  
   328  func (c *Coherent) View(ctx context.Context, tx kv.Tx) (CacheView, error) {
   329  	idBytes, err := tx.GetOne(kv.Sequence, kv.PlainStateVersion)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  	var id uint64
   334  	if len(idBytes) == 0 {
   335  		id = 0
   336  	} else {
   337  		id = binary.BigEndian.Uint64(idBytes)
   338  	}
   339  	r := c.selectOrCreateRoot(id)
   340  
   341  	if !c.cfg.WaitForNewBlock || c.waitExceededCount.Load() >= MAX_WAITS {
   342  		return &CoherentView{stateVersionID: id, tx: tx, cache: c}, nil
   343  	}
   344  
   345  	select { // fast non-blocking path
   346  	case <-r.ready:
   347  		//fmt.Printf("recv broadcast: %d\n", id)
   348  		return &CoherentView{stateVersionID: id, tx: tx, cache: c}, nil
   349  	default:
   350  	}
   351  
   352  	select { // slow blocking path
   353  	case <-r.ready:
   354  		//fmt.Printf("recv broadcast2: %d\n", tx.ViewID())
   355  	case <-ctx.Done():
   356  		return nil, fmt.Errorf("kvcache rootNum=%x, %w", tx.ViewID(), ctx.Err())
   357  	case <-time.After(c.cfg.NewBlockWait): //TODO: switch to timer to save resources
   358  		c.timeout.Inc()
   359  		c.waitExceededCount.Add(1)
   360  		//log.Info("timeout", "db_id", id, "has_btree", r.cache != nil)
   361  	}
   362  	return &CoherentView{stateVersionID: id, tx: tx, cache: c}, nil
   363  }
   364  
   365  func (c *Coherent) getFromCache(k []byte, id uint64, code bool) (*Element, *CoherentRoot, error) {
   366  	// using the full lock here rather than RLock as RLock causes a lot of calls to runtime.usleep degrading
   367  	// performance under load
   368  	c.lock.Lock()
   369  	defer c.lock.Unlock()
   370  	r, ok := c.roots[id]
   371  	if !ok {
   372  		return nil, r, fmt.Errorf("too old ViewID: %d, latestStateVersionID=%d", id, c.latestStateVersionID)
   373  	}
   374  	isLatest := c.latestStateVersionID == id
   375  
   376  	var it *Element
   377  	if code {
   378  		it, _ = r.codeCache.Get(&Element{K: k})
   379  	} else {
   380  		it, _ = r.cache.Get(&Element{K: k})
   381  	}
   382  	if it != nil && isLatest {
   383  		c.stateEvict.MoveToFront(it)
   384  	}
   385  
   386  	return it, r, nil
   387  }
   388  func (c *Coherent) Get(k []byte, tx kv.Tx, id uint64) ([]byte, error) {
   389  	it, r, err := c.getFromCache(k, id, false)
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  
   394  	if it != nil {
   395  		//fmt.Printf("from cache:  %#x,%x\n", k, it.(*Element).V)
   396  		c.hits.Inc()
   397  		return it.V, nil
   398  	}
   399  	c.miss.Inc()
   400  
   401  	v, err := tx.GetOne(kv.PlainState, k)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  	//fmt.Printf("from db: %#x,%x\n", k, v)
   406  
   407  	c.lock.Lock()
   408  	defer c.lock.Unlock()
   409  	v = c.add(common.Copy(k), common.Copy(v), r, id).V
   410  	return v, nil
   411  }
   412  
   413  func (c *Coherent) GetCode(k []byte, tx kv.Tx, id uint64) ([]byte, error) {
   414  	it, r, err := c.getFromCache(k, id, true)
   415  	if err != nil {
   416  		return nil, err
   417  	}
   418  
   419  	if it != nil {
   420  		//fmt.Printf("from cache:  %#x,%x\n", k, it.(*Element).V)
   421  		c.codeHits.Inc()
   422  		return it.V, nil
   423  	}
   424  	c.codeMiss.Inc()
   425  
   426  	v, err := tx.GetOne(kv.Code, k)
   427  	if err != nil {
   428  		return nil, err
   429  	}
   430  	//fmt.Printf("from db: %#x,%x\n", k, v)
   431  
   432  	c.lock.Lock()
   433  	defer c.lock.Unlock()
   434  	v = c.addCode(common.Copy(k), common.Copy(v), r, id).V
   435  	return v, nil
   436  }
   437  func (c *Coherent) removeOldest(r *CoherentRoot) {
   438  	e := c.stateEvict.Oldest()
   439  	if e != nil {
   440  		c.stateEvict.Remove(e)
   441  		r.cache.Delete(e)
   442  	}
   443  }
   444  func (c *Coherent) removeOldestCode(r *CoherentRoot) {
   445  	e := c.codeEvict.Oldest()
   446  	if e != nil {
   447  		c.codeEvict.Remove(e)
   448  		r.codeCache.Delete(e)
   449  	}
   450  }
   451  func (c *Coherent) add(k, v []byte, r *CoherentRoot, id uint64) *Element {
   452  	it := &Element{K: k, V: v}
   453  	replaced, _ := r.cache.Set(it)
   454  	if c.latestStateVersionID != id {
   455  		//fmt.Printf("add to non-last viewID: %d<%d\n", c.latestViewID, id)
   456  		return it
   457  	}
   458  	if replaced != nil {
   459  		c.stateEvict.Remove(replaced)
   460  	}
   461  	c.stateEvict.PushFront(it)
   462  
   463  	// clear down cache until size below the configured limit
   464  	for c.stateEvict.Size() > int(c.cfg.CacheSize.Bytes()) {
   465  		c.removeOldest(r)
   466  	}
   467  
   468  	return it
   469  }
   470  func (c *Coherent) addCode(k, v []byte, r *CoherentRoot, id uint64) *Element {
   471  	it := &Element{K: k, V: v}
   472  	replaced, _ := r.codeCache.Set(it)
   473  	if c.latestStateVersionID != id {
   474  		//fmt.Printf("add to non-last viewID: %d<%d\n", c.latestViewID, id)
   475  		return it
   476  	}
   477  	if replaced != nil {
   478  		c.codeEvict.Remove(replaced)
   479  	}
   480  	c.codeEvict.PushFront(it)
   481  
   482  	for c.codeEvict.Size() > int(c.cfg.CodeCacheSize.Bytes()) {
   483  		c.removeOldestCode(r)
   484  	}
   485  
   486  	return it
   487  }
   488  
   489  func (c *Coherent) ValidateCurrentRoot(ctx context.Context, tx kv.Tx) (*CacheValidationResult, error) {
   490  
   491  	result := &CacheValidationResult{
   492  		Enabled:          true,
   493  		RequestCancelled: false,
   494  	}
   495  
   496  	select {
   497  	case <-ctx.Done():
   498  		result.RequestCancelled = true
   499  		return result, nil
   500  	default:
   501  	}
   502  
   503  	idBytes, err := tx.GetOne(kv.Sequence, kv.PlainStateVersion)
   504  	if err != nil {
   505  		return nil, err
   506  	}
   507  	stateID := binary.BigEndian.Uint64(idBytes)
   508  	result.LatestStateID = stateID
   509  
   510  	// if the latest view id in the cache is not the same as the tx or one below it
   511  	// then the cache will be a new one for the next call so return early
   512  	if stateID > c.latestStateVersionID {
   513  		result.LatestStateBehind = true
   514  		return result, nil
   515  	}
   516  
   517  	root := c.selectOrCreateRoot(c.latestStateVersionID)
   518  
   519  	// ensure the root is ready or wait and press on
   520  	select {
   521  	case <-root.ready:
   522  	case <-time.After(c.cfg.NewBlockWait):
   523  	}
   524  
   525  	// check context again after potentially waiting for root to be ready
   526  	select {
   527  	case <-ctx.Done():
   528  		result.RequestCancelled = true
   529  		return result, nil
   530  	default:
   531  	}
   532  
   533  	clearCache := false
   534  
   535  	compare := func(cache *btree2.BTreeG[*Element], bucket string) (bool, [][]byte, error) {
   536  		keys := make([][]byte, 0)
   537  
   538  		for {
   539  			val, ok := cache.PopMax()
   540  			if !ok {
   541  				break
   542  			}
   543  
   544  			// check the db
   545  			inDb, err := tx.GetOne(bucket, val.K)
   546  			if err != nil {
   547  				return false, keys, err
   548  			}
   549  
   550  			if !bytes.Equal(inDb, val.V) {
   551  				keys = append(keys, val.K)
   552  				clearCache = true
   553  			}
   554  
   555  			select {
   556  			case <-ctx.Done():
   557  				return true, keys, nil
   558  			default:
   559  			}
   560  		}
   561  
   562  		return false, keys, nil
   563  	}
   564  
   565  	cache, codeCache := c.cloneCaches(root)
   566  
   567  	cancelled, keys, err := compare(cache, kv.PlainState)
   568  	if err != nil {
   569  		return nil, err
   570  	}
   571  	result.StateKeysOutOfSync = keys
   572  	if cancelled {
   573  		result.RequestCancelled = true
   574  		return result, nil
   575  	}
   576  
   577  	cancelled, keys, err = compare(codeCache, kv.Code)
   578  	if err != nil {
   579  		return nil, err
   580  	}
   581  	result.CodeKeysOutOfSync = keys
   582  	if cancelled {
   583  		result.RequestCancelled = true
   584  		return result, nil
   585  	}
   586  
   587  	if clearCache {
   588  		c.clearCaches(root)
   589  	}
   590  	result.CacheCleared = clearCache
   591  
   592  	return result, nil
   593  }
   594  
   595  func (c *Coherent) cloneCaches(r *CoherentRoot) (cache *btree2.BTreeG[*Element], codeCache *btree2.BTreeG[*Element]) {
   596  	c.lock.Lock()
   597  	defer c.lock.Unlock()
   598  	cache = r.cache.Copy()
   599  	codeCache = r.codeCache.Copy()
   600  	return cache, codeCache
   601  }
   602  
   603  func (c *Coherent) clearCaches(r *CoherentRoot) {
   604  	c.lock.Lock()
   605  	defer c.lock.Unlock()
   606  	r.cache.Clear()
   607  	r.codeCache.Clear()
   608  }
   609  
   610  type Stat struct {
   611  	BlockNum  uint64
   612  	BlockHash [32]byte
   613  	Lenght    int
   614  }
   615  
   616  func DebugStats(cache Cache) []Stat {
   617  	res := []Stat{}
   618  	casted, ok := cache.(*Coherent)
   619  	if !ok {
   620  		return res
   621  	}
   622  	casted.lock.Lock()
   623  	for root, r := range casted.roots {
   624  		res = append(res, Stat{
   625  			BlockNum: root,
   626  			Lenght:   r.cache.Len(),
   627  		})
   628  	}
   629  	casted.lock.Unlock()
   630  	sort.Slice(res, func(i, j int) bool { return res[i].BlockNum < res[j].BlockNum })
   631  	return res
   632  }
   633  func AssertCheckValues(ctx context.Context, tx kv.Tx, cache Cache) (int, error) {
   634  	defer func(t time.Time) { fmt.Printf("AssertCheckValues:327: %s\n", time.Since(t)) }(time.Now())
   635  	view, err := cache.View(ctx, tx)
   636  	if err != nil {
   637  		return 0, err
   638  	}
   639  	castedView, ok := view.(*CoherentView)
   640  	if !ok {
   641  		return 0, nil
   642  	}
   643  	casted, ok := cache.(*Coherent)
   644  	if !ok {
   645  		return 0, nil
   646  	}
   647  	checked := 0
   648  	casted.lock.Lock()
   649  	defer casted.lock.Unlock()
   650  	//log.Info("AssertCheckValues start", "db_id", tx.ViewID(), "mem_id", casted.id.Load(), "len", casted.cache.Len())
   651  	root, ok := casted.roots[castedView.stateVersionID]
   652  	if !ok {
   653  		return 0, nil
   654  	}
   655  	root.cache.Walk(func(items []*Element) bool {
   656  		for _, i := range items {
   657  			k, v := i.K, i.V
   658  			var dbV []byte
   659  			dbV, err = tx.GetOne(kv.PlainState, k)
   660  			if err != nil {
   661  				return false
   662  			}
   663  			if !bytes.Equal(dbV, v) {
   664  				err = fmt.Errorf("key: %x, has different values: %x != %x", k, v, dbV)
   665  				return false
   666  			}
   667  			checked++
   668  		}
   669  		return true
   670  	})
   671  	return checked, err
   672  }
   673  func (c *Coherent) evictRoots() {
   674  	if c.latestStateVersionID <= c.cfg.KeepViews {
   675  		return
   676  	}
   677  	if len(c.roots) < int(c.cfg.KeepViews) {
   678  		return
   679  	}
   680  	to := c.latestStateVersionID - c.cfg.KeepViews
   681  	toDel := make([]uint64, 0, len(c.roots))
   682  	for txID := range c.roots {
   683  		if txID > to {
   684  			continue
   685  		}
   686  		toDel = append(toDel, txID)
   687  	}
   688  	//log.Info("forget old roots", "list", fmt.Sprintf("%d", toDel))
   689  	for _, txID := range toDel {
   690  		delete(c.roots, txID)
   691  	}
   692  }
   693  func (c *Coherent) Len() int {
   694  	c.lock.Lock()
   695  	defer c.lock.Unlock()
   696  	if c.latestStateView == nil {
   697  		return 0
   698  	}
   699  	return c.latestStateView.cache.Len() //todo: is it same with cache.len()?
   700  }
   701  
   702  // Element is an element of a linked list.
   703  type Element struct {
   704  	// Next and previous pointers in the doubly-linked list of elements.
   705  	// To simplify the implementation, internally a list l is implemented
   706  	// as a ring, such that &l.root is both the next element of the last
   707  	// list element (l.Back()) and the previous element of the first list
   708  	// element (l.Front()).
   709  	next, prev *Element
   710  
   711  	// The list to which this element belongs.
   712  	list *List
   713  
   714  	// The value stored with this element.
   715  	K, V []byte
   716  }
   717  
   718  func (e *Element) Size() int { return len(e.K) + len(e.V) }
   719  
   720  func Less(a, b *Element) bool { return bytes.Compare(a.K, b.K) < 0 }
   721  
   722  type ThreadSafeEvictionList struct {
   723  	l    *List
   724  	lock sync.Mutex
   725  }
   726  
   727  func (l *ThreadSafeEvictionList) Init() {
   728  	l.lock.Lock()
   729  	l.l.Init()
   730  	l.lock.Unlock()
   731  }
   732  func (l *ThreadSafeEvictionList) PushFront(e *Element) {
   733  	l.lock.Lock()
   734  	l.l.PushFront(e)
   735  	l.lock.Unlock()
   736  }
   737  
   738  func (l *ThreadSafeEvictionList) MoveToFront(e *Element) {
   739  	l.lock.Lock()
   740  	l.l.MoveToFront(e)
   741  	l.lock.Unlock()
   742  }
   743  
   744  func (l *ThreadSafeEvictionList) Remove(e *Element) {
   745  	l.lock.Lock()
   746  	l.l.Remove(e)
   747  	l.lock.Unlock()
   748  }
   749  
   750  func (l *ThreadSafeEvictionList) Oldest() *Element {
   751  	l.lock.Lock()
   752  	e := l.l.Back()
   753  	l.lock.Unlock()
   754  	return e
   755  }
   756  
   757  func (l *ThreadSafeEvictionList) Len() int {
   758  	l.lock.Lock()
   759  	length := l.l.Len()
   760  	l.lock.Unlock()
   761  	return length
   762  }
   763  
   764  func (l *ThreadSafeEvictionList) Size() int {
   765  	l.lock.Lock()
   766  	size := l.l.Size()
   767  	l.lock.Unlock()
   768  	return size
   769  }
   770  
   771  // ========= copypaste of List implementation from stdlib ========
   772  
   773  // Next returns the next list element or nil.
   774  func (e *Element) Next() *Element {
   775  	if p := e.next; e.list != nil && p != &e.list.root {
   776  		return p
   777  	}
   778  	return nil
   779  }
   780  
   781  // Prev returns the previous list element or nil.
   782  func (e *Element) Prev() *Element {
   783  	if p := e.prev; e.list != nil && p != &e.list.root {
   784  		return p
   785  	}
   786  	return nil
   787  }
   788  
   789  // List represents a doubly linked list.
   790  // The zero value for List is an empty list ready to use.
   791  type List struct {
   792  	root Element // sentinel list element, only &root, root.prev, and root.next are used
   793  	len  int     // current list length excluding (this) sentinel element
   794  	size int     // size of items in list in bytes
   795  }
   796  
   797  // Init initializes or clears list l.
   798  func (l *List) Init() *List {
   799  	l.root.next = &l.root
   800  	l.root.prev = &l.root
   801  	l.len = 0
   802  	l.size = 0
   803  	return l
   804  }
   805  
   806  // New returns an initialized list.
   807  func NewList() *List { return new(List).Init() }
   808  
   809  // Len returns the number of elements of list l.
   810  // The complexity is O(1).
   811  func (l *List) Len() int { return l.len }
   812  
   813  // Size returns the size of the elements in the list by bytes
   814  func (l *List) Size() int { return l.size }
   815  
   816  // Front returns the first element of list l or nil if the list is empty.
   817  func (l *List) Front() *Element {
   818  	if l.len == 0 {
   819  		return nil
   820  	}
   821  	return l.root.next
   822  }
   823  
   824  // Back returns the last element of list l or nil if the list is empty.
   825  func (l *List) Back() *Element {
   826  	if l.len == 0 {
   827  		return nil
   828  	}
   829  	return l.root.prev
   830  }
   831  
   832  // lazyInit lazily initializes a zero List value.
   833  func (l *List) lazyInit() {
   834  	if l.root.next == nil {
   835  		l.Init()
   836  	}
   837  }
   838  
   839  // insert inserts e after at, increments l.len, and returns e.
   840  func (l *List) insert(e, at *Element) *Element {
   841  	e.prev = at
   842  	e.next = at.next
   843  	e.prev.next = e
   844  	e.next.prev = e
   845  	e.list = l
   846  	l.len++
   847  	l.size += e.Size()
   848  	return e
   849  }
   850  
   851  // insertValue is a convenience wrapper for insert(&Element{Value: v}, at).
   852  func (l *List) insertValue(e, at *Element) *Element {
   853  	return l.insert(e, at)
   854  }
   855  
   856  // remove removes e from its list, decrements l.len, and returns e.
   857  func (l *List) remove(e *Element) *Element {
   858  	e.prev.next = e.next
   859  	e.next.prev = e.prev
   860  	e.next = nil // avoid memory leaks
   861  	e.prev = nil // avoid memory leaks
   862  	e.list = nil
   863  	l.len--
   864  	l.size -= e.Size()
   865  	return e
   866  }
   867  
   868  // move moves e to next to at and returns e.
   869  func (l *List) move(e, at *Element) *Element {
   870  	if e == at {
   871  		return e
   872  	}
   873  	e.prev.next = e.next
   874  	e.next.prev = e.prev
   875  
   876  	e.prev = at
   877  	e.next = at.next
   878  	e.prev.next = e
   879  	e.next.prev = e
   880  
   881  	return e
   882  }
   883  
   884  // Remove removes e from l if e is an element of list l.
   885  // It returns the element value e.Value.
   886  // The element must not be nil.
   887  func (l *List) Remove(e *Element) ([]byte, []byte) {
   888  	if e.list == l {
   889  		// if e.list == l, l must have been initialized when e was inserted
   890  		// in l or l == nil (e is a zero Element) and l.remove will crash
   891  		l.remove(e)
   892  	}
   893  	return e.K, e.V
   894  }
   895  
   896  // PushFront inserts a new element e with value v at the front of list l and returns e.
   897  func (l *List) PushFront(e *Element) *Element {
   898  	l.lazyInit()
   899  	return l.insertValue(e, &l.root)
   900  }
   901  
   902  // PushBack inserts a new element e with value v at the back of list l and returns e.
   903  func (l *List) PushBack(e *Element) *Element {
   904  	l.lazyInit()
   905  	return l.insertValue(e, l.root.prev)
   906  }
   907  
   908  // InsertBefore inserts a new element e with value v immediately before mark and returns e.
   909  // If mark is not an element of l, the list is not modified.
   910  // The mark must not be nil.
   911  func (l *List) InsertBefore(e *Element, mark *Element) *Element {
   912  	if mark.list != l {
   913  		return nil
   914  	}
   915  	// see comment in List.Remove about initialization of l
   916  	return l.insertValue(e, mark.prev)
   917  }
   918  
   919  // InsertAfter inserts a new element e with value v immediately after mark and returns e.
   920  // If mark is not an element of l, the list is not modified.
   921  // The mark must not be nil.
   922  func (l *List) InsertAfter(e *Element, mark *Element) *Element {
   923  	if mark.list != l {
   924  		return nil
   925  	}
   926  	// see comment in List.Remove about initialization of l
   927  	return l.insertValue(e, mark)
   928  }
   929  
   930  // MoveToFront moves element e to the front of list l.
   931  // If e is not an element of l, the list is not modified.
   932  // The element must not be nil.
   933  func (l *List) MoveToFront(e *Element) {
   934  	if e.list != l || l.root.next == e {
   935  		return
   936  	}
   937  	// see comment in List.Remove about initialization of l
   938  	l.move(e, &l.root)
   939  }
   940  
   941  // MoveToBack moves element e to the back of list l.
   942  // If e is not an element of l, the list is not modified.
   943  // The element must not be nil.
   944  func (l *List) MoveToBack(e *Element) {
   945  	if e.list != l || l.root.prev == e {
   946  		return
   947  	}
   948  	// see comment in List.Remove about initialization of l
   949  	l.move(e, l.root.prev)
   950  }
   951  
   952  // MoveBefore moves element e to its new position before mark.
   953  // If e or mark is not an element of l, or e == mark, the list is not modified.
   954  // The element and mark must not be nil.
   955  func (l *List) MoveBefore(e, mark *Element) {
   956  	if e.list != l || e == mark || mark.list != l {
   957  		return
   958  	}
   959  	l.move(e, mark.prev)
   960  }
   961  
   962  // MoveAfter moves element e to its new position after mark.
   963  // If e or mark is not an element of l, or e == mark, the list is not modified.
   964  // The element and mark must not be nil.
   965  func (l *List) MoveAfter(e, mark *Element) {
   966  	if e.list != l || e == mark || mark.list != l {
   967  		return
   968  	}
   969  	l.move(e, mark)
   970  }