diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go new file mode 100644 index 0000000..432b036 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go | |||
@@ -0,0 +1,151 @@ | |||
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 | } | ||