use current cache implementation

This commit is contained in:
adlerhurst
2025-03-16 14:12:40 +01:00
parent ff25a516cf
commit 2edcffc751
21 changed files with 1183 additions and 190 deletions

View File

@@ -1,56 +0,0 @@
package cache
import (
"context"
"log"
"sync"
"github.com/zitadel/zitadel/backend/repository"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/cache/gomap"
)
type Instance struct {
mu *sync.RWMutex
byID cache.Cache[string, *repository.Instance]
byDomain cache.Cache[string, *repository.Instance]
}
func NewInstance() *Instance {
return &Instance{
mu: &sync.RWMutex{},
byID: gomap.New[string, *repository.Instance](),
byDomain: gomap.New[string, *repository.Instance](),
}
}
func (i *Instance) Set(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
log.Println("cache.instance.set")
i.set(instance, "")
return instance, nil
}
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
i.mu.RLock()
defer i.mu.RUnlock()
log.Println("cache.instance.byID")
instance, _ := i.byID.Get(id)
return instance, nil
}
func (i *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
i.mu.RLock()
defer i.mu.RUnlock()
log.Println("cache.instance.byDomain")
instance, _ := i.byDomain.Get(domain)
return instance, nil
}
func (i *Instance) set(instance *repository.Instance, domain string) {
i.mu.Lock()
defer i.mu.Unlock()
if domain != "" {
i.byDomain.Set(domain, instance)
}
i.byID.Set(instance.ID, instance)
}

View File

@@ -1,38 +0,0 @@
package cache
import (
"context"
"log"
"github.com/zitadel/zitadel/backend/repository"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/cache/gomap"
)
type User struct {
cache.Cache[string, *repository.User]
}
func NewUser() *User {
return &User{
Cache: gomap.New[string, *repository.User](),
}
}
// ByID implements repository.UserRepository.
func (u *User) ByID(ctx context.Context, id string) (*repository.User, error) {
log.Println("cache.user.byid")
user, _ := u.Get(id)
return user, nil
}
func (u *User) Set(ctx context.Context, user *repository.User) (*repository.User, error) {
log.Println("cache.user.set")
u.set(user)
return user, nil
}
func (u *User) set(user *repository.User) {
u.Cache.Set(user.ID, user)
}

View File

@@ -1,10 +1,37 @@
package repository
import "github.com/zitadel/zitadel/backend/storage/cache"
type Instance struct {
ID string
Name string
}
type InstanceIndex uint8
var InstanceIndices = []InstanceIndex{
InstanceByID,
InstanceByDomain,
}
const (
InstanceByID InstanceIndex = iota
InstanceByDomain
)
var _ cache.Entry[InstanceIndex, string] = (*Instance)(nil)
// Keys implements [cache.Entry].
func (i *Instance) Keys(index InstanceIndex) (key []string) {
switch index {
case InstanceByID:
return []string{i.ID}
case InstanceByDomain:
return []string{i.Name}
}
return nil
}
type ListRequest struct {
Limit uint16
}

View File

