summaryrefslogtreecommitdiff
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/.travis.yml18
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/LICENSE21
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/Readme.md71
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/cache.go307
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/go.mod9
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/go.sum11
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/item.go46
-rw-r--r--vendor/github.com/ReneKroon/ttlcache/priority_queue.go71
8 files changed, 554 insertions, 0 deletions
diff --git a/vendor/github.com/ReneKroon/ttlcache/.travis.yml b/vendor/github.com/ReneKroon/ttlcache/.travis.yml
new file mode 100644
index 000000000..095be4ff3
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/.travis.yml
@@ -0,0 +1,18 @@
+language: go
+
+go:
+ - "1.14"
+ - "1.13"
+git:
+ depth: 1
+
+install:
+ - go install -race std
+ - go install golang.org/x/tools/cmd/cover
+ - go install golang.org/x/lint/golint
+ - export PATH=$HOME/gopath/bin:$PATH
+
+script:
+ - golint .
+ - go test -cover -race -count=1 -timeout=30s -run .
+ - cd bench; go test -run=Bench.* -bench=. -benchmem \ No newline at end of file
diff --git a/vendor/github.com/ReneKroon/ttlcache/LICENSE b/vendor/github.com/ReneKroon/ttlcache/LICENSE
new file mode 100644
index 000000000..b3b587dce
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Rene Kroon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/ReneKroon/ttlcache/Readme.md b/vendor/github.com/ReneKroon/ttlcache/Readme.md
new file mode 100644
index 000000000..9c537fbdc
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/Readme.md
@@ -0,0 +1,71 @@
+## TTLCache - an in-memory cache with expiration
+
+TTLCache is a simple key/value cache in golang with the following functions:
+
+1. Thread-safe
+2. Individual expiring time or global expiring time, you can choose
+3. Auto-Extending expiration on `Get` -or- DNS style TTL, see `SkipTtlExtensionOnHit(bool)`
+4. Fast and memory efficient
+5. Can trigger callback on key expiration
+6. Cleanup resources by calling `Close()` at end of lifecycle.
+
+Note (issue #25): by default, due to historic reasons, the TTL will be reset on each cache hit and you need to explicitly configure the cache to use a TTL that will not get extended.
+
+[![Build Status](https://travis-ci.org/ReneKroon/ttlcache.svg?branch=master)](https://travis-ci.org/ReneKroon/ttlcache)
+
+#### Usage
+```go
+import (
+ "time"
+ "fmt"
+
+ "github.com/ReneKroon/ttlcache"
+)
+
+func main () {
+ newItemCallback := func(key string, value interface{}) {
+ fmt.Printf("New key(%s) added\n", key)
+ }
+ checkExpirationCallback := func(key string, value interface{}) bool {
+ if key == "key1" {
+ // if the key equals "key1", the value
+ // will not be allowed to expire
+ return false
+ }
+ // all other values are allowed to expire
+ return true
+ }
+ expirationCallback := func(key string, value interface{}) {
+ fmt.Printf("This key(%s) has expired\n", key)
+ }
+
+ cache := ttlcache.NewCache()
+ defer cache.Close()
+ cache.SetTTL(time.Duration(10 * time.Second))
+ cache.SetExpirationCallback(expirationCallback)
+
+ cache.Set("key", "value")
+ cache.SetWithTTL("keyWithTTL", "value", 10 * time.Second)
+
+ value, exists := cache.Get("key")
+ count := cache.Count()
+ result := cache.Remove("key")
+}
+```
+
+#### TTLCache - Some design considerations
+
+1. The complexity of the current cache is already quite high. Therefore i will not add 'convenience' features like an interface to supply a function to get missing keys.
+2. The locking should be done only in the functions of the Cache struct. Else data races can occur or recursive locks are needed, which are both unwanted.
+3. I prefer correct functionality over fast tests. It's ok for new tests to take seconds to proof something.
+
+#### Original Project
+
+TTLCache was forked from [wunderlist/ttlcache](https://github.com/wunderlist/ttlcache) to add extra functions not avaiable in the original scope.
+The main differences are:
+
+1. A item can store any kind of object, previously, only strings could be saved
+2. Optionally, you can add callbacks too: check if a value should expire, be notified if a value expires, and be notified when new values are added to the cache
+3. The expiration can be either global or per item
+4. Can exist items without expiration time
+5. Expirations and callbacks are realtime. Don't have a pooling time to check anymore, now it's done with a heap.
diff --git a/vendor/github.com/ReneKroon/ttlcache/cache.go b/vendor/github.com/ReneKroon/ttlcache/cache.go
new file mode 100644
index 000000000..f772d0c7c
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/cache.go
@@ -0,0 +1,307 @@
+package ttlcache
+
+import (
+ "sync"
+ "time"
+)
+
+// CheckExpireCallback is used as a callback for an external check on item expiration
+type checkExpireCallback func(key string, value interface{}) bool
+
+// ExpireCallback is used as a callback on item expiration or when notifying of an item new to the cache
+type expireCallback func(key string, value interface{})
+
+// Cache is a synchronized map of items that can auto-expire once stale
+type Cache struct {
+ mutex sync.Mutex
+ ttl time.Duration
+ items map[string]*item
+ expireCallback expireCallback
+ checkExpireCallback checkExpireCallback
+ newItemCallback expireCallback
+ priorityQueue *priorityQueue
+ expirationNotification chan bool
+ expirationTime time.Time
+ skipTTLExtension bool
+ shutdownSignal chan (chan struct{})
+ isShutDown bool
+}
+
+func (cache *Cache) getItem(key string) (*item, bool, bool) {
+ item, exists := cache.items[key]
+ if !exists || item.expired() {
+ return nil, false, false
+ }
+
+ if item.ttl >= 0 && (item.ttl > 0 || cache.ttl > 0) {
+ if cache.ttl > 0 && item.ttl == 0 {
+ item.ttl = cache.ttl
+ }
+
+ if !cache.skipTTLExtension {
+ item.touch()
+ }
+ cache.priorityQueue.update(item)
+ }
+
+ expirationNotification := false
+ if cache.expirationTime.After(time.Now().Add(item.ttl)) {
+ expirationNotification = true
+ }
+ return item, exists, expirationNotification
+}
+
+func (cache *Cache) startExpirationProcessing() {
+ timer := time.NewTimer(time.Hour)
+ for {
+ var sleepTime time.Duration
+ cache.mutex.Lock()
+ if cache.priorityQueue.Len() > 0 {
+ sleepTime = time.Until(cache.priorityQueue.items[0].expireAt)
+ if sleepTime < 0 && cache.priorityQueue.items[0].expireAt.IsZero() {
+ sleepTime = time.Hour
+ } else if sleepTime < 0 {
+ sleepTime = time.Microsecond
+ }
+ if cache.ttl > 0 {
+ sleepTime = min(sleepTime, cache.ttl)
+ }
+
+ } else if cache.ttl > 0 {
+ sleepTime = cache.ttl
+ } else {
+ sleepTime = time.Hour
+ }
+
+ cache.expirationTime = time.Now().Add(sleepTime)
+ cache.mutex.Unlock()
+
+ timer.Reset(sleepTime)
+ select {
+ case shutdownFeedback := <-cache.shutdownSignal:
+ timer.Stop()
+ cache.mutex.Lock()
+ if cache.priorityQueue.Len() > 0 {
+ cache.evictjob()
+ }
+ cache.mutex.Unlock()
+ shutdownFeedback <- struct{}{}
+ return
+ case <-timer.C:
+ timer.Stop()
+ cache.mutex.Lock()
+ if cache.priorityQueue.Len() == 0 {
+ cache.mutex.Unlock()
+ continue
+ }
+
+ cache.cleanjob()
+ cache.mutex.Unlock()
+
+ case <-cache.expirationNotification:
+ timer.Stop()
+ continue
+ }
+ }
+}
+
+func (cache *Cache) evictjob() {
+ // index will only be advanced if the current entry will not be evicted
+ i := 0
+ for item := cache.priorityQueue.items[i]; ; item = cache.priorityQueue.items[i] {
+
+ cache.priorityQueue.remove(item)
+ delete(cache.items, item.key)
+ if cache.expireCallback != nil {
+ go cache.expireCallback(item.key, item.data)
+ }
+ if cache.priorityQueue.Len() == 0 {
+ return
+ }
+ }
+}
+
+func (cache *Cache) cleanjob() {
+ // index will only be advanced if the current entry will not be evicted
+ i := 0
+ for item := cache.priorityQueue.items[i]; item.expired(); item = cache.priorityQueue.items[i] {
+
+ if cache.checkExpireCallback != nil {
+ if !cache.checkExpireCallback(item.key, item.data) {
+ item.touch()
+ cache.priorityQueue.update(item)
+ i++
+ if i == cache.priorityQueue.Len() {
+ break
+ }
+ continue
+ }
+ }
+
+ cache.priorityQueue.remove(item)
+ delete(cache.items, item.key)
+ if cache.expireCallback != nil {
+ go cache.expireCallback(item.key, item.data)
+ }
+ if cache.priorityQueue.Len() == 0 {
+ return
+ }
+ }
+}
+
+// Close calls Purge, and then stops the goroutine that does ttl checking, for a clean shutdown.
+// The cache is no longer cleaning up after the first call to Close, repeated calls are safe though.
+func (cache *Cache) Close() {
+
+ cache.mutex.Lock()
+ if !cache.isShutDown {
+ cache.isShutDown = true
+ cache.mutex.Unlock()
+ feedback := make(chan struct{})
+ cache.shutdownSignal <- feedback
+ <-feedback
+ close(cache.shutdownSignal)
+ } else {
+ cache.mutex.Unlock()
+ }
+ cache.Purge()
+}
+
+// Set is a thread-safe way to add new items to the map
+func (cache *Cache) Set(key string, data interface{}) {
+ cache.SetWithTTL(key, data, ItemExpireWithGlobalTTL)
+}
+
+// SetWithTTL is a thread-safe way to add new items to the map with individual ttl
+func (cache *Cache) SetWithTTL(key string, data interface{}, ttl time.Duration) {
+ cache.mutex.Lock()
+ item, exists, _ := cache.getItem(key)
+
+ if exists {
+ item.data = data
+ item.ttl = ttl
+ } else {
+ item = newItem(key, data, ttl)
+ cache.items[key] = item
+ }
+
+ if item.ttl >= 0 && (item.ttl > 0 || cache.ttl > 0) {
+ if cache.ttl > 0 && item.ttl == 0 {
+ item.ttl = cache.ttl
+ }
+ item.touch()
+ }
+
+ if exists {
+ cache.priorityQueue.update(item)
+ } else {
+ cache.priorityQueue.push(item)
+ }
+
+ cache.mutex.Unlock()
+ if !exists && cache.newItemCallback != nil {
+ cache.newItemCallback(key, data)
+ }
+ cache.expirationNotification <- true
+}
+
+// Get is a thread-safe way to lookup items
+// Every lookup, also touches the item, hence extending it's life
+func (cache *Cache) Get(key string) (interface{}, bool) {
+ cache.mutex.Lock()
+ item, exists, triggerExpirationNotification := cache.getItem(key)
+
+ var dataToReturn interface{}
+ if exists {
+ dataToReturn = item.data
+ }
+ cache.mutex.Unlock()
+ if triggerExpirationNotification {
+ cache.expirationNotification <- true
+ }
+ return dataToReturn, exists
+}
+
+func (cache *Cache) Remove(key string) bool {
+ cache.mutex.Lock()
+ object, exists := cache.items[key]
+ if !exists {
+ cache.mutex.Unlock()
+ return false
+ }
+ delete(cache.items, object.key)
+ cache.priorityQueue.remove(object)
+ cache.mutex.Unlock()
+
+ return true
+}
+
+// Count returns the number of items in the cache
+func (cache *Cache) Count() int {
+ cache.mutex.Lock()
+ length := len(cache.items)
+ cache.mutex.Unlock()
+ return length
+}
+
+func (cache *Cache) SetTTL(ttl time.Duration) {
+ cache.mutex.Lock()
+ cache.ttl = ttl
+ cache.mutex.Unlock()
+ cache.expirationNotification <- true
+}
+
+// SetExpirationCallback sets a callback that will be called when an item expires
+func (cache *Cache) SetExpirationCallback(callback expireCallback) {
+ cache.expireCallback = callback
+}
+
+// SetCheckExpirationCallback sets a callback that will be called when an item is about to expire
+// in order to allow external code to decide whether the item expires or remains for another TTL cycle
+func (cache *Cache) SetCheckExpirationCallback(callback checkExpireCallback) {
+ cache.checkExpireCallback = callback
+}
+
+// SetNewItemCallback sets a callback that will be called when a new item is added to the cache
+func (cache *Cache) SetNewItemCallback(callback expireCallback) {
+ cache.newItemCallback = callback
+}
+
+// SkipTtlExtensionOnHit allows the user to change the cache behaviour. When this flag is set to true it will
+// no longer extend TTL of items when they are retrieved using Get, or when their expiration condition is evaluated
+// using SetCheckExpirationCallback.
+func (cache *Cache) SkipTtlExtensionOnHit(value bool) {
+ cache.skipTTLExtension = value
+}
+
+// Purge will remove all entries
+func (cache *Cache) Purge() {
+ cache.mutex.Lock()
+ cache.items = make(map[string]*item)
+ cache.priorityQueue = newPriorityQueue()
+ cache.mutex.Unlock()
+}
+
+// NewCache is a helper to create instance of the Cache struct
+func NewCache() *Cache {
+
+ shutdownChan := make(chan chan struct{})
+
+ cache := &Cache{
+ items: make(map[string]*item),
+ priorityQueue: newPriorityQueue(),
+ expirationNotification: make(chan bool),
+ expirationTime: time.Now(),
+ shutdownSignal: shutdownChan,
+ isShutDown: false,
+ }
+ go cache.startExpirationProcessing()
+ return cache
+}
+
+func min(duration time.Duration, second time.Duration) time.Duration {
+ if duration < second {
+ return duration
+ }
+ return second
+}
diff --git a/vendor/github.com/ReneKroon/ttlcache/go.mod b/vendor/github.com/ReneKroon/ttlcache/go.mod
new file mode 100644
index 000000000..6806b2859
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/go.mod
@@ -0,0 +1,9 @@
+module github.com/ReneKroon/ttlcache
+
+go 1.14
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/stretchr/testify v1.3.0
+ go.uber.org/goleak v0.10.0
+)
diff --git a/vendor/github.com/ReneKroon/ttlcache/go.sum b/vendor/github.com/ReneKroon/ttlcache/go.sum
new file mode 100644
index 000000000..5701e60f9
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/go.sum
@@ -0,0 +1,11 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
+go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
diff --git a/vendor/github.com/ReneKroon/ttlcache/item.go b/vendor/github.com/ReneKroon/ttlcache/item.go
new file mode 100644
index 000000000..2f78f49cc
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/item.go
@@ -0,0 +1,46 @@
+package ttlcache
+
+import (
+ "time"
+)
+
+const (
+ // ItemNotExpire Will avoid the item being expired by TTL, but can still be exired by callback etc.
+ ItemNotExpire time.Duration = -1
+ // ItemExpireWithGlobalTTL will use the global TTL when set.
+ ItemExpireWithGlobalTTL time.Duration = 0
+)
+
+func newItem(key string, data interface{}, ttl time.Duration) *item {
+ item := &item{
+ data: data,
+ ttl: ttl,
+ key: key,
+ }
+ // since nobody is aware yet of this item, it's safe to touch without lock here
+ item.touch()
+ return item
+}
+
+type item struct {
+ key string
+ data interface{}
+ ttl time.Duration
+ expireAt time.Time
+ queueIndex int
+}
+
+// Reset the item expiration time
+func (item *item) touch() {
+ if item.ttl > 0 {
+ item.expireAt = time.Now().Add(item.ttl)
+ }
+}
+
+// Verify if the item is expired
+func (item *item) expired() bool {
+ if item.ttl <= 0 {
+ return false
+ }
+ return item.expireAt.Before(time.Now())
+}
diff --git a/vendor/github.com/ReneKroon/ttlcache/priority_queue.go b/vendor/github.com/ReneKroon/ttlcache/priority_queue.go
new file mode 100644
index 000000000..11b9c3140
--- /dev/null
+++ b/vendor/github.com/ReneKroon/ttlcache/priority_queue.go
@@ -0,0 +1,71 @@
+package ttlcache
+
+import (
+ "container/heap"
+)
+
+func newPriorityQueue() *priorityQueue {
+ queue := &priorityQueue{}
+ heap.Init(queue)
+ return queue
+}
+
+type priorityQueue struct {
+ items []*item
+}
+
+func (pq *priorityQueue) update(item *item) {
+ heap.Fix(pq, item.queueIndex)
+}
+
+func (pq *priorityQueue) push(item *item) {
+ heap.Push(pq, item)
+}
+
+func (pq *priorityQueue) pop() *item {
+ if pq.Len() == 0 {
+ return nil
+ }
+ return heap.Pop(pq).(*item)
+}
+
+func (pq *priorityQueue) remove(item *item) {
+ heap.Remove(pq, item.queueIndex)
+}
+
+func (pq priorityQueue) Len() int {
+ length := len(pq.items)
+ return length
+}
+
+// Less will consider items with time.Time default value (epoch start) as more than set items.
+func (pq priorityQueue) Less(i, j int) bool {
+ if pq.items[i].expireAt.IsZero() {
+ return false
+ }
+ if pq.items[j].expireAt.IsZero() {
+ return true
+ }
+ return pq.items[i].expireAt.Before(pq.items[j].expireAt)
+}
+
+func (pq priorityQueue) Swap(i, j int) {
+ pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
+ pq.items[i].queueIndex = i
+ pq.items[j].queueIndex = j
+}
+
+func (pq *priorityQueue) Push(x interface{}) {
+ item := x.(*item)
+ item.queueIndex = len(pq.items)
+ pq.items = append(pq.items, item)
+}
+
+func (pq *priorityQueue) Pop() interface{} {
+ old := pq.items
+ n := len(old)
+ item := old[n-1]
+ item.queueIndex = -1
+ pq.items = old[0 : n-1]
+ return item
+}