Skip to content

Commit 65c0ed3

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
code cleanup
1 parent c628fb3 commit 65c0ed3

File tree

3 files changed

+309
-322
lines changed

3 files changed

+309
-322
lines changed

β€ŽREADME.mdβ€Ž

Lines changed: 104 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,58 @@
1010

1111
Stupid fast in-memory Go cache with optional L2 persistence layer.
1212

13-
## Install
13+
Designed originally for persistently caching HTTP fetches in unreliable environments like Google Cloud Run, this cache has something for everyone.
1414

15-
```bash
16-
go get github.com/codeGROOVE-dev/bdcache
15+
## Features
16+
17+
- **Faster than a bat out of hell** - Best-in-class latency and throughput
18+
- **S3-FIFO eviction** - Better hit-rates than LRU ([learn more](https://s3fifo.com/))
19+
- **Pluggable persistence** - Bring your own database or use built-in backends:
20+
- [`persist/localfs`](persist/localfs) - Local files (gob encoding, zero dependencies)
21+
- [`persist/datastore`](persist/datastore) - Google Cloud Datastore
22+
- [`persist/valkey`](persist/valkey) - Valkey/Redis
23+
- [`persist/cloudrun`](persist/cloudrun) - Auto-detect Cloud Run
24+
- **Per-item TTL** - Optional expiration
25+
- **Graceful degradation** - Cache works even if persistence fails
26+
- **Zero allocation reads** - minimal GC thrashing
27+
- **Type safe** - Go generics
28+
29+
## Usage
30+
31+
As a stupid-fast in-memory cache:
32+
33+
```go
34+
import "github.com/codeGROOVE-dev/bdcache"
35+
36+
// strings as keys, ints as values
37+
cache, _ := bdcache.New[string, int](ctx)
38+
cache.Set(ctx, "answer", 42, 0)
39+
val, found, err := cache.Get(ctx, "answer")
1740
```
1841

19-
## Use
42+
With local file persistence to survive restarts:
2043

2144
```go
2245
import (
23-
"github.com/codeGROOVE-dev/bdcache"
24-
"github.com/codeGROOVE-dev/bdcache/persist/localfs"
46+
"github.com/codeGROOVE-dev/bdcache"
47+
"github.com/codeGROOVE-dev/bdcache/persist/localfs"
2548
)
2649

27-
// Memory only
28-
cache, _ := bdcache.New[string, int](ctx)
29-
cache.Set(ctx, "answer", 42, 0) // Synchronous: returns after persistence completes
30-
cache.SetAsync(ctx, "answer", 42, 0) // Async: returns immediately, persists in background
31-
val, found, _ := cache.Get(ctx, "answer")
50+
p, err := localfs.New[string, User]("myapp", "")
51+
cache, _ := bdcache.New[string, User](ctx, bdcache.WithPersistence(p))
3252

