Skip to content

Commit

Permalink
Use "github.com/hashicorp/golang-lru" (#1064)
Browse files Browse the repository at this point in the history
  • Loading branch information
ije authored Jan 30, 2025
1 parent 6daf7d1 commit d6bae9b
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 37 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
go.etcd.io/bbolt v1.3.11
golang.org/x/net v0.34.0
golang.org/x/term v0.28.0
github.com/hashicorp/golang-lru/v2 v2.0.7
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/evanw/esbuild v0.24.2 h1:PQExybVBrjHjN6/JJiShRGIXh1hWVm6NepVnhZhrt0A=
github.com/evanw/esbuild v0.24.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/ije/esbuild-internal v0.24.2 h1:i1sjIu6suFZ1Arc4w0gWNE8OLLiAhEQ3nhU987uB+5w=
github.com/ije/esbuild-internal v0.24.2/go.mod h1:s7HvKZ4ZGifyzvgWpSwnJOQTr6b+bsgfNBZ8HAEwwSM=
github.com/ije/gox v0.9.7 h1:KfEiWOvk/ZqhJnTxJCWMB8mkBLi3HYhGJrrxQyua204=
Expand Down
54 changes: 17 additions & 37 deletions server/cache.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
package server

import (
"container/list"
"strings"
"sync"
"time"

lru "github.com/hashicorp/golang-lru/v2"
syncx "github.com/ije/gox/sync"
)

var (
cacheMutex syncx.KeyedMutex
cacheStore sync.Map
cacheLRU *list.List
cacheLRU *lru.Cache[string, any]
)

type cacheRecord struct {
key string
value any
}

type cacheItem struct {
exp int64
data any
Expand All @@ -36,7 +30,7 @@ func withCache[T any](key string, cacheTtl time.Duration, fetch func() (T, strin
}
}

unlock := cacheMutex.Lock(key)
unlock := cacheMutex.Lock("lru:" + key)
defer unlock()

// check cache store again after get lock
Expand Down Expand Up @@ -66,52 +60,34 @@ func withCache[T any](key string, cacheTtl time.Duration, fetch func() (T, strin
}

func withLRUCache[T any](key string, fetch func() (T, error)) (data T, err error) {
cacheKey := "lru:" + key

// check cache store first
if v, ok := cacheStore.Load(cacheKey); ok {
el := v.(*cacheItem).data.(*list.Element)
cacheLRU.MoveToFront(el)
return el.Value.(cacheRecord).value.(T), nil
if v, ok := cacheLRU.Get(key); ok {
return v.(T), nil
}

unlock := cacheMutex.Lock(cacheKey)
unlock := cacheMutex.Lock(key)
defer unlock()

// check cache store again after get lock
if v, ok := cacheStore.Load(cacheKey); ok {
el := v.(*cacheItem).data.(*list.Element)
return el.Value.(cacheRecord).value.(T), nil
if v, ok := cacheLRU.Get(key); ok {
return v.(T), nil
}

data, err = fetch()
if err != nil {
return
}

el := cacheLRU.PushFront(cacheRecord{cacheKey, data})
cacheStore.Store(cacheKey, &cacheItem{-1, el})

// delete the oldest item if cache store is full
if cacheLRU.Len() > 1000 {
el := cacheLRU.Back()
if el != nil {
cacheLRU.Remove(el)
cacheStore.Delete(el.Value.(cacheRecord).key)
}
}

cacheLRU.Add(key, data)
return
}

func gc(now time.Time) {
expKeys := []string{}
cacheStore.Range(func(key, value any) bool {
if !strings.HasPrefix(key.(string), "lru:") {
item := value.(*cacheItem)
if item.exp > 0 && item.exp < now.UnixMilli() {
expKeys = append(expKeys, key.(string))
}
item := value.(*cacheItem)
if item.exp > 0 && item.exp < now.UnixMilli() {
expKeys = append(expKeys, key.(string))
}
return true
})
Expand All @@ -121,7 +97,11 @@ func gc(now time.Time) {
}

func init() {
cacheLRU = list.New()
var err error
cacheLRU, err = lru.New[string, any](lruCacheCapacity)
if err != nil {
panic(err)
}
// cache GC
go func() {
tick := time.NewTicker(10 * time.Minute)
Expand Down
4 changes: 4 additions & 0 deletions server/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"testing"
"time"

lru "github.com/hashicorp/golang-lru/v2"
)

func getCacheSize() int {
Expand Down Expand Up @@ -44,6 +46,8 @@ func TestCache(t *testing.T) {
}

func TestLRUCache(t *testing.T) {
cacheLRU, _ = lru.New[string, any](1000)

for i := 0; i < 2000; i++ {
withLRUCache(fmt.Sprintf("item-%d", i), func() ([]byte, error) {
return []byte{byte(i % 256)}, nil
Expand Down
1 change: 1 addition & 0 deletions server/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const (
MB = 1 << 20
maxAssetFileSize = 50 * MB
maxPackageTarballSize = 256 * MB
lruCacheCapacity = 10000
)

// asset extensions
Expand Down

0 comments on commit d6bae9b

Please sign in to comment.