|
- package cache
-
- import (
- "container/list"
- "sync"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- )
-
- // ObjectLRU implements an object cache with an LRU eviction policy and a
- // maximum size (measured in object size).
- type ObjectLRU struct {
- MaxSize FileSize
-
- actualSize FileSize
- ll *list.List
- cache map[interface{}]*list.Element
- mut sync.Mutex
- }
-
- // NewObjectLRU creates a new ObjectLRU with the given maximum size. The maximum
- // size will never be exceeded.
- func NewObjectLRU(maxSize FileSize) *ObjectLRU {
- return &ObjectLRU{MaxSize: maxSize}
- }
-
- // NewObjectLRUDefault creates a new ObjectLRU with the default cache size.
- func NewObjectLRUDefault() *ObjectLRU {
- return &ObjectLRU{MaxSize: DefaultMaxSize}
- }
-
- // Put puts an object into the cache. If the object is already in the cache, it
- // will be marked as used. Otherwise, it will be inserted. A single object might
- // be evicted to make room for the new object.
- func (c *ObjectLRU) Put(obj plumbing.EncodedObject) {
- c.mut.Lock()
- defer c.mut.Unlock()
-
- if c.cache == nil {
- c.actualSize = 0
- c.cache = make(map[interface{}]*list.Element, 1000)
- c.ll = list.New()
- }
-
- objSize := FileSize(obj.Size())
- key := obj.Hash()
- if ee, ok := c.cache[key]; ok {
- oldObj := ee.Value.(plumbing.EncodedObject)
- // in this case objSize is a delta: new size - old size
- objSize -= FileSize(oldObj.Size())
- c.ll.MoveToFront(ee)
- ee.Value = obj
- } else {
- if objSize > c.MaxSize {
- return
- }
- ee := c.ll.PushFront(obj)
- c.cache[key] = ee
- }
-
- c.actualSize += objSize
- for c.actualSize > c.MaxSize {
- last := c.ll.Back()
- if last == nil {
- c.actualSize = 0
- break
- }
-
- lastObj := last.Value.(plumbing.EncodedObject)
- lastSize := FileSize(lastObj.Size())
-
- c.ll.Remove(last)
- delete(c.cache, lastObj.Hash())
- c.actualSize -= lastSize
- }
- }
-
- // Get returns an object by its hash. It marks the object as used. If the object
- // is not in the cache, (nil, false) will be returned.
- func (c *ObjectLRU) Get(k plumbing.Hash) (plumbing.EncodedObject, bool) {
- c.mut.Lock()
- defer c.mut.Unlock()
-
- ee, ok := c.cache[k]
- if !ok {
- return nil, false
- }
-
- c.ll.MoveToFront(ee)
- return ee.Value.(plumbing.EncodedObject), true
- }
-
- // Clear the content of this object cache.
- func (c *ObjectLRU) Clear() {
- c.mut.Lock()
- defer c.mut.Unlock()
-
- c.ll = nil
- c.cache = nil
- c.actualSize = 0
- }
|