Skip to content

Commit 72ed054

Browse files
authored
extend cache (#10)
1 parent 1344919 commit 72ed054

File tree

6 files changed

+113
-37
lines changed

6 files changed

+113
-37
lines changed

cache/cache.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
package cache
77

88
import (
9+
"iter"
910
"sync"
11+
12+
"go.osspkg.com/random"
1013
)
1114

1215
type (
@@ -57,6 +60,20 @@ func (v *_cache[K, V]) Get(key K) (V, bool) {
5760
return item, true
5861
}
5962

63+
func (v *_cache[K, V]) One() (key K, val V, ok bool) {
64+
keys := v._keys(30)
65+
if len(keys) == 0 {
66+
return
67+
}
68+
69+
random.Shuffle(keys)
70+
71+
key = keys[0]
72+
val, ok = v.Get(key)
73+
74+
return
75+
}
76+
6077
func (v *_cache[K, V]) Extract(key K) (V, bool) {
6178
v.mux.Lock()
6279
defer v.mux.Unlock()
@@ -94,12 +111,21 @@ func (v *_cache[K, V]) Del(key K) {
94111
}
95112

96113
func (v *_cache[K, V]) Keys() []K {
114+
return v._keys(v.Size())
115+
}
116+
117+
func (v *_cache[K, V]) _keys(limit int) []K {
97118
v.mux.RLock()
98119
defer v.mux.RUnlock()
99120

100-
result := make([]K, 0, len(v.list))
121+
i := 0
122+
result := make([]K, 0, limit)
101123
for k := range v.list {
102124
result = append(result, k)
125+
i++
126+
if i >= limit {
127+
break
128+
}
103129
}
104130

105131
return result
@@ -113,3 +139,21 @@ func (v *_cache[K, V]) Flush() {
113139
delete(v.list, k)
114140
}
115141
}
142+
143+
func (v *_cache[K, V]) Yield(limit int) iter.Seq2[K, V] {
144+
if limit < 1 {
145+
limit = v.Size()
146+
}
147+
148+
keys := v._keys(limit)
149+
150+
return func(yield func(K, V) bool) {
151+
for _, key := range keys {
152+
if val, ok := v.Get(key); ok {
153+
if !yield(key, val) {
154+
return
155+
}
156+
}
157+
}
158+
}
159+
}

cache/cache_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package cache_test
77

88
import (
99
"context"
10+
"fmt"
1011
"testing"
1112
"time"
1213

@@ -78,6 +79,31 @@ func TestUnit_OptTimeClean(t *testing.T) {
7879
casecheck.False(t, c.Has("foo"))
7980
}
8081

82+
func TestUnit_Yield(t *testing.T) {
83+
c := cache.New[string, int64]()
84+
85+
c.Set("foo1", 1)
86+
c.Set("foo2", 2)
87+
casecheck.True(t, c.Has("foo1"))
88+
casecheck.True(t, c.Has("foo2"))
89+
90+
for k, v := range c.Yield(0) {
91+
fmt.Println(k, v)
92+
}
93+
94+
list := map[string]int{}
95+
for i := 0; i < 10; i++ {
96+
k, _, ok := c.One()
97+
casecheck.True(t, ok)
98+
list[k] += 1
99+
}
100+
casecheck.Equal(t, 2, len(list))
101+
102+
for k, v := range list {
103+
fmt.Println(k, v)
104+
}
105+
}
106+
81107
func TestUnit_OptCountRandomClean(t *testing.T) {
82108
ctx, cancel := context.WithCancel(context.Background())
83109
defer cancel()
@@ -122,3 +148,20 @@ func Benchmark_New(b *testing.B) {
122148
}
123149
})
124150
}
151+
152+
func Benchmark_One(b *testing.B) {
153+
c := cache.New[int, int]()
154+
155+
for i := 0; i < 200; i++ {
156+
c.Set(i, i)
157+
}
158+
159+
b.ReportAllocs()
160+
b.ResetTimer()
161+
162+
b.RunParallel(func(pb *testing.PB) {
163+
for pb.Next() {
164+
c.One()
165+
}
166+
})
167+
}

cache/options.go

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,14 @@ func OptTimeClean[K comparable, V Timestamp](ctx context.Context, interval time.
2121
Calls: []routine.TickFunc{
2222
func(ctx context.Context, t time.Time) {
2323
curr := t.Unix()
24-
keys := make([]K, 0, 10)
25-
26-
v.mux.RLock()
27-
for key, value := range v.list {
28-
if value.Timestamp() < curr {
29-
keys = append(keys, key)
30-
}
31-
}
32-
v.mux.RUnlock()
33-
34-
if len(keys) == 0 {
35-
return
36-
}
3724

3825
v.mux.Lock()
3926
defer v.mux.Unlock()
4027

41-
for _, key := range keys {
42-
delete(v.list, key)
28+
for key, value := range v.list {
29+
if value.Timestamp() < curr {
30+
delete(v.list, key)
31+
}
4332
}
4433
},
4534
},
@@ -62,24 +51,13 @@ func OptCountRandomClean[K comparable, V any](ctx context.Context, maxCount int,
6251
Calls: []routine.TickFunc{
6352
func(ctx context.Context, _ time.Time) {
6453

65-
v.mux.RLock()
66-
removeCount := len(v.list) - maxCount
67-
v.mux.RUnlock()
68-
54+
removeCount := v.Size() - maxCount
6955
if removeCount <= 0 {
7056
return
7157
}
7258

73-
v.mux.Lock()
74-
defer v.mux.Unlock()
75-
76-
for key := range v.list {
77-
if removeCount <= 0 {
78-
return
79-
}
80-
81-
delete(v.list, key)
82-
removeCount--
59+
for key := range v.Yield(removeCount) {
60+
v.Del(key)
8361
}
8462
},
8563
},

cache/types.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@
55

66
package cache
77

8+
import "iter"
9+
810
type Cache[K comparable, V any] interface {
9-
Has(key K) bool
10-
Get(key K) (V, bool)
11-
Extract(key K) (V, bool)
12-
Set(key K, value V)
13-
Replace(data map[K]V)
14-
Del(key K)
11+
Has(K) bool
12+
Get(K) (V, bool)
13+
//Yield if limit <=0 then got all elements for range
14+
Yield(limit int) iter.Seq2[K, V]
15+
//Extract getting element and delete form cache
16+
Extract(K) (V, bool)
17+
//One getting one random key-value element
18+
One() (K, V, bool)
19+
Set(K, V)
20+
//Replace replace all elements
21+
Replace(map[K]V)
22+
Del(K)
1523
Keys() []K
1624
Size() int
1725
Flush()

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module go.osspkg.com/ioutils
22

3-
go 1.24.0
3+
go 1.24.6
44

55
require (
66
github.com/BurntSushi/toml v1.5.0
77
go.osspkg.com/casecheck v0.3.0
88
go.osspkg.com/errors v0.3.1
9+
go.osspkg.com/random v0.5.0
910
go.osspkg.com/routine v0.4.0
1011
go.osspkg.com/syncing v0.4.0
1112
gopkg.in/yaml.v3 v3.0.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ go.osspkg.com/casecheck v0.3.0 h1:x15blEszElbrHrEH5H02JIIhGIg/lGZzIt1kQlD3pwM=
44
go.osspkg.com/casecheck v0.3.0/go.mod h1:TRFXDMFJEOtnlp3ET2Hix3osbxwPWhvaiT/HfD3+gBA=
55
go.osspkg.com/errors v0.3.1 h1:F9m/EEd/Ot2jba/TV7tvVRIpWXzIpNLc7vRJKcBD86A=
66
go.osspkg.com/errors v0.3.1/go.mod h1:dKXe6Rt07nzY7OyKQNZ8HGBicZ2uQ5TKEoVFnVFOK44=
7+
go.osspkg.com/random v0.5.0 h1:6x2CQ5Vb6PVyuGi6Ao3K6Pr2fzVviBPCEEJC5HQNSmg=
8+
go.osspkg.com/random v0.5.0/go.mod h1:lsg3FI87PQdjhVWIVo2GXyPBclipljUxjMlWqRl2cck=
79
go.osspkg.com/routine v0.4.0 h1:fEDOI3BTaM/rt5pYT+qPq4gFxvw8WJVY2jMeczB7F9A=
810
go.osspkg.com/routine v0.4.0/go.mod h1:HUVnPHLFzNCYEGOqUiQWL+av73aFJ6H57XutFxhA+eU=
911
go.osspkg.com/syncing v0.4.0 h1:9ytMfGHd6Ew69D2n/1syj0FTujNfb1KBiUSZ+KsMTqk=

0 commit comments

Comments
 (0)