You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
2.4 KiB

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