parent
749eb11830
commit
3e30e50a09
@ -1,108 +1,20 @@
|
|||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import "github.com/hashicorp/golang-lru/v2/simplelru"
|
||||||
"github.com/hashicorp/golang-lru/v2/simplelru"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LRU1[K comparable, V any] interface {
|
type EvictCallback[K comparable, V any] simplelru.EvictCallback[K, V]
|
||||||
|
|
||||||
|
type LRU[K comparable, V any] interface {
|
||||||
Get(key K, fetch func() (V, error)) (V, error)
|
Get(key K, fetch func() (V, error)) (V, error)
|
||||||
Del(key K) bool
|
Del(key K) bool
|
||||||
Stop()
|
Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
//type expirableLRU[K comparable, V any] struct {
|
type Target interface {
|
||||||
// core expirable.LRU[K, V]
|
IncrGetHit()
|
||||||
//}
|
IncrGetSuccess()
|
||||||
//
|
IncrGetFailed()
|
||||||
//func (x *expirableLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
|
||||||
//
|
|
||||||
// return x.core.Get(key, fetch)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (x *expirableLRU[K, V]) Del(key K) bool {
|
|
||||||
// return x.core.Remove(key)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (x *expirableLRU[K, V]) Stop() {
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
|
||||||
type waitItem[V any] struct {
|
|
||||||
lock sync.Mutex
|
|
||||||
expires int64
|
|
||||||
err error
|
|
||||||
value V
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) *LRU[K, V] {
|
|
||||||
var cb simplelru.EvictCallback[K, *waitItem[V]]
|
|
||||||
if onEvict != nil {
|
|
||||||
cb = func(key K, value *waitItem[V]) {
|
|
||||||
onEvict(key, value.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
core, err := simplelru.NewLRU[K, *waitItem[V]](size, cb)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return &LRU[K, V]{
|
|
||||||
core: core,
|
|
||||||
successTTL: successTTL,
|
|
||||||
failedTTL: failedTTL,
|
|
||||||
target: target,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type LRU[K comparable, V any] struct {
|
|
||||||
lock sync.Mutex
|
|
||||||
core *simplelru.LRU[K, *waitItem[V]]
|
|
||||||
successTTL time.Duration
|
|
||||||
failedTTL time.Duration
|
|
||||||
target Target
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
|
||||||
x.lock.Lock()
|
|
||||||
v, ok := x.core.Get(key)
|
|
||||||
if ok {
|
|
||||||
x.lock.Unlock()
|
|
||||||
v.lock.Lock()
|
|
||||||
expires, value, err := v.expires, v.value, v.err
|
|
||||||
if expires != 0 && expires > time.Now().UnixMilli() {
|
|
||||||
v.lock.Unlock()
|
|
||||||
x.target.IncrGetHit()
|
|
||||||
return value, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
v = &waitItem[V]{}
|
|
||||||
x.core.Add(key, v)
|
|
||||||
v.lock.Lock()
|
|
||||||
x.lock.Unlock()
|
|
||||||
}
|
|
||||||
defer v.lock.Unlock()
|
|
||||||
if v.expires > time.Now().UnixMilli() {
|
|
||||||
return v.value, v.err
|
|
||||||
}
|
|
||||||
v.value, v.err = fetch()
|
|
||||||
if v.err == nil {
|
|
||||||
v.expires = time.Now().Add(x.successTTL).UnixMilli()
|
|
||||||
x.target.IncrGetSuccess()
|
|
||||||
} else {
|
|
||||||
v.expires = time.Now().Add(x.failedTTL).UnixMilli()
|
|
||||||
x.target.IncrGetFailed()
|
|
||||||
}
|
|
||||||
return v.value, v.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LRU[K, V]) Del(key K) bool {
|
|
||||||
x.lock.Lock()
|
|
||||||
ok := x.core.Remove(key)
|
|
||||||
x.lock.Unlock()
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LRU[K, V]) Stop() {
|
|
||||||
|
|
||||||
|
IncrDelHit()
|
||||||
|
IncrDelNotFound()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewExpirableLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) LRU[K, V] {
|
||||||
|
var cb expirable.EvictCallback[K, *expirableLruItem[V]]
|
||||||
|
if onEvict != nil {
|
||||||
|
cb = func(key K, value *expirableLruItem[V]) {
|
||||||
|
onEvict(key, value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core := expirable.NewLRU[K, *expirableLruItem[V]](size, cb, successTTL)
|
||||||
|
return &expirableLRU[K, V]{
|
||||||
|
core: core,
|
||||||
|
successTTL: successTTL,
|
||||||
|
failedTTL: failedTTL,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type expirableLruItem[V any] struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
err error
|
||||||
|
value V
|
||||||
|
}
|
||||||
|
|
||||||
|
type expirableLRU[K comparable, V any] struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
core *expirable.LRU[K, *expirableLruItem[V]]
|
||||||
|
successTTL time.Duration
|
||||||
|
failedTTL time.Duration
|
||||||
|
target Target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *expirableLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
||||||
|
x.lock.Lock()
|
||||||
|
v, ok := x.core.Get(key)
|
||||||
|
if ok {
|
||||||
|
x.lock.Unlock()
|
||||||
|
x.target.IncrGetSuccess()
|
||||||
|
v.lock.RLock()
|
||||||
|
defer v.lock.RUnlock()
|
||||||
|
return v.value, v.err
|
||||||
|
} else {
|
||||||
|
v = &expirableLruItem[V]{}
|
||||||
|
x.core.Add(key, v)
|
||||||
|
v.lock.Lock()
|
||||||
|
x.lock.Unlock()
|
||||||
|
defer v.lock.Unlock()
|
||||||
|
v.value, v.err = fetch()
|
||||||
|
if v.err == nil {
|
||||||
|
x.target.IncrGetSuccess()
|
||||||
|
} else {
|
||||||
|
x.target.IncrGetFailed()
|
||||||
|
x.core.Remove(key)
|
||||||
|
}
|
||||||
|
return v.value, v.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *expirableLRU[K, V]) Del(key K) bool {
|
||||||
|
x.lock.Lock()
|
||||||
|
ok := x.core.Remove(key)
|
||||||
|
x.lock.Unlock()
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *expirableLRU[K, V]) Stop() {
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type inertiaLruItem[V any] struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
expires int64
|
||||||
|
err error
|
||||||
|
value V
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInertiaLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) *InertiaLRU[K, V] {
|
||||||
|
var cb simplelru.EvictCallback[K, *inertiaLruItem[V]]
|
||||||
|
if onEvict != nil {
|
||||||
|
cb = func(key K, value *inertiaLruItem[V]) {
|
||||||
|
onEvict(key, value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core, err := simplelru.NewLRU[K, *inertiaLruItem[V]](size, cb)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return &InertiaLRU[K, V]{
|
||||||
|
core: core,
|
||||||
|
successTTL: successTTL,
|
||||||
|
failedTTL: failedTTL,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type InertiaLRU[K comparable, V any] struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
core *simplelru.LRU[K, *inertiaLruItem[V]]
|
||||||
|
successTTL time.Duration
|
||||||
|
failedTTL time.Duration
|
||||||
|
target Target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *InertiaLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
||||||
|
x.lock.Lock()
|
||||||
|
v, ok := x.core.Get(key)
|
||||||
|
if ok {
|
||||||
|
x.lock.Unlock()
|
||||||
|
v.lock.Lock()
|
||||||
|
expires, value, err := v.expires, v.value, v.err
|
||||||
|
if expires != 0 && expires > time.Now().UnixMilli() {
|
||||||
|
v.lock.Unlock()
|
||||||
|
x.target.IncrGetHit()
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = &inertiaLruItem[V]{}
|
||||||
|
x.core.Add(key, v)
|
||||||
|
v.lock.Lock()
|
||||||
|
x.lock.Unlock()
|
||||||
|
}
|
||||||
|
defer v.lock.Unlock()
|
||||||
|
if v.expires > time.Now().UnixMilli() {
|
||||||
|
return v.value, v.err
|
||||||
|
}
|
||||||
|
v.value, v.err = fetch()
|
||||||
|
if v.err == nil {
|
||||||
|
v.expires = time.Now().Add(x.successTTL).UnixMilli()
|
||||||
|
x.target.IncrGetSuccess()
|
||||||
|
} else {
|
||||||
|
v.expires = time.Now().Add(x.failedTTL).UnixMilli()
|
||||||
|
x.target.IncrGetFailed()
|
||||||
|
}
|
||||||
|
return v.value, v.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *InertiaLRU[K, V]) Del(key K) bool {
|
||||||
|
x.lock.Lock()
|
||||||
|
ok := x.core.Remove(key)
|
||||||
|
x.lock.Unlock()
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *InertiaLRU[K, V]) Stop() {
|
||||||
|
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
package local
|
|
||||||
|
|
||||||
type Target interface {
|
|
||||||
IncrGetHit()
|
|
||||||
IncrGetSuccess()
|
|
||||||
IncrGetFailed()
|
|
||||||
|
|
||||||
IncrDelHit()
|
|
||||||
IncrDelNotFound()
|
|
||||||
}
|
|
Loading…
Reference in new issue