| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package cache
- import (
- "time"
- )
- // Single is a simple in-memory cache that stores a single value until a
- // defined time before it is re-fetched. It also supports returning a
- // previously-expired value if refreshing the value in the cache fails.
- //
- // Single is not safe for concurrent use.
- type Single[K comparable, V any] struct {
- key K
- val V
- goodUntil time.Time
- timeNow func() time.Time // for tests
- // ServeExpired indicates that if an error occurs when filling the
- // cache, an expired value can be returned instead of an error.
- //
- // This value should only be set when this struct is created.
- ServeExpired bool
- }
- var _ Cache[int, int] = (*Single[int, int])(nil)
- // Get will return the cached value, if any, or fill the cache by calling f and
- // return the corresponding value. If f returns an error and c.ServeExpired is
- // true, then a previous expired value can be returned with no error.
- func (c *Single[K, V]) Get(key K, f FillFunc[V]) (V, error) {
- var now time.Time
- if c.timeNow != nil {
- now = c.timeNow()
- } else {
- now = time.Now()
- }
- if c.key == key && now.Before(c.goodUntil) {
- return c.val, nil
- }
- // Re-fill cached entry
- val, until, err := f()
- if err == nil {
- c.key = key
- c.val = val
- c.goodUntil = until
- return val, nil
- }
- // Never serve an expired entry for the wrong key.
- if c.key == key && c.ServeExpired && !c.goodUntil.IsZero() {
- return c.val, nil
- }
- var zero V
- return zero, err
- }
- // Forget implements Cache.
- func (c *Single[K, V]) Forget(key K) {
- if c.key != key {
- return
- }
- c.Empty()
- }
- // Empty implements Cache.
- func (c *Single[K, V]) Empty() {
- c.goodUntil = time.Time{}
- var zeroKey K
- c.key = zeroKey
- var zeroVal V
- c.val = zeroVal
- }
|