Skip to content

Commit ca8cc16

Browse files
重构 cache 为 metadata
1 parent 9ddf398 commit ca8cc16

5 files changed

Lines changed: 52 additions & 78 deletions

File tree

cache/common.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@ import (
1616
const TTLKeep = -1
1717

1818
type Cache interface {
19-
Put(ctx context.Context, key string, value io.Reader, ttl time.Duration) error
19+
Put(ctx context.Context, key string, metadata map[string]string, value io.Reader, ttl time.Duration) error
2020
Get(ctx context.Context, key string) (*Content, error)
2121
Delete(ctx context.Context, key string) error
2222
io.Closer
2323
}
2424

2525
type Content struct {
2626
io.ReadSeekCloser
27-
Length uint64
28-
LastModified time.Time
27+
Metadata map[string]string
2928
}
3029

3130
func (c *Content) ReadToString() (string, error) {

cache/common_test.go

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212
"time"
1313

14+
"github.com/stretchr/testify/assert"
1415
"gopkg.d7z.net/middleware/connects"
1516
)
1617

@@ -39,7 +40,10 @@ func testPutGet(t *testing.T, factory CacheFactory) {
3940
value := []byte("test-value")
4041

4142
// 测试正常存入和读取
42-
err := cache.Put(ctx, key, bytes.NewReader(value), TTLKeep)
43+
metadata := map[string]string{
44+
"key": "value",
45+
}
46+
err := cache.Put(ctx, key, metadata, bytes.NewReader(value), TTLKeep)
4347
if err != nil {
4448
t.Fatalf("Put failed: %v", err)
4549
}
@@ -59,15 +63,7 @@ func testPutGet(t *testing.T, factory CacheFactory) {
5963
if !bytes.Equal(data, value) {
6064
t.Errorf("Content mismatch: expected %q, got %q", value, data)
6165
}
62-
63-
// 验证元数据
64-
if content.Length != uint64(len(value)) {
65-
t.Errorf("Length mismatch: expected %d, got %d", len(value), content.Length)
66-
}
67-
68-
if content.LastModified.IsZero() {
69-
t.Error("LastModified should not be zero")
70-
}
66+
assert.Equal(t, metadata, content.Metadata)
7167
}
7268

7369
// testPutInvalidTTL 测试无效 TTL 的处理
@@ -80,13 +76,13 @@ func testPutInvalidTTL(t *testing.T, factory CacheFactory) {
8076
value := []byte("test-value")
8177

8278
// 测试负 TTL
83-
err := cache.Put(ctx, key, bytes.NewReader(value), -time.Second)
79+
err := cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value), -time.Second)
8480
if !errors.Is(err, ErrInvalidTTL) {
8581
t.Errorf("Expected ErrInvalidTTL for negative TTL, got: %v", err)
8682
}
8783

8884
// 测试零 TTL
89-
err = cache.Put(ctx, key, bytes.NewReader(value), 0)
85+
err = cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value), 0)
9086
if !errors.Is(err, ErrInvalidTTL) {
9187
t.Errorf("Expected ErrInvalidTTL for zero TTL, got: %v", err)
9288
}
@@ -116,7 +112,7 @@ func testDelete(t *testing.T, factory CacheFactory) {
116112
value := []byte("delete-value")
117113

118114
// 先存入
119-
err := cache.Put(ctx, key, bytes.NewReader(value), TTLKeep)
115+
err := cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value), TTLKeep)
120116
if err != nil {
121117
t.Fatalf("Put failed: %v", err)
122118
}
@@ -157,13 +153,13 @@ func testUpdate(t *testing.T, factory CacheFactory) {
157153
value2 := []byte("value2-updated")
158154

159155
// 第一次存入
160-
err := cache.Put(ctx, key, bytes.NewReader(value1), TTLKeep)
156+
err := cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value1), TTLKeep)
161157
if err != nil {
162158
t.Fatalf("First Put failed: %v", err)
163159
}
164160

