| package cache |
| |
| import ( |
| "container/list" |
| |
| "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 |
| } |
| |
| // 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} |
| } |
| |
| // 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) { |
| if c.cache == nil { |
| c.actualSize = 0 |
| c.cache = make(map[interface{}]*list.Element, 1000) |
| c.ll = list.New() |
| } |
| |
| key := obj.Hash() |
| if ee, ok := c.cache[key]; ok { |
| c.ll.MoveToFront(ee) |
| ee.Value = obj |
| return |
| } |
| |
| objSize := FileSize(obj.Size()) |
| |
| if objSize >= c.MaxSize { |
| return |
| } |
| |
| if c.actualSize+objSize > c.MaxSize { |
| last := c.ll.Back() |
| lastObj := last.Value.(plumbing.EncodedObject) |
| lastSize := FileSize(lastObj.Size()) |
| |
| c.ll.Remove(last) |
| delete(c.cache, lastObj.Hash()) |
| c.actualSize -= lastSize |
| |
| if c.actualSize+objSize > c.MaxSize { |
| return |
| } |
| } |
| |
| ee := c.ll.PushFront(obj) |
| c.cache[key] = ee |
| c.actualSize += objSize |
| } |
| |
| // 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) { |
| 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.ll = nil |
| c.cache = nil |
| c.actualSize = 0 |
| } |