Skip to content

Commit c66936b

Browse files
author
coder2z
committed
xcache
1 parent 163e16b commit c66936b

File tree

4 files changed

+137
-47
lines changed

4 files changed

+137
-47
lines changed

xcache/basis.go

Lines changed: 97 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package xcache
22

33
import (
4+
"context"
45
"github.com/pkg/errors"
56
"golang.org/x/sync/singleflight"
67
"time"
@@ -10,39 +11,78 @@ type (
1011
basis struct {
1112
data map[string]node
1213
loadGroup *singleflight.Group
14+
ctx context.Context
1315
}
1416

1517
node struct {
1618
data []byte
1719
expire time.Duration
1820
creatTime time.Time
1921
}
22+
23+
do func() (interface{}, error)
2024
)
2125

26+
func (b *basis) GetContext() context.Context {
27+
if b.ctx == nil {
28+
b.ctx = context.Background()
29+
}
30+
return b.ctx
31+
}
32+
33+
func (b *basis) WithContext(ctx context.Context) Cache {
34+
b.ctx = ctx
35+
return b
36+
}
37+
2238
func NewBasis() *basis {
2339
return &basis{
2440
data: make(map[string]node),
2541
loadGroup: &singleflight.Group{},
2642
}
2743
}
2844

29-
func (b basis) Del(keys ...string) error {
30-
for _, key := range keys {
31-
b.doDel(key)
45+
func (b *basis) Del(keys ...string) error {
46+
_, err := done(b.GetContext(), func() (interface{}, error) {
47+
for _, key := range keys {
48+
b.doDel(key)
49+
}
50+
return nil, nil
51+
})
52+
return err
53+
}
54+
55+
func done(ctx context.Context, df do) (interface{}, error) {
56+
var (
57+
c = make(chan struct{})
58+
ret interface{}
59+
err error
60+
)
61+
go func() {
62+
ret, err = df()
63+
close(c)
64+
}()
65+
select {
66+
case <-ctx.Done():
67+
return nil, ctx.Err()
68+
case <-c:
3269
}
33-
return nil
70+
return ret, err
3471
}
3572

3673
func (b basis) GetE(key string) ([]byte, error) {
37-
node, ok := b.data[key]
38-
if !ok {
39-
return nil, nilError
40-
}
41-
if b.checkExpire(node) {
42-
b.doDel(key)
43-
return nil, nilError
44-
}
45-
return node.data, nil
74+
ret, err := done(b.GetContext(), func() (interface{}, error) {
75+
node, ok := b.data[key]
76+
if !ok {
77+
return nil, nilError
78+
}
79+
if b.checkExpire(node) {
80+
b.doDel(key)
81+
return nil, nilError
82+
}
83+
return node.data, nil
84+
})
85+
return toByte(ret, err)
4686
}
4787

4888
func (b basis) Get(key string) []byte {
@@ -51,22 +91,27 @@ func (b basis) Get(key string) []byte {
5191
}
5292

5393
func (b basis) GetWithCreateE(key string, h Handle) ([]byte, error) {
54-
data, err := b.GetE(key)
55-
if err == nil {
56-
return data, err
57-
}
58-
if !b.IsNilError(err) {
59-
return nil, err
60-
}
61-
do, err, _ := b.loadGroup.Do(key, func() (interface{}, error) {
62-
return h.Create()
94+
ret, err := done(b.GetContext(), func() (interface{}, error) {
95+
data, err := b.GetE(key)
96+
if err == nil {
97+
return data, err
98+
}
99+
if !b.IsNilError(err) {
100+
return nil, err
101+
}
102+
doData, err, _ := b.loadGroup.Do(key, func() (interface{}, error) {
103+
data, err := h.Create(b.GetContext())
104+
if err == nil {
105+
b.doSetWithData(key, data, h.Expire())
106+
}
107+
return data, err
108+
})
109+
if err != nil {
110+
return nil, errors.Wrap(err, "x cache create data error")
111+
}
112+
return doData, err
63113
})
64-
if err != nil {
65-
return nil, errors.Wrap(err, "x cache create data error")
66-
}
67-
data, _ = do.([]byte)
68-
b.doSetWithData(key, data, h.Expire())
69-
return data, nil
114+
return toByte(ret, err)
70115
}
71116

72117
func (b basis) GetWithCreate(key string, h Handle) []byte {
@@ -83,23 +128,31 @@ func (b basis) doSetWithData(key string, data []byte, expire time.Duration) {
83128
}
84129

85130
func (b basis) Set(key string, h Handle) error {
86-
do, err, _ := b.loadGroup.Do(key, func() (interface{}, error) {
87-
return h.Create()
131+
_, err := done(b.GetContext(), func() (interface{}, error) {
132+
_, err, _ := b.loadGroup.Do(key, func() (interface{}, error) {
133+
data, err := h.Create(b.GetContext())
134+
if err == nil {
135+
b.doSetWithData(key, data, h.Expire())
136+
}
137+
return data, err
138+
})
139+
if err != nil {
140+
return nil, errors.Wrap(err, "x cache create data error")
141+
}
142+
return nil, nil
88143
})
89-
if err != nil {
90-
return errors.Wrap(err, "x cache create data error")
91-
}
92-
data, _ := do.([]byte)
93-
b.doSetWithData(key, data, h.Expire())
94-
return nil
144+
return err
95145
}
96146

97147
func (b basis) IsNilError(err error) bool {
98148
return err == nilError
99149
}
100150

101151
func (b basis) IsExist(key string) bool {
102-
return b.doIsExist(key) == nilError
152+
_, err := done(b.GetContext(), func() (interface{}, error) {
153+
return nil, b.doIsExist(key)
154+
})
155+
return err == nilError
103156
}
104157

105158
func (b basis) checkExpire(n node) bool {
@@ -119,3 +172,10 @@ func (b basis) doIsExist(key string) error {
119172
func (b basis) doDel(key string) {
120173
delete(b.data, key)
121174
}
175+
176+
func toByte(ret interface{}, err error) ([]byte, error) {
177+
if data, ok := ret.([]byte); ok {
178+
return data, err
179+
}
180+
return nil, err
181+
}

xcache/basis_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package xcache
22

33
import (
4+
"context"
45
"fmt"
56
"testing"
67
"time"
78
)
89

910
type testdata struct{}
1011

11-
func (t testdata) Create() ([]byte, error) {
12-
return []byte("test"), nil
12+
func (t testdata) Create(ctx context.Context) ([]byte, error) {
13+
time.Sleep(1900 * time.Millisecond)
14+
return []byte("test Create"), nil
1315
}
1416

1517
func (t testdata) Expire() time.Duration {
@@ -29,3 +31,20 @@ func BenchmarkBasis(b *testing.B) {
2931
}
3032
}
3133
}
34+
35+
func TestBasis(t *testing.T) {
36+
ctx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second)
37+
defer cancelFunc()
38+
39+
c := NewBasis().WithContext(ctx)
40+
if err := c.Set("abc", new(testdata)); err != nil {
41+
t.Error(err)
42+
return
43+
}
44+
data, err := c.GetE("abc")
45+
if err != nil {
46+
t.Error(err)
47+
return
48+
}
49+
t.Log(string(data))
50+
}

xcache/lru/lru.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import "container/list"
55
// Cache is a LRU cache. It is not safe for concurrent access.
66
type Cache struct {
77
maxBytes int64
8-
nbytes int64
8+
nBytes int64
99
ll *list.List
1010
cache map[string]*list.Element
1111
}
@@ -33,14 +33,14 @@ func (c *Cache) Add(key string, value Value) {
3333
if ele, ok := c.cache[key]; ok {
3434
c.ll.MoveToFront(ele)
3535
kv := ele.Value.(*entry)
36-
c.nbytes += int64(value.Len()) - int64(kv.value.Len())
36+
c.nBytes += int64(value.Len()) - int64(kv.value.Len())
3737
kv.value = value
3838
} else {
3939
ele := c.ll.PushFront(&entry{key, value})
4040
c.cache[key] = ele
41-
c.nbytes += int64(len(key)) + int64(value.Len())
41+
c.nBytes += int64(len(key)) + int64(value.Len())
4242
}
43-
for c.maxBytes != 0 && c.maxBytes < c.nbytes {
43+
for c.maxBytes != 0 && c.maxBytes < c.nBytes {
4444
c.RemoveOldest()
4545
}
4646
}
@@ -62,7 +62,7 @@ func (c *Cache) RemoveOldest() {
6262
c.ll.Remove(ele)
6363
kv := ele.Value.(*entry)
6464
delete(c.cache, kv.key)
65-
c.nbytes -= int64(len(kv.key)) + int64(kv.value.Len())
65+
c.nBytes -= int64(len(kv.key)) + int64(kv.value.Len())
6666
}
6767
}
6868

xcache/xcache.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package xcache
22

33
import (
4+
"context"
45
"errors"
56
"sync"
67
"time"
@@ -18,7 +19,7 @@ type (
1819
// @return []byte
1920
// @return error
2021
//
21-
Create() ([]byte, error)
22+
Create(ctx context.Context) ([]byte, error)
2223
//
2324
// Expire
2425
// @Description: 设置时间过期时间
@@ -44,6 +45,8 @@ type (
4445
GetE(key string) ([]byte, error)
4546

4647
Get(key string) []byte
48+
49+
GetWithCreateE(key string, h Handle) ([]byte, error)
4750
//
4851
// GetWithCreate 获取缓存,如果没有就使用Handle创建并放回
4952
// @Description:
@@ -52,8 +55,6 @@ type (
5255
// @param h Handle
5356
// @return error
5457
//
55-
GetWithCreateE(key string, h Handle) ([]byte, error)
56-
5758
GetWithCreate(key string, h Handle) []byte
5859
//
5960
// Set
@@ -77,6 +78,16 @@ type (
7778
// @return bool
7879
//
7980
IsExist(key string) bool
81+
82+
//
83+
// WithContext
84+
// @Description:
85+
// @param ctx context.Context
86+
// @return Cache
87+
//
88+
WithContext(ctx context.Context) Cache
89+
90+
GetContext() context.Context
8091
}
8192

8293
Basis struct {

0 commit comments

Comments
 (0)