File: iterator.go

package info (click to toggle)
golang-github-allegro-bigcache 3.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 380 kB
  • sloc: makefile: 6
file content (146 lines) | stat: -rw-r--r-- 3,232 bytes parent folder | download | duplicates (3)
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
	err       error
}

// 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
	currentEntryInfo EntryInfo
	elements         []uint64
	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

		empty := it.setCurrentEntry()
		it.mutex.Unlock()

		if empty {
			return it.SetNext()
		}
		return true
	}

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

		// Non empty shard - stick with it
		if it.elementsCount > 0 {
			it.currentIndex = 0
			it.currentShard = i
			it.valid = true

			empty := it.setCurrentEntry()
			it.mutex.Unlock()

			if empty {
				return it.SetNext()
			}
			return true
		}
	}
	it.mutex.Unlock()
	return false
}

func (it *EntryInfoIterator) setCurrentEntry() bool {
	var entryNotFound = false
	entry, err := it.cache.shards[it.currentShard].getEntry(it.elements[it.currentIndex])

	if err == ErrEntryNotFound {
		it.currentEntryInfo = emptyEntryInfo
		entryNotFound = true
	} else if err != nil {
		it.currentEntryInfo = EntryInfo{
			err: err,
		}
	} else {
		it.currentEntryInfo = EntryInfo{
			timestamp: readTimestampFromEntry(entry),
			hash:      readHashFromEntry(entry),
			key:       readKeyFromEntry(entry),
			value:     readEntry(entry),
			err:       err,
		}
	}

	return entryNotFound
}

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

	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) {
	if !it.valid {
		return emptyEntryInfo, ErrInvalidIteratorState
	}

	return it.currentEntryInfo, it.currentEntryInfo.err
}