Files
gf/os/gcache/gcache_adapter_memory_lru.go

113 lines
2.9 KiB
Go
Raw Normal View History

2021-01-17 21:46:25 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2018-03-27 17:53:46 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2018-03-27 17:53:46 +08:00
package gcache
import (
"context"
2019-06-11 20:57:43 +08:00
"time"
2019-07-29 21:01:19 +08:00
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/os/gtimer"
2018-03-27 17:53:46 +08:00
)
2019-06-11 20:57:43 +08:00
// LRU cache object.
// It uses list.List from stdlib for its underlying doubly linked list.
2020-09-26 20:47:29 +08:00
type adapterMemoryLru struct {
cache *AdapterMemory // Parent cache object.
2020-09-26 20:47:29 +08:00
data *gmap.Map // Key mapping to the item of the list.
list *glist.List // Key list.
rawList *glist.List // History for key adding.
closed *gtype.Bool // Closed or not.
2018-03-27 17:53:46 +08:00
}
2019-06-11 20:57:43 +08:00
// newMemCacheLru creates and returns a new LRU object.
func newMemCacheLru(cache *AdapterMemory) *adapterMemoryLru {
2020-09-26 20:47:29 +08:00
lru := &adapterMemoryLru{
2019-06-19 09:06:52 +08:00
cache: cache,
data: gmap.New(true),
list: glist.New(true),
rawList: glist.New(true),
2019-06-19 09:06:52 +08:00
closed: gtype.NewBool(),
}
gtimer.AddSingleton(context.Background(), time.Second, lru.SyncAndClear)
2019-06-19 09:06:52 +08:00
return lru
2018-03-27 17:53:46 +08:00
}
2019-06-11 20:57:43 +08:00
// Close closes the LRU object.
2020-09-26 20:47:29 +08:00
func (lru *adapterMemoryLru) Close() {
2019-06-19 09:06:52 +08:00
lru.closed.Set(true)
2018-03-27 17:53:46 +08:00
}
2021-08-27 00:01:15 +08:00
// Remove deletes the `key` FROM `lru`.
2020-09-26 20:47:29 +08:00
func (lru *adapterMemoryLru) Remove(key interface{}) {
2019-06-19 09:06:52 +08:00
if v := lru.data.Get(key); v != nil {
lru.data.Remove(key)
lru.list.Remove(v.(*glist.Element))
}
}
2021-08-27 00:01:15 +08:00
// Size returns the size of `lru`.
2020-09-26 20:47:29 +08:00
func (lru *adapterMemoryLru) Size() int {
2019-06-19 09:06:52 +08:00
return lru.data.Size()
2018-09-19 09:47:50 +08:00
}
2021-08-27 00:01:15 +08:00
// Push pushes `key` to the tail of `lru`.
2020-09-26 20:47:29 +08:00
func (lru *adapterMemoryLru) Push(key interface{}) {
2019-06-19 09:06:52 +08:00
lru.rawList.PushBack(key)
2018-03-27 17:53:46 +08:00
}
2021-08-27 00:01:15 +08:00
// Pop deletes and returns the key from tail of `lru`.
2020-09-26 20:47:29 +08:00
func (lru *adapterMemoryLru) Pop() interface{} {
2019-06-19 09:06:52 +08:00
if v := lru.list.PopBack(); v != nil {
lru.data.Remove(v)
return v
}
return nil
2018-03-27 17:53:46 +08:00
}
2019-06-11 20:57:43 +08:00
// Print is used for test only.
2021-11-15 20:26:31 +08:00
// func (lru *adapterMemoryLru) Print() {
2019-06-11 20:57:43 +08:00
// for _, v := range lru.list.FrontAll() {
// fmt.Printf("%v ", v)
// }
// fmt.Println()
2021-11-15 20:26:31 +08:00
// }
2018-03-27 17:53:46 +08:00
2021-08-27 00:01:15 +08:00
// SyncAndClear synchronizes the keys from `rawList` to `list` and `data`
2019-06-11 20:57:43 +08:00
// using Least Recently Used algorithm.
func (lru *adapterMemoryLru) SyncAndClear(ctx context.Context) {
2019-06-19 09:06:52 +08:00
if lru.closed.Val() {
gtimer.Exit()
return
}
// Data synchronization.
2021-10-30 16:00:38 +08:00
var (
alreadyExistItem interface{}
)
2019-06-19 09:06:52 +08:00
for {
2021-10-30 16:00:38 +08:00
if rawListItem := lru.rawList.PopFront(); rawListItem != nil {
2019-06-19 09:06:52 +08:00
// Deleting the key from list.
2021-10-30 16:00:38 +08:00
if alreadyExistItem = lru.data.Get(rawListItem); alreadyExistItem != nil {
lru.list.Remove(alreadyExistItem.(*glist.Element))
2019-06-19 09:06:52 +08:00
}
// Pushing key to the head of the list
// and setting its list item to hash table for quick indexing.
2021-10-30 16:00:38 +08:00
lru.data.Set(rawListItem, lru.list.PushFront(rawListItem))
2019-06-19 09:06:52 +08:00
} else {
break
}
}
// Data cleaning up.
for i := lru.Size() - lru.cache.cap; i > 0; i-- {
if s := lru.Pop(); s != nil {
lru.cache.clearByKey(s, true)
}
}
}