This commit is contained in:
root
2019-04-22 02:59:20 +00:00
commit beccf3fe43
25440 changed files with 4054998 additions and 0 deletions

33
vendor/github.com/bluele/gcache/BUILD.bazel generated vendored Normal file
View File

@ -0,0 +1,33 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"arc.go",
"cache.go",
"clock.go",
"lfu.go",
"lru.go",
"simple.go",
"singleflight.go",
"stats.go",
"utils.go",
],
importmap = "go-common/vendor/github.com/bluele/gcache",
importpath = "github.com/bluele/gcache",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

21
vendor/github.com/bluele/gcache/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Jun Kimura
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.

319
vendor/github.com/bluele/gcache/README.md generated vendored Normal file
View File

@ -0,0 +1,319 @@
# GCache
[![wercker status](https://app.wercker.com/status/1471b6c9cbc9ebbd15f8f9fe8f71ac67/m/master "wercker status")](https://app.wercker.com/project/bykey/1471b6c9cbc9ebbd15f8f9fe8f71ac67)[![GoDoc](https://godoc.org/github.com/bluele/gcache?status.png)](https://godoc.org/github.com/bluele/gcache)
Cache library for golang. It supports expirable Cache, LFU, LRU and ARC.
## Features
* Supports expirable Cache, LFU, LRU and ARC.
* Goroutine safe.
* Supports event handlers which evict, purge, and add entry. (Optional)
* Automatically load cache if it doesn't exists. (Optional)
## Install
```
$ go get github.com/bluele/gcache
```
## Example
### Manually set a key-value pair.
```go
package main
import (
"github.com/bluele/gcache"
"fmt"
)
func main() {
gc := gcache.New(20).
LRU().
Build()
gc.Set("key", "ok")
value, err := gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
```
```
Get: ok
```
### Manually set a key-value pair, with an expiration time.
```go
package main
import (
"github.com/bluele/gcache"
"fmt"
"time"
)
func main() {
gc := gcache.New(20).
LRU().
Build()
gc.SetWithExpire("key", "ok", time.Second*10)
value, _ := gc.Get("key")
fmt.Println("Get:", value)
// Wait for value to expire
time.Sleep(time.Second*10)
value, err = gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
```
```
Get: ok
// 10 seconds later, new attempt:
panic: ErrKeyNotFound
```
### Automatically load value
```go
package main
import (
"github.com/bluele/gcache"
"fmt"
)
func main() {
gc := gcache.New(20).
LRU().
LoaderFunc(func(key interface{}) (interface{}, error) {
return "ok", nil
}).
Build()
value, err := gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
```
```
Get: ok
```
### Automatically load value with expiration
```go
package main
import (
"fmt"
"time"
"github.com/bluele/gcache"
)
func main() {
var evictCounter, loaderCounter, purgeCounter int
gc := gcache.New(20).
LRU().
LoaderExpireFunc(func(key interface{}) (interface{}, *time.Duration, error) {
loaderCounter++
expire := 1 * time.Second
return "ok", &expire, nil
}).
EvictedFunc(func(key, value interface{}) {
evictCounter++
fmt.Println("evicted key:", key)
}).
PurgeVisitorFunc(func(key, value interface{}) {
purgeCounter++
fmt.Println("purged key:", key)
}).
Build()
value, err := gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
time.Sleep(1 * time.Second)
value, err = gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
gc.Purge()
if loaderCounter != evictCounter+purgeCounter {
panic("bad")
}
}
```
```
Get: ok
evicted key: key
Get: ok
purged key: key
```
## Cache Algorithm
* Least-Frequently Used (LFU)
Discards the least frequently used items first.
```go
func main() {
// size: 10
gc := gcache.New(10).
LFU().
Build()
gc.Set("key", "value")
}
```
* Least Recently Used (LRU)
Discards the least recently used items first.
```go
func main() {
// size: 10
gc := gcache.New(10).
LRU().
Build()
gc.Set("key", "value")
}
```
* Adaptive Replacement Cache (ARC)
Constantly balances between LRU and LFU, to improve the combined result.
detail: http://en.wikipedia.org/wiki/Adaptive_replacement_cache
```go
func main() {
// size: 10
gc := gcache.New(10).
ARC().
Build()
gc.Set("key", "value")
}
```
* SimpleCache (Default)
SimpleCache has no clear priority for evict cache. It depends on key-value map order.
```go
func main() {
// size: 10
gc := gcache.New(10).Build()
gc.Set("key", "value")
v, err := gc.Get("key")
if err != nil {
panic(err)
}
}
```
## Loading Cache
If specified `LoaderFunc`, values are automatically loaded by the cache, and are stored in the cache until either evicted or manually invalidated.
```go
func main() {
gc := gcache.New(10).
LRU().
LoaderFunc(func(key interface{}) (interface{}, error) {
return "value", nil
}).
Build()
v, _ := gc.Get("key")
// output: "value"
fmt.Println(v)
}
```
GCache coordinates cache fills such that only one load in one process of an entire replicated set of processes populates the cache, then multiplexes the loaded value to all callers.
## Expirable cache
```go
func main() {
// LRU cache, size: 10, expiration: after a hour
gc := gcache.New(10).
LRU().
Expiration(time.Hour).
Build()
}
```
## Event handlers
### Evicted handler
Event handler for evict the entry.
```go
func main() {
gc := gcache.New(2).
EvictedFunc(func(key, value interface{}) {
fmt.Println("evicted key:", key)
}).
Build()
for i := 0; i < 3; i++ {
gc.Set(i, i*i)
}
}
```
```
evicted key: 0
```
### Added handler
Event handler for add the entry.
```go
func main() {
gc := gcache.New(2).
AddedFunc(func(key, value interface{}) {
fmt.Println("added key:", key)
}).
Build()
for i := 0; i < 3; i++ {
gc.Set(i, i*i)
}
}
```
```
added key: 0
added key: 1
added key: 2
```
# Author
**Jun Kimura**
* <http://github.com/bluele>
* <junkxdev@gmail.com>

418
vendor/github.com/bluele/gcache/arc.go generated vendored Normal file
View File

@ -0,0 +1,418 @@
package gcache
import (
"container/list"
"time"
)
// Constantly balances between LRU and LFU, to improve the combined result.
type ARC struct {
baseCache
items map[interface{}]*arcItem
part int
t1 *arcList
t2 *arcList
b1 *arcList
b2 *arcList
}
func newARC(cb *CacheBuilder) *ARC {
c := &ARC{}
buildCache(&c.baseCache, cb)
c.init()
c.loadGroup.cache = c
return c
}
func (c *ARC) init() {
c.items = make(map[interface{}]*arcItem)
c.t1 = newARCList()
c.t2 = newARCList()
c.b1 = newARCList()
c.b2 = newARCList()
}
func (c *ARC) replace(key interface{}) {
var old interface{}
if (c.t1.Len() > 0 && c.b2.Has(key) && c.t1.Len() == c.part) || (c.t1.Len() > c.part) {
old = c.t1.RemoveTail()
c.b1.PushFront(old)
} else if c.t2.l.Len() > 0 {
old = c.t2.RemoveTail()
c.b2.PushFront(old)
} else {
return
}
item, ok := c.items[old]
if ok {
delete(c.items, old)
if c.evictedFunc != nil {
c.evictedFunc(item.key, item.value)
}
}
}
func (c *ARC) Set(key, value interface{}) error {
c.mu.Lock()
defer c.mu.Unlock()
_, err := c.set(key, value)
return err
}
// Set a new key-value pair with an expiration time
func (c *ARC) SetWithExpire(key, value interface{}, expiration time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, value)
if err != nil {
return err
}
t := c.clock.Now().Add(expiration)
item.(*arcItem).expiration = &t
return nil
}
func (c *ARC) set(key, value interface{}) (interface{}, error) {
var err error
if c.serializeFunc != nil {
value, err = c.serializeFunc(key, value)
if err != nil {
return nil, err
}
}
item, ok := c.items[key]
if ok {
item.value = value
} else {
item = &arcItem{
clock: c.clock,
key: key,
value: value,
}
c.items[key] = item
}
if c.expiration != nil {
t := c.clock.Now().Add(*c.expiration)
item.expiration = &t
}
defer func() {
if c.addedFunc != nil {
c.addedFunc(key, value)
}
}()
if c.t1.Has(key) || c.t2.Has(key) {
return item, nil
}
if elt := c.b1.Lookup(key); elt != nil {
c.part = minInt(c.size, c.part+maxInt(c.b2.Len()/c.b1.Len(), 1))
c.replace(key)
c.b1.Remove(key, elt)
c.t2.PushFront(key)
return item, nil
}
if elt := c.b2.Lookup(key); elt != nil {
c.part = maxInt(0, c.part-maxInt(c.b1.Len()/c.b2.Len(), 1))
c.replace(key)
c.b2.Remove(key, elt)
c.t2.PushFront(key)
return item, nil
}
if c.t1.Len()+c.b1.Len() == c.size {
if c.t1.Len() < c.size {
c.b1.RemoveTail()
c.replace(key)
} else {
pop := c.t1.RemoveTail()
item, ok := c.items[pop]
if ok {
delete(c.items, pop)
if c.evictedFunc != nil {
c.evictedFunc(item.key, item.value)
}
}
}
} else {
total := c.t1.Len() + c.b1.Len() + c.t2.Len() + c.b2.Len()
if total >= c.size {
if total == (2 * c.size) {
c.b2.RemoveTail()
}
c.replace(key)
}
}
c.t1.PushFront(key)
return item, nil
}
// Get a value from cache pool using key if it exists. If not exists and it has LoaderFunc, it will generate the value using you have specified LoaderFunc method returns value.
func (c *ARC) Get(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, true)
}
return v, err
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key, returns KeyNotFoundError.
// And send a request which refresh value for specified key if cache object has LoaderFunc.
func (c *ARC) GetIFPresent(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, false)
}
return v, err
}
func (c *ARC) get(key interface{}, onLoad bool) (interface{}, error) {
v, err := c.getValue(key, onLoad)
if err != nil {
return nil, err
}
if c.deserializeFunc != nil {
return c.deserializeFunc(key, v)
}
return v, nil
}
func (c *ARC) getValue(key interface{}, onLoad bool) (interface{}, error) {
c.mu.Lock()
defer c.mu.Unlock()
if elt := c.t1.Lookup(key); elt != nil {
c.t1.Remove(key, elt)
item := c.items[key]
if !item.IsExpired(nil) {
c.t2.PushFront(key)
if !onLoad {
c.stats.IncrHitCount()
}
return item.value, nil
} else {
delete(c.items, key)
c.b1.PushFront(key)
if c.evictedFunc != nil {
c.evictedFunc(item.key, item.value)
}
}
}
if elt := c.t2.Lookup(key); elt != nil {
item := c.items[key]
if !item.IsExpired(nil) {
c.t2.MoveToFront(elt)
if !onLoad {
c.stats.IncrHitCount()
}
return item.value, nil
} else {
delete(c.items, key)
c.t2.Remove(key, elt)
c.b2.PushFront(key)
if c.evictedFunc != nil {
c.evictedFunc(item.key, item.value)
}
}
}
if !onLoad {
c.stats.IncrMissCount()
}
return nil, KeyNotFoundError
}
func (c *ARC) getWithLoader(key interface{}, isWait bool) (interface{}, error) {
if c.loaderExpireFunc == nil {
return nil, KeyNotFoundError
}
value, _, err := c.load(key, func(v interface{}, expiration *time.Duration, e error) (interface{}, error) {
if e != nil {
return nil, e
}
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, v)
if err != nil {
return nil, err
}
if expiration != nil {
t := c.clock.Now().Add(*expiration)
item.(*arcItem).expiration = &t
}
return v, nil
}, isWait)
if err != nil {
return nil, err
}
return value, nil
}
// Remove removes the provided key from the cache.
func (c *ARC) Remove(key interface{}) bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.remove(key)
}
func (c *ARC) remove(key interface{}) bool {
if elt := c.t1.Lookup(key); elt != nil {
c.t1.Remove(key, elt)
item := c.items[key]
delete(c.items, key)
c.b1.PushFront(key)
if c.evictedFunc != nil {
c.evictedFunc(key, item.value)
}
return true
}
if elt := c.t2.Lookup(key); elt != nil {
c.t2.Remove(key, elt)
item := c.items[key]
delete(c.items, key)
c.b2.PushFront(key)
if c.evictedFunc != nil {
c.evictedFunc(key, item.value)
}
return true
}
return false
}
func (c *ARC) keys() []interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
keys := make([]interface{}, len(c.items))
var i = 0
for k := range c.items {
keys[i] = k
i++
}
return keys
}
// Keys returns a slice of the keys in the cache.
func (c *ARC) Keys() []interface{} {
keys := []interface{}{}
for _, k := range c.keys() {
_, err := c.GetIFPresent(k)
if err == nil {
keys = append(keys, k)
}
}
return keys
}
// Returns all key-value pairs in the cache.
func (c *ARC) GetALL() map[interface{}]interface{} {
m := make(map[interface{}]interface{})
for _, k := range c.keys() {
v, err := c.GetIFPresent(k)
if err == nil {
m[k] = v
}
}
return m
}
// Len returns the number of items in the cache.
func (c *ARC) Len() int {
return len(c.GetALL())
}
// Purge is used to completely clear the cache
func (c *ARC) Purge() {
c.mu.Lock()
defer c.mu.Unlock()
if c.purgeVisitorFunc != nil {
for _, item := range c.items {
c.purgeVisitorFunc(item.key, item.value)
}
}
c.init()
}
// returns boolean value whether this item is expired or not.
func (it *arcItem) IsExpired(now *time.Time) bool {
if it.expiration == nil {
return false
}
if now == nil {
t := it.clock.Now()
now = &t
}
return it.expiration.Before(*now)
}
type arcList struct {
l *list.List
keys map[interface{}]*list.Element
}
type arcItem struct {
clock Clock
key interface{}
value interface{}
expiration *time.Time
}
func newARCList() *arcList {
return &arcList{
l: list.New(),
keys: make(map[interface{}]*list.Element),
}
}
func (al *arcList) Has(key interface{}) bool {
_, ok := al.keys[key]
return ok
}
func (al *arcList) Lookup(key interface{}) *list.Element {
elt := al.keys[key]
return elt
}
func (al *arcList) MoveToFront(elt *list.Element) {
al.l.MoveToFront(elt)
}
func (al *arcList) PushFront(key interface{}) {
if elt, ok := al.keys[key]; ok {
al.l.MoveToFront(elt)
return
}
elt := al.l.PushFront(key)
al.keys[key] = elt
}
func (al *arcList) Remove(key interface{}, elt *list.Element) {
delete(al.keys, key)
al.l.Remove(elt)
}
func (al *arcList) RemoveTail() interface{} {
elt := al.l.Back()
al.l.Remove(elt)
key := elt.Value
delete(al.keys, key)
return key
}
func (al *arcList) Len() int {
return al.l.Len()
}

