| 
							- package cache
 - 
 - import (
 - 	"container/list"
 - 	"sync"
 - )
 - 
 - // BufferLRU implements an object cache with an LRU eviction policy and a
 - // maximum size (measured in object size).
 - type BufferLRU struct {
 - 	MaxSize FileSize
 - 
 - 	actualSize FileSize
 - 	ll         *list.List
 - 	cache      map[int64]*list.Element
 - 	mut        sync.Mutex
 - }
 - 
 - // NewBufferLRU creates a new BufferLRU with the given maximum size. The maximum
 - // size will never be exceeded.
 - func NewBufferLRU(maxSize FileSize) *BufferLRU {
 - 	return &BufferLRU{MaxSize: maxSize}
 - }
 - 
 - // NewBufferLRUDefault creates a new BufferLRU with the default cache size.
 - func NewBufferLRUDefault() *BufferLRU {
 - 	return &BufferLRU{MaxSize: DefaultMaxSize}
 - }
 - 
 - type buffer struct {
 - 	Key   int64
 - 	Slice []byte
 - }
 - 
 - // Put puts a buffer into the cache. If the buffer is already in the cache, it
 - // will be marked as used. Otherwise, it will be inserted. A buffers might
 - // be evicted to make room for the new one.
 - func (c *BufferLRU) Put(key int64, slice []byte) {
 - 	c.mut.Lock()
 - 	defer c.mut.Unlock()
 - 
 - 	if c.cache == nil {
 - 		c.actualSize = 0
 - 		c.cache = make(map[int64]*list.Element, 1000)
 - 		c.ll = list.New()
 - 	}
 - 
 - 	bufSize := FileSize(len(slice))
 - 	if ee, ok := c.cache[key]; ok {
 - 		oldBuf := ee.Value.(buffer)
 - 		// in this case bufSize is a delta: new size - old size
 - 		bufSize -= FileSize(len(oldBuf.Slice))
 - 		c.ll.MoveToFront(ee)
 - 		ee.Value = buffer{key, slice}
 - 	} else {
 - 		if bufSize > c.MaxSize {
 - 			return
 - 		}
 - 		ee := c.ll.PushFront(buffer{key, slice})
 - 		c.cache[key] = ee
 - 	}
 - 
 - 	c.actualSize += bufSize
 - 	for c.actualSize > c.MaxSize {
 - 		last := c.ll.Back()
 - 		lastObj := last.Value.(buffer)
 - 		lastSize := FileSize(len(lastObj.Slice))
 - 
 - 		c.ll.Remove(last)
 - 		delete(c.cache, lastObj.Key)
 - 		c.actualSize -= lastSize
 - 	}
 - }
 - 
 - // Get returns a buffer by its key. It marks the buffer as used. If the buffer
 - // is not in the cache, (nil, false) will be returned.
 - func (c *BufferLRU) Get(key int64) ([]byte, bool) {
 - 	c.mut.Lock()
 - 	defer c.mut.Unlock()
 - 
 - 	ee, ok := c.cache[key]
 - 	if !ok {
 - 		return nil, false
 - 	}
 - 
 - 	c.ll.MoveToFront(ee)
 - 	return ee.Value.(buffer).Slice, true
 - }
 - 
 - // Clear the content of this buffer cache.
 - func (c *BufferLRU) Clear() {
 - 	c.mut.Lock()
 - 	defer c.mut.Unlock()
 - 
 - 	c.ll = nil
 - 	c.cache = nil
 - 	c.actualSize = 0
 - }
 
 
  |