gitea源码

ephemeral.go 2.1KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright 2025 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package cache
  4. import (
  5. "context"
  6. "sync"
  7. "time"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/util"
  10. )
  11. // EphemeralCache is a cache that can be used to store data in a request level context
  12. // This is useful for caching data that is expensive to calculate and is likely to be
  13. // used multiple times in a request.
  14. type EphemeralCache struct {
  15. data map[any]map[any]any
  16. lock sync.RWMutex
  17. created time.Time
  18. checkLifeTime time.Duration
  19. }
  20. var timeNow = time.Now
  21. func NewEphemeralCache(checkLifeTime ...time.Duration) *EphemeralCache {
  22. return &EphemeralCache{
  23. data: make(map[any]map[any]any),
  24. created: timeNow(),
  25. checkLifeTime: util.OptionalArg(checkLifeTime, 0),
  26. }
  27. }
  28. func (cc *EphemeralCache) checkExceededLifeTime(tp, key any) bool {
  29. if cc.checkLifeTime > 0 && timeNow().Sub(cc.created) > cc.checkLifeTime {
  30. log.Warn("EphemeralCache is expired, is highly likely to be abused for long-life tasks: %v, %v", tp, key)
  31. return true
  32. }
  33. return false
  34. }
  35. func (cc *EphemeralCache) Get(tp, key any) (any, bool) {
  36. if cc.checkExceededLifeTime(tp, key) {
  37. return nil, false
  38. }
  39. cc.lock.RLock()
  40. defer cc.lock.RUnlock()
  41. ret, ok := cc.data[tp][key]
  42. return ret, ok
  43. }
  44. func (cc *EphemeralCache) Put(tp, key, value any) {
  45. if cc.checkExceededLifeTime(tp, key) {
  46. return
  47. }
  48. cc.lock.Lock()
  49. defer cc.lock.Unlock()
  50. d := cc.data[tp]
  51. if d == nil {
  52. d = make(map[any]any)
  53. cc.data[tp] = d
  54. }
  55. d[key] = value
  56. }
  57. func (cc *EphemeralCache) Delete(tp, key any) {
  58. if cc.checkExceededLifeTime(tp, key) {
  59. return
  60. }
  61. cc.lock.Lock()
  62. defer cc.lock.Unlock()
  63. delete(cc.data[tp], key)
  64. }
  65. func GetWithEphemeralCache[T, K any](ctx context.Context, c *EphemeralCache, groupKey string, targetKey K, f func(context.Context, K) (T, error)) (T, error) {
  66. v, has := c.Get(groupKey, targetKey)
  67. if vv, ok := v.(T); has && ok {
  68. return vv, nil
  69. }
  70. t, err := f(ctx, targetKey)
  71. if err != nil {
  72. return t, err
  73. }
  74. c.Put(groupKey, targetKey, t)
  75. return t, nil
  76. }