mirror of https://github.com/prometheus/prometheus
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.
176 lines
3.6 KiB
176 lines
3.6 KiB
// Copyright 2013 Prometheus Team |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
package utility |
|
|
|
import ( |
|
"container/list" |
|
"sync" |
|
) |
|
|
|
type Cache interface { |
|
Put(k, v interface{}) (replaced bool, err error) |
|
PutIfAbsent(k, v interface{}) (put bool, err error) |
|
Get(k interface{}) (v interface{}, ok bool, err error) |
|
Has(k interface{}) (ok bool, err error) |
|
Delete(k interface{}) (deleted bool, err error) |
|
Clear() (cleared bool, err error) |
|
} |
|
|
|
type LRUCache struct { |
|
list *list.List |
|
table map[interface{}]*list.Element |
|
|
|
limit uint |
|
size uint |
|
} |
|
|
|
func NewLRUCache(limit uint) *LRUCache { |
|
return &LRUCache{ |
|
list: list.New(), |
|
table: map[interface{}]*list.Element{}, |
|
|
|
limit: limit, |
|
} |
|
} |
|
|
|
func (c *LRUCache) Has(k interface{}) (has bool, err error) { |
|
_, ok := c.table[k] |
|
return ok, nil |
|
} |
|
|
|
func (c *LRUCache) Get(k interface{}) (v interface{}, ok bool, err error) { |
|
element, ok := c.table[k] |
|
if !ok { |
|
return nil, false, nil |
|
} |
|
|
|
c.moveToFront(element) |
|
|
|
return element.Value, true, nil |
|
} |
|
|
|
func (c *LRUCache) Put(k, v interface{}) (replaced bool, err error) { |
|
element, ok := c.table[k] |
|
if ok { |
|
c.updateInplace(element, v) |
|
return true, nil |
|
} |
|
|
|
c.addNew(k, v) |
|
return false, nil |
|
} |
|
|
|
func (c *LRUCache) PutIfAbsent(k, v interface{}) (put bool, err error) { |
|
if _, ok := c.table[k]; ok { |
|
return false, nil |
|
} |
|
|
|
c.addNew(k, v) |
|
return true, nil |
|
} |
|
|
|
func (c *LRUCache) Delete(k interface{}) (deleted bool, err error) { |
|
element, ok := c.table[k] |
|
if !ok { |
|
return false, nil |
|
} |
|
|
|
c.list.Remove(element) |
|
delete(c.table, k) |
|
|
|
return true, nil |
|
} |
|
|
|
func (c *LRUCache) Clear() (cleared bool, err error) { |
|
c.list.Init() |
|
c.table = map[interface{}]*list.Element{} |
|
c.size = 0 |
|
|
|
return true, nil |
|
} |
|
|
|
func (c *LRUCache) updateInplace(e *list.Element, v interface{}) { |
|
e.Value = v |
|
c.moveToFront(e) |
|
c.checkCapacity() |
|
} |
|
|
|
func (c *LRUCache) moveToFront(e *list.Element) { |
|
c.list.MoveToFront(e) |
|
} |
|
|
|
func (c *LRUCache) addNew(k, v interface{}) { |
|
c.table[k] = c.list.PushFront(v) |
|
c.checkCapacity() |
|
} |
|
|
|
func (c *LRUCache) checkCapacity() { |
|
for c.size > c.limit { |
|
delElem := c.list.Back() |
|
v := delElem.Value |
|
c.list.Remove(delElem) |
|
delete(c.table, v) |
|
} |
|
} |
|
|
|
type SynchronizedCache struct { |
|
mu sync.Mutex |
|
c Cache |
|
} |
|
|
|
func (c *SynchronizedCache) Put(k, v interface{}) (replaced bool, err error) { |
|
c.mu.Lock() |
|
defer c.mu.Unlock() |
|
|
|
return c.c.Put(k, v) |
|
} |
|
func (c *SynchronizedCache) PutIfAbsent(k, v interface{}) (put bool, err error) { |
|
c.mu.Lock() |
|
defer c.mu.Unlock() |
|
|
|
return c.PutIfAbsent(k, v) |
|
} |
|
|
|
func (c *SynchronizedCache) Get(k interface{}) (v interface{}, ok bool, err error) { |
|
c.mu.Lock() |
|
defer c.mu.Unlock() |
|
|
|
return c.c.Get(k) |
|
} |
|
func (c *SynchronizedCache) Has(k interface{}) (ok bool, err error) { |
|
c.mu.Lock() |
|
defer c.mu.Unlock() |
|
|
|
return c.c.Has(k) |
|
} |
|
|
|
func (c *SynchronizedCache) Delete(k interface{}) (deleted bool, err error) { |
|
c.mu.Lock() |
|
defer c.mu.Unlock() |
|
|
|
return c.c.Delete(k) |
|
} |
|
|
|
func (c *SynchronizedCache) Clear() (cleared bool, err error) { |
|
c.mu.Lock() |
|
defer c.mu.Unlock() |
|
|
|
return c.c.Clear() |
|
} |
|
|
|
func NewSynchronizedCache(c Cache) *SynchronizedCache { |
|
return &SynchronizedCache{ |
|
c: c, |
|
} |
|
}
|
|
|