165161
// 更新
166-
err = cache.Put(ctx, key, bytes.NewReader(value2), TTLKeep)
162+
err = cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value2), TTLKeep)
167163
if err != nil {
168164
t.Fatalf("Second Put failed: %v", err)
169165
}
@@ -196,7 +192,7 @@ func testTTL(t *testing.T, factory CacheFactory) {
196192
ttl := 1 * time.Second
197193

198194
// 存入带 TTL 的缓存
199-
err := cache.Put(ctx, key, bytes.NewReader(value), ttl)
195+
err := cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value), ttl)
200196
if err != nil {
201197
t.Fatalf("Put with TTL failed: %v", err)
202198
}
@@ -241,7 +237,7 @@ func testConcurrency(t *testing.T, factory CacheFactory) {
241237
// 随机执行操作
242238
switch j % 3 {
243239
case 0: // Put
244-
err := cache.Put(ctx, key, bytes.NewReader(value), TTLKeep)
240+
err := cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value), TTLKeep)
245241
if err != nil {
246242
t.Logf("Concurrent Put error: %v", err)
247243
}
@@ -269,7 +265,7 @@ func testConcurrency(t *testing.T, factory CacheFactory) {
269265
// 验证缓存仍然可用
270266
key := "final-check"
271267
value := []byte("final-value")
272-
err := cache.Put(ctx, key, bytes.NewReader(value), TTLKeep)
268+
err := cache.Put(ctx, key, map[string]string{}, bytes.NewReader(value), TTLKeep)
273269
if err != nil {
274270
t.Errorf("Put after concurrency test failed: %v", err)
275271
}
@@ -299,7 +295,7 @@ func testClose(t *testing.T, factory CacheFactory) {
299295

300296
// 关闭后尝试操作(具体行为取决于实现,这里只测试不会 panic)
301297
ctx := context.Background()
302-
_ = cache.Put(ctx, "closed-key", bytes.NewReader([]byte("value")), TTLKeep)
298+
_ = cache.Put(ctx, "closed-key", map[string]string{}, bytes.NewReader([]byte("value")), TTLKeep)
303299
_, _ = cache.Get(ctx, "closed-key")
304300
_ = cache.Delete(ctx, "closed-key")
305301
}
@@ -315,7 +311,7 @@ func testCacheErrorReader(t *testing.T, factory CacheFactory) {
315311
// 创建会返回错误的 Reader
316312
errorReader := &errorReader{err: errors.New("mock read error")}
317313

318-
err := cache.Put(ctx, key, errorReader, TTLKeep)
314+
err := cache.Put(ctx, key, map[string]string{}, errorReader, TTLKeep)
319315
if err == nil {
320316
t.Error("Expected error from faulty reader, but got none")
321317
}

cache/memory.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cache
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"io"
78
"sync"
89
"time"
@@ -17,10 +18,10 @@ type NopCloser struct {
1718
func (NopCloser) Close() error { return nil }
1819

1920
type internalValue struct {
20-
data []byte
21-
length uint64
22-
lastModify time.Time
23-
expiresAt time.Time
21+
data []byte
22+
length uint64
23+
metadata []byte
24+
expiresAt time.Time
2425
}
2526

2627
type MemoryCache struct {
@@ -62,7 +63,7 @@ func NewMemoryCache(config MemoryCacheConfig) (*MemoryCache, error) {
6263
return mc, nil
6364
}
6465

65-
func (mc *MemoryCache) Put(_ context.Context, key string, value io.Reader, ttl time.Duration) error {
66+
func (mc *MemoryCache) Put(_ context.Context, key string, metadata map[string]string, value io.Reader, ttl time.Duration) error {
6667
data, err := io.ReadAll(value)
6768
if err != nil {
6869
return wrapError("read value failed", err)
@@ -77,12 +78,15 @@ func (mc *MemoryCache) Put(_ context.Context, key string, value io.Reader, ttl t
7778
if ttl != TTLKeep {
7879
expiresAt = now.Add(ttl)
7980
}
80-
81+
metaRaw, err := json.Marshal(metadata)
82+
if err != nil {
83+
return wrapError("marshal metadata failed", err)
84+
}
8185
internalVal := &internalValue{
82-
data: data,
83-
length: uint64(len(data)),
84-
lastModify: now,
85-
expiresAt: expiresAt,
86+
data: data,
87+
length: uint64(len(data)),
88+
metadata: metaRaw,
89+
expiresAt: expiresAt,
8690
}
8791

8892
mc.lruCache.Add(key, internalVal)
@@ -103,10 +107,14 @@ func (mc *MemoryCache) Get(_ context.Context, key string) (*Content, error) {
103107
}
104108

105109
reader := bytes.NewReader(internalVal.data)
110+
meta := make(map[string]string)
111+
err := json.Unmarshal(internalVal.metadata, &meta)
112+
if err != nil {
113+
return nil, wrapError("unmarshal metadata failed", err)
114+
}
106115
return &Content{
107116
ReadSeekCloser: NopCloser{reader},
108-
Length: internalVal.length,
109-
LastModified: internalVal.lastModify,
117+
Metadata: meta,
110118
}, nil
111119
}
112120

cache/memory_test.go

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func TestMemoryCache_PutAndGet(t *testing.T) {
9393
key := "test-key"
9494
data := "test data"
9595

96-
err = cache.Put(ctx, key, strings.NewReader(data), TTLKeep)
96+
err = cache.Put(ctx, key, map[string]string{}, strings.NewReader(data), TTLKeep)
9797
if err != nil {
9898
t.Fatalf("Put failed: %v", err)
9999
}
@@ -103,10 +103,6 @@ func TestMemoryCache_PutAndGet(t *testing.T) {
103103
t.Fatalf("Get failed: %v", err)
104104
}
105105

106-
if content.Length != uint64(len(data)) {
107-
t.Errorf("expected length %d, got %d", len(data), content.Length)
108-
}
109-
110106
// Read and verify data
111107
readData, err := io.ReadAll(content.ReadSeekCloser)
112108
if err != nil {
@@ -159,7 +155,7 @@ func TestMemoryCache_Put_InvalidTTL(t *testing.T) {
159155

160156
for _, tt := range tests {
161157
t.Run(tt.name, func(t *testing.T) {
162-
err := cache.Put(ctx, "key", strings.NewReader("data"), tt.ttl)
158+
err := cache.Put(ctx, "key", map[string]string{}, strings.NewReader("data"), tt.ttl)
163159
if !errors.Is(err, ErrInvalidTTL) {
164160
t.Errorf("expected ErrInvalidTTL, got %v", err)
165161
}
@@ -183,7 +179,7 @@ func TestMemoryCache_Put_ReadError(t *testing.T) {
183179
// Create a reader that will return an error
184180
errorReader := &errorReader{err: errors.New("read error")}
185181

186-
err = cache.Put(ctx, "key", errorReader, TTLKeep)
182+
err = cache.Put(ctx, "key", map[string]string{}, errorReader, TTLKeep)
187183
if err == nil {
188184
t.Error("expected error but got none")
189185
}
@@ -212,7 +208,7 @@ func TestMemoryCache_Delete(t *testing.T) {
212208
key := "test-key"
213209

214210
// Put then delete
215-
err = cache.Put(ctx, key, strings.NewReader("data"), TTLKeep)
211+
err = cache.Put(ctx, key, map[string]string{}, strings.NewReader("data"), TTLKeep)
216212
if err != nil {
217213
t.Fatalf("Put failed: %v", err)
218214
}
@@ -244,7 +240,7 @@ func TestMemoryCache_Expiration(t *testing.T) {
244240
key := "expiring-key"
245241

246242
// Put with very short TTL
247-
err = cache.Put(ctx, key, strings.NewReader("data"), 50*time.Millisecond)
243+
err = cache.Put(ctx, key, map[string]string{}, strings.NewReader("data"), 50*time.Millisecond)
248244
if err != nil {
249245
t.Fatalf("Put failed: %v", err)
250246
}
@@ -279,18 +275,18 @@ func TestMemoryCache_LRU_Eviction(t *testing.T) {
279275
ctx := context.Background()
280276

281277
// Fill cache to capacity
282-
err = cache.Put(ctx, "key1", strings.NewReader("data1"), TTLKeep)
278+
err = cache.Put(ctx, "key1", map[string]string{}, strings.NewReader("data1"), TTLKeep)
283279
if err != nil {
284280
t.Fatalf("Put key1 failed: %v", err)
285281
}
286282

287-
err = cache.Put(ctx, "key2", strings.NewReader("data2"), TTLKeep)
283+
err = cache.Put(ctx, "key2", map[string]string{}, strings.NewReader("data2"), TTLKeep)
288284
if err != nil {
289285
t.Fatalf("Put key2 failed: %v", err)
290286
}
291287

292288
// Add third item, should trigger eviction
293-
err = cache.Put(ctx, "key3", strings.NewReader("data3"), TTLKeep)
289+
err = cache.Put(ctx, "key3", map[string]string{}, strings.NewReader("data3"), TTLKeep)
294290
if err != nil {
295291
t.Fatalf("Put key3 failed: %v", err)
296292
}
@@ -360,7 +356,7 @@ func TestMemoryCache_ConcurrentAccess(t *testing.T) {
360356
key := string(rune('A' + id))
361357
data := string(rune('a' + j))
362358

363-
_ = cache.Put(ctx, key, strings.NewReader(data), TTLKeep)
359+
_ = cache.Put(ctx, key, map[string]string{}, strings.NewReader(data), TTLKeep)
364360
_, _ = cache.Get(ctx, key)
365361
_ = cache.Delete(ctx, key)
366362
}
@@ -405,20 +401,10 @@ func TestCacheContent(t *testing.T) {
405401
data := []byte("test data")
406402
reader := bytes.NewReader(data)
407403
nopCloser := NopCloser{reader}
408-
now := time.Now()
409404

410405
content := &Content{
411406
ReadSeekCloser: nopCloser,
412-
Length: uint64(len(data)),
413-
LastModified: now,
414-
}
415-
416-
if content.Length != uint64(len(data)) {
417-
t.Errorf("expected length %d, got %d", len(data), content.Length)
418-
}
419-
420-
if !content.LastModified.Equal(now) {
421-
t.Error("LastModified time mismatch")
407+
Metadata: map[string]string{},
422408
}
423409

424410
// Test that the content can be read

cache/redis.go

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ import (
1313
"github.com/go-redis/redis/v8"
1414
)
1515

16-
type redisCacheMeta struct {
17-
Length uint64 `json:"length"`
18-
LastModified time.Time `json:"last_modified"`
19-
}
20-
2116
type RedisCache struct {
2217
client *redis.Client
2318
prefix string
@@ -46,7 +41,7 @@ func (rc *RedisCache) metaKey(key string) string {
4641
return fmt.Sprintf("%s%s:meta", rc.prefix, key)
4742
}
4843

49-
func (rc *RedisCache) Put(ctx context.Context, key string, value io.Reader, ttl time.Duration) error {
44+
func (rc *RedisCache) Put(ctx context.Context, key string, metadata map[string]string, value io.Reader, ttl time.Duration) error {
5045
if rc.isClosed() {
5146
return errors.New("cache is closed")
5247
}
@@ -60,12 +55,7 @@ func (rc *RedisCache) Put(ctx context.Context, key string, value io.Reader, ttl
6055
return ErrInvalidTTL
6156
}
6257

63-
meta := redisCacheMeta{
64-
Length: uint64(len(data)),
65-
LastModified: time.Now(),
66-
}
67-
68-
metaJSON, err := json.Marshal(meta)
58+
metaJSON, err := json.Marshal(metadata)
6959
if err != nil {
7060
return fmt.Errorf("marshal meta: %w", err)
7161
}
@@ -104,7 +94,7 @@ func (rc *RedisCache) Get(ctx context.Context, key string) (*Content, error) {
10494
return nil, fmt.Errorf("get meta: %w", err)
10595
}
10696

107-
var meta redisCacheMeta
97+
var meta map[string]string
10898
if err := json.Unmarshal(metaJSON, &meta); err != nil {
10999
return nil, fmt.Errorf("unmarshal meta: %w", err)
110100
}
@@ -118,15 +108,10 @@ func (rc *RedisCache) Get(ctx context.Context, key string) (*Content, error) {
118108
return nil, fmt.Errorf("get data: %w", err)
119109
}
120110

121-
if uint64(len(data)) != meta.Length {
122-
return nil, fmt.Errorf("data length mismatch: expected %d, got %d", meta.Length, len(data))
123-
}
124-
125111
reader := bytes.NewReader(data)
126112
return &Content{
127113
ReadSeekCloser: NopCloser{reader},
128-
Length: meta.Length,
129-
LastModified: meta.LastModified,
114+
Metadata: meta,
130115
}, nil
131116
}
132117

0 commit comments

Comments
 (0)