From 992a7bbad531b9f44e84dfe5a779e7a6146d194d Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 18 Feb 2019 09:15:55 +0100 Subject: vendor: update bigcache (cherry picked from commit 37e5a908e7368d84beef14a3ee8c534f34aa636f) --- vendor/github.com/allegro/bigcache/bigcache.go | 2 +- .../allegro/bigcache/entry_not_found_error.go | 17 ++------- .../allegro/bigcache/queue/bytes_queue.go | 34 ++++++++++++++++-- vendor/github.com/allegro/bigcache/shard.go | 41 +++++++++++++++++----- 4 files changed, 67 insertions(+), 27 deletions(-) (limited to 'vendor/github.com') diff --git a/vendor/github.com/allegro/bigcache/bigcache.go b/vendor/github.com/allegro/bigcache/bigcache.go index e6aee8663..b3879264a 100644 --- a/vendor/github.com/allegro/bigcache/bigcache.go +++ b/vendor/github.com/allegro/bigcache/bigcache.go @@ -102,7 +102,7 @@ func (c *BigCache) Close() error { } // Get reads entry for the key. -// It returns an EntryNotFoundError when +// It returns an ErrEntryNotFound when // no entry exists for the given key. func (c *BigCache) Get(key string) ([]byte, error) { hashedKey := c.hash.Sum64(key) diff --git a/vendor/github.com/allegro/bigcache/entry_not_found_error.go b/vendor/github.com/allegro/bigcache/entry_not_found_error.go index 883bdc29e..051a71230 100644 --- a/vendor/github.com/allegro/bigcache/entry_not_found_error.go +++ b/vendor/github.com/allegro/bigcache/entry_not_found_error.go @@ -1,17 +1,6 @@ package bigcache -import "fmt" +import "errors" -// EntryNotFoundError is an error type struct which is returned when entry was not found for provided key -type EntryNotFoundError struct { - key string -} - -func notFound(key string) error { - return &EntryNotFoundError{key} -} - -// Error returned when entry does not exist. -func (e EntryNotFoundError) Error() string { - return fmt.Sprintf("Entry %q not found", e.key) -} +// ErrEntryNotFound is an error type struct which is returned when entry was not found for provided key +var ErrEntryNotFound = errors.New("Entry not found") diff --git a/vendor/github.com/allegro/bigcache/queue/bytes_queue.go b/vendor/github.com/allegro/bigcache/queue/bytes_queue.go index 0285c72cd..bda737403 100644 --- a/vendor/github.com/allegro/bigcache/queue/bytes_queue.go +++ b/vendor/github.com/allegro/bigcache/queue/bytes_queue.go @@ -16,6 +16,12 @@ const ( minimumEmptyBlobSize = 32 + headerEntrySize ) +var ( + errEmptyQueue = &queueError{"Empty queue"} + errInvalidIndex = &queueError{"Index must be greater than zero. Invalid index."} + errIndexOutOfBounds = &queueError{"Index out of range"} +) + // BytesQueue is a non-thread safe queue type of fifo based on bytes array. // For every push operation index of entry is returned. It can be used to read the entry later type BytesQueue struct { @@ -162,6 +168,11 @@ func (q *BytesQueue) Get(index int) ([]byte, error) { return data, err } +// CheckGet checks if an entry can be read from index +func (q *BytesQueue) CheckGet(index int) error { + return q.peekCheckErr(index) +} + // Capacity returns number of allocated bytes for queue func (q *BytesQueue) Capacity() int { return q.capacity @@ -177,18 +188,35 @@ func (e *queueError) Error() string { return e.message } +// peekCheckErr is identical to peek, but does not actually return any data +func (q *BytesQueue) peekCheckErr(index int) error { + + if q.count == 0 { + return errEmptyQueue + } + + if index <= 0 { + return errInvalidIndex + } + + if index+headerEntrySize >= len(q.array) { + return errIndexOutOfBounds + } + return nil +} + func (q *BytesQueue) peek(index int) ([]byte, int, error) { if q.count == 0 { - return nil, 0, &queueError{"Empty queue"} + return nil, 0, errEmptyQueue } if index <= 0 { - return nil, 0, &queueError{"Index must be grater than zero. Invalid index."} + return nil, 0, errInvalidIndex } if index+headerEntrySize >= len(q.array) { - return nil, 0, &queueError{"Index out of range"} + return nil, 0, errIndexOutOfBounds } blockSize := int(binary.LittleEndian.Uint32(q.array[index : index+headerEntrySize])) diff --git a/vendor/github.com/allegro/bigcache/shard.go b/vendor/github.com/allegro/bigcache/shard.go index 56a9fb089..a31094ff3 100644 --- a/vendor/github.com/allegro/bigcache/shard.go +++ b/vendor/github.com/allegro/bigcache/shard.go @@ -32,7 +32,7 @@ func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) { if itemIndex == 0 { s.lock.RUnlock() s.miss() - return nil, notFound(key) + return nil, ErrEntryNotFound } wrappedEntry, err := s.entries.Get(int(itemIndex)) @@ -47,11 +47,12 @@ func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) { } s.lock.RUnlock() s.collision() - return nil, notFound(key) + return nil, ErrEntryNotFound } + entry := readEntry(wrappedEntry) s.lock.RUnlock() s.hit() - return readEntry(wrappedEntry), nil + return entry, nil } func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error { @@ -85,17 +86,17 @@ func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error { } func (s *cacheShard) del(key string, hashedKey uint64) error { + // Optimistic pre-check using only readlock s.lock.RLock() itemIndex := s.hashmap[hashedKey] if itemIndex == 0 { s.lock.RUnlock() s.delmiss() - return notFound(key) + return ErrEntryNotFound } - wrappedEntry, err := s.entries.Get(int(itemIndex)) - if err != nil { + if err := s.entries.CheckGet(int(itemIndex)); err != nil { s.lock.RUnlock() s.delmiss() return err @@ -104,6 +105,23 @@ func (s *cacheShard) del(key string, hashedKey uint64) error { s.lock.Lock() { + // After obtaining the writelock, we need to read the same again, + // since the data delivered earlier may be stale now + itemIndex = s.hashmap[hashedKey] + + if itemIndex == 0 { + s.lock.Unlock() + s.delmiss() + return ErrEntryNotFound + } + + wrappedEntry, err := s.entries.Get(int(itemIndex)) + if err != nil { + s.lock.Unlock() + s.delmiss() + return err + } + delete(s.hashmap, hashedKey) s.onRemove(wrappedEntry, Deleted) resetKeyFromEntry(wrappedEntry) @@ -136,17 +154,22 @@ func (s *cacheShard) cleanUp(currentTimestamp uint64) { } func (s *cacheShard) getOldestEntry() ([]byte, error) { + s.lock.RLock() + defer s.lock.RUnlock() return s.entries.Peek() } func (s *cacheShard) getEntry(index int) ([]byte, error) { - return s.entries.Get(index) + s.lock.RLock() + entry, err := s.entries.Get(index) + s.lock.RUnlock() + + return entry, err } func (s *cacheShard) copyKeys() (keys []uint32, next int) { - keys = make([]uint32, len(s.hashmap)) - s.lock.RLock() + keys = make([]uint32, len(s.hashmap)) for _, index := range s.hashmap { keys[next] = index -- cgit