2
0
Files
logikonline 12f4ea03a8
Some checks failed
Build and Release / Create Release (push) Successful in 0s
Trigger Vault Plugin Rebuild / Trigger Vault Rebuild (push) Successful in 0s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 2m48s
Build and Release / Lint (push) Failing after 5m2s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been skipped
Build and Release / Build Binaries (amd64, darwin, linux-latest) (push) Has been skipped
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin, linux-latest) (push) Has been skipped
Build and Release / Build Binaries (arm64, linux, linux-latest) (push) Has been skipped
Build and Release / Unit Tests (push) Successful in 5m37s
refactor: add /v3 suffix to module path for proper Go semver
Go's semantic import versioning requires v2+ modules to include the
major version in the module path. This enables using proper version
tags (v3.x.x) instead of pseudo-versions.

Updated module path: code.gitcaddy.com/server/v3
2026-01-17 17:53:59 -05:00

91 lines
2.1 KiB
Go

// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cache
import (
"context"
"sync"
"time"
"code.gitcaddy.com/server/v3/modules/log"
"code.gitcaddy.com/server/v3/modules/util"
)
// EphemeralCache is a cache that can be used to store data in a request level context
// This is useful for caching data that is expensive to calculate and is likely to be
// used multiple times in a request.
type EphemeralCache struct {
data map[any]map[any]any
lock sync.RWMutex
created time.Time
checkLifeTime time.Duration
}
var timeNow = time.Now
func NewEphemeralCache(checkLifeTime ...time.Duration) *EphemeralCache {
return &EphemeralCache{
data: make(map[any]map[any]any),
created: timeNow(),
checkLifeTime: util.OptionalArg(checkLifeTime, 0),
}
}
func (cc *EphemeralCache) checkExceededLifeTime(tp, key any) bool {
if cc.checkLifeTime > 0 && timeNow().Sub(cc.created) > cc.checkLifeTime {
log.Warn("EphemeralCache is expired, is highly likely to be abused for long-life tasks: %v, %v", tp, key)
return true
}
return false
}
func (cc *EphemeralCache) Get(tp, key any) (any, bool) {
if cc.checkExceededLifeTime(tp, key) {
return nil, false
}
cc.lock.RLock()
defer cc.lock.RUnlock()
ret, ok := cc.data[tp][key]
return ret, ok
}
func (cc *EphemeralCache) Put(tp, key, value any) {
if cc.checkExceededLifeTime(tp, key) {
return
}
cc.lock.Lock()
defer cc.lock.Unlock()
d := cc.data[tp]
if d == nil {
d = make(map[any]any)
cc.data[tp] = d
}
d[key] = value
}
func (cc *EphemeralCache) Delete(tp, key any) {
if cc.checkExceededLifeTime(tp, key) {
return
}
cc.lock.Lock()
defer cc.lock.Unlock()
delete(cc.data[tp], key)
}
func GetWithEphemeralCache[T, K any](ctx context.Context, c *EphemeralCache, groupKey string, targetKey K, f func(context.Context, K) (T, error)) (T, error) {
v, has := c.Get(groupKey, targetKey)
if vv, ok := v.(T); has && ok {
return vv, nil
}
t, err := f(ctx, targetKey)
if err != nil {
return t, err
}
c.Put(groupKey, targetKey, t)
return t, nil
}