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  }