204
vendor/github.com/bluele/gcache/cache.go generated vendored Normal file
View File

@ -0,0 +1,204 @@
package gcache
import (
"errors"
"fmt"
"sync"
"time"
)
const (
TYPE_SIMPLE = "simple"
TYPE_LRU = "lru"
TYPE_LFU = "lfu"
TYPE_ARC = "arc"
)
var KeyNotFoundError = errors.New("Key not found.")
type Cache interface {
Set(interface{}, interface{}) error
SetWithExpire(interface{}, interface{}, time.Duration) error
Get(interface{}) (interface{}, error)
GetIFPresent(interface{}) (interface{}, error)
GetALL() map[interface{}]interface{}
get(interface{}, bool) (interface{}, error)
Remove(interface{}) bool
Purge()
Keys() []interface{}
Len() int
statsAccessor
}
type baseCache struct {
clock Clock
size int
loaderExpireFunc LoaderExpireFunc
evictedFunc EvictedFunc
purgeVisitorFunc PurgeVisitorFunc
addedFunc AddedFunc
deserializeFunc DeserializeFunc
serializeFunc SerializeFunc
expiration *time.Duration
mu sync.RWMutex
loadGroup Group
*stats
}
type (
LoaderFunc func(interface{}) (interface{}, error)
LoaderExpireFunc func(interface{}) (interface{}, *time.Duration, error)
EvictedFunc func(interface{}, interface{})
PurgeVisitorFunc func(interface{}, interface{})
AddedFunc func(interface{}, interface{})
DeserializeFunc func(interface{}, interface{}) (interface{}, error)
SerializeFunc func(interface{}, interface{}) (interface{}, error)
)
type CacheBuilder struct {
clock Clock
tp string
size int
loaderExpireFunc LoaderExpireFunc
evictedFunc EvictedFunc
purgeVisitorFunc PurgeVisitorFunc
addedFunc AddedFunc
expiration *time.Duration
deserializeFunc DeserializeFunc
serializeFunc SerializeFunc
}
func New(size int) *CacheBuilder {
return &CacheBuilder{
clock: NewRealClock(),
tp: TYPE_SIMPLE,
size: size,
}
}
func (cb *CacheBuilder) Clock(clock Clock) *CacheBuilder {
cb.clock = clock
return cb
}
// Set a loader function.
// loaderFunc: create a new value with this function if cached value is expired.
func (cb *CacheBuilder) LoaderFunc(loaderFunc LoaderFunc) *CacheBuilder {
cb.loaderExpireFunc = func(k interface{}) (interface{}, *time.Duration, error) {
v, err := loaderFunc(k)
return v, nil, err
}
return cb
}
// Set a loader function with expiration.
// loaderExpireFunc: create a new value with this function if cached value is expired.
// If nil returned instead of time.Duration from loaderExpireFunc than value will never expire.
func (cb *CacheBuilder) LoaderExpireFunc(loaderExpireFunc LoaderExpireFunc) *CacheBuilder {
cb.loaderExpireFunc = loaderExpireFunc
return cb
}
func (cb *CacheBuilder) EvictType(tp string) *CacheBuilder {
cb.tp = tp
return cb
}
func (cb *CacheBuilder) Simple() *CacheBuilder {
return cb.EvictType(TYPE_SIMPLE)
}
func (cb *CacheBuilder) LRU() *CacheBuilder {
return cb.EvictType(TYPE_LRU)
}
func (cb *CacheBuilder) LFU() *CacheBuilder {
return cb.EvictType(TYPE_LFU)
}
func (cb *CacheBuilder) ARC() *CacheBuilder {
return cb.EvictType(TYPE_ARC)
}
func (cb *CacheBuilder) EvictedFunc(evictedFunc EvictedFunc) *CacheBuilder {
cb.evictedFunc = evictedFunc
return cb
}
func (cb *CacheBuilder) PurgeVisitorFunc(purgeVisitorFunc PurgeVisitorFunc) *CacheBuilder {
cb.purgeVisitorFunc = purgeVisitorFunc
return cb
}
func (cb *CacheBuilder) AddedFunc(addedFunc AddedFunc) *CacheBuilder {
cb.addedFunc = addedFunc
return cb
}
func (cb *CacheBuilder) DeserializeFunc(deserializeFunc DeserializeFunc) *CacheBuilder {
cb.deserializeFunc = deserializeFunc
return cb
}
func (cb *CacheBuilder) SerializeFunc(serializeFunc SerializeFunc) *CacheBuilder {
cb.serializeFunc = serializeFunc
return cb
}
func (cb *CacheBuilder) Expiration(expiration time.Duration) *CacheBuilder {
cb.expiration = &expiration
return cb
}
func (cb *CacheBuilder) Build() Cache {
if cb.size <= 0 && cb.tp != TYPE_SIMPLE {
panic("gcache: Cache size <= 0")
}
return cb.build()
}
func (cb *CacheBuilder) build() Cache {
switch cb.tp {
case TYPE_SIMPLE:
return newSimpleCache(cb)
case TYPE_LRU:
return newLRUCache(cb)
case TYPE_LFU:
return newLFUCache(cb)
case TYPE_ARC:
return newARC(cb)
default:
panic("gcache: Unknown type " + cb.tp)
}
}
func buildCache(c *baseCache, cb *CacheBuilder) {
c.clock = cb.clock
c.size = cb.size
c.loaderExpireFunc = cb.loaderExpireFunc
c.expiration = cb.expiration
c.addedFunc = cb.addedFunc
c.deserializeFunc = cb.deserializeFunc
c.serializeFunc = cb.serializeFunc
c.evictedFunc = cb.evictedFunc
c.purgeVisitorFunc = cb.purgeVisitorFunc
c.stats = &stats{}
}
// load a new value using by specified key.
func (c *baseCache) load(key interface{}, cb func(interface{}, *time.Duration, error) (interface{}, error), isWait bool) (interface{}, bool, error) {
v, called, err := c.loadGroup.Do(key, func() (v interface{}, e error) {
defer func() {
if r := recover(); r != nil {
e = fmt.Errorf("Loader panics: %v", r)
}
}()
return cb(c.loaderExpireFunc(key))
}, isWait)
if err != nil {
return nil, called, err
}
return v, called, nil
}

