single.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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. // Get will return the cached value, if any, or fill the cache by calling f and
  24. // return the corresponding value. If f returns an error and c.ServeExpired is
  25. // true, then a previous expired value can be returned with no error.
  26. func (c *Single[K, V]) Get(key K, f FillFunc[V]) (V, error) {
  27. var now time.Time
  28. if c.timeNow != nil {
  29. now = c.timeNow()
  30. } else {
  31. now = time.Now()
  32. }
  33. if c.key == key && now.Before(c.goodUntil) {
  34. return c.val, nil
  35. }
  36. // Re-fill cached entry
  37. val, until, err := f()
  38. if err == nil {
  39. c.key = key
  40. c.val = val
  41. c.goodUntil = until
  42. return val, nil
  43. }
  44. // Never serve an expired entry for the wrong key.
  45. if c.key == key && c.ServeExpired && !c.goodUntil.IsZero() {
  46. return c.val, nil
  47. }
  48. var zero V
  49. return zero, err
  50. }
  51. // Forget implements Cache.
  52. func (c *Single[K, V]) Forget(key K) {
  53. if c.key != key {
  54. return
  55. }
  56. c.Empty()
  57. }
  58. // Empty implements Cache.
  59. func (c *Single[K, V]) Empty() {
  60. c.goodUntil = time.Time{}
  61. var zeroKey K
  62. c.key = zeroKey
  63. var zeroVal V
  64. c.val = zeroVal
  65. }