You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

59 lines
1.7 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package atomiccache provides a map-based cache that supports very fast
  15. // reads.
  16. package atomiccache
  17. import (
  18. "sync"
  19. "sync/atomic"
  20. )
  21. type mapType map[interface{}]interface{}
  22. // Cache is a map-based cache that supports fast reads via use of atomics.
  23. // Writes are slow, requiring a copy of the entire cache.
  24. // The zero Cache is an empty cache, ready for use.
  25. type Cache struct {
  26. val atomic.Value // mapType
  27. mu sync.Mutex // used only by writers
  28. }
  29. // Get returns the value of the cache at key. If there is no value,
  30. // getter is called to provide one, and the cache is updated.
  31. // The getter function may be called concurrently. It should be pure,
  32. // returning the same value for every call.
  33. func (c *Cache) Get(key interface{}, getter func() interface{}) interface{} {
  34. mp, _ := c.val.Load().(mapType)
  35. if v, ok := mp[key]; ok {
  36. return v
  37. }
  38. // Compute value without lock.
  39. // Might duplicate effort but won't hold other computations back.
  40. newV := getter()
  41. c.mu.Lock()
  42. mp, _ = c.val.Load().(mapType)
  43. newM := make(mapType, len(mp)+1)
  44. for k, v := range mp {
  45. newM[k] = v
  46. }
  47. newM[key] = newV
  48. c.val.Store(newM)
  49. c.mu.Unlock()
  50. return newV
  51. }