123 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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
 | 
						|
}
 |