aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/allegro/bigcache/iterator.go
blob: 70b98d900435b76d7947ad5fbe3255bf6f18dee2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package bigcache

import "sync"

type iteratorError string

func (e iteratorError) Error() string {
    return string(e)
}

// ErrInvalidIteratorState is reported when iterator is in invalid state
const ErrInvalidIteratorState = iteratorError("Iterator is in invalid state. Use SetNext() to move to next position")

// ErrCannotRetrieveEntry is reported when entry cannot be retrieved from underlying
const ErrCannotRetrieveEntry = iteratorError("Could not retrieve entry from cache")

var emptyEntryInfo = EntryInfo{}

// EntryInfo holds informations about entry in the cache
type EntryInfo struct {
    timestamp uint64
    hash      uint64
    key       string
    value     []byte
}

// Key returns entry's underlying key
func (e EntryInfo) Key() string {
    return e.key
}

// Hash returns entry's hash value
func (e EntryInfo) Hash() uint64 {
    return e.hash
}

// Timestamp returns entry's timestamp (time of insertion)
func (e EntryInfo) Timestamp() uint64 {
    return e.timestamp
}

// Value returns entry's underlying value
func (e EntryInfo) Value() []byte {
    return e.value
}

// EntryInfoIterator allows to iterate over entries in the cache
type EntryInfoIterator struct {
    mutex         sync.Mutex
    cache         *BigCache
    currentShard  int
    currentIndex  int
    elements      []uint32
    elementsCount int
    valid         bool
}

// SetNext moves to next element and returns true if it exists.
func (it *EntryInfoIterator) SetNext() bool {
    it.mutex.Lock()

    it.valid = false
    it.currentIndex++

    if it.elementsCount > it.currentIndex {
        it.valid = true
        it.mutex.Unlock()
        return true
    }

    for i := it.currentShard + 1; i < it.cache.config.Shards; i++ {
        it.elements, it.elementsCount = it.cache.shards[i].copyKeys()

        // Non empty shard - stick with it
        if it.elementsCount > 0 {
            it.currentIndex = 0
            it.currentShard = i
            it.valid = true
            it.mutex.Unlock()
            return true
        }
    }
    it.mutex.Unlock()
    return false
}

func newIterator(cache *BigCache) *EntryInfoIterator {
    elements, count := cache.shards[0].copyKeys()

    return &EntryInfoIterator{
        cache:         cache,
        currentShard:  0,
        currentIndex:  -1,
        elements:      elements,
        elementsCount: count,
    }
}

// Value returns current value from the iterator
func (it *EntryInfoIterator) Value() (EntryInfo, error) {
    it.mutex.Lock()

    if !it.valid {
        it.mutex.Unlock()
        return emptyEntryInfo, ErrInvalidIteratorState
    }

    entry, err := it.cache.shards[it.currentShard].getEntry(int(it.elements[it.currentIndex]))

    if err != nil {
        it.mutex.Unlock()
        return emptyEntryInfo, ErrCannotRetrieveEntry
    }
    it.mutex.Unlock()

    return EntryInfo{
        timestamp: readTimestampFromEntry(entry),
        hash:      readHashFromEntry(entry),
        key:       readKeyFromEntry(entry),
        value:     readEntry(entry),
    }, nil
}