123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- package cache
- import (
- "container/list"
- "sync"
- "sync/atomic"
- )
- const (
-
- concurrencyLevel = 2
- segmentCount = 1 << concurrencyLevel
- segmentMask = segmentCount - 1
- )
- type entry struct {
-
-
-
- hash uint64
-
- accessTime int64
-
- writeTime int64
-
- invalidated int32
- loading int32
- key Key
- value atomic.Value
-
-
- accessList *list.Element
-
- writeList *list.Element
-
- listID uint8
- }
- func newEntry(k Key, v Value, h uint64) *entry {
- en := &entry{
- key: k,
- hash: h,
- }
- en.setValue(v)
- return en
- }
- func (e *entry) getValue() Value {
- return e.value.Load().(Value)
- }
- func (e *entry) setValue(v Value) {
- e.value.Store(v)
- }
- func (e *entry) getAccessTime() int64 {
- return atomic.LoadInt64(&e.accessTime)
- }
- func (e *entry) setAccessTime(v int64) {
- atomic.StoreInt64(&e.accessTime, v)
- }
- func (e *entry) getWriteTime() int64 {
- return atomic.LoadInt64(&e.writeTime)
- }
- func (e *entry) setWriteTime(v int64) {
- atomic.StoreInt64(&e.writeTime, v)
- }
- func (e *entry) getLoading() bool {
- return atomic.LoadInt32(&e.loading) != 0
- }
- func (e *entry) setLoading(v bool) bool {
- if v {
- return atomic.CompareAndSwapInt32(&e.loading, 0, 1)
- }
- return atomic.CompareAndSwapInt32(&e.loading, 1, 0)
- }
- func (e *entry) getInvalidated() bool {
- return atomic.LoadInt32(&e.invalidated) != 0
- }
- func (e *entry) setInvalidated(v bool) {
- if v {
- atomic.StoreInt32(&e.invalidated, 1)
- } else {
- atomic.StoreInt32(&e.invalidated, 0)
- }
- }
- func getEntry(el *list.Element) *entry {
- return el.Value.(*entry)
- }
- type event uint8
- const (
- eventWrite event = iota
- eventAccess
- eventDelete
- eventClose
- )
- type entryEvent struct {
- entry *entry
- event event
- }
- type cache struct {
- size int64
- segs [segmentCount]sync.Map
- }
- func (c *cache) get(k Key, h uint64) *entry {
- seg := c.segment(h)
- v, ok := seg.Load(k)
- if ok {
- return v.(*entry)
- }
- return nil
- }
- func (c *cache) getOrSet(v *entry) *entry {
- seg := c.segment(v.hash)
- en, ok := seg.LoadOrStore(v.key, v)
- if ok {
- return en.(*entry)
- }
- atomic.AddInt64(&c.size, 1)
- return nil
- }
- func (c *cache) delete(v *entry) {
- seg := c.segment(v.hash)
- seg.Delete(v.key)
- atomic.AddInt64(&c.size, -1)
- }
- func (c *cache) len() int {
- return int(atomic.LoadInt64(&c.size))
- }
- func (c *cache) walk(fn func(*entry)) {
- for i := range c.segs {
- c.segs[i].Range(func(k, v interface{}) bool {
- fn(v.(*entry))
- return true
- })
- }
- }
- func (c *cache) segment(h uint64) *sync.Map {
- return &c.segs[h&segmentMask]
- }
- type policy interface {
-
- init(cache *cache, maximumSize int)
-
-
- write(entry *entry) *entry
-
-
- access(entry *entry)
-
- remove(entry *entry) *entry
-
- iterate(func(entry *entry) bool)
- }
- func newPolicy(name string) policy {
- switch name {
- case "", "slru":
- return &slruCache{}
- case "lru":
- return &lruCache{}
- case "tinylfu":
- return &tinyLFU{}
- default:
- panic("cache: unsupported policy " + name)
- }
- }
- type recencyQueue struct {
- ls list.List
- }
- func (w *recencyQueue) init(cache *cache, maximumSize int) {
- w.ls.Init()
- }
- func (w *recencyQueue) write(en *entry) *entry {
- if en.writeList == nil {
- en.writeList = w.ls.PushFront(en)
- } else {
- w.ls.MoveToFront(en.writeList)
- }
- return nil
- }
- func (w *recencyQueue) access(en *entry) {
- }
- func (w *recencyQueue) remove(en *entry) *entry {
- if en.writeList == nil {
- return en
- }
- w.ls.Remove(en.writeList)
- en.writeList = nil
- return en
- }
- func (w *recencyQueue) iterate(fn func(en *entry) bool) {
- iterateListFromBack(&w.ls, fn)
- }
- type discardingQueue struct{}
- func (discardingQueue) init(cache *cache, maximumSize int) {
- }
- func (discardingQueue) write(en *entry) *entry {
- return nil
- }
- func (discardingQueue) access(en *entry) {
- }
- func (discardingQueue) remove(en *entry) *entry {
- return en
- }
- func (discardingQueue) iterate(fn func(en *entry) bool) {
- }
- func iterateListFromBack(ls *list.List, fn func(en *entry) bool) {
- for el := ls.Back(); el != nil; {
- en := getEntry(el)
- prev := el.Prev()
- if !fn(en) {
- return
- }
- el = prev
- }
- }
|