github.com/Oyster-zx/tendermint@v0.34.24-fork/mempool/cache.go (about) 1 package mempool 2 3 import ( 4 "container/list" 5 6 tmsync "github.com/tendermint/tendermint/libs/sync" 7 "github.com/tendermint/tendermint/types" 8 ) 9 10 // TxCache defines an interface for raw transaction caching in a mempool. 11 // Currently, a TxCache does not allow direct reading or getting of transaction 12 // values. A TxCache is used primarily to push transactions and removing 13 // transactions. Pushing via Push returns a boolean telling the caller if the 14 // transaction already exists in the cache or not. 15 type TxCache interface { 16 // Reset resets the cache to an empty state. 17 Reset() 18 19 // Push adds the given raw transaction to the cache and returns true if it was 20 // newly added. Otherwise, it returns false. 21 Push(tx types.Tx) bool 22 23 // Remove removes the given raw transaction from the cache. 24 Remove(tx types.Tx) 25 26 // Has reports whether tx is present in the cache. Checking for presence is 27 // not treated as an access of the value. 28 Has(tx types.Tx) bool 29 } 30 31 var _ TxCache = (*LRUTxCache)(nil) 32 33 // LRUTxCache maintains a thread-safe LRU cache of raw transactions. The cache 34 // only stores the hash of the raw transaction. 35 type LRUTxCache struct { 36 mtx tmsync.Mutex 37 size int 38 cacheMap map[types.TxKey]*list.Element 39 list *list.List 40 } 41 42 func NewLRUTxCache(cacheSize int) *LRUTxCache { 43 return &LRUTxCache{ 44 size: cacheSize, 45 cacheMap: make(map[types.TxKey]*list.Element, cacheSize), 46 list: list.New(), 47 } 48 } 49 50 // GetList returns the underlying linked-list that backs the LRU cache. Note, 51 // this should be used for testing purposes only! 52 func (c *LRUTxCache) GetList() *list.List { 53 return c.list 54 } 55 56 func (c *LRUTxCache) Reset() { 57 c.mtx.Lock() 58 defer c.mtx.Unlock() 59 60 c.cacheMap = make(map[types.TxKey]*list.Element, c.size) 61 c.list.Init() 62 } 63 64 func (c *LRUTxCache) Push(tx types.Tx) bool { 65 c.mtx.Lock() 66 defer c.mtx.Unlock() 67 68 key := tx.Key() 69 70 moved, ok := c.cacheMap[key] 71 if ok { 72 c.list.MoveToBack(moved) 73 return false 74 } 75 76 if c.list.Len() >= c.size { 77 front := c.list.Front() 78 if front != nil { 79 frontKey := front.Value.(types.TxKey) 80 delete(c.cacheMap, frontKey) 81 c.list.Remove(front) 82 } 83 } 84 85 e := c.list.PushBack(key) 86 c.cacheMap[key] = e 87 88 return true 89 } 90 91 func (c *LRUTxCache) Remove(tx types.Tx) { 92 c.mtx.Lock() 93 defer c.mtx.Unlock() 94 95 key := tx.Key() 96 e := c.cacheMap[key] 97 delete(c.cacheMap, key) 98 99 if e != nil { 100 c.list.Remove(e) 101 } 102 } 103 104 func (c *LRUTxCache) Has(tx types.Tx) bool { 105 c.mtx.Lock() 106 defer c.mtx.Unlock() 107 108 _, ok := c.cacheMap[tx.Key()] 109 return ok 110 } 111 112 // NopTxCache defines a no-op raw transaction cache. 113 type NopTxCache struct{} 114 115 var _ TxCache = (*NopTxCache)(nil) 116 117 func (NopTxCache) Reset() {} 118 func (NopTxCache) Push(types.Tx) bool { return true } 119 func (NopTxCache) Remove(types.Tx) {} 120 func (NopTxCache) Has(types.Tx) bool { return false }