Skip to content

Commit

Permalink
Merge pull request #21 from chenyanchen/docs/example/cache-and-telemetry
Browse files Browse the repository at this point in the history
doc: add example implementations for caching and telemetry
  • Loading branch information
chenyanchen authored Dec 10, 2024
2 parents 24c0996 + d483533 commit 1725e24
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 4 deletions.
65 changes: 65 additions & 0 deletions examples/cache/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package main

import (
"context"
"fmt"

"github.com/chenyanchen/db/cachekv"
"github.com/chenyanchen/db/layerkv"
)

func main() {
userDatabaseKV := &databaseKV{}
userLRUKV, err := cachekv.NewLRU[int, *User](1<<10, nil, 0)
if err != nil {
panic(err)
}

userKV, err := layerkv.New(userLRUKV, userDatabaseKV)
if err != nil {
panic(err)
}

ctx := context.Background()

// 1st get user from database
user, err := userKV.Get(ctx, 1)
if err != nil {
panic(err)
}

// 2nd get user from cache
user, err = userKV.Get(ctx, 1)
if err != nil {
panic(err)
}

fmt.Printf("user: %+v\n", user)
}

type User struct {
ID int
Name string
}

// Database implementation

type databaseKV struct {
// uncomment the following line to use the database
// db *sql.DB
}

func (s *databaseKV) Get(ctx context.Context, id int) (*User, error) {
return &User{
ID: id,
Name: "Mock Name",
}, nil
}

func (s *databaseKV) Set(ctx context.Context, id int, user *User) error {
return nil
}

func (s *databaseKV) Del(ctx context.Context, id int) error {
return nil
}
17 changes: 15 additions & 2 deletions examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@ module github.com/chenyanchen/db/examples

go 1.23

require github.com/chenyanchen/db v0.0.0-00010101000000-000000000000
require (
github.com/chenyanchen/db v0.0.0-00010101000000-000000000000
github.com/prometheus/client_golang v1.20.5
)

replace github.com/chenyanchen/db => ../

require github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
golang.org/x/sys v0.27.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)
26 changes: 24 additions & 2 deletions examples/go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
123 changes: 123 additions & 0 deletions examples/telemetry/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package main

import (
"context"
"fmt"
"strconv"
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"

"github.com/chenyanchen/db"
"github.com/chenyanchen/db/cachekv"
"github.com/chenyanchen/db/layerkv"
)

func main() {
userDatabaseKV := &databaseKV{}
userLRUKV, err := cachekv.NewLRU[int, *User](1<<10, nil, 0)
if err != nil {
panic(err)
}

// For example cache hit ratio:
// rate(example_kv_user_kv_operation_duration_seconds_count{name="user_lru_kv", operation="Get", success="true"}[$__rate_interval])) /
// (rate(example_kv_user_kv_operation_duration_seconds_count{name="user_lru_kv", operation="Get", success="true"}[$__rate_interval]) + rate(example_kv_user_kv_operation_duration_seconds_count{name="user_database_kv", operation="Get", success="true"}[$__rate_interval]))
userKV, err := layerkv.New(
NewTelemetry(userLRUKV, NewRecorder("user_lru_kv")),
NewTelemetry(userDatabaseKV, NewRecorder("user_database_kv")),
)
if err != nil {
panic(err)
}

ctx := context.Background()

// 1st get user from database
user, err := userKV.Get(ctx, 1)
if err != nil {
panic(err)
}

// 2nd get user from cache
user, err = userKV.Get(ctx, 1)
if err != nil {
panic(err)
}

fmt.Printf("user: %+v\n", user)
}

type User struct {
ID int
Name string
}

// Database implementation

type databaseKV struct {
// uncomment the following line to use the database
// db *sql.DB
}

func (s *databaseKV) Get(ctx context.Context, id int) (*User, error) {
return &User{
ID: id,
Name: "Mock Name",
}, nil
}

func (s *databaseKV) Set(ctx context.Context, id int, user *User) error {
return nil
}

func (s *databaseKV) Del(ctx context.Context, id int) error {
return nil
}

// Telemetry implementation

type recordFunc func(operation string, success bool, duration time.Duration)

type telemetry[K comparable, V any] struct {
next db.KV[K, V]
record recordFunc
}

func NewTelemetry[K comparable, V any](next db.KV[K, V], record recordFunc) telemetry[K, V] {
return telemetry[K, V]{next: next, record: record}
}

func (t telemetry[K, V]) Get(ctx context.Context, k K) (V, error) {
now := time.Now()
v, err := t.next.Get(ctx, k)
t.record("Get", err == nil, time.Since(now))
return v, err
}

func (t telemetry[K, V]) Set(ctx context.Context, k K, v V) error {
now := time.Now()
err := t.next.Set(ctx, k, v)
t.record("Set", err == nil, time.Since(now))
return err
}

func (t telemetry[K, V]) Del(ctx context.Context, k K) error {
now := time.Now()
err := t.next.Del(ctx, k)
t.record("Del", err == nil, time.Since(now))
return err
}

var histogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: "example",
Subsystem: "kv",
Name: "user_kv_operation_duration_seconds",
}, []string{"name", "operation", "success"})

func NewRecorder(name string) recordFunc {
return func(operation string, success bool, duration time.Duration) {
histogram.WithLabelValues(name, operation, strconv.FormatBool(success)).Observe(duration.Seconds())
}
}

0 comments on commit 1725e24

Please sign in to comment.