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 }