Skip to content

Commit 3f3ee33

Browse files
committed
rebrand multicache as fido
1 parent 7ed9aac commit 3f3ee33

36 files changed

Lines changed: 128 additions & 130 deletions

Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ tag:
99
fi
1010
@echo "=== Releasing $(VERSION) ==="
1111
@echo ""
12-
@echo "Step 1: Update submodule go.mod files to require multicache $(VERSION)..."
13-
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/multicache v[^ ]*|github.com/codeGROOVE-dev/multicache $(VERSION)|' {}
12+
@echo "Step 1: Update submodule go.mod files to require fido $(VERSION)..."
13+
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/fido v[^ ]*|github.com/codeGROOVE-dev/fido $(VERSION)|' {}
1414
@# Update store submodule dependencies (compress must be first as others depend on it)
15-
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/multicache/pkg/store/compress v[^ ]*|github.com/codeGROOVE-dev/multicache/pkg/store/compress $(VERSION)|' {}
16-
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/multicache/pkg/store/localfs v[^ ]*|github.com/codeGROOVE-dev/multicache/pkg/store/localfs $(VERSION)|' {}
17-
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/multicache/pkg/store/datastore v[^ ]*|github.com/codeGROOVE-dev/multicache/pkg/store/datastore $(VERSION)|' {}
18-
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/multicache/pkg/store/valkey v[^ ]*|github.com/codeGROOVE-dev/multicache/pkg/store/valkey $(VERSION)|' {}
15+
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/fido/pkg/store/compress v[^ ]*|github.com/codeGROOVE-dev/fido/pkg/store/compress $(VERSION)|' {}
16+
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/fido/pkg/store/localfs v[^ ]*|github.com/codeGROOVE-dev/fido/pkg/store/localfs $(VERSION)|' {}
17+
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/fido/pkg/store/datastore v[^ ]*|github.com/codeGROOVE-dev/fido/pkg/store/datastore $(VERSION)|' {}
18+
@find . -path ./go.mod -prune -o -name go.mod -print | xargs -I{} sed -i '' 's|github.com/codeGROOVE-dev/fido/pkg/store/valkey v[^ ]*|github.com/codeGROOVE-dev/fido/pkg/store/valkey $(VERSION)|' {}
1919
@echo ""
2020
@echo "Step 2: Commit go.mod changes..."
2121
@git add -A

README.md

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
11
<p align="center">
2-
<img src="media/logo-small.png" alt="multicache logo" width="200">
2+
<img src="media/logo-small.png" alt="fido logo" width="200">
33
</p>
44

5-
# multicache
5+
# fido
66

