From 0e8ab3307dc499a958709985099dde5e64ebb8a2 Mon Sep 17 00:00:00 2001 From: renbiao Date: Wed, 28 Sep 2022 15:40:52 +0800 Subject: [PATCH] add bettermap instead of go map --- simplelru/bettermap.go | 106 +++++++++++++++++++++++++++++++++++++++++ simplelru/lru.go | 54 ++++++++++----------- 2 files changed, 131 insertions(+), 29 deletions(-) create mode 100644 simplelru/bettermap.go diff --git a/simplelru/bettermap.go b/simplelru/bettermap.go new file mode 100644 index 0000000..586c032 --- /dev/null +++ b/simplelru/bettermap.go @@ -0,0 +1,106 @@ +package simplelru + +type BetterMap struct { + firstMap map[interface{}]interface{} + secondMap map[interface{}]interface{} + deleteNumThresh int32 + totalDeleteNum int32 + useMapIndex int32 +} + +func NewBetterMap(deleteNumThresh int32) *BetterMap { + return &BetterMap{ + firstMap: make(map[interface{}]interface{}, 0), + secondMap: make(map[interface{}]interface{}, 0), + deleteNumThresh: deleteNumThresh, + totalDeleteNum: 0, + useMapIndex: 1, + } +} + +func (bmap *BetterMap) Set(key interface{}, value interface{}) { + if bmap.useMapIndex == 1 { + bmap.firstMap[key] = value + } else { + bmap.secondMap[key] = value + } + +} + +func (bmap *BetterMap) GetValue(key interface{}) (interface{}, bool) { + if value, ok := bmap.firstMap[key]; ok { + return value, ok + } + + value, ok := bmap.secondMap[key] + + return value, ok + +} + +func (bmap *BetterMap) GetValues() []interface{} { + values := make([]interface{}, 0) + if bmap.useMapIndex == 1 { + for _, value := range bmap.firstMap { + values = append(values, value) + } + } else { + for _, value := range bmap.secondMap { + values = append(values, value) + } + } + + return values +} + +func (bmap *BetterMap) GetMap() map[interface{}]interface{} { + if bmap.useMapIndex == 1 { + return bmap.firstMap + } + + return bmap.secondMap +} + +func (bmap *BetterMap) GetLen() int { + if bmap.useMapIndex == 1 { + return len(bmap.firstMap) + } + + return len(bmap.secondMap) +} + +func (bmap *BetterMap) Purge() { + bmap.firstMap = nil + bmap.secondMap = nil +} + +func (bmap *BetterMap) DelKey(key interface{}) { + if bmap.useMapIndex == 1 { + delete(bmap.firstMap, key) + bmap.totalDeleteNum++ + if bmap.totalDeleteNum >= bmap.deleteNumThresh { + bmap.secondMap = make(map[interface{}]interface{}, len(bmap.firstMap)) + for i, v := range bmap.firstMap { + bmap.secondMap[i] = v + } + + bmap.useMapIndex = 2 + bmap.totalDeleteNum = 0 + bmap.firstMap = nil + } + } else { + delete(bmap.secondMap, key) + bmap.totalDeleteNum++ + if bmap.totalDeleteNum >= bmap.deleteNumThresh { + bmap.firstMap = make(map[interface{}]interface{}, len(bmap.secondMap)) + for i, v := range bmap.secondMap { + bmap.firstMap[i] = v + } + + bmap.useMapIndex = 1 + bmap.totalDeleteNum = 0 + bmap.secondMap = nil + } + } + +} diff --git a/simplelru/lru.go b/simplelru/lru.go index 9233583..0410702 100644 --- a/simplelru/lru.go +++ b/simplelru/lru.go @@ -12,7 +12,8 @@ type EvictCallback func(key interface{}, value interface{}) type LRU struct { size int evictList *list.List - items map[interface{}]*list.Element + //items map[interface{}]*list.Element + betterMap *BetterMap onEvict EvictCallback } @@ -25,12 +26,12 @@ type entry struct { // NewLRU constructs an LRU of the given size func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { if size <= 0 { - return nil, errors.New("must provide a positive size") + return nil, errors.New("Must provide a positive size") } c := &LRU{ size: size, evictList: list.New(), - items: make(map[interface{}]*list.Element), + betterMap: NewBetterMap(int32(size)), onEvict: onEvict, } return c, nil @@ -38,29 +39,25 @@ func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { // Purge is used to completely clear the cache. func (c *LRU) Purge() { - for k, v := range c.items { - if c.onEvict != nil { - c.onEvict(k, v.Value.(*entry).value) - } - delete(c.items, k) - } + c.betterMap.Purge() + c.betterMap = NewBetterMap(int32(c.size)) c.evictList.Init() } // Add adds a value to the cache. Returns true if an eviction occurred. func (c *LRU) Add(key, value interface{}) (evicted bool) { // Check for existing item - if ent, ok := c.items[key]; ok { - c.evictList.MoveToFront(ent) - ent.Value.(*entry).value = value + if ent, ok := c.betterMap.GetValue(key); ok { + c.evictList.MoveToFront(ent.(*list.Element)) + + ent.(*list.Element).Value.(*entry).value = value return false } - // Add new item ent := &entry{key, value} entry := c.evictList.PushFront(ent) - c.items[key] = entry - + //c.items[key] = entry + c.betterMap.Set(key, entry) evict := c.evictList.Len() > c.size // Verify size not exceeded if evict { @@ -71,12 +68,10 @@ func (c *LRU) Add(key, value interface{}) (evicted bool) { // Get looks up a key's value from the cache. func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { - if ent, ok := c.items[key]; ok { - c.evictList.MoveToFront(ent) - if ent.Value.(*entry) == nil { - return nil, false - } - return ent.Value.(*entry).value, true + + if ent, ok := c.betterMap.GetValue(key); ok { + c.evictList.MoveToFront(ent.(*list.Element)) + return ent.(*list.Element).Value.(*entry).value, true } return } @@ -84,16 +79,16 @@ func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { // Contains checks if a key is in the cache, without updating the recent-ness // or deleting it for being stale. func (c *LRU) Contains(key interface{}) (ok bool) { - _, ok = c.items[key] + _, ok = c.betterMap.GetValue(key) return ok } // Peek returns the key value (or undefined if not found) without updating // the "recently used"-ness of the key. func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) { - var ent *list.Element - if ent, ok = c.items[key]; ok { - return ent.Value.(*entry).value, true + + if ent, ok := c.betterMap.GetValue(key); ok { + return ent.(*list.Element).Value.(*entry).value, true } return nil, ok } @@ -101,10 +96,11 @@ func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) { // Remove removes the provided key from the cache, returning if the // key was contained. func (c *LRU) Remove(key interface{}) (present bool) { - if ent, ok := c.items[key]; ok { - c.removeElement(ent) + if ent, ok := c.betterMap.GetValue(key); ok { + c.removeElement(ent.(*list.Element)) return true } + return false } @@ -131,7 +127,7 @@ func (c *LRU) GetOldest() (key, value interface{}, ok bool) { // Keys returns a slice of the keys in the cache, from oldest to newest. func (c *LRU) Keys() []interface{} { - keys := make([]interface{}, len(c.items)) + keys := make([]interface{}, c.betterMap.GetLen()) i := 0 for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() { keys[i] = ent.Value.(*entry).key @@ -170,7 +166,7 @@ func (c *LRU) removeOldest() { func (c *LRU) removeElement(e *list.Element) { c.evictList.Remove(e) kv := e.Value.(*entry) - delete(c.items, kv.key) + c.betterMap.DelKey(kv.key) if c.onEvict != nil { c.onEvict(kv.key, kv.value) }