entitycache

package
v0.0.18 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package entitycache 提供通用实体缓存抽象。

EntityCache[K, V] 是 K→V 的缓存接口,由两种实现提供服务:

  • FullCache:永远写入,等价于现有 SyncMap 行为(用于 admin 维护的小规模实体)
  • LRUCache:基于 hashicorp/golang-lru,按容量淘汰,支持 miss 时 RPC 拉取、 负缓存与 apply-if-present 推送语义(用于高基数实体如 token / user)

抽象层不知道任何业务概念。Token 双键索引、关联实体 warm 等组合 行为由 cache.Store 包内的派生层负责。

Index

Constants

This section is empty.

Variables

View Source
var ErrLoadInvalidated = errors.New("entitycache: load invalidated")

ErrLoadInvalidated means a key was invalidated while its cold load was in flight. Callers must retry instead of using the stale loader result.

View Source
var ErrLoadLimitReached = errors.New("entitycache: concurrent load limit reached")

ErrLoadLimitReached 表示已有过多不同 key 正在加载;同 key follower 不受影响。

View Source
var ErrNotFound = errors.New("entity not found")

ErrNotFound 表示 Loader 已确认 key 在源端不存在。 LRUCache 据此触发负缓存。

Functions

This section is empty.

Types

type Action

type Action int

Action 描述一次数据变更事件的语义。

const (
	// ActionSet 表示写入或更新一条记录。
	ActionSet Action = iota
	// ActionDelete 表示删除一条记录。
	ActionDelete
)

type Config

type Config[K comparable, V any] struct {
	// Capacity 是最大条目数(必须 > 0)。
	Capacity int

	// MaxConcurrentLoads 限制同时冷加载的不同 key 数。0 使用有界默认值;负值非法。
	MaxConcurrentLoads int

	// Loader 在 Get miss 时被调用。可为 nil(仅本地缓存)。
	Loader Loader[K, V]

	// NegativeTTL 是负缓存("key 不存在")的过期时间。0 表示禁用负缓存。
	NegativeTTL time.Duration

	// Now 用于测试控制时间。零值时使用 time.Now。
	Now func() time.Time

	// OnEvict 在 LRU 因容量淘汰一条**正常**条目时被调用(负缓存条目不触发)。
	// 用于派生反向索引同步清理(如 tokenStore.byID)。可为 nil。
	OnEvict func(key K, value V)

	// Refresh 提供缓存韧性参数(动态读取,支持运行时改值)。
	// 非 nil 且 Loader 非 nil 时启用 stale-while-revalidate + detached 冷 miss。
	// nil 时退化为原行为(冷 miss 沿用调用方 ctx,不做后台刷新)。
	Refresh func() RefreshConfig

	Lifecycle *Lifecycle
}

Config 是 LRUCache 的构造参数。

type EntityCache

type EntityCache[K comparable, V any] interface {
	// Get 命中返回 (v, true, nil);未命中且未配置 Loader 返回 (zero, false, nil);
	// 已配置 Loader 时同步触发拉取。Loader 返回 ErrNotFound 走负缓存
	// 后续返回 (zero, false, ErrNotFound);其他错误透传。
	Get(ctx context.Context, key K) (V, bool, error)

	// Peek 仅查本地,不触发 Loader。
	Peek(key K) (V, bool)

	// Apply 处理 push 事件。
	// FullCache 永远写入或删除;LRUCache 仅当 key 已在缓存时操作。
	Apply(action Action, key K, value V)

	// Set 直接写入,不经 apply-if-present 检查(用于 FullSync 等主动加载场景)。
	Set(key K, value V)

	// Delete 直接删除。
	Delete(key K)

	// Clear 删除所有正向、负向和可见缓存状态。
	Clear()

	// Len 返回当前条目数。
	Len() int

	// Range 遍历当前所有条目。回调返回 false 终止遍历。
	Range(func(K, V) bool)

	// Stats 返回运行计数快照。
	Stats() Stats
}

EntityCache 是通用实体缓存接口。

type FullCache

type FullCache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

FullCache 永远写入,等价于现有 SyncMap 行为。无 LRU 淘汰、无 Loader。

func NewFullCache

func NewFullCache[K comparable, V any]() *FullCache[K, V]

NewFullCache 创建一个空的 FullCache。

func (*FullCache[K, V]) Apply

func (c *FullCache[K, V]) Apply(action Action, key K, value V)