@@ -2,6 +2,8 @@ package handler
import (
"context"
"github.com/zitadel/zitadel/backend/storage/cache"
)
// Handler is a function that handles the request.
@@ -65,7 +67,7 @@ func SkipNext[Req, Res any](handle Handler[Req, Res], next Handler[Req, Res]) Ha
// SkipNilHandler skips the handle function if the handler is nil.
// The function is safe to call with nil handler.
func SkipNilHandler[O, R any](handler *O, handle Handler[R, R]) Handler[R, R] {
func SkipNilHandler[R any](handler any, handle Handler[R, R]) Handler[R, R] {
return func(ctx context.Context, request R) (res R, err error) {
if handler == nil {
return request, nil
@@ -73,3 +75,27 @@ func SkipNilHandler[O, R any](handler *O, handle Handler[R, R]) Handler[R, R] {
return handle(ctx, request)
}
}
func ErrFuncToHandle[R any](fn func(context.Context, R) error) Handler[R, R] {
return func(ctx context.Context, request R) (res R, err error) {
err = fn(ctx, request)
if err != nil {
return res, err
}
return request, nil
}
}
func NoReturnToHandle[R any](fn func(context.Context, R)) Handler[R, R] {
return func(ctx context.Context, request R) (res R, err error) {
fn(ctx, request)
return request, nil
}
}
func CacheGetToHandle[I, K comparable, E cache.Entry[I, K]](fn func(context.Context, I, K) (E, bool), index I) Handler[K, E] {
return func(ctx context.Context, request K) (res E, err error) {
res, _ = fn(ctx, index, request)
return res, nil
}
}

View File

@@ -4,18 +4,19 @@ import (
"context"
"github.com/zitadel/zitadel/backend/repository"
"github.com/zitadel/zitadel/backend/repository/cache"
"github.com/zitadel/zitadel/backend/repository/event"
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
"github.com/zitadel/zitadel/backend/repository/sql"
"github.com/zitadel/zitadel/backend/repository/telemetry/logged"
"github.com/zitadel/zitadel/backend/repository/telemetry/traced"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/cache/connector/noop"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/telemetry/tracing"
)
type InstanceOptions struct {
cache *cache.Instance
cache cache.Cache[repository.InstanceIndex, string, *repository.Instance]
}
type instance struct {
@@ -24,17 +25,17 @@ type instance struct {
}
func Instance(opts ...Option[InstanceOptions]) *instance {
i := instance{
options: newOptions[InstanceOptions](),
}
i.InstanceOptions = i.options.custom
i := new(instance)
i.InstanceOptions = &i.options.custom
i.cache = noop.NewCache[repository.InstanceIndex, string, *repository.Instance]()
for _, opt := range opts {
opt.apply(&i.options)
}
return &i
return i
}
func WithInstanceCache(cache *cache.Instance) Option[InstanceOptions] {
func WithInstanceCache(cache cache.Cache[repository.InstanceIndex, string, *repository.Instance]) Option[InstanceOptions] {
return func(opts *options[InstanceOptions]) {
opts.custom.cache = cache
}
@@ -55,7 +56,7 @@ func (i *instance) Create(ctx context.Context, tx database.Transaction, instance
),
handler.SkipNilHandler(i.cache,
handler.Decorates(
i.cache.Set,
handler.NoReturnToHandle(i.cache.Set),
traced.Decorate[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.cache.SetUp")),
logged.Decorate[*repository.Instance, *repository.Instance](i.logger, "instance.cache.SetUp"),
),
@@ -66,26 +67,26 @@ func (i *instance) Create(ctx context.Context, tx database.Transaction, instance
func (i *instance) ByID(ctx context.Context, querier database.Querier, id string) (*repository.Instance, error) {
return handler.SkipNext(
i.cache.ByID,
handler.CacheGetToHandle(i.cache.Get, repository.InstanceByID),
handler.Chain(
handler.Decorate(
sql.Query(querier).InstanceByID,
traced.Decorate[string, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.ByID")),
),
handler.SkipNilHandler(i.cache, i.cache.Set),
handler.SkipNilHandler(i.cache, handler.NoReturnToHandle(i.cache.Set)),
),
)(ctx, id)
}
func (i *instance) ByDomain(ctx context.Context, querier database.Querier, domain string) (*repository.Instance, error) {
return handler.SkipNext(
i.cache.ByDomain,
handler.CacheGetToHandle(i.cache.Get, repository.InstanceByDomain),
handler.Chain(
handler.Decorate(
sql.Query(querier).InstanceByDomain,
traced.Decorate[string, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.ByDomain")),
),
handler.SkipNilHandler(i.cache, i.cache.Set),
handler.SkipNilHandler(i.cache, handler.NoReturnToHandle(i.cache.Set)),
),
)(ctx, domain)
}

View File

@@ -8,8 +8,9 @@ import (
"testing"
"github.com/zitadel/zitadel/backend/repository"
"github.com/zitadel/zitadel/backend/repository/cache"
"github.com/zitadel/zitadel/backend/repository/orchestrate"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/cache/connector/gomap"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/storage/database/mock"
"github.com/zitadel/zitadel/backend/telemetry/logging"
@@ -34,7 +35,9 @@ func Test_instance_SetUp(t *testing.T) {
opts: []orchestrate.Option[orchestrate.InstanceOptions]{
orchestrate.WithTracer[orchestrate.InstanceOptions](tracing.NewTracer("test")),
orchestrate.WithLogger[orchestrate.InstanceOptions](logging.New(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})))),
orchestrate.WithInstanceCache(cache.NewInstance()),
orchestrate.WithInstanceCache(
gomap.NewCache[repository.InstanceIndex, string, *repository.Instance](context.Background(), repository.InstanceIndices, cache.Config{}),
),
},
args: args{
ctx: context.Background(),

View File

@@ -7,21 +7,15 @@ import (
// options are the default options for orchestrators.
type options[T any] struct {
custom *T
custom T
defaultOptions
}
type defaultOptions struct {
tracer *tracing.Tracer
logger *logging.Logger
}
func newOptions[T any]() options[T] {
return options[T]{
custom: new(T),
}
}
type applier interface {
apply()
}
type Option[T any] func(*options[T])
func WithTracer[T any](tracer *tracing.Tracer) Option[T] {

View File

@@ -4,17 +4,18 @@ import (
"context"
"github.com/zitadel/zitadel/backend/repository"
"github.com/zitadel/zitadel/backend/repository/cache"
"github.com/zitadel/zitadel/backend/repository/event"
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
"github.com/zitadel/zitadel/backend/repository/sql"
"github.com/zitadel/zitadel/backend/repository/telemetry/traced"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/cache/connector/noop"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/telemetry/tracing"
)
type UserOptions struct {
cache *cache.User
cache cache.Cache[repository.UserIndex, string, *repository.User]
}
type user struct {
@@ -23,17 +24,17 @@ type user struct {
}
func User(opts ...Option[UserOptions]) *user {
i := user{
options: newOptions[UserOptions](),
}
i.UserOptions = i.options.custom
i := new(user)
i.UserOptions = &i.options.custom
i.cache = noop.NewCache[repository.UserIndex, string, *repository.User]()
for _, opt := range opts {
opt(&i.options)
}
return &i
return i
}
func WithUserCache(cache *cache.User) Option[UserOptions] {
func WithUserCache(cache cache.Cache[repository.UserIndex, string, *repository.User]) Option[UserOptions] {
return func(i *options[UserOptions]) {
i.custom.cache = cache
}
@@ -56,13 +57,13 @@ func (i *user) Create(ctx context.Context, tx database.Transaction, user *reposi
func (i *user) ByID(ctx context.Context, querier database.Querier, id string) (*repository.User, error) {
return handler.SkipNext(
i.custom.cache.ByID,
handler.CacheGetToHandle(i.cache.Get, repository.UserByID),
handler.Chain(
handler.Decorate(
sql.Query(querier).UserByID,
traced.Decorate[string, *repository.User](i.tracer, tracing.WithSpanName("user.sql.ByID")),
),
handler.SkipNilHandler(i.custom.cache, i.custom.cache.Set),
handler.SkipNilHandler(i.custom.cache, handler.NoReturnToHandle(i.cache.Set)),
),
)(ctx, id)
}

View File

@@ -1,6 +1,33 @@
package repository
import "github.com/zitadel/zitadel/backend/storage/cache"
type User struct {
ID string
Username string
}
type UserIndex uint8
var UserIndices = []UserIndex{
UserByID,
UserByUsername,
}
const (
UserByID UserIndex = iota
UserByUsername
)
var _ cache.Entry[UserIndex, string] = (*User)(nil)
// Keys implements [cache.Entry].
func (u *User) Keys(index UserIndex) (key []string) {
switch index {
case UserByID:
return []string{u.ID}
case UserByUsername:
return []string{u.Username}
}
return nil
}