]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
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 | } |