53
vendor/github.com/bluele/gcache/clock.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
package gcache
import (
"sync"
"time"
)
type Clock interface {
Now() time.Time
}
type RealClock struct{}
func NewRealClock() Clock {
return RealClock{}
}
func (rc RealClock) Now() time.Time {
t := time.Now()
return t
}
type FakeClock interface {
Clock
Advance(d time.Duration)
}
func NewFakeClock() FakeClock {
return &fakeclock{
// Taken from github.com/jonboulle/clockwork: use a fixture that does not fulfill Time.IsZero()
now: time.Date(1984, time.April, 4, 0, 0, 0, 0, time.UTC),
}
}
type fakeclock struct {
now time.Time
mutex sync.RWMutex
}
func (fc *fakeclock) Now() time.Time {
fc.mutex.RLock()
defer fc.mutex.RUnlock()
t := fc.now
return t
}
func (fc *fakeclock) Advance(d time.Duration) {
fc.mutex.Lock()
defer fc.mutex.Unlock()
fc.now = fc.now.Add(d)
}

319
vendor/github.com/bluele/gcache/lfu.go generated vendored Normal file
View File

@ -0,0 +1,319 @@
package gcache
import (
"container/list"
"time"
)
// Discards the least frequently used items first.
type LFUCache struct {
baseCache
items map[interface{}]*lfuItem
freqList *list.List // list for freqEntry
}
func newLFUCache(cb *CacheBuilder) *LFUCache {
c := &LFUCache{}
buildCache(&c.baseCache, cb)
c.init()
c.loadGroup.cache = c
return c
}
func (c *LFUCache) init() {
c.freqList = list.New()
c.items = make(map[interface{}]*lfuItem, c.size+1)
c.freqList.PushFront(&freqEntry{
freq: 0,
items: make(map[*lfuItem]struct{}),
})
}
// Set a new key-value pair
func (c *LFUCache) Set(key, value interface{}) error {
c.mu.Lock()
defer c.mu.Unlock()
_, err := c.set(key, value)
return err
}
// Set a new key-value pair with an expiration time
func (c *LFUCache) SetWithExpire(key, value interface{}, expiration time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, value)
if err != nil {
return err
}
t := c.clock.Now().Add(expiration)
item.(*lfuItem).expiration = &t
return nil
}
func (c *LFUCache) set(key, value interface{}) (interface{}, error) {
var err error
if c.serializeFunc != nil {
value, err = c.serializeFunc(key, value)
if err != nil {
return nil, err
}
}
// Check for existing item
item, ok := c.items[key]
if ok {
item.value = value
} else {
// Verify size not exceeded
if len(c.items) >= c.size {
c.evict(1)
}
item = &lfuItem{
clock: c.clock,
key: key,
value: value,
freqElement: nil,
}
el := c.freqList.Front()
fe := el.Value.(*freqEntry)
fe.items[item] = struct{}{}
item.freqElement = el
c.items[key] = item
}
if c.expiration != nil {
t := c.clock.Now().Add(*c.expiration)
item.expiration = &t
}
if c.addedFunc != nil {
c.addedFunc(key, value)
}
return item, nil
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key and has LoaderFunc,
// generate a value using `LoaderFunc` method returns value.
func (c *LFUCache) Get(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, true)
}
return v, err
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key, returns KeyNotFoundError.
// And send a request which refresh value for specified key if cache object has LoaderFunc.
func (c *LFUCache) GetIFPresent(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, false)
}
return v, err
}
func (c *LFUCache) get(key interface{}, onLoad bool) (interface{}, error) {
v, err := c.getValue(key, onLoad)
if err != nil {
return nil, err
}
if c.deserializeFunc != nil {
return c.deserializeFunc(key, v)
}
return v, nil
}
func (c *LFUCache) getValue(key interface{}, onLoad bool) (interface{}, error) {
c.mu.Lock()
item, ok := c.items[key]
if ok {
if !item.IsExpired(nil) {
c.increment(item)
v := item.value
c.mu.Unlock()
if !onLoad {
c.stats.IncrHitCount()
}
return v, nil
}
c.removeItem(item)
}
c.mu.Unlock()
if !onLoad {
c.stats.IncrMissCount()
}
return nil, KeyNotFoundError
}
func (c *LFUCache) getWithLoader(key interface{}, isWait bool) (interface{}, error) {
if c.loaderExpireFunc == nil {
return nil, KeyNotFoundError
}
value, _, err := c.load(key, func(v interface{}, expiration *time.Duration, e error) (interface{}, error) {
if e != nil {
return nil, e
}
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, v)
if err != nil {
return nil, err
}
if expiration != nil {
t := c.clock.Now().Add(*expiration)
item.(*lfuItem).expiration = &t
}
return v, nil
}, isWait)
if err != nil {
return nil, err
}
return value, nil
}
func (c *LFUCache) increment(item *lfuItem) {
currentFreqElement := item.freqElement
currentFreqEntry := currentFreqElement.Value.(*freqEntry)
nextFreq := currentFreqEntry.freq + 1
delete(currentFreqEntry.items, item)
nextFreqElement := currentFreqElement.Next()
if nextFreqElement == nil {
nextFreqElement = c.freqList.InsertAfter(&freqEntry{
freq: nextFreq,
items: make(map[*lfuItem]struct{}),
}, currentFreqElement)
}
nextFreqElement.Value.(*freqEntry).items[item] = struct{}{}
item.freqElement = nextFreqElement
}
// evict removes the least frequence item from the cache.
func (c *LFUCache) evict(count int) {
entry := c.freqList.Front()
for i := 0; i < count; {
if entry == nil {
return
} else {
for item, _ := range entry.Value.(*freqEntry).items {
if i >= count {
return
}
c.removeItem(item)
i++
}
entry = entry.Next()
}
}
}
// Removes the provided key from the cache.
func (c *LFUCache) Remove(key interface{}) bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.remove(key)
}
func (c *LFUCache) remove(key interface{}) bool {
if item, ok := c.items[key]; ok {
c.removeItem(item)
return true
}
return false
}
// removeElement is used to remove a given list element from the cache
func (c *LFUCache) removeItem(item *lfuItem) {
delete(c.items, item.key)
delete(item.freqElement.Value.(*freqEntry).items, item)
if c.evictedFunc != nil {
c.evictedFunc(item.key, item.value)
}
}
func (c *LFUCache) keys() []interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
keys := make([]interface{}, len(c.items))
var i = 0
for k := range c.items {
keys[i] = k
i++
}
return keys
}
// Returns a slice of the keys in the cache.
func (c *LFUCache) Keys() []interface{} {
keys := []interface{}{}
for _, k := range c.keys() {
_, err := c.GetIFPresent(k)
if err == nil {
keys = append(keys, k)
}
}
return keys
}
// Returns all key-value pairs in the cache.
func (c *LFUCache) GetALL() map[interface{}]interface{} {
m := make(map[interface{}]interface{})
for _, k := range c.keys() {
v, err := c.GetIFPresent(k)
if err == nil {
m[k] = v
}
}
return m
}
// Returns the number of items in the cache.
func (c *LFUCache) Len() int {
return len(c.GetALL())
}
// Completely clear the cache
func (c *LFUCache) Purge() {
c.mu.Lock()
defer c.mu.Unlock()
if c.purgeVisitorFunc != nil {
for key, item := range c.items {
c.purgeVisitorFunc(key, item.value)
}
}
c.init()
}
type freqEntry struct {
freq uint
items map[*lfuItem]struct{}
}
type lfuItem struct {
clock Clock
key interface{}
value interface{}
freqElement *list.Element
expiration *time.Time
}
// returns boolean value whether this item is expired or not.
func (it *lfuItem) IsExpired(now *time.Time) bool {
if it.expiration == nil {
return false
}
if now == nil {
t := it.clock.Now()
now = &t
}
return it.expiration.Before(*now)
}

