Repository navigation
Expand file tree
/
Copy pathmain.go
More file actions
148 lines (121 loc) · 3.18 KB
/
Copy pathmain.go
File metadata and controls
148 lines (121 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/mkbeh/pacecache"
)
type user struct {
ID int64
Name string
}
type userRepository struct {
users map[int64]user
loads int
}
func main() {
if err := run(context.Background()); err != nil {
log.Fatal(err)
}
}
func run(ctx context.Context) error {
repository := &userRepository{
users: map[int64]user{
42: {
ID: 42,
Name: "Ada",
},
},
}
users := pacecache.NewWithLoader[int64, user](
repository.find,
pacecache.WithTTL(30*time.Second),
)
// The first lookup loads the user from the underlying repository.
first, found, err := users.GetOrLoad(ctx, 42)
if err != nil {
return fmt.Errorf("load user: %w", err)
}
if !found {
return fmt.Errorf("user 42 was not found")
}
fmt.Println("cache:")
fmt.Printf("- first lookup: found=%t user=%+v\n", found, first)
// A direct lookup reads the already cached value without invoking the loader.
cached, found := users.Get(42)
if !found {
return fmt.Errorf("cached user 42 was not found")
}
fmt.Printf("- direct lookup: user=%+v\n", cached)
// GetEntry exposes cache metadata without changing the value lookup semantics.
entry, found := users.GetEntry(42)
if !found {
return fmt.Errorf("cached entry 42 was not found")
}
fmt.Printf("- entry has expiration: %t\n", !entry.ExpiresAt().IsZero())
fmt.Printf("- repository loads: %d\n", repository.loads)
// Not-found loader results are returned but are not stored by pacecache.
_, found, err = users.GetOrLoad(ctx, 404)
if err != nil {
return fmt.Errorf("load missing user: %w", err)
}
if found {
return fmt.Errorf("user 404 unexpectedly exists")
}
fmt.Println()
fmt.Println("not found:")
fmt.Printf("- first lookup: found=%t\n", found)
_, found, err = users.GetOrLoad(ctx, 404)
if err != nil {
return fmt.Errorf("load missing user again: %w", err)
}
if found {
return fmt.Errorf("user 404 unexpectedly exists")
}
fmt.Printf("- second lookup: found=%t\n", found)
fmt.Printf("- repository loads: %d\n", repository.loads)
// Explicit deletion forces the next lookup to reload the value.
users.Delete(42)
reloaded, found, err := users.GetOrLoad(ctx, 42)
if err != nil {
return fmt.Errorf("reload deleted user: %w", err)
}
if !found {
return fmt.Errorf("reloaded user 42 was not found")
}
fmt.Println()
fmt.Println("deletion:")
fmt.Printf("- lookup after deletion: found=%t user=%+v\n", found, reloaded)
fmt.Printf("- repository loads: %d\n", repository.loads)
stats := users.Stats()
fmt.Println()
fmt.Println("stats:")
fmt.Printf(
"- entries=%d hits=%d misses=%d\n",
stats.EntryCount,
stats.HitCount,
stats.MissCount,
)
fmt.Printf(
"- loads_found=%d loads_not_found=%d load_errors=%d\n",
stats.LoadFoundCount,
stats.LoadNotFoundCount,
stats.LoadErrorCount,
)
fmt.Printf(
"- deleted_entries=%d evictions=%d expirations=%d\n",
stats.DeletedEntryCount,
stats.EvictionCount,
stats.ExpirationCount,
)
return nil
}
func (repository *userRepository) find(ctx context.Context, id int64) (user, bool, error) {
if err := ctx.Err(); err != nil {
return user{}, false, err
}
repository.loads++
value, found := repository.users[id]
return value, found, nil
}