code.gitea.io/gitea@v1.19.3/modules/cache/context.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package cache 5 6 import ( 7 "context" 8 "sync" 9 10 "code.gitea.io/gitea/modules/log" 11 ) 12 13 // cacheContext is a context that can be used to cache data in a request level context 14 // This is useful for caching data that is expensive to calculate and is likely to be 15 // used multiple times in a request. 16 type cacheContext struct { 17 ctx context.Context 18 data map[any]map[any]any 19 lock sync.RWMutex 20 } 21 22 func (cc *cacheContext) Get(tp, key any) any { 23 cc.lock.RLock() 24 defer cc.lock.RUnlock() 25 if cc.data[tp] == nil { 26 return nil 27 } 28 return cc.data[tp][key] 29 } 30 31 func (cc *cacheContext) Put(tp, key, value any) { 32 cc.lock.Lock() 33 defer cc.lock.Unlock() 34 if cc.data[tp] == nil { 35 cc.data[tp] = make(map[any]any) 36 } 37 cc.data[tp][key] = value 38 } 39 40 func (cc *cacheContext) Delete(tp, key any) { 41 cc.lock.Lock() 42 defer cc.lock.Unlock() 43 if cc.data[tp] == nil { 44 return 45 } 46 delete(cc.data[tp], key) 47 } 48 49 var cacheContextKey = struct{}{} 50 51 func WithCacheContext(ctx context.Context) context.Context { 52 return context.WithValue(ctx, cacheContextKey, &cacheContext{ 53 ctx: ctx, 54 data: make(map[any]map[any]any), 55 }) 56 } 57 58 func GetContextData(ctx context.Context, tp, key any) any { 59 if c, ok := ctx.Value(cacheContextKey).(*cacheContext); ok { 60 return c.Get(tp, key) 61 } 62 log.Warn("cannot get cache context when getting data: %v", ctx) 63 return nil 64 } 65 66 func SetContextData(ctx context.Context, tp, key, value any) { 67 if c, ok := ctx.Value(cacheContextKey).(*cacheContext); ok { 68 c.Put(tp, key, value) 69 return 70 } 71 log.Warn("cannot get cache context when setting data: %v", ctx) 72 } 73 74 func RemoveContextData(ctx context.Context, tp, key any) { 75 if c, ok := ctx.Value(cacheContextKey).(*cacheContext); ok { 76 c.Delete(tp, key) 77 } 78 } 79 80 // GetWithContextCache returns the cache value of the given key in the given context. 81 func GetWithContextCache[T any](ctx context.Context, cacheGroupKey string, cacheTargetID any, f func() (T, error)) (T, error) { 82 v := GetContextData(ctx, cacheGroupKey, cacheTargetID) 83 if vv, ok := v.(T); ok { 84 return vv, nil 85 } 86 t, err := f() 87 if err != nil { 88 return t, err 89 } 90 SetContextData(ctx, cacheGroupKey, cacheTargetID, t) 91 return t, nil 92 }