285
vendor/github.com/bluele/gcache/lru.go generated vendored Normal file
View File

@ -0,0 +1,285 @@
package gcache
import (
"container/list"
"time"
)
// Discards the least recently used items first.
type LRUCache struct {
baseCache
items map[interface{}]*list.Element
evictList *list.List
}
func newLRUCache(cb *CacheBuilder) *LRUCache {
c := &LRUCache{}
buildCache(&c.baseCache, cb)
c.init()
c.loadGroup.cache = c
return c
}
func (c *LRUCache) init() {
c.evictList = list.New()
c.items = make(map[interface{}]*list.Element, c.size+1)
}
func (c *LRUCache) set(key, value interface{}) (interface{}, error) {
var err error
if c.serializeFunc != nil {
value, err = c.serializeFunc(key, value)
if err != nil {
return nil, err
}
}
// Check for existing item
var item *lruItem
if it, ok := c.items[key]; ok {
c.evictList.MoveToFront(it)
item = it.Value.(*lruItem)
item.value = value
} else {
// Verify size not exceeded
if c.evictList.Len() >= c.size {
c.evict(1)
}
item = &lruItem{
clock: c.clock,
key: key,
value: value,
}
c.items[key] = c.evictList.PushFront(item)
}
if c.expiration != nil {
t := c.clock.Now().Add(*c.expiration)
item.expiration = &t
}
if c.addedFunc != nil {
c.addedFunc(key, value)
}
return item, nil
}
// set a new key-value pair
func (c *LRUCache) Set(key, value interface{}) error {
c.mu.Lock()
defer c.mu.Unlock()
_, err := c.set(key, value)
return err
}
// Set a new key-value pair with an expiration time
func (c *LRUCache) SetWithExpire(key, value interface{}, expiration time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, value)
if err != nil {
return err
}
t := c.clock.Now().Add(expiration)
item.(*lruItem).expiration = &t
return nil
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key and has LoaderFunc,
// generate a value using `LoaderFunc` method returns value.
func (c *LRUCache) Get(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, true)
}
return v, err
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key, returns KeyNotFoundError.
// And send a request which refresh value for specified key if cache object has LoaderFunc.
func (c *LRUCache) GetIFPresent(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, false)
}
return v, err
}
func (c *LRUCache) get(key interface{}, onLoad bool) (interface{}, error) {
v, err := c.getValue(key, onLoad)
if err != nil {
return nil, err
}
if c.deserializeFunc != nil {
return c.deserializeFunc(key, v)
}
return v, nil
}
func (c *LRUCache) getValue(key interface{}, onLoad bool) (interface{}, error) {
c.mu.Lock()
item, ok := c.items[key]
if ok {
it := item.Value.(*lruItem)
if !it.IsExpired(nil) {
c.evictList.MoveToFront(item)
v := it.value
c.mu.Unlock()
if !onLoad {
c.stats.IncrHitCount()
}
return v, nil
}
c.removeElement(item)
}
c.mu.Unlock()
if !onLoad {
c.stats.IncrMissCount()
}
return nil, KeyNotFoundError
}
func (c *LRUCache) getWithLoader(key interface{}, isWait bool) (interface{}, error) {
if c.loaderExpireFunc == nil {
return nil, KeyNotFoundError
}
value, _, err := c.load(key, func(v interface{}, expiration *time.Duration, e error) (interface{}, error) {
if e != nil {
return nil, e
}
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, v)
if err != nil {
return nil, err
}
if expiration != nil {
t := c.clock.Now().Add(*expiration)
item.(*lruItem).expiration = &t
}
return v, nil
}, isWait)
if err != nil {
return nil, err
}
return value, nil
}
// evict removes the oldest item from the cache.
func (c *LRUCache) evict(count int) {
for i := 0; i < count; i++ {
ent := c.evictList.Back()
if ent == nil {
return
} else {
c.removeElement(ent)
}
}
}
// Removes the provided key from the cache.
func (c *LRUCache) Remove(key interface{}) bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.remove(key)
}
func (c *LRUCache) remove(key interface{}) bool {
if ent, ok := c.items[key]; ok {
c.removeElement(ent)
return true
}
return false
}
func (c *LRUCache) removeElement(e *list.Element) {
c.evictList.Remove(e)
entry := e.Value.(*lruItem)
delete(c.items, entry.key)
if c.evictedFunc != nil {
entry := e.Value.(*lruItem)
c.evictedFunc(entry.key, entry.value)
}
}
func (c *LRUCache) keys() []interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
keys := make([]interface{}, len(c.items))
var i = 0
for k := range c.items {
keys[i] = k
i++
}
return keys
}
// Returns a slice of the keys in the cache.
func (c *LRUCache) Keys() []interface{} {
keys := []interface{}{}
for _, k := range c.keys() {
_, err := c.GetIFPresent(k)
if err == nil {
keys = append(keys, k)
}
}
return keys
}
// Returns all key-value pairs in the cache.
func (c *LRUCache) GetALL() map[interface{}]interface{} {
m := make(map[interface{}]interface{})
for _, k := range c.keys() {
v, err := c.GetIFPresent(k)
if err == nil {
m[k] = v
}
}
return m
}
// Returns the number of items in the cache.
func (c *LRUCache) Len() int {
return len(c.GetALL())
}
// Completely clear the cache
func (c *LRUCache) Purge() {
c.mu.Lock()
defer c.mu.Unlock()
if c.purgeVisitorFunc != nil {
for key, item := range c.items {
it := item.Value.(*lruItem)
v := it.value
c.purgeVisitorFunc(key, v)
}
}
c.init()
}
type lruItem struct {
clock Clock
key interface{}
value interface{}
expiration *time.Time
}
// returns boolean value whether this item is expired or not.
func (it *lruItem) IsExpired(now *time.Time) bool {
if it.expiration == nil {
return false
}
if now == nil {
t := it.clock.Now()
now = &t
}
return it.expiration.Before(*now)
}