7-
[![CI](https://github.com/codeGROOVE-dev/multicache/actions/workflows/ci.yml/badge.svg)](https://github.com/codeGROOVE-dev/multicache/actions/workflows/ci.yml)
8-
[![Go Report Card](https://goreportcard.com/badge/github.com/codeGROOVE-dev/multicache)](https://goreportcard.com/report/github.com/codeGROOVE-dev/multicache)
9-
[![Go Reference](https://pkg.go.dev/badge/github.com/codeGROOVE-dev/multicache.svg)](https://pkg.go.dev/github.com/codeGROOVE-dev/multicache)
10-
[![codecov](https://codecov.io/gh/codeGROOVE-dev/multicache/graph/badge.svg)](https://codecov.io/gh/codeGROOVE-dev/multicache)
11-
[![Release](https://img.shields.io/github/v/release/codeGROOVE-dev/multicache)](https://github.com/codeGROOVE-dev/multicache/releases)
7+
[![Go Report Card](https://goreportcard.com/badge/github.com/codeGROOVE-dev/fido)](https://goreportcard.com/report/github.com/codeGROOVE-dev/fido)
8+
[![Go Reference](https://pkg.go.dev/badge/github.com/codeGROOVE-dev/fido.svg)](https://pkg.go.dev/github.com/codeGROOVE-dev/fido)
9+
[![Release](https://img.shields.io/github/v/release/codeGROOVE-dev/fido)](https://github.com/codeGROOVE-dev/fido/releases)
1210
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
1311

14-
multicache is the most well-rounded cache implementation for Go today.
12+
fido is the most well-rounded cache implementation for Go today.
1513

1614
Designed for real-world applications in unstable environments, it has a higher average hit rate, higher throughput, and lower latency for production workloads than any other cache. To deal with process eviction in environments like Kubernetes, Cloud Run, or Borg, it also offers an optional persistence tier.
1715

1816
## Install
1917

2018
```
21-
go get github.com/codeGROOVE-dev/multicache
19+
go get github.com/codeGROOVE-dev/fido
2220
```
2321

2422
## Use
2523

2624
```go
27-
cache := multicache.New[string, int](multicache.Size(10000))
25+
cache := fido.New[string, int](fido.Size(10000))
2826
cache.Set("answer", 42)
2927
val, ok := cache.Get("answer")
3028
```
@@ -33,7 +31,7 @@ With persistence:
3331

3432
```go
3533
store, _ := localfs.New[string, User]("myapp", "")
36-
cache, _ := multicache.NewTiered(store)
34+
cache, _ := fido.NewTiered(store)
3735

3836
_ = cache.Set(ctx, "user:123", user) // sync write
3937
_ = cache.SetAsync(ctx, "user:456", user) // async write
@@ -50,8 +48,8 @@ user, err := cache.GetSet("user:123", func() (User, error) {
5048
## Options
5149

5250
```go
53-
multicache.Size(n) // max entries (default 16384)
54-
multicache.TTL(time.Hour) // default expiration
51+
fido.Size(n) // max entries (default 16384)
52+
fido.TTL(time.Hour) // default expiration
5553
```
5654

5755
## Persistence
@@ -69,9 +67,9 @@ For maximum efficiency, all backends support S2 or Zstd compression via `pkg/sto
6967

7068
## Performance
7169

72-
multicache has been exhaustively tested for performance using [gocachemark](https://github.com/tstromberg/gocachemark).
70+
fido has been exhaustively tested for performance using [gocachemark](https://github.com/tstromberg/gocachemark).
7371

74-
Where multicache wins:
72+
Where fido wins:
7573

7674
- **Throughput**: 551M int gets/sec avg (2.4X faster than otter). 89M string sets/sec avg (27X faster than otter).
7775
- **Hit rate**: Wins 6 of 9 workloads. Highest average across all datasets (+2.7% vs otter, +0.9% vs sieve).
@@ -88,9 +86,9 @@ Run `make benchmark` for full results, or see [benchmarks/gocachemark_results.md
8886

8987
## Algorithm
9088

91-
multicache uses [S3-FIFO](https://s3fifo.com/), which features three queues: small (new entries), main (promoted entries), and ghost (recently evicted keys). New items enter small; items accessed twice move to main. The ghost queue tracks evicted keys in a bloom filter to fast-track their return.
89+
fido uses [S3-FIFO](https://s3fifo.com/), which features three queues: small (new entries), main (promoted entries), and ghost (recently evicted keys). New items enter small; items accessed twice move to main. The ghost queue tracks evicted keys in a bloom filter to fast-track their return.
9290

93-
multicache has been hyper-tuned for high performance, and deviates from the original paper in a handful of ways:
91+
fido has been hyper-tuned for high performance, and deviates from the original paper in a handful of ways:
9492

9593
- **Tuned small queue** - 13.7% vs paper's 10%, tuned via binary search to maximize average hit rate across 9 production traces
9694
- **Full ghost frequency restoration** - returning keys restore 100% of their previous access count

benchmarks/runner.go

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55
// Usage:
66
//
7-
// go run benchmarks/runner.go # solo multicache, validate hitrate
7+
// go run benchmarks/runner.go # solo fido, validate hitrate
88
// go run benchmarks/runner.go -competitive # gold medalists, track rankings
99
//
1010
// Environment variables:
@@ -53,7 +53,7 @@ var hitRateKeys = map[string]string{
5353
}
5454

5555
// goldMedalists are the caches to compare in competitive mode.
56-
var goldMedalists = "multicache,otter,clock,theine,sieve,freelru-sync"
56+
var goldMedalists = "fido,otter,clock,theine,sieve,freelru-sync"
5757

5858
// suiteGoals are the minimum/maximum acceptable averages across all tests in each suite.
5959
// Note: latency and throughput absolute values are hardware-dependent and validated via
@@ -71,37 +71,37 @@ var suiteGoals = struct {
7171
}
7272

7373
const (
74-
minMulticacheScore = 154
75-
gocachemarkRepo = "github.com/tstromberg/gocachemark"
76-
multicacheModule = "github.com/codeGROOVE-dev/multicache"
74+
minFidoScore = 154
75+
gocachemarkRepo = "github.com/tstromberg/gocachemark"
76+
fidoModule = "github.com/codeGROOVE-dev/fido"
7777
)
7878

7979
func main() {
8080
competitive := flag.Bool("competitive", false, "Run competitive benchmark with gold medalists")
8181
flag.Parse()
8282

83-
// Find multicache root (where we're running from).
84-
multicacheDir, err := findMulticacheDir()
83+
// Find fido root (where we're running from).
84+
fidoDir, err := findFidoDir()
8585
if err != nil {
86-
fatal("finding multicache directory: %v", err)
86+
fatal("finding fido directory: %v", err)
8787
}
8888

8989
// Find or clone gocachemark.
90-
gocachemarkDir, err := findOrCloneGocachemark(multicacheDir)
90+
gocachemarkDir, err := findOrCloneGocachemark(fidoDir)
9191
if err != nil {
9292
fatal("finding gocachemark: %v", err)
9393
}
9494

9595
// Update go.mod replace directive.
96-
cmd := exec.Command("go", "mod", "edit", "-replace", multicacheModule+"="+multicacheDir)
96+
cmd := exec.Command("go", "mod", "edit", "-replace", fidoModule+"="+fidoDir)
9797
cmd.Dir = gocachemarkDir
9898
cmd.Stderr = os.Stderr
9999
if err := cmd.Run(); err != nil {
100100
fatal("updating go.mod replace: %v", err)
101101
}
102102

103103
// Prepare output directory for results.
104-
benchmarksDir := filepath.Join(multicacheDir, "benchmarks")
104+
benchmarksDir := filepath.Join(fidoDir, "benchmarks")
105105

106106
// Load reference results for comparison.
107107
ref, _ := loadResults(filepath.Join(benchmarksDir, "gocachemark_results.json"))
@@ -111,7 +111,7 @@ func main() {
111111
if *competitive {
112112
args = append(args, "-caches", goldMedalists)
113113
} else {
114-
args = append(args, "-caches", "multicache")
114+
args = append(args, "-caches", "fido")
115115
}
116116

117117
// Always use temp directory for output first.
@@ -140,7 +140,7 @@ func main() {
140140
fullRun := testsFilter == "" && suitesFilter == "" && sizesFilter == ""
141141

142142
// Run gocachemark with streaming output.
143-
mode := "multicache"
143+
mode := "fido"
144144
if *competitive {
145145
mode = "competitive"
146146
}
@@ -179,8 +179,8 @@ func main() {
179179
}
180180
}
181181

182-
func findMulticacheDir() (string, error) {
183-
// Look for go.mod with multicache module.
182+
func findFidoDir() (string, error) {
183+
// Look for go.mod with fido module.
184184
dir, err := os.Getwd()
185185
if err != nil {
186186
return "", err
@@ -189,7 +189,7 @@ func findMulticacheDir() (string, error) {
189189
for {
190190
modPath := filepath.Join(dir, "go.mod")
191191
if data, err := os.ReadFile(modPath); err == nil {
192-
if strings.Contains(string(data), multicacheModule) {
192+
if strings.Contains(string(data), fidoModule) {
193193
return dir, nil
194194
}
195195
}
@@ -201,15 +201,15 @@ func findMulticacheDir() (string, error) {
201201
dir = parent
202202
}
203203

204-
return "", fmt.Errorf("could not find multicache root (no go.mod with %s)", multicacheModule)
204+
return "", fmt.Errorf("could not find fido root (no go.mod with %s)", fidoModule)
205205
}
206206

207-
func findOrCloneGocachemark(multicacheDir string) (string, error) {
207+
func findOrCloneGocachemark(fidoDir string) (string, error) {
208208
// Check locations in order of preference.
209209
locations := []string{
210210
os.Getenv("GOCACHEMARK_DIR"),
211211
filepath.Join(os.Getenv("HOME"), "src", "gocachemark"),
212-
filepath.Join(multicacheDir, "out", "gocachemark"),
212+
filepath.Join(fidoDir, "out", "gocachemark"),
213213
}
214214

215215
for _, loc := range locations {
@@ -222,7 +222,7 @@ func findOrCloneGocachemark(multicacheDir string) (string, error) {
222222
}
223223

224224
// Clone to out/gocachemark.
225-
cloneDir := filepath.Join(multicacheDir, "out", "gocachemark")
225+
cloneDir := filepath.Join(fidoDir, "out", "gocachemark")
226226
fmt.Printf("Cloning gocachemark to %s...\n", cloneDir)
227227

228228
if err := os.MkdirAll(filepath.Dir(cloneDir), 0755); err != nil {
@@ -389,14 +389,14 @@ func validateHitrate(res *Results) error {
389389
var avg float64
390390
var found bool
391391
for _, c := range caches {
392-
if c.Name == "multicache" {
392+
if c.Name == "fido" {
393393
avg = c.AvgRate
394394
found = true
395395
break
396396
}
397397
}
398398
if !found {
399-
fmt.Printf("? %s: multicache not found\n", name)
399+
fmt.Printf("? %s: fido not found\n", name)
400400
continue
401401
}
402402

@@ -430,7 +430,7 @@ func validateSuiteGoals(res *Results) error {
430430
if err != nil {
431431
continue
432432
}
433-
if rate := findHitRate(caches, "multicache"); rate > 0 {
433+
if rate := findHitRate(caches, "fido"); rate > 0 {
434434
hitRates = append(hitRates, rate)
435435
}
436436
}
@@ -449,7 +449,7 @@ func validateSuiteGoals(res *Results) error {
449449

450450
// Memory.
451451
if res.Memory != nil {
452-
if bytes := findMemory(res.Memory.Results, "multicache"); bytes > 0 {
452+
if bytes := findMemory(res.Memory.Results, "fido"); bytes > 0 {
453453
if bytes <= suiteGoals.maxMemory {
454454
fmt.Printf("✓ memory: %d bytes/item (goal: ≤%d)\n", bytes, suiteGoals.maxMemory)
455455
} else {
@@ -490,8 +490,8 @@ func showDeltas(ref, curr *Results) {
490490
if err != nil {
491491
continue
492492
}
493-
refVal := findHitRate(refCaches, "multicache")
494-
currVal := findHitRate(currCaches, "multicache")
493+
refVal := findHitRate(refCaches, "fido")
494+
currVal := findHitRate(currCaches, "fido")
495495
if refVal == 0 {
496496
continue
497497
}
@@ -510,8 +510,8 @@ func showDeltas(ref, curr *Results) {
510510
if raw, ok := curr.Latency[name]; ok {
511511
json.Unmarshal(raw, &currResults)
512512
}
513-
refVal := findLatency(refResults, "multicache")
514-
currVal := findLatency(currResults, "multicache")
513+
refVal := findLatency(refResults, "fido")
514+
currVal := findLatency(currResults, "fido")
515515
if refVal == 0 {
516516
continue
517517
}
@@ -534,8 +534,8 @@ func showDeltas(ref, curr *Results) {
534534
if raw, ok := curr.Throughput[name]; ok {
535535
json.Unmarshal(raw, &currResults)
536536
}
537-
refVal := findThroughput(refResults, "multicache")
538-
currVal := findThroughput(currResults, "multicache")
537+
refVal := findThroughput(refResults, "fido")
538+
currVal := findThroughput(currResults, "fido")
539539
if refVal == 0 {
540540
continue
541541
}
@@ -547,8 +547,8 @@ func showDeltas(ref, curr *Results) {
547547

548548
// Memory delta (lower is better).
549549
if ref.Memory != nil && curr.Memory != nil {
550-
refVal := findMemory(ref.Memory.Results, "multicache")
551-
currVal := findMemory(curr.Memory.Results, "multicache")
550+
refVal := findMemory(ref.Memory.Results, "fido")
551+
currVal := findMemory(curr.Memory.Results, "fido")
552552
if refVal > 0 && currVal > 0 {
553553
delta := currVal - refVal
554554
pct := float64(delta) / float64(refVal) * 100
@@ -600,16 +600,16 @@ func findMemory(results []MemoryEntry, name string) int {
600600
}
601601

602602
func validateCompetitive(res, prev *Results, testsFilter, suitesFilter string) error {
603-
// Find multicache in rankings.
603+
// Find fido in rankings.
604604
var mc *RankEntry
605605
for i := range res.Rankings {
606-
if res.Rankings[i].Name == "multicache" {
606+
if res.Rankings[i].Name == "fido" {
607607
mc = &res.Rankings[i]
608608
break
609609
}
610610
}
611611
if mc == nil {
612-
return fmt.Errorf("multicache not found in rankings")
612+
return fmt.Errorf("fido not found in rankings")
613613
}
614614

615615
if prev != nil {
@@ -641,17 +641,17 @@ func validateCompetitive(res, prev *Results, testsFilter, suitesFilter string) e
641641
if fullRun {
642642
fmt.Println("\n=== Final Validation ===")
643643
headerPrinted = true
644-
if mc.Score >= minMulticacheScore {
645-
fmt.Printf("✓ multicache score: %d (goal: ≥%d)\n", mc.Score, minMulticacheScore)
644+
if mc.Score >= minFidoScore {
645+
fmt.Printf("✓ fido score: %d (goal: ≥%d)\n", mc.Score, minFidoScore)
646646
} else {
647-
fmt.Printf("✗ multicache score: %d (goal: ≥%d)\n", mc.Score, minMulticacheScore)
648-
fails = append(fails, fmt.Sprintf("score %d < %d", mc.Score, minMulticacheScore))
647+
fmt.Printf("✗ fido score: %d (goal: ≥%d)\n", mc.Score, minFidoScore)
648+
fails = append(fails, fmt.Sprintf("score %d < %d", mc.Score, minFidoScore))
649649
}
650650

651651
if prev != nil {
652652
var prevScore int
653653
for _, r := range prev.Rankings {
654-
if r.Name == "multicache" {
654+
if r.Name == "fido" {
655655
prevScore = r.Score
656656
break
657657
}
@@ -683,7 +683,7 @@ func validateCompetitive(res, prev *Results, testsFilter, suitesFilter string) e
683683
}
684684

685685
for _, r := range cat.Rankings {
686-
if r.Name == "multicache" {
686+
if r.Name == "fido" {
687687
if !headerPrinted {
688688
fmt.Println("\n=== Final Validation ===")
689689
headerPrinted = true

bloom.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package multicache
1+
package fido
22

33
import (
44
"math"

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/codeGROOVE-dev/multicache
1+
module github.com/codeGROOVE-dev/fido
22

33
go 1.25.4
44

media/logo-small.png

-9.66 KB
Loading

media/logo.png

-17.3 KB
Loading

memory.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// Package multicache provides a high-performance cache with optional persistence.
2-
package multicache
1+
// Package fido provides a high-performance cache with optional persistence.
2+
package fido
33

44
import (
55
"sync"

memory_race_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//go:build !race
22

3-
package multicache
3+
package fido
44

55
import (
66
"sync"

memory_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package multicache
1+
package fido
22

33
import (
44
"fmt"

0 commit comments

Comments
 (0)