iterator.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package bigcache
  2. import "sync"
  3. type iteratorError string
  4. func (e iteratorError) Error() string {
  5. return string(e)
  6. }
  7. // ErrInvalidIteratorState is reported when iterator is in invalid state
  8. const ErrInvalidIteratorState = iteratorError("Iterator is in invalid state. Use SetNext() to move to next position")
  9. // ErrCannotRetrieveEntry is reported when entry cannot be retrieved from underlying
  10. const ErrCannotRetrieveEntry = iteratorError("Could not retrieve entry from cache")
  11. var emptyEntryInfo = EntryInfo{}
  12. // EntryInfo holds informations about entry in the cache
  13. type EntryInfo struct {
  14. timestamp uint64
  15. hash uint64
  16. key string
  17. value []byte
  18. }
  19. // Key returns entry's underlying key
  20. func (e EntryInfo) Key() string {
  21. return e.key
  22. }
  23. // Hash returns entry's hash value
  24. func (e EntryInfo) Hash() uint64 {
  25. return e.hash
  26. }
  27. // Timestamp returns entry's timestamp (time of insertion)
  28. func (e EntryInfo) Timestamp() uint64 {
  29. return e.timestamp
  30. }
  31. // Value returns entry's underlying value
  32. func (e EntryInfo) Value() []byte {
  33. return e.value
  34. }
  35. // EntryInfoIterator allows to iterate over entries in the cache
  36. type EntryInfoIterator struct {
  37. mutex sync.Mutex
  38. cache *BigCache
  39. currentShard int
  40. currentIndex int
  41. elements []uint32
  42. elementsCount int
  43. valid bool
  44. }
  45. // SetNext moves to next element and returns true if it exists.
  46. func (it *EntryInfoIterator) SetNext() bool {
  47. it.mutex.Lock()
  48. it.valid = false
  49. it.currentIndex++
  50. if it.elementsCount > it.currentIndex {
  51. it.valid = true
  52. it.mutex.Unlock()
  53. return true
  54. }
  55. for i := it.currentShard + 1; i < it.cache.config.Shards; i++ {
  56. it.elements, it.elementsCount = it.cache.shards[i].copyKeys()
  57. // Non empty shard - stick with it
  58. if it.elementsCount > 0 {
  59. it.currentIndex = 0
  60. it.currentShard = i
  61. it.valid = true
  62. it.mutex.Unlock()
  63. return true
  64. }
  65. }
  66. it.mutex.Unlock()
  67. return false
  68. }
  69. func newIterator(cache *BigCache) *EntryInfoIterator {
  70. elements, count := cache.shards[0].copyKeys()
  71. return &EntryInfoIterator{
  72. cache: cache,
  73. currentShard: 0,
  74. currentIndex: -1,
  75. elements: elements,
  76. elementsCount: count,
  77. }
  78. }
  79. // Value returns current value from the iterator
  80. func (it *EntryInfoIterator) Value() (EntryInfo, error) {
  81. it.mutex.Lock()
  82. if !it.valid {
  83. it.mutex.Unlock()
  84. return emptyEntryInfo, ErrInvalidIteratorState
  85. }
  86. entry, err := it.cache.shards[it.currentShard].getEntry(int(it.elements[it.currentIndex]))
  87. if err != nil {
  88. it.mutex.Unlock()
  89. return emptyEntryInfo, ErrCannotRetrieveEntry
  90. }
  91. it.mutex.Unlock()
  92. return EntryInfo{
  93. timestamp: readTimestampFromEntry(entry),
  94. hash: readHashFromEntry(entry),
  95. key: readKeyFromEntry(entry),
  96. value: readEntry(entry),
  97. }, nil
  98. }