273
vendor/github.com/bluele/gcache/simple.go generated vendored Normal file
View File

@ -0,0 +1,273 @@
package gcache
import "time"
// SimpleCache has no clear priority for evict cache. It depends on key-value map order.
type SimpleCache struct {
baseCache
items map[interface{}]*simpleItem
}
func newSimpleCache(cb *CacheBuilder) *SimpleCache {
c := &SimpleCache{}
buildCache(&c.baseCache, cb)
c.init()
c.loadGroup.cache = c
return c
}
func (c *SimpleCache) init() {
if c.size <= 0 {
c.items = make(map[interface{}]*simpleItem)
} else {
c.items = make(map[interface{}]*simpleItem, c.size)
}
}
// Set a new key-value pair
func (c *SimpleCache) Set(key, value interface{}) error {
c.mu.Lock()
defer c.mu.Unlock()
_, err := c.set(key, value)
return err
}
// Set a new key-value pair with an expiration time
func (c *SimpleCache) SetWithExpire(key, value interface{}, expiration time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, value)
if err != nil {
return err
}
t := c.clock.Now().Add(expiration)
item.(*simpleItem).expiration = &t
return nil
}
func (c *SimpleCache) set(key, value interface{}) (interface{}, error) {
var err error
if c.serializeFunc != nil {
value, err = c.serializeFunc(key, value)
if err != nil {
return nil, err
}
}
// Check for existing item
item, ok := c.items[key]
if ok {
item.value = value
} else {
// Verify size not exceeded
if (len(c.items) >= c.size) && c.size > 0 {
c.evict(1)
}
item = &simpleItem{
clock: c.clock,
value: value,
}
c.items[key] = item
}
if c.expiration != nil {
t := c.clock.Now().Add(*c.expiration)
item.expiration = &t
}
if c.addedFunc != nil {
c.addedFunc(key, value)
}
return item, nil
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key and has LoaderFunc,
// generate a value using `LoaderFunc` method returns value.
func (c *SimpleCache) Get(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, true)
}
return v, err
}
// Get a value from cache pool using key if it exists.
// If it dose not exists key, returns KeyNotFoundError.
// And send a request which refresh value for specified key if cache object has LoaderFunc.
func (c *SimpleCache) GetIFPresent(key interface{}) (interface{}, error) {
v, err := c.get(key, false)
if err == KeyNotFoundError {
return c.getWithLoader(key, false)
}
return v, nil
}
func (c *SimpleCache) get(key interface{}, onLoad bool) (interface{}, error) {
v, err := c.getValue(key, onLoad)
if err != nil {
return nil, err
}
if c.deserializeFunc != nil {
return c.deserializeFunc(key, v)
}
return v, nil
}
func (c *SimpleCache) getValue(key interface{}, onLoad bool) (interface{}, error) {
c.mu.Lock()
item, ok := c.items[key]
if ok {
if !item.IsExpired(nil) {
v := item.value
c.mu.Unlock()
if !onLoad {
c.stats.IncrHitCount()
}
return v, nil
}
c.remove(key)
}
c.mu.Unlock()
if !onLoad {
c.stats.IncrMissCount()
}
return nil, KeyNotFoundError
}
func (c *SimpleCache) getWithLoader(key interface{}, isWait bool) (interface{}, error) {
if c.loaderExpireFunc == nil {
return nil, KeyNotFoundError
}
value, _, err := c.load(key, func(v interface{}, expiration *time.Duration, e error) (interface{}, error) {
if e != nil {
return nil, e
}
c.mu.Lock()
defer c.mu.Unlock()
item, err := c.set(key, v)
if err != nil {
return nil, err
}
if expiration != nil {
t := c.clock.Now().Add(*expiration)
item.(*simpleItem).expiration = &t
}
return v, nil
}, isWait)
if err != nil {
return nil, err
}
return value, nil
}
func (c *SimpleCache) evict(count int) {
now := c.clock.Now()
current := 0
for key, item := range c.items {
if current >= count {
return
}
if item.expiration == nil || now.After(*item.expiration) {
defer c.remove(key)
current++
}
}
}
// Removes the provided key from the cache.
func (c *SimpleCache) Remove(key interface{}) bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.remove(key)
}
func (c *SimpleCache) remove(key interface{}) bool {
item, ok := c.items[key]
if ok {
delete(c.items, key)
if c.evictedFunc != nil {
c.evictedFunc(key, item.value)
}
return true
}
return false
}
// Returns a slice of the keys in the cache.
func (c *SimpleCache) keys() []interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
keys := make([]interface{}, len(c.items))
var i = 0
for k := range c.items {
keys[i] = k
i++
}
return keys
}
// Returns a slice of the keys in the cache.
func (c *SimpleCache) Keys() []interface{} {
keys := []interface{}{}
for _, k := range c.keys() {
_, err := c.GetIFPresent(k)
if err == nil {
keys = append(keys, k)
}
}
return keys
}
// Returns all key-value pairs in the cache.
func (c *SimpleCache) GetALL() map[interface{}]interface{} {
m := make(map[interface{}]interface{})
for _, k := range c.keys() {
v, err := c.GetIFPresent(k)
if err == nil {
m[k] = v
}
}
return m
}
// Returns the number of items in the cache.
func (c *SimpleCache) Len() int {
return len(c.GetALL())
}
// Completely clear the cache
func (c *SimpleCache) Purge() {
c.mu.Lock()
defer c.mu.Unlock()
if c.purgeVisitorFunc != nil {
for key, item := range c.items {
c.purgeVisitorFunc(key, item.value)
}
}
c.init()
}
type simpleItem struct {
clock Clock
value interface{}
expiration *time.Time
}
// returns boolean value whether this item is expired or not.
func (si *simpleItem) IsExpired(now *time.Time) bool {
if si.expiration == nil {
return false
}
if now == nil {
t := si.clock.Now()
now = &t
}
return si.expiration.Before(*now)
}