33-
// With local file persistence
34-
p, _ := localfs.New[string, User]("myapp", "")
35-
cache, _ := bdcache.New[string, User](ctx,
36-
bdcache.WithPersistence(p))
53+
cache.SetAsync(ctx, "answer", 42, 0) // Don't wait for the key to persist
54+
```
3755

38-
// With Valkey/Redis persistence
39-
p, _ := valkey.New[string, User](ctx, "myapp", "localhost:6379")
40-
cache, _ := bdcache.New[string, User](ctx,
41-
bdcache.WithPersistence(p))
56+
A persistent cache suitable for Cloud Run or local development; uses Cloud Datastore if available
4257

43-
// Cloud Run auto-detection (datastore in Cloud Run, localfs elsewhere)
58+
```go
4459
p, _ := cloudrun.New[string, User](ctx, "myapp")
45-
cache, _ := bdcache.New[string, User](ctx,
46-
bdcache.WithPersistence(p))
60+
cache, _ := bdcache.New[string, User](ctx, bdcache.WithPersistence(p))
4761
```
4862

49-
## Features
5063

51-
- **Faster than a bat out of hell** - Low latency, high throughput
52-
- **S3-FIFO eviction** - Better hit-rates than LRU ([learn more](https://s3fifo.com/))
53-
- **Pluggable persistence** - Bring your own database or use built-in backends:
54-
- [`persist/localfs`](persist/localfs) - Local files (gob encoding, zero dependencies)
55-
- [`persist/datastore`](persist/datastore) - Google Cloud Datastore
56-
- [`persist/valkey`](persist/valkey) - Valkey/Redis
57-
- [`persist/cloudrun`](persist/cloudrun) - Auto-detect Cloud Run
58-
- **Per-item TTL** - Optional expiration
59-
- **Graceful degradation** - Cache works even if persistence fails
60-
- **Zero allocation reads** - minimal GC thrashing
61-
- **Type safe** - Go generics
64+
6265

6366
## Performance against the Competition
6467

@@ -71,8 +74,8 @@ Here's the results from an M4 MacBook Pro - run `make bench` to see the results
7174
| Cache | Size=1% | Size=2.5% | Size=5% |
7275
|---------------|---------|-----------|---------|
7376
| bdcache 🟑 | 94.46% | 94.89% | 95.09% |
74-
| otter 🦦 | 94.28% | 94.69% | 95.09% |
75-
| ristretto β˜• | 91.62% | 92.45% | 93.03% |
77+
| otter 🦦 | 94.27% | 94.68% | 95.09% |
78+
| ristretto β˜• | 91.63% | 92.44% | 93.02% |
7679
| tinylfu πŸ”¬ | 94.31% | 94.87% | 95.09% |
7780
| freecache πŸ†“ | 94.03% | 94.15% | 94.75% |
7881
| lru πŸ“š | 94.10% | 94.84% | 95.09% |
@@ -83,113 +86,113 @@ Here's the results from an M4 MacBook Pro - run `make bench` to see the results
8386

8487
| Cache | Get ns/op | Get B/op | Get allocs | Set ns/op | Set B/op | Set allocs |
8588
|---------------|-----------|----------|------------|-----------|----------|------------|
86-
| bdcache 🟑 | 9.0 | 0 | 0 | 21.0 | 0 | 0 |
87-
| lru πŸ“š | 24.0 | 0 | 0 | 23.0 | 0 | 0 |
88-
| ristretto β˜• | 32.0 | 14 | 0 | 67.0 | 119 | 3 |
89-
| otter 🦦 | 35.0 | 0 | 0 | 140.0 | 51 | 1 |
90-
| freecache πŸ†“ | 73.0 | 15 | 1 | 58.0 | 4 | 0 |
91-
| tinylfu πŸ”¬ | 88.0 | 3 | 0 | 107.0 | 175 | 3 |
89+
| bdcache 🟑 | 9.0 | 0 | 0 | 20.0 | 0 | 0 |
90+
| lru πŸ“š | 22.0 | 0 | 0 | 22.0 | 0 | 0 |
91+
| ristretto β˜• | 31.0 | 14 | 0 | 68.0 | 120 | 3 |
92+
| otter 🦦 | 34.0 | 0 | 0 | 138.0 | 51 | 1 |
93+
| freecache πŸ†“ | 71.0 | 15 | 1 | 56.0 | 4 | 0 |
94+
| tinylfu πŸ”¬ | 84.0 | 3 | 0 | 105.0 | 175 | 3 |
9295

93-
πŸ† Get latency: +167% faster than 2nd best (lru)
94-
πŸ† Set latency: +9.5% faster than 2nd best (lru)
96+
πŸ† Get latency: +144% faster than 2nd best (lru)
97+
πŸ† Set latency: +10% faster than 2nd best (lru)
9598

9699
### Single-Threaded Throughput (mixed read/write)
97100

98101
| Cache | Get QPS | Set QPS |
99102
|---------------|------------|------------|
100-
| bdcache 🟑 | 75.49M | 41.56M |
101-
| lru πŸ“š | 34.86M | 35.33M |
102-
| ristretto β˜• | 28.38M | 13.59M |
103-
| otter 🦦 | 25.59M | 7.17M |
104-
| freecache πŸ†“ | 12.79M | 15.80M |
105-
| tinylfu πŸ”¬ | 10.77M | 8.94M |
103+
| bdcache 🟑 | 79.25M | 43.15M |
104+
| lru πŸ“š | 36.39M | 36.88M |
105+
| ristretto β˜• | 28.22M | 13.46M |
106+
| otter 🦦 | 25.46M | 7.16M |
107+
| freecache πŸ†“ | 13.30M | 16.32M |
108+
| tinylfu πŸ”¬ | 11.32M | 9.34M |
106109

107-
πŸ† Get throughput: +117% faster than 2nd best (lru)
108-
πŸ† Set throughput: +18% faster than 2nd best (lru)
110+
πŸ† Get throughput: +118% faster than 2nd best (lru)
111+
πŸ† Set throughput: +17% faster than 2nd best (lru)
109112

110113
### Concurrent Throughput (mixed read/write): 4 threads
111114

112115
| Cache | Get QPS | Set QPS |
113116
|---------------|------------|------------|
114-
| bdcache 🟑 | 29.51M | 31.43M |
115-
| otter 🦦 | 28.96M | 4.17M |
116-
| ristretto β˜• | 27.16M | 13.23M |
117-
| freecache πŸ†“ | 25.06M | 21.94M |
118-
| lru πŸ“š | 9.43M | 9.59M |
119-
| tinylfu πŸ”¬ | 5.51M | 4.85M |
117+
| bdcache 🟑 | 29.62M | 29.92M |
118+
| ristretto β˜• | 25.98M | 13.12M |
119+
| freecache πŸ†“ | 25.36M | 21.84M |
120+
| otter 🦦 | 23.14M | 3.99M |
121+
| lru πŸ“š | 9.39M | 9.64M |
122+
| tinylfu πŸ”¬ | 5.75M | 4.91M |
120123

121-
πŸ† Get throughput: +1.9% faster than 2nd best (otter)
122-
πŸ† Set throughput: +43% faster than 2nd best (freecache)
124+
πŸ† Get throughput: +14% faster than 2nd best (ristretto)
125+
πŸ† Set throughput: +37% faster than 2nd best (freecache)
123126

124127
### Concurrent Throughput (mixed read/write): 8 threads
125128

126129
| Cache | Get QPS | Set QPS |
127130
|---------------|------------|------------|
128-
| bdcache 🟑 | 22.16M | 18.82M |
129-
| otter 🦦 | 19.51M | 3.14M |
130-
| ristretto β˜• | 18.62M | 11.60M |
131-
| freecache πŸ†“ | 16.60M | 15.92M |
132-
| lru πŸ“š | 7.62M | 7.75M |
133-
| tinylfu πŸ”¬ | 4.95M | 4.26M |
131+
| bdcache 🟑 | 22.19M | 18.68M |
132+
| otter 🦦 | 19.74M | 3.03M |
133+
| ristretto β˜• | 18.82M | 11.39M |
134+
| freecache πŸ†“ | 16.83M | 16.30M |
135+
| lru πŸ“š | 7.55M | 7.68M |
136+
| tinylfu πŸ”¬ | 4.95M | 4.15M |
134137

135-
πŸ† Get throughput: +14% faster than 2nd best (otter)
136-
πŸ† Set throughput: +18% faster than 2nd best (freecache)
138+
πŸ† Get throughput: +12% faster than 2nd best (otter)
139+
πŸ† Set throughput: +15% faster than 2nd best (freecache)
137140

138141
### Concurrent Throughput (mixed read/write): 12 threads
139142

140143
| Cache | Get QPS | Set QPS |
141144
|---------------|------------|------------|
142-
| bdcache 🟑 | 24.29M | 24.21M |
143-
| ristretto β˜• | 22.76M | 11.54M |
144-
| otter 🦦 | 21.65M | 2.79M |
145-
| freecache πŸ†“ | 17.25M | 16.53M |
146-
| lru πŸ“š | 7.58M | 7.62M |
147-
| tinylfu πŸ”¬ | 4.51M | 3.87M |
145+
| bdcache 🟑 | 24.49M | 24.03M |
146+
| ristretto β˜• | 22.85M | 11.48M |
147+
| otter 🦦 | 21.77M | 2.92M |
148+
| freecache πŸ†“ | 17.45M | 16.70M |
149+
| lru πŸ“š | 7.42M | 7.62M |
150+
| tinylfu πŸ”¬ | 4.55M | 3.70M |
148151

149-
πŸ† Get throughput: +6.7% faster than 2nd best (ristretto)
150-
πŸ† Set throughput: +47% faster than 2nd best (freecache)
152+
πŸ† Get throughput: +7.2% faster than 2nd best (ristretto)
153+
πŸ† Set throughput: +44% faster than 2nd best (freecache)
151154

152155
### Concurrent Throughput (mixed read/write): 16 threads
153156

154157
| Cache | Get QPS | Set QPS |
155158
|---------------|------------|------------|
156-
| bdcache 🟑 | 16.24M | 15.77M |
157-
| otter 🦦 | 16.02M | 2.76M |
158-
| ristretto β˜• | 15.41M | 12.50M |
159-
| freecache πŸ†“ | 15.05M | 14.61M |
160-
| lru πŸ“š | 7.45M | 7.47M |
161-
| tinylfu πŸ”¬ | 4.71M | 3.61M |
159+
| bdcache 🟑 | 15.96M | 15.55M |
160+
| otter 🦦 | 15.64M | 2.84M |
161+
| ristretto β˜• | 15.59M | 12.31M |
162+
| freecache πŸ†“ | 15.24M | 14.72M |
163+
| lru πŸ“š | 7.47M | 7.42M |
164+
| tinylfu πŸ”¬ | 4.71M | 3.43M |
162165

163-
πŸ† Get throughput: +1.4% faster than 2nd best (otter)
164-
πŸ† Set throughput: +8.0% faster than 2nd best (freecache)
166+
πŸ† Get throughput: +2.0% faster than 2nd best (otter)
167+
πŸ† Set throughput: +5.6% faster than 2nd best (freecache)
165168

166169
### Concurrent Throughput (mixed read/write): 24 threads
167170

168171
| Cache | Get QPS | Set QPS |
169172
|---------------|------------|------------|
170-
| bdcache 🟑 | 16.16M | 15.47M |
171-
| otter 🦦 | 15.80M | 2.87M |
172-
| ristretto β˜• | 15.48M | 13.28M |
173-
| freecache πŸ†“ | 14.92M | 14.36M |
174-
| lru πŸ“š | 7.69M | 7.59M |
175-
| tinylfu πŸ”¬ | 5.03M | 3.84M |
173+
| bdcache 🟑 | 15.93M | 15.41M |
174+
| otter 🦦 | 15.81M | 2.88M |
175+
| ristretto β˜• | 15.57M | 13.20M |
176+
| freecache πŸ†“ | 14.58M | 14.10M |
177+
| lru πŸ“š | 7.59M | 7.80M |
178+
| tinylfu πŸ”¬ | 4.96M | 3.73M |
176179

177-
πŸ† Get throughput: +2.3% faster than 2nd best (otter)
178-
πŸ† Set throughput: +7.7% faster than 2nd best (freecache)
180+
πŸ† Get throughput: +0.7% faster than 2nd best (otter)
181+
πŸ† Set throughput: +9.2% faster than 2nd best (freecache)
179182

180183
### Concurrent Throughput (mixed read/write): 32 threads
181184

182185
| Cache | Get QPS | Set QPS |
183186
|---------------|------------|------------|
184-
| bdcache 🟑 | 15.85M | 15.41M |
185-
| otter 🦦 | 15.71M | 2.85M |
186-
| ristretto β˜• | 15.60M | 13.16M |
187-
| freecache πŸ†“ | 14.33M | 14.13M |
188-
| lru πŸ“š | 7.70M | 8.07M |
189-
| tinylfu πŸ”¬ | 5.32M | 2.99M |
190-
191-
πŸ† Get throughput: +0.9% faster than 2nd best (otter)
192-
πŸ† Set throughput: +9.1% faster than 2nd best (freecache)
187+
| bdcache 🟑 | 16.68M | 15.38M |
188+
| otter 🦦 | 15.87M | 2.87M |
189+
| ristretto β˜• | 15.55M | 13.50M |
190+
| freecache πŸ†“ | 14.64M | 13.84M |
191+
| lru πŸ“š | 7.87M | 8.01M |
192+
| tinylfu πŸ”¬ | 5.12M | 3.01M |
193+
194+
πŸ† Get throughput: +5.1% faster than 2nd best (otter)
195+
πŸ† Set throughput: +11% faster than 2nd best (freecache)
193196

194197
NOTE: Performance characteristics often have trade-offs. There are almost certainly workloads where other cache implementations are faster, but nobody blends speed and persistence the way that bdcache does.
195198

0 commit comments

Comments
Β (0)