package mempool import ( "container/list" tmsync "github.com/tendermint/tendermint/internal/libs/sync" "github.com/tendermint/tendermint/types" ) // TxCache defines an interface for raw transaction caching in a mempool. // Currently, a TxCache does not allow direct reading or getting of transaction // values. A TxCache is used primarily to push transactions and removing // transactions. Pushing via Push returns a boolean telling the caller if the // transaction already exists in the cache or not. type TxCache interface { // Reset resets the cache to an empty state. Reset() // Push adds the given raw transaction to the cache and returns true if it was // newly added. Otherwise, it returns false. Push(tx types.Tx) bool // Remove removes the given raw transaction from the cache. Remove(tx types.Tx) } var _ TxCache = (*LRUTxCache)(nil) // LRUTxCache maintains a thread-safe LRU cache of raw transactions. The cache // only stores the hash of the raw transaction. type LRUTxCache struct { mtx tmsync.Mutex size int cacheMap map[types.TxKey]*list.Element list *list.List } func NewLRUTxCache(cacheSize int) *LRUTxCache { return &LRUTxCache{ size: cacheSize, cacheMap: make(map[types.TxKey]*list.Element, cacheSize), list: list.New(), } } // GetList returns the underlying linked-list that backs the LRU cache. Note, // this should be used for testing purposes only! func (c *LRUTxCache) GetList() *list.List { return c.list } func (c *LRUTxCache) Reset() { c.mtx.Lock() defer c.mtx.Unlock() c.cacheMap = make(map[types.TxKey]*list.Element, c.size) c.list.Init() } func (c *LRUTxCache) Push(tx types.Tx) bool { c.mtx.Lock() defer c.mtx.Unlock() key := tx.Key() moved, ok := c.cacheMap[key] if ok { c.list.MoveToBack(moved) return false } if c.list.Len() >= c.size { front := c.list.Front() if front != nil { frontKey := front.Value.(types.TxKey) delete(c.cacheMap, frontKey) c.list.Remove(front) } } e := c.list.PushBack(key) c.cacheMap[key] = e return true } func (c *LRUTxCache) Remove(tx types.Tx) { c.mtx.Lock() defer c.mtx.Unlock() key := tx.Key() e := c.cacheMap[key] delete(c.cacheMap, key) if e != nil { c.list.Remove(e) } } // NopTxCache defines a no-op raw transaction cache. type NopTxCache struct{} var _ TxCache = (*NopTxCache)(nil) func (NopTxCache) Reset() {} func (NopTxCache) Push(types.Tx) bool { return true } func (NopTxCache) Remove(types.Tx) {}