github.com/aergoio/aergo@v1.3.1/state/storage.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"sync"
     6  
     7  	"github.com/aergoio/aergo-lib/db"
     8  	"github.com/aergoio/aergo/internal/common"
     9  	"github.com/aergoio/aergo/internal/enc"
    10  	"github.com/aergoio/aergo/pkg/trie"
    11  	"github.com/aergoio/aergo/types"
    12  )
    13  
    14  var (
    15  	checkpointKey = types.ToHashID([]byte("checkpoint"))
    16  )
    17  
    18  type storageCache struct {
    19  	lock     sync.RWMutex
    20  	storages map[types.AccountID]*bufferedStorage
    21  }
    22  
    23  func newStorageCache() *storageCache {
    24  	return &storageCache{
    25  		storages: map[types.AccountID]*bufferedStorage{},
    26  	}
    27  }
    28  
    29  func (cache *storageCache) get(key types.AccountID) *bufferedStorage {
    30  	cache.lock.RLock()
    31  	defer cache.lock.RUnlock()
    32  	if storage, ok := cache.storages[key]; ok && storage != nil {
    33  		return storage
    34  	}
    35  	return nil
    36  }
    37  func (cache *storageCache) put(key types.AccountID, storage *bufferedStorage) {
    38  	cache.lock.Lock()
    39  	defer cache.lock.Unlock()
    40  	cache.storages[key] = storage
    41  }
    42  
    43  type bufferedStorage struct {
    44  	buffer *stateBuffer
    45  	trie   *trie.Trie
    46  	dirty  bool
    47  }
    48  
    49  func newBufferedStorage(root []byte, store db.DB) *bufferedStorage {
    50  	return &bufferedStorage{
    51  		buffer: newStateBuffer(),
    52  		trie:   trie.NewTrie(root, common.Hasher, store),
    53  		dirty:  false,
    54  	}
    55  }
    56  
    57  func (storage *bufferedStorage) has(key types.HashID, lookupTrie bool) bool {
    58  	if storage.buffer.has(key) {
    59  		return true
    60  	}
    61  	if lookupTrie {
    62  		if buf, _ := storage.trie.Get(key.Bytes()); buf != nil {
    63  			return true
    64  		}
    65  	}
    66  	return false
    67  }
    68  func (storage *bufferedStorage) get(key types.HashID) entry {
    69  	return storage.buffer.get(key)
    70  }
    71  func (storage *bufferedStorage) put(et entry) {
    72  	storage.buffer.put(et)
    73  }
    74  
    75  func (storage *bufferedStorage) checkpoint(revision int) {
    76  	storage.buffer.put(newMetaEntry(checkpointKey, revision))
    77  }
    78  
    79  func (storage *bufferedStorage) rollback(revision int) {
    80  	checkpoints, ok := storage.buffer.indexes[checkpointKey]
    81  	if !ok {
    82  		// do nothing
    83  		return
    84  	}
    85  	it := checkpoints.iter()
    86  	for rev := it(); rev >= 0; rev = it() {
    87  		et := storage.buffer.entries[rev]
    88  		if et == nil {
    89  			continue
    90  		}
    91  		me, ok := et.(*metaEntry)
    92  		if !ok {
    93  			continue
    94  		}
    95  		val, ok := me.Value().(int)
    96  		if !ok {
    97  			continue
    98  		}
    99  		if val < revision {
   100  			break
   101  		}
   102  		storage.buffer.rollback(rev)
   103  	}
   104  }
   105  
   106  func (storage *bufferedStorage) update() error {
   107  	before := storage.trie.Root
   108  	if err := storage.buffer.updateTrie(storage.trie); err != nil {
   109  		return err
   110  	}
   111  	if !bytes.Equal(before, storage.trie.Root) {
   112  		logger.Debug().Str("before", enc.ToString(before)).
   113  			Str("after", enc.ToString(storage.trie.Root)).Msg("Changed storage trie root")
   114  		storage.dirty = true
   115  	}
   116  	return nil
   117  }
   118  
   119  func (storage *bufferedStorage) isDirty() bool {
   120  	return storage.dirty
   121  }
   122  
   123  func (storage *bufferedStorage) stage(txn trie.DbTx) error {
   124  	storage.trie.StageUpdates(txn)
   125  	if err := storage.buffer.stage(txn); err != nil {
   126  		return err
   127  	}
   128  	if err := storage.buffer.reset(); err != nil {
   129  		return err
   130  	}
   131  	return nil
   132  }