single.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package cache
  4. import (
  5. "time"
  6. )
  7. // Single is a simple in-memory cache that stores a single value until a
  8. // defined time before it is re-fetched. It also supports returning a
  9. // previously-expired value if refreshing the value in the cache fails.
  10. //
  11. // Single is not safe for concurrent use.
  12. type Single[K comparable, V any] struct {
  13. key K
  14. val V
  15. goodUntil time.Time
  16. timeNow func() time.Time // for tests
  17. // ServeExpired indicates that if an error occurs when filling the
  18. // cache, an expired value can be returned instead of an error.
  19. //
  20. // This value should only be set when this struct is created.
  21. ServeExpired bool
  22. }
  23. var _ Cache[int, int] = (*Single[int, int])(nil)
  24. // Get will return the cached value, if any, or fill the cache by calling f and
  25. // return the corresponding value. If f returns an error and c.ServeExpired is
  26. // true, then a previous expired value can be returned with no error.
  27. func (c *Single[K, V]) Get(key K, f FillFunc[V]) (V, error) {
  28. var now time.Time
  29. if c.timeNow != nil {
  30. now = c.timeNow()
  31. } else {
  32. now = time.Now()
  33. }
  34. if c.key == key && now.Before(c.goodUntil) {
  35. return c.val, nil
  36. }
  37. // Re-fill cached entry
  38. val, until, err := f()
  39. if err == nil {
  40. c.key = key
  41. c.val = val
  42. c.goodUntil = until
  43. return val, nil
  44. }
  45. // Never serve an expired entry for the wrong key.
  46. if c.key == key && c.ServeExpired && !c.goodUntil.IsZero() {
  47. return c.val, nil
  48. }
  49. var zero V
  50. return zero, err
  51. }
  52. // Forget implements Cache.
  53. func (c *Single[K, V]) Forget(key K) {
  54. if c.key != key {
  55. return
  56. }
  57. c.Empty()
  58. }
  59. // Empty implements Cache.
  60. func (c *Single[K, V]) Empty() {
  61. c.goodUntil = time.Time{}
  62. var zeroKey K
  63. c.key = zeroKey
  64. var zeroVal V
  65. c.val = zeroVal
  66. }