caching_handler.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package syspolicy
  4. import (
  5. "errors"
  6. "sync"
  7. )
  8. // CachingHandler is a handler that reads policies from an underlying handler the first time each key is requested
  9. // and permanently caches the result unless there is an error. If there is an ErrNoSuchKey error, that result is cached,
  10. // otherwise the actual error is returned and the next read for that key will retry using the handler.
  11. type CachingHandler struct {
  12. mu sync.Mutex
  13. strings map[string]string
  14. uint64s map[string]uint64
  15. bools map[string]bool
  16. strArrs map[string][]string
  17. notFound map[string]bool
  18. handler Handler
  19. }
  20. // NewCachingHandler creates a CachingHandler given a handler.
  21. func NewCachingHandler(handler Handler) *CachingHandler {
  22. return &CachingHandler{
  23. handler: handler,
  24. strings: make(map[string]string),
  25. uint64s: make(map[string]uint64),
  26. bools: make(map[string]bool),
  27. strArrs: make(map[string][]string),
  28. notFound: make(map[string]bool),
  29. }
  30. }
  31. // ReadString reads the policy settings value string given the key.
  32. // ReadString first reads from the handler's cache before resorting to using the handler.
  33. func (ch *CachingHandler) ReadString(key string) (string, error) {
  34. ch.mu.Lock()
  35. defer ch.mu.Unlock()
  36. if val, ok := ch.strings[key]; ok {
  37. return val, nil
  38. }
  39. if notFound := ch.notFound[key]; notFound {
  40. return "", ErrNoSuchKey
  41. }
  42. val, err := ch.handler.ReadString(key)
  43. if errors.Is(err, ErrNoSuchKey) {
  44. ch.notFound[key] = true
  45. return "", err
  46. } else if err != nil {
  47. return "", err
  48. }
  49. ch.strings[key] = val
  50. return val, nil
  51. }
  52. // ReadUInt64 reads the policy settings uint64 value given the key.
  53. // ReadUInt64 first reads from the handler's cache before resorting to using the handler.
  54. func (ch *CachingHandler) ReadUInt64(key string) (uint64, error) {
  55. ch.mu.Lock()
  56. defer ch.mu.Unlock()
  57. if val, ok := ch.uint64s[key]; ok {
  58. return val, nil
  59. }
  60. if notFound := ch.notFound[key]; notFound {
  61. return 0, ErrNoSuchKey
  62. }
  63. val, err := ch.handler.ReadUInt64(key)
  64. if errors.Is(err, ErrNoSuchKey) {
  65. ch.notFound[key] = true
  66. return 0, err
  67. } else if err != nil {
  68. return 0, err
  69. }
  70. ch.uint64s[key] = val
  71. return val, nil
  72. }
  73. // ReadBoolean reads the policy settings boolean value given the key.
  74. // ReadBoolean first reads from the handler's cache before resorting to using the handler.
  75. func (ch *CachingHandler) ReadBoolean(key string) (bool, error) {
  76. ch.mu.Lock()
  77. defer ch.mu.Unlock()
  78. if val, ok := ch.bools[key]; ok {
  79. return val, nil
  80. }
  81. if notFound := ch.notFound[key]; notFound {
  82. return false, ErrNoSuchKey
  83. }
  84. val, err := ch.handler.ReadBoolean(key)
  85. if errors.Is(err, ErrNoSuchKey) {
  86. ch.notFound[key] = true
  87. return false, err
  88. } else if err != nil {
  89. return false, err
  90. }
  91. ch.bools[key] = val
  92. return val, nil
  93. }
  94. // ReadBoolean reads the policy settings boolean value given the key.
  95. // ReadBoolean first reads from the handler's cache before resorting to using the handler.
  96. func (ch *CachingHandler) ReadStringArray(key string) ([]string, error) {
  97. ch.mu.Lock()
  98. defer ch.mu.Unlock()
  99. if val, ok := ch.strArrs[key]; ok {
  100. return val, nil
  101. }
  102. if notFound := ch.notFound[key]; notFound {
  103. return nil, ErrNoSuchKey
  104. }
  105. val, err := ch.handler.ReadStringArray(key)
  106. if errors.Is(err, ErrNoSuchKey) {
  107. ch.notFound[key] = true
  108. return nil, err
  109. } else if err != nil {
  110. return nil, err
  111. }
  112. ch.strArrs[key] = val
  113. return val, nil
  114. }