github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/baseapp/gasuseddb.go (about)

     1  package baseapp
     2  
     3  import (
     4  	"encoding/binary"
     5  	"path/filepath"
     6  	"sync"
     7  
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  	db "github.com/fibonacci-chain/fbc/libs/tm-db"
    11  	lru "github.com/hashicorp/golang-lru"
    12  	"github.com/spf13/viper"
    13  )
    14  
    15  const (
    16  	HistoryGasUsedDbDir  = "data"
    17  	HistoryGasUsedDBName = "hgu"
    18  
    19  	FlagGasUsedFactor = "gu_factor"
    20  )
    21  
    22  var (
    23  	once          sync.Once
    24  	GasUsedFactor = 0.4
    25  	jobQueueLen   = 10
    26  	cacheSize     = 10000
    27  
    28  	historyGasUsedRecordDB HistoryGasUsedRecordDB
    29  )
    30  
    31  type gasKey struct {
    32  	gas int64
    33  	key string
    34  }
    35  
    36  type HistoryGasUsedRecordDB struct {
    37  	latestGuMtx sync.Mutex
    38  	latestGu    map[string]int64
    39  	cache       *lru.Cache
    40  	guDB        db.DB
    41  
    42  	jobQueue chan func()
    43  }
    44  
    45  func InstanceOfHistoryGasUsedRecordDB() *HistoryGasUsedRecordDB {
    46  	once.Do(func() {
    47  		cache, _ := lru.New(cacheSize)
    48  		historyGasUsedRecordDB = HistoryGasUsedRecordDB{
    49  			latestGu: make(map[string]int64),
    50  			cache:    cache,
    51  			guDB:     initDb(),
    52  			jobQueue: make(chan func(), jobQueueLen),
    53  		}
    54  		go historyGasUsedRecordDB.updateRoutine()
    55  	})
    56  	return &historyGasUsedRecordDB
    57  }
    58  
    59  func (h *HistoryGasUsedRecordDB) UpdateGasUsed(key []byte, gasUsed int64) {
    60  	h.latestGuMtx.Lock()
    61  	h.latestGu[string(key)] = gasUsed
    62  	h.latestGuMtx.Unlock()
    63  }
    64  
    65  func (h *HistoryGasUsedRecordDB) GetHgu(key []byte) int64 {
    66  	hgu, cacheHit := h.getHgu(key)
    67  	if !cacheHit && hgu != -1 {
    68  		// add to cache before returning hgu
    69  		h.cache.Add(string(key), hgu)
    70  	}
    71  	return hgu
    72  }
    73  
    74  func (h *HistoryGasUsedRecordDB) FlushHgu() {
    75  	if len(h.latestGu) == 0 {
    76  		return
    77  	}
    78  	latestGasKeys := make([]gasKey, len(h.latestGu))
    79  	for key, gas := range h.latestGu {
    80  		latestGasKeys = append(latestGasKeys, gasKey{
    81  			gas: gas,
    82  			key: key,
    83  		})
    84  		delete(h.latestGu, key)
    85  	}
    86  	h.jobQueue <- func() { h.flushHgu(latestGasKeys...) } // closure
    87  }
    88  
    89  func (h *HistoryGasUsedRecordDB) getHgu(key []byte) (hgu int64, fromCache bool) {
    90  	v, ok := h.cache.Get(string(key))
    91  	if ok {
    92  		return v.(int64), true
    93  	}
    94  
    95  	data, err := h.guDB.Get(key)
    96  	if err != nil || len(data) == 0 {
    97  		return -1, false
    98  	}
    99  
   100  	return bytesToInt64(data), false
   101  }
   102  
   103  func (h *HistoryGasUsedRecordDB) flushHgu(gks ...gasKey) {
   104  	for _, gk := range gks {
   105  		hgu, cacheHit := h.getHgu([]byte(gk.key))
   106  		// avgGas = 0.4 * newGas + 0.6 * oldGas
   107  		avgGas := int64(GasUsedFactor*float64(gk.gas) + (1.0-GasUsedFactor)*float64(hgu))
   108  		// add to cache if hit
   109  		if cacheHit {
   110  			h.cache.Add(gk.key, avgGas)
   111  		}
   112  		h.guDB.Set([]byte(gk.key), int64ToBytes(avgGas))
   113  	}
   114  }
   115  
   116  func (h *HistoryGasUsedRecordDB) updateRoutine() {
   117  	for job := range h.jobQueue {
   118  		job()
   119  	}
   120  }
   121  
   122  func initDb() db.DB {
   123  	homeDir := viper.GetString(flags.FlagHome)
   124  	dbPath := filepath.Join(homeDir, HistoryGasUsedDbDir)
   125  
   126  	db, err := sdk.NewDB(HistoryGasUsedDBName, dbPath)
   127  	if err != nil {
   128  		panic(err)
   129  	}
   130  	return db
   131  }
   132  
   133  func int64ToBytes(i int64) []byte {
   134  	var buf = make([]byte, 8)
   135  	binary.BigEndian.PutUint64(buf, uint64(i))
   136  	return buf
   137  }
   138  
   139  func bytesToInt64(buf []byte) int64 {
   140  	return int64(binary.BigEndian.Uint64(buf))
   141  }