aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/cache/object_lru.go
diff options
context:
space:
mode:
authorSantiago M. Mola <santi@mola.io>2017-07-24 14:19:21 +0200
committerSantiago M. Mola <santi@mola.io>2017-07-27 14:22:40 +0200
commitae1c4f3df729c3a7fed4cd5a1f530c95d640497a (patch)
treea1468ab8a942435435c644abdc9bac3338990bc2 /plumbing/cache/object_lru.go
parentb3fc7760ba332306bb1faa64c8a101a2e605077f (diff)
downloadgo-git-ae1c4f3df729c3a7fed4cd5a1f530c95d640497a.tar.gz
plumbing/cache: change FIFO to LRU cache
Diffstat (limited to 'plumbing/cache/object_lru.go')
-rw-r--r--plumbing/cache/object_lru.go84
1 files changed, 84 insertions, 0 deletions
diff --git a/plumbing/cache/object_lru.go b/plumbing/cache/object_lru.go
new file mode 100644
index 0000000..e4c3160
--- /dev/null
+++ b/plumbing/cache/object_lru.go
@@ -0,0 +1,84 @@
+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
+}