mempool: Keep cache hashmap and linked list in sync (#2188)

* mempool: Keep cache hashmap and linked list in sync

This removes bugs with the linked list being full, but hashmap empty

* address PR comments

* switch clist back to list
This commit is contained in:
Dev Ojha
2018-08-13 03:42:33 -07:00
committed by Anton Kaliaev
parent 9c6fdad276
commit 8a1a79257e
3 changed files with 67 additions and 8 deletions

View File

@@ -488,7 +488,7 @@ type txCache interface {
type mapTxCache struct {
mtx sync.Mutex
size int
map_ map[string]struct{}
map_ map[string]*list.Element
list *list.List // to remove oldest tx when cache gets too big
}
@@ -498,7 +498,7 @@ var _ txCache = (*mapTxCache)(nil)
func newMapTxCache(cacheSize int) *mapTxCache {
return &mapTxCache{
size: cacheSize,
map_: make(map[string]struct{}, cacheSize),
map_: make(map[string]*list.Element, cacheSize),
list: list.New(),
}
}
@@ -506,7 +506,7 @@ func newMapTxCache(cacheSize int) *mapTxCache {
// Reset resets the cache to an empty state.
func (cache *mapTxCache) Reset() {
cache.mtx.Lock()
cache.map_ = make(map[string]struct{}, cache.size)
cache.map_ = make(map[string]*list.Element, cache.size)
cache.list.Init()
cache.mtx.Unlock()
}
@@ -524,20 +524,26 @@ func (cache *mapTxCache) Push(tx types.Tx) bool {
if cache.list.Len() >= cache.size {
popped := cache.list.Front()
poppedTx := popped.Value.(types.Tx)
// NOTE: the tx may have already been removed from the map
// but deleting a non-existent element is fine
delete(cache.map_, string(poppedTx))
cache.list.Remove(popped)
if popped != nil {
cache.list.Remove(popped)
}
}
cache.map_[string(tx)] = struct{}{}
cache.list.PushBack(tx)
cache.map_[string(tx)] = cache.list.Back()
return true
}
// Remove removes the given tx from the cache.
func (cache *mapTxCache) Remove(tx types.Tx) {
cache.mtx.Lock()
delete(cache.map_, string(tx))
stx := string(tx)
popped := cache.map_[stx]
delete(cache.map_, stx)
if popped != nil {
cache.list.Remove(popped)
}
cache.mtx.Unlock()
}