本站源代码
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.

102 lines
2.3KB

  1. package cache
  2. import (
  3. "container/list"
  4. "sync"
  5. "gopkg.in/src-d/go-git.v4/plumbing"
  6. )
  7. // ObjectLRU implements an object cache with an LRU eviction policy and a
  8. // maximum size (measured in object size).
  9. type ObjectLRU struct {
  10. MaxSize FileSize
  11. actualSize FileSize
  12. ll *list.List
  13. cache map[interface{}]*list.Element
  14. mut sync.Mutex
  15. }
  16. // NewObjectLRU creates a new ObjectLRU with the given maximum size. The maximum
  17. // size will never be exceeded.
  18. func NewObjectLRU(maxSize FileSize) *ObjectLRU {
  19. return &ObjectLRU{MaxSize: maxSize}
  20. }
  21. // NewObjectLRUDefault creates a new ObjectLRU with the default cache size.
  22. func NewObjectLRUDefault() *ObjectLRU {
  23. return &ObjectLRU{MaxSize: DefaultMaxSize}
  24. }
  25. // Put puts an object into the cache. If the object is already in the cache, it
  26. // will be marked as used. Otherwise, it will be inserted. A single object might
  27. // be evicted to make room for the new object.
  28. func (c *ObjectLRU) Put(obj plumbing.EncodedObject) {
  29. c.mut.Lock()
  30. defer c.mut.Unlock()
  31. if c.cache == nil {
  32. c.actualSize = 0
  33. c.cache = make(map[interface{}]*list.Element, 1000)
  34. c.ll = list.New()
  35. }
  36. objSize := FileSize(obj.Size())
  37. key := obj.Hash()
  38. if ee, ok := c.cache[key]; ok {
  39. oldObj := ee.Value.(plumbing.EncodedObject)
  40. // in this case objSize is a delta: new size - old size
  41. objSize -= FileSize(oldObj.Size())
  42. c.ll.MoveToFront(ee)
  43. ee.Value = obj
  44. } else {
  45. if objSize > c.MaxSize {
  46. return
  47. }
  48. ee := c.ll.PushFront(obj)
  49. c.cache[key] = ee
  50. }
  51. c.actualSize += objSize
  52. for c.actualSize > c.MaxSize {
  53. last := c.ll.Back()
  54. if last == nil {
  55. c.actualSize = 0
  56. break
  57. }
  58. lastObj := last.Value.(plumbing.EncodedObject)
  59. lastSize := FileSize(lastObj.Size())
  60. c.ll.Remove(last)
  61. delete(c.cache, lastObj.Hash())
  62. c.actualSize -= lastSize
  63. }
  64. }
  65. // Get returns an object by its hash. It marks the object as used. If the object
  66. // is not in the cache, (nil, false) will be returned.
  67. func (c *ObjectLRU) Get(k plumbing.Hash) (plumbing.EncodedObject, bool) {
  68. c.mut.Lock()
  69. defer c.mut.Unlock()
  70. ee, ok := c.cache[k]
  71. if !ok {
  72. return nil, false
  73. }
  74. c.ll.MoveToFront(ee)
  75. return ee.Value.(plumbing.EncodedObject), true
  76. }
  77. // Clear the content of this object cache.
  78. func (c *ObjectLRU) Clear() {
  79. c.mut.Lock()
  80. defer c.mut.Unlock()
  81. c.ll = nil
  82. c.cache = nil
  83. c.actualSize = 0
  84. }
上海开阖软件有限公司 沪ICP备12045867号-1