github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/p2p/trust/store.go (about) 1 // Copyright 2017 Tendermint. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package trust 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "sync" 10 "time" 11 12 dbm "github.com/tendermint/tm-db" 13 14 "github.com/tendermint/tendermint/libs/service" 15 ) 16 17 const defaultStorePeriodicSaveInterval = 1 * time.Minute 18 19 var trustMetricKey = []byte("trustMetricStore") 20 21 // MetricStore - Manages all trust metrics for peers 22 type MetricStore struct { 23 service.BaseService 24 25 // Maps a Peer.Key to that peer's TrustMetric 26 peerMetrics map[string]*Metric 27 28 // Mutex that protects the map and history data file 29 mtx sync.Mutex 30 31 // The db where peer trust metric history data will be stored 32 db dbm.DB 33 34 // This configuration will be used when creating new TrustMetrics 35 config MetricConfig 36 } 37 38 // NewTrustMetricStore returns a store that saves data to the DB 39 // and uses the config when creating new trust metrics. 40 // Use Start to to initialize the trust metric store 41 func NewTrustMetricStore(db dbm.DB, tmc MetricConfig) *MetricStore { 42 tms := &MetricStore{ 43 peerMetrics: make(map[string]*Metric), 44 db: db, 45 config: tmc, 46 } 47 48 tms.BaseService = *service.NewBaseService(nil, "MetricStore", tms) 49 return tms 50 } 51 52 // OnStart implements Service 53 func (tms *MetricStore) OnStart() error { 54 if err := tms.BaseService.OnStart(); err != nil { 55 return err 56 } 57 58 tms.mtx.Lock() 59 defer tms.mtx.Unlock() 60 61 tms.loadFromDB() 62 go tms.saveRoutine() 63 return nil 64 } 65 66 // OnStop implements Service 67 func (tms *MetricStore) OnStop() { 68 tms.BaseService.OnStop() 69 70 tms.mtx.Lock() 71 defer tms.mtx.Unlock() 72 73 // Stop all trust metric go-routines 74 for _, tm := range tms.peerMetrics { 75 tm.Stop() 76 } 77 78 // Make the final trust history data save 79 tms.saveToDB() 80 } 81 82 // Size returns the number of entries in the trust metric store 83 func (tms *MetricStore) Size() int { 84 tms.mtx.Lock() 85 defer tms.mtx.Unlock() 86 87 return tms.size() 88 } 89 90 // AddPeerTrustMetric takes an existing trust metric and associates it with a peer key. 91 // The caller is expected to call Start on the TrustMetric being added 92 func (tms *MetricStore) AddPeerTrustMetric(key string, tm *Metric) { 93 tms.mtx.Lock() 94 defer tms.mtx.Unlock() 95 96 if key == "" || tm == nil { 97 return 98 } 99 tms.peerMetrics[key] = tm 100 } 101 102 // GetPeerTrustMetric returns a trust metric by peer key 103 func (tms *MetricStore) GetPeerTrustMetric(key string) *Metric { 104 tms.mtx.Lock() 105 defer tms.mtx.Unlock() 106 107 tm, ok := tms.peerMetrics[key] 108 if !ok { 109 // If the metric is not available, we will create it 110 tm = NewMetricWithConfig(tms.config) 111 tm.Start() 112 // The metric needs to be in the map 113 tms.peerMetrics[key] = tm 114 } 115 return tm 116 } 117 118 // PeerDisconnected pauses the trust metric associated with the peer identified by the key 119 func (tms *MetricStore) PeerDisconnected(key string) { 120 tms.mtx.Lock() 121 defer tms.mtx.Unlock() 122 123 // If the Peer that disconnected has a metric, pause it 124 if tm, ok := tms.peerMetrics[key]; ok { 125 tm.Pause() 126 } 127 } 128 129 // Saves the history data for all peers to the store DB. 130 // This public method acquires the trust metric store lock 131 func (tms *MetricStore) SaveToDB() { 132 tms.mtx.Lock() 133 defer tms.mtx.Unlock() 134 135 tms.saveToDB() 136 } 137 138 /* Private methods */ 139 140 // size returns the number of entries in the store without acquiring the mutex 141 func (tms *MetricStore) size() int { 142 return len(tms.peerMetrics) 143 } 144 145 /* Loading & Saving */ 146 /* Both loadFromDB and savetoDB assume the mutex has been acquired */ 147 148 // Loads the history data for all peers from the store DB 149 // cmn.Panics if file is corrupt 150 func (tms *MetricStore) loadFromDB() bool { 151 // Obtain the history data we have so far 152 bytes, err := tms.db.Get(trustMetricKey) 153 if err != nil { 154 panic(err) 155 } 156 if bytes == nil { 157 return false 158 } 159 160 peers := make(map[string]MetricHistoryJSON) 161 err = json.Unmarshal(bytes, &peers) 162 if err != nil { 163 panic(fmt.Sprintf("Could not unmarshal Trust Metric Store DB data: %v", err)) 164 } 165 166 // If history data exists in the file, 167 // load it into trust metric 168 for key, p := range peers { 169 tm := NewMetricWithConfig(tms.config) 170 171 tm.Start() 172 tm.Init(p) 173 // Load the peer trust metric into the store 174 tms.peerMetrics[key] = tm 175 } 176 return true 177 } 178 179 // Saves the history data for all peers to the store DB 180 func (tms *MetricStore) saveToDB() { 181 tms.Logger.Debug("Saving TrustHistory to DB", "size", tms.size()) 182 183 peers := make(map[string]MetricHistoryJSON) 184 185 for key, tm := range tms.peerMetrics { 186 // Add an entry for the peer identified by key 187 peers[key] = tm.HistoryJSON() 188 } 189 190 // Write all the data back to the DB 191 bytes, err := json.Marshal(peers) 192 if err != nil { 193 tms.Logger.Error("Failed to encode the TrustHistory", "err", err) 194 return 195 } 196 tms.db.SetSync(trustMetricKey, bytes) 197 } 198 199 // Periodically saves the trust history data to the DB 200 func (tms *MetricStore) saveRoutine() { 201 t := time.NewTicker(defaultStorePeriodicSaveInterval) 202 defer t.Stop() 203 loop: 204 for { 205 select { 206 case <-t.C: 207 tms.SaveToDB() 208 case <-tms.Quit(): 209 break loop 210 } 211 } 212 }