Apply 永远写入或删除(FullCache 不区分 push 与 set 语义)。

func (*FullCache[K, V]) Clear added in v0.0.16

func (c *FullCache[K, V]) Clear()

Clear 删除所有条目。

func (*FullCache[K, V]) Delete

func (c *FullCache[K, V]) Delete(key K)

Delete 直接删除。

func (*FullCache[K, V]) Get

func (c *FullCache[K, V]) Get(_ context.Context, key K) (V, bool, error)

Get 仅查本地。FullCache 不接 Loader,未命中返回 (zero, false, nil)。

func (*FullCache[K, V]) Len

func (c *FullCache[K, V]) Len() int

Len 返回条目数。

func (*FullCache[K, V]) Peek

func (c *FullCache[K, V]) Peek(key K) (V, bool)

Peek 同 Get,无副作用语义。

func (*FullCache[K, V]) Range

func (c *FullCache[K, V]) Range(fn func(K, V) bool)

Range 遍历所有条目。

func (*FullCache[K, V]) Set

func (c *FullCache[K, V]) Set(key K, value V)

Set 直接写入。

func (*FullCache[K, V]) Stats

func (c *FullCache[K, V]) Stats() Stats

Stats 仅维护 Size。

type LRUCache

type LRUCache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

LRUCache 基于 hashicorp/golang-lru,带 Loader、负缓存、metrics。

func NewLRUCache

func NewLRUCache[K comparable, V any](cfg Config[K, V]) (*LRUCache[K, V], error)

NewLRUCache 构造 LRUCache。Capacity <= 0 返回错误(fail-fast)。

func (*LRUCache[K, V]) Apply

func (c *LRUCache[K, V]) Apply(action Action, key K, value V)

Apply:apply-if-present。LRU 仅当 key 存在时写入或删除。

已知非原子窗口:ActionSet 的 Contains→store(Add) 之间若有并发 Delete, 这次 re-add 会复活已删条目(resurrection)。这是被接受的——写入幂等,SWR 刷新本就罕见,且 hashicorp/lru 不提供原子的 update-if-present。不加锁。

func (*LRUCache[K, V]) Clear added in v0.0.16

func (c *LRUCache[K, V]) Clear()

Clear purges positive and negative entries and invalidates every active cold load. Only active-flight generations are retained, so bookkeeping is bounded by MaxConcurrentLoads and is removed when each flight completes.

func (*LRUCache[K, V]) Delete

func (c *LRUCache[K, V]) Delete(key K)

Delete 删除。

func (*LRUCache[K, V]) Get

func (c *LRUCache[K, V]) Get(ctx context.Context, key K) (V, bool, error)

Get 命中返回 (v, true, nil)。 miss 且配置了 Loader 时通过 singleflight 单飞调用,结果写入缓存。 Loader 返回 ErrNotFound 时进入负缓存(如启用),返回 (zero, false, ErrNotFound)。 Loader 返回其他错误透传不缓存。

func (*LRUCache[K, V]) Len

func (c *LRUCache[K, V]) Len() int

Len 返回当前条目数(包含负缓存)。

func (*LRUCache[K, V]) MutationEpoch added in v0.0.16

func (c *LRUCache[K, V]) MutationEpoch() uint64

func (*LRUCache[K, V]) Peek

func (c *LRUCache[K, V]) Peek(key K) (V, bool)

Peek 仅查本地。负缓存条目对调用方表现为 miss。

func (*LRUCache[K, V]) Range

func (c *LRUCache[K, V]) Range(fn func(K, V) bool)

Range 遍历所有非负缓存条目。

func (*LRUCache[K, V]) Set

func (c *LRUCache[K, V]) Set(key K, value V)

Set 直接写入(覆盖负缓存)。

func (*LRUCache[K, V]) SetIfMutationEpoch added in v0.0.16

func (c *LRUCache[K, V]) SetIfMutationEpoch(epoch uint64, key K, value V) bool

func (*LRUCache[K, V]) Stats

func (c *LRUCache[K, V]) Stats() Stats

Stats 返回快照。

type Lifecycle added in v0.0.13

type Lifecycle struct {
	// contains filtered or unexported fields
}

func NewLifecycle added in v0.0.13

func NewLifecycle() *Lifecycle

func (*Lifecycle) Close added in v0.0.13

func (l *Lifecycle) Close()

func (*Lifecycle) Context added in v0.0.13

