context.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Package gls implements goroutine-local storage.
  2. package gls
  3. import (
  4. "sync"
  5. )
  6. var (
  7. mgrRegistry = make(map[*ContextManager]bool)
  8. mgrRegistryMtx sync.RWMutex
  9. )
  10. // Values is simply a map of key types to value types. Used by SetValues to
  11. // set multiple values at once.
  12. type Values map[interface{}]interface{}
  13. // ContextManager is the main entrypoint for interacting with
  14. // Goroutine-local-storage. You can have multiple independent ContextManagers
  15. // at any given time. ContextManagers are usually declared globally for a given
  16. // class of context variables. You should use NewContextManager for
  17. // construction.
  18. type ContextManager struct {
  19. mtx sync.Mutex
  20. values map[uint]Values
  21. }
  22. // NewContextManager returns a brand new ContextManager. It also registers the
  23. // new ContextManager in the ContextManager registry which is used by the Go
  24. // method. ContextManagers are typically defined globally at package scope.
  25. func NewContextManager() *ContextManager {
  26. mgr := &ContextManager{values: make(map[uint]Values)}
  27. mgrRegistryMtx.Lock()
  28. defer mgrRegistryMtx.Unlock()
  29. mgrRegistry[mgr] = true
  30. return mgr
  31. }
  32. // Unregister removes a ContextManager from the global registry, used by the
  33. // Go method. Only intended for use when you're completely done with a
  34. // ContextManager. Use of Unregister at all is rare.
  35. func (m *ContextManager) Unregister() {
  36. mgrRegistryMtx.Lock()
  37. defer mgrRegistryMtx.Unlock()
  38. delete(mgrRegistry, m)
  39. }
  40. // SetValues takes a collection of values and a function to call for those
  41. // values to be set in. Anything further down the stack will have the set
  42. // values available through GetValue. SetValues will add new values or replace
  43. // existing values of the same key and will not mutate or change values for
  44. // previous stack frames.
  45. // SetValues is slow (makes a copy of all current and new values for the new
  46. // gls-context) in order to reduce the amount of lookups GetValue requires.
  47. func (m *ContextManager) SetValues(new_values Values, context_call func()) {
  48. if len(new_values) == 0 {
  49. context_call()
  50. return
  51. }
  52. mutated_keys := make([]interface{}, 0, len(new_values))
  53. mutated_vals := make(Values, len(new_values))
  54. EnsureGoroutineId(func(gid uint) {
  55. m.mtx.Lock()
  56. state, found := m.values[gid]
  57. if !found {
  58. state = make(Values, len(new_values))
  59. m.values[gid] = state
  60. }
  61. m.mtx.Unlock()
  62. for key, new_val := range new_values {
  63. mutated_keys = append(mutated_keys, key)
  64. if old_val, ok := state[key]; ok {
  65. mutated_vals[key] = old_val
  66. }
  67. state[key] = new_val
  68. }
  69. defer func() {
  70. if !found {
  71. m.mtx.Lock()
  72. delete(m.values, gid)
  73. m.mtx.Unlock()
  74. return
  75. }
  76. for _, key := range mutated_keys {
  77. if val, ok := mutated_vals[key]; ok {
  78. state[key] = val
  79. } else {
  80. delete(state, key)
  81. }
  82. }
  83. }()
  84. context_call()
  85. })
  86. }
  87. // GetValue will return a previously set value, provided that the value was set
  88. // by SetValues somewhere higher up the stack. If the value is not found, ok
  89. // will be false.
  90. func (m *ContextManager) GetValue(key interface{}) (
  91. value interface{}, ok bool) {
  92. gid, ok := GetGoroutineId()
  93. if !ok {
  94. return nil, false
  95. }
  96. m.mtx.Lock()
  97. state, found := m.values[gid]
  98. m.mtx.Unlock()
  99. if !found {
  100. return nil, false
  101. }
  102. value, ok = state[key]
  103. return value, ok
  104. }
  105. func (m *ContextManager) getValues() Values {
  106. gid, ok := GetGoroutineId()
  107. if !ok {
  108. return nil
  109. }
  110. m.mtx.Lock()
  111. state, _ := m.values[gid]
  112. m.mtx.Unlock()
  113. return state
  114. }
  115. // Go preserves ContextManager values and Goroutine-local-storage across new
  116. // goroutine invocations. The Go method makes a copy of all existing values on
  117. // all registered context managers and makes sure they are still set after
  118. // kicking off the provided function in a new goroutine. If you don't use this
  119. // Go method instead of the standard 'go' keyword, you will lose values in
  120. // ContextManagers, as goroutines have brand new stacks.
  121. func Go(cb func()) {
  122. mgrRegistryMtx.RLock()
  123. defer mgrRegistryMtx.RUnlock()
  124. for mgr := range mgrRegistry {
  125. values := mgr.getValues()
  126. if len(values) > 0 {
  127. cb = func(mgr *ContextManager, cb func()) func() {
  128. return func() { mgr.SetValues(values, cb) }
  129. }(mgr, cb)
  130. }
  131. }
  132. go cb()
  133. }