MM-30140 LRU critical section optimization (#16184)

* MM-30140 LRU critical section optimization

* Remove empty line

* Renamed lru function
Этот коммит содержится в:
Akshay Chhajed
2020-11-20 15:59:27 +05:30
коммит произвёл GitHub
родитель d274cf8afa
Коммит 26676953a4

35
services/cache/lru.go поставляемый
Просмотреть файл

@@ -79,16 +79,12 @@ func (l *LRU) SetWithDefaultExpiry(key string, value interface{}) error {
// SetWithExpiry adds the given key and value to the cache with the given expiry. If the key // SetWithExpiry adds the given key and value to the cache with the given expiry. If the key
// already exists, it will overwrite the previoous value // already exists, it will overwrite the previoous value
func (l *LRU) SetWithExpiry(key string, value interface{}, ttl time.Duration) error { func (l *LRU) SetWithExpiry(key string, value interface{}, ttl time.Duration) error {
l.lock.Lock()
defer l.lock.Unlock()
return l.set(key, value, ttl) return l.set(key, value, ttl)
} }
// Get the content stored in the cache for the given key, and decode it into the value interface. // Get the content stored in the cache for the given key, and decode it into the value interface.
// return ErrKeyNotFound if the key is missing from the cache // return ErrKeyNotFound if the key is missing from the cache
func (l *LRU) Get(key string, value interface{}) error { func (l *LRU) Get(key string, value interface{}) error {
l.lock.Lock()
defer l.lock.Unlock()
return l.get(key, value) return l.get(key, value)
} }
@@ -160,6 +156,9 @@ func (l *LRU) set(key string, value interface{}, ttl time.Duration) error {
} }
} }
l.lock.Lock()
defer l.lock.Unlock()
// Check for existing item, ignoring expiry since we'd update anyway. // Check for existing item, ignoring expiry since we'd update anyway.
if ent, ok := l.items[key]; ok { if ent, ok := l.items[key]; ok {
l.evictList.MoveToFront(ent) l.evictList.MoveToFront(ent)
@@ -186,16 +185,11 @@ func (l *LRU) set(key string, value interface{}, ttl time.Duration) error {
} }
func (l *LRU) get(key string, value interface{}) error { func (l *LRU) get(key string, value interface{}) error {
if ent, ok := l.items[key]; ok { e, err := l.getItem(key)
e := ent.Value.(*entry) if err != nil {
return err
if e.generation != l.currentGeneration || (!e.expires.IsZero() && time.Now().After(e.expires)) {
l.removeElement(ent)
return ErrKeyNotFound
} }
l.evictList.MoveToFront(ent)
// We use a fast path for hot structs. // We use a fast path for hot structs.
if msgpVal, ok := value.(msgp.Unmarshaler); ok { if msgpVal, ok := value.(msgp.Unmarshaler); ok {
_, err := msgpVal.UnmarshalMsg(e.value) _, err := msgpVal.UnmarshalMsg(e.value)
@@ -231,7 +225,22 @@ func (l *LRU) get(key string, value interface{}) error {
// Slow path for other structs. // Slow path for other structs.
return msgpack.Unmarshal(e.value, value) return msgpack.Unmarshal(e.value, value)
} }
return ErrKeyNotFound
func (l *LRU) getItem(key string) (*entry, error) {
l.lock.Lock()
defer l.lock.Unlock()
ent, ok := l.items[key]
if !ok {
return nil, ErrKeyNotFound
}
e := ent.Value.(*entry)
if e.generation != l.currentGeneration || (!e.expires.IsZero() && time.Now().After(e.expires)) {
l.removeElement(ent)
return nil, ErrKeyNotFound
}
l.evictList.MoveToFront(ent)
return e, nil
} }
func (l *LRU) removeElement(e *list.Element) { func (l *LRU) removeElement(e *list.Element) {