Skip to content

Commit

Permalink
feat: support lru store
Browse files Browse the repository at this point in the history
  • Loading branch information
vicanso committed Aug 13, 2023
1 parent 49ada93 commit 7c7ec73
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 2 deletions.
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ jobs:
- '1.20'
- '1.19'
- '1.18'
- '1.17'
steps:

- name: Go ${{ matrix.go }} test
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
module github.com/vicanso/elton

go 1.17
go 1.18

require (
github.com/andybalholm/brotli v1.0.5
github.com/hashicorp/golang-lru/v2 v2.0.5
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.15.0
github.com/vicanso/hes v0.6.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
93 changes: 93 additions & 0 deletions middleware/lru_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// MIT License

// Copyright (c) 2023 Tree Xie

// 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.
package middleware

import (
"context"
"encoding/binary"
"time"

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

var _ CacheStore = (*lruStore)(nil)

type lruStore struct {
usePeek bool
store *lru.Cache[string, []byte]
}

const expiredByteSize = 4

func now_seconds() uint32 {
return uint32(time.Now().Unix())
}

func (s *lruStore) Get(ctx context.Context, key string) ([]byte, error) {
var value []byte
var ok bool
// 使用peek更高性能
if s.usePeek {
value, ok = s.store.Peek(key)
} else {
value, ok = s.store.Get(key)
}
if !ok || len(value) < expiredByteSize {
return nil, nil
}
expired := binary.BigEndian.Uint32(value)
if now_seconds() > expired {
return nil, nil
}
return value[expiredByteSize:], nil
}

func (s *lruStore) Set(ctx context.Context, key string, data []byte, ttl time.Duration) error {
buf := make([]byte, len(data)+expiredByteSize)
expired := now_seconds() + uint32(ttl/time.Second)
binary.BigEndian.PutUint32(buf, expired)
copy(buf[expiredByteSize:], data)
s.store.Add(key, buf)
return nil
}

func newLruStore(size int, usePeek bool) *lruStore {
if size <= 0 {
size = 128
}
// 只要size > 0则不会出错
s, _ := lru.New[string, []byte](size)
return &lruStore{
usePeek: usePeek,
store: s,
}
}

// NewPeekLruStore creates a lru store use peek
func NewPeekLruStore(size int) *lruStore {
return newLruStore(size, true)
}

// NewLruStore creates a lru store
func NewLruStore(size int) *lruStore {
return newLruStore(size, false)
}
50 changes: 50 additions & 0 deletions middleware/lru_store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// MIT License

// Copyright (c) 2023 Tree Xie

// 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.

package middleware

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestLruStore(t *testing.T) {
assert := assert.New(t)

store := NewLruStore(128)

ctx := context.Background()
key1 := "1"
buf, _ := store.Get(ctx, key1)
assert.Empty(buf)

_ = store.Set(ctx, key1, []byte("Hello world!"), time.Second)
buf, _ = store.Get(ctx, key1)
assert.Equal([]byte("Hello world!"), buf)

time.Sleep(2 * time.Second)
buf, _ = store.Get(ctx, key1)
assert.Empty(buf)
}

0 comments on commit 7c7ec73

Please sign in to comment.