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.

buffer_lru.go 2.2KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package cache
  2. import (
  3. "container/list"
  4. "sync"
  5. )
  6. // BufferLRU implements an object cache with an LRU eviction policy and a
  7. // maximum size (measured in object size).
  8. type BufferLRU struct {
  9. MaxSize FileSize
  10. actualSize FileSize
  11. ll *list.List
  12. cache map[int64]*list.Element
  13. mut sync.Mutex
  14. }
  15. // NewBufferLRU creates a new BufferLRU with the given maximum size. The maximum
  16. // size will never be exceeded.
  17. func NewBufferLRU(maxSize FileSize) *BufferLRU {
  18. return &BufferLRU{MaxSize: maxSize}
  19. }
  20. // NewBufferLRUDefault creates a new BufferLRU with the default cache size.
  21. func NewBufferLRUDefault() *BufferLRU {
  22. return &BufferLRU{MaxSize: DefaultMaxSize}
  23. }
  24. type buffer struct {
  25. Key int64
  26. Slice []byte
  27. }
  28. // Put puts a buffer into the cache. If the buffer is already in the cache, it
  29. // will be marked as used. Otherwise, it will be inserted. A buffers might
  30. // be evicted to make room for the new one.
  31. func (c *BufferLRU) Put(key int64, slice []byte) {
  32. c.mut.Lock()
  33. defer c.mut.Unlock()
  34. if c.cache == nil {
  35. c.actualSize = 0
  36. c.cache = make(map[int64]*list.Element, 1000)
  37. c.ll = list.New()
  38. }
  39. bufSize := FileSize(len(slice))
  40. if ee, ok := c.cache[key]; ok {
  41. oldBuf := ee.Value.(buffer)
  42. // in this case bufSize is a delta: new size - old size
  43. bufSize -= FileSize(len(oldBuf.Slice))
  44. c.ll.MoveToFront(ee)
  45. ee.Value = buffer{key, slice}
  46. } else {
  47. if bufSize > c.MaxSize {
  48. return
  49. }
  50. ee := c.ll.PushFront(buffer{key, slice})
  51. c.cache[key] = ee
  52. }
  53. c.actualSize += bufSize
  54. for c.actualSize > c.MaxSize {
  55. last := c.ll.Back()
  56. lastObj := last.Value.(buffer)
  57. lastSize := FileSize(len(lastObj.Slice))
  58. c.ll.Remove(last)
  59. delete(c.cache, lastObj.Key)
  60. c.actualSize -= lastSize
  61. }
  62. }
  63. // Get returns a buffer by its key. It marks the buffer as used. If the buffer
  64. // is not in the cache, (nil, false) will be returned.
  65. func (c *BufferLRU) Get(key int64) ([]byte, bool) {
  66. c.mut.Lock()
  67. defer c.mut.Unlock()
  68. ee, ok := c.cache[key]
  69. if !ok {
  70. return nil, false
  71. }
  72. c.ll.MoveToFront(ee)
  73. return ee.Value.(buffer).Slice, true
  74. }
  75. // Clear the content of this buffer cache.
  76. func (c *BufferLRU) Clear() {
  77. c.mut.Lock()
  78. defer c.mut.Unlock()
  79. c.ll = nil
  80. c.cache = nil
  81. c.actualSize = 0
  82. }