aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/allegro/bigcache/iterator.go
blob: 70b98d900435b76d7947ad5fbe3255bf6f18dee2 (plain) (tree)

























































































































                                                                                                                     
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
}