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[[TxKeySize]byte]*list.Element
|
|
list *list.List
|
|
}
|
|
|
|
func NewLRUTxCache(cacheSize int) *LRUTxCache {
|
|
return &LRUTxCache{
|
|
size: cacheSize,
|
|
cacheMap: make(map[[TxKeySize]byte]*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[[TxKeySize]byte]*list.Element, c.size)
|
|
c.list.Init()
|
|
}
|
|
|
|
func (c *LRUTxCache) Push(tx types.Tx) bool {
|
|
c.mtx.Lock()
|
|
defer c.mtx.Unlock()
|
|
|
|
key := TxKey(tx)
|
|
|
|
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.([TxKeySize]byte)
|
|
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 := TxKey(tx)
|
|
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) {}
|