82
vendor/github.com/bluele/gcache/singleflight.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
package gcache
/*
Copyright 2012 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This module provides a duplicate function call suppression
// mechanism.
import "sync"
// call is an in-flight or completed Do call
type call struct {
wg sync.WaitGroup
val interface{}
err error
}
// Group represents a class of work and forms a namespace in which
// units of work can be executed with duplicate suppression.
type Group struct {
cache Cache
mu sync.Mutex // protects m
m map[interface{}]*call // lazily initialized
}
// Do executes and returns the results of the given function, making
// sure that only one execution is in-flight for a given key at a
// time. If a duplicate comes in, the duplicate caller waits for the
// original to complete and receives the same results.
func (g *Group) Do(key interface{}, fn func() (interface{}, error), isWait bool) (interface{}, bool, error) {
g.mu.Lock()
v, err := g.cache.get(key, true)
if err == nil {
g.mu.Unlock()
return v, false, nil
}
if g.m == nil {
g.m = make(map[interface{}]*call)
}
if c, ok := g.m[key]; ok {
g.mu.Unlock()
if !isWait {
return nil, false, KeyNotFoundError
}
c.wg.Wait()
return c.val, false, c.err
}
c := new(call)
c.wg.Add(1)
g.m[key] = c
g.mu.Unlock()
if !isWait {
go g.call(c, key, fn)
return nil, false, KeyNotFoundError
}
v, err = g.call(c, key, fn)
return v, true, err
}
func (g *Group) call(c *call, key interface{}, fn func() (interface{}, error)) (interface{}, error) {
c.val, c.err = fn()
c.wg.Done()
g.mu.Lock()
delete(g.m, key)
g.mu.Unlock()
return c.val, c.err
}

53
vendor/github.com/bluele/gcache/stats.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
package gcache
import (
"sync/atomic"
)
type statsAccessor interface {
HitCount() uint64
MissCount() uint64
LookupCount() uint64
HitRate() float64
}
// statistics
type stats struct {
hitCount uint64
missCount uint64
}
// increment hit count
func (st *stats) IncrHitCount() uint64 {
return atomic.AddUint64(&st.hitCount, 1)
}
// increment miss count
func (st *stats) IncrMissCount() uint64 {
return atomic.AddUint64(&st.missCount, 1)
}
// HitCount returns hit count
func (st *stats) HitCount() uint64 {
return atomic.LoadUint64(&st.hitCount)
}
// MissCount returns miss count
func (st *stats) MissCount() uint64 {
return atomic.LoadUint64(&st.missCount)
}
// LookupCount returns lookup count
func (st *stats) LookupCount() uint64 {
return st.HitCount() + st.MissCount()
}
// HitRate returns rate for cache hitting
func (st *stats) HitRate() float64 {
hc, mc := st.HitCount(), st.MissCount()
total := hc + mc
if total == 0 {
return 0.0
}
return float64(hc) / float64(total)
}

15
vendor/github.com/bluele/gcache/utils.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
package gcache
func minInt(x, y int) int {
if x < y {
return x
}
return y
}
func maxInt(x, y int) int {
if x > y {
return x
}
return y
}

51
vendor/github.com/bluele/gcache/wercker.yml generated vendored Normal file
View File

@ -0,0 +1,51 @@
# This references the default golang container from
# the Docker Hub: https://registry.hub.docker.com/u/library/golang/
# If you want Google's container you would reference google/golang
# Read more about containers on our dev center
# http://devcenter.wercker.com/docs/containers/index.html
box: golang
# This is the build pipeline. Pipelines are the core of wercker
# Read more about pipelines on our dev center
# http://devcenter.wercker.com/docs/pipelines/index.html
# You can also use services such as databases. Read more on our dev center:
# http://devcenter.wercker.com/docs/services/index.html
# services:
# - postgres
# http://devcenter.wercker.com/docs/services/postgresql.html
# - mongo
# http://devcenter.wercker.com/docs/services/mongodb.html
build:
# The steps that will be executed on build
# Steps make up the actions in your pipeline
# Read more about steps on our dev center:
# http://devcenter.wercker.com/docs/steps/index.html
steps:
# Sets the go workspace and places you package
# at the right place in the workspace tree
- setup-go-workspace
# Prints go version
- script:
name: go version
code: |
go version
# Gets the dependencies
- script:
name: go get
code: |
go get
# Build the project
- script:
name: go build
code: |
go build
# Test the project
- script:
name: go test
code: |
go test -v