github.com/sylr/terraform@v0.11.12-beta1/helper/shadow/keyed_value.go (about) 1 package shadow 2 3 import ( 4 "sync" 5 ) 6 7 // KeyedValue is a struct that coordinates a value by key. If a value is 8 // not available for a give key, it'll block until it is available. 9 type KeyedValue struct { 10 lock sync.Mutex 11 once sync.Once 12 values map[string]interface{} 13 waiters map[string]*Value 14 closed bool 15 } 16 17 // Close closes the value. This can never fail. For a definition of 18 // "close" see the ErrClosed docs. 19 func (w *KeyedValue) Close() error { 20 w.lock.Lock() 21 defer w.lock.Unlock() 22 23 // Set closed to true always 24 w.closed = true 25 26 // For all waiters, complete with ErrClosed 27 for k, val := range w.waiters { 28 val.SetValue(ErrClosed) 29 delete(w.waiters, k) 30 } 31 32 return nil 33 } 34 35 // Value returns the value that was set for the given key, or blocks 36 // until one is available. 37 func (w *KeyedValue) Value(k string) interface{} { 38 w.lock.Lock() 39 v, val := w.valueWaiter(k) 40 w.lock.Unlock() 41 42 // If we have no waiter, then return the value 43 if val == nil { 44 return v 45 } 46 47 // We have a waiter, so wait 48 return val.Value() 49 } 50 51 // WaitForChange waits for the value with the given key to be set again. 52 // If the key isn't set, it'll wait for an initial value. Note that while 53 // it is called "WaitForChange", the value isn't guaranteed to _change_; 54 // this will return when a SetValue is called for the given k. 55 func (w *KeyedValue) WaitForChange(k string) interface{} { 56 w.lock.Lock() 57 w.once.Do(w.init) 58 59 // If we're closed, we're closed 60 if w.closed { 61 w.lock.Unlock() 62 return ErrClosed 63 } 64 65 // Check for an active waiter. If there isn't one, make it 66 val := w.waiters[k] 67 if val == nil { 68 val = new(Value) 69 w.waiters[k] = val 70 } 71 w.lock.Unlock() 72 73 // And wait 74 return val.Value() 75 } 76 77 // ValueOk gets the value for the given key, returning immediately if the 78 // value doesn't exist. The second return argument is true if the value exists. 79 func (w *KeyedValue) ValueOk(k string) (interface{}, bool) { 80 w.lock.Lock() 81 defer w.lock.Unlock() 82 83 v, val := w.valueWaiter(k) 84 return v, val == nil 85 } 86 87 func (w *KeyedValue) SetValue(k string, v interface{}) { 88 w.lock.Lock() 89 defer w.lock.Unlock() 90 w.setValue(k, v) 91 } 92 93 // Init will initialize the key to a given value only if the key has 94 // not been set before. This is safe to call multiple times and in parallel. 95 func (w *KeyedValue) Init(k string, v interface{}) { 96 w.lock.Lock() 97 defer w.lock.Unlock() 98 99 // If we have a waiter, set the value. 100 _, val := w.valueWaiter(k) 101 if val != nil { 102 w.setValue(k, v) 103 } 104 } 105 106 // Must be called with w.lock held. 107 func (w *KeyedValue) init() { 108 w.values = make(map[string]interface{}) 109 w.waiters = make(map[string]*Value) 110 } 111 112 // setValue is like SetValue but assumes the lock is held. 113 func (w *KeyedValue) setValue(k string, v interface{}) { 114 w.once.Do(w.init) 115 116 // Set the value, always 117 w.values[k] = v 118 119 // If we have a waiter, set it 120 if val, ok := w.waiters[k]; ok { 121 val.SetValue(v) 122 delete(w.waiters, k) 123 } 124 } 125 126 // valueWaiter gets the value or the Value waiter for a given key. 127 // 128 // This must be called with lock held. 129 func (w *KeyedValue) valueWaiter(k string) (interface{}, *Value) { 130 w.once.Do(w.init) 131 132 // If we have this value already, return it 133 if v, ok := w.values[k]; ok { 134 return v, nil 135 } 136 137 // If we're closed, return that 138 if w.closed { 139 return ErrClosed, nil 140 } 141 142 // No pending value, check for a waiter 143 val := w.waiters[k] 144 if val == nil { 145 val = new(Value) 146 w.waiters[k] = val 147 } 148 149 // Return the waiter 150 return nil, val 151 }