func (l *Lifecycle) Context() context.Context

func (*Lifecycle) Done added in v0.0.13

func (l *Lifecycle) Done() <-chan struct{}

func (*Lifecycle) Go added in v0.0.13

func (l *Lifecycle) Go(run func(context.Context)) bool

func (*Lifecycle) GoLoad added in v0.0.13

func (l *Lifecycle) GoLoad(run func(context.Context)) bool

func (*Lifecycle) GoRefresh added in v0.0.13

func (l *Lifecycle) GoRefresh(run func(context.Context)) bool

func (*Lifecycle) ResourceCounts added in v0.0.13

func (l *Lifecycle) ResourceCounts() (loads, refreshes int64)

type Loader

type Loader[K comparable, V any] interface {
	Load(ctx context.Context, key K) (V, error)
}

Loader 封装一次 miss 时的远端拉取。 返回 ErrNotFound 时缓存写入负条目;其他错误透传不缓存。

type LoaderFunc

type LoaderFunc[K comparable, V any] func(context.Context, K) (V, error)

LoaderFunc 适配普通函数到 Loader 接口。

func (LoaderFunc[K, V]) Load

func (f LoaderFunc[K, V]) Load(ctx context.Context, k K) (V, error)

Load 实现 Loader 接口。

type MutationEpochCache added in v0.0.16

type MutationEpochCache[K comparable, V any] interface {
	MutationEpoch() uint64
	SetIfMutationEpoch(epoch uint64, key K, value V) bool
}

MutationEpochCache lets side loaders conditionally warm a cache only when no invalidation happened after the remote request began.

type RefreshConfig added in v0.0.8

type RefreshConfig struct {
	LoadTimeout        time.Duration // 冷 miss 阻塞加载超时(detached)
	RefreshAfter       time.Duration // 条目多旧触发后台刷新;<=0 禁用 soft-TTL
	RefreshTimeout     time.Duration // 单次后台刷新尝试超时
	RefreshMaxRetries  int           // 单次触发内 failsafe 重试次数
	RefreshBackoffBase time.Duration
	RefreshBackoffMax  time.Duration
}

RefreshConfig 是缓存韧性参数快照,由调用方通过 Config.Refresh 动态提供 (通常映射自管理后台 Settings,支持运行时改值即时生效)。

type RefreshOutcome added in v0.0.8

type RefreshOutcome int

RefreshOutcome 是一次后台刷新的三态结果。

const (
	// RefreshOK 成功拿到新值。
	RefreshOK RefreshOutcome = iota
	// RefreshGone 源端明确返回 ErrNotFound(可达且已删/吊销)→ 应逐出。
	RefreshGone
	// RefreshUnavailable 连接/超时错误(源端不可达)→ 应保留旧值。
	RefreshUnavailable
)

type Refresher added in v0.0.8

type Refresher[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Refresher 在后台韧性地把 key 拉回来,不持有任何缓存引用——只通过 handler 回调结果。 同 key 同时只有一次刷新在跑(去重)。失败带 failsafe 退避重试;ErrNotFound 不重试。

func NewRefresher added in v0.0.8

func NewRefresher[K comparable, V any](load Loader[K, V], cfg func() RefreshConfig) *Refresher[K, V]

NewRefresher 构造。load 与 cfg 必须非 nil。

func NewRefresherWithLifecycle added in v0.0.13

func NewRefresherWithLifecycle[K comparable, V any](load Loader[K, V], cfg func() RefreshConfig, lifecycle *Lifecycle) *Refresher[K, V]

func (*Refresher[K, V]) TriggerRefresh added in v0.0.8

func (r *Refresher[K, V]) TriggerRefresh(key K, handler func(RefreshOutcome, V))

TriggerRefresh 异步触发一次刷新;同 key 已在刷新则直接返回(去重),不重复打远端。 完成后回调 (outcome, value):RefreshOK 时 value 为新值,否则为零值。 in-flight 标记一直持有到 handler 回调返回:同 key 的并发触发在整个 load + handler 期间被丢弃(去重窗口覆盖全程,设计如此)。

type Stats

type Stats struct {
	Hits          int64
	Misses        int64
	Evictions     int64
	NegativeHits  int64
	LoadErrors    int64
	Invalidations int64
	Size          int
	Capacity      int
}

Stats 是缓存的运行计数。LRUCache 按调用累加;FullCache 仅维护 Size。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL