Merge lp:~chipaca/ubuntu-push/flapping-fixes into lp:ubuntu-push/automatic

Proposed by John Lenton
Status: Merged
Approved by: John Lenton
Approved revision: 360
Merged at revision: 356
Proposed branch: lp:~chipaca/ubuntu-push/flapping-fixes
Merge into: lp:ubuntu-push/automatic
Prerequisite: lp:~chipaca/ubuntu-push/lots-of-small-logging-changes
Diff against target: 674 lines (+139/-87)
23 files modified
bus/connectivity/connectivity.go (+11/-7)
bus/connectivity/connectivity_test.go (+10/-11)
bus/endpoint.go (+6/-6)
bus/networkmanager/networkmanager.go (+6/-6)
bus/notifications/raw.go (+1/-1)
client/client.go (+2/-3)
client/client_test.go (+1/-1)
client/service/service.go (+3/-3)
client/session/session.go (+34/-2)
identifier/identifier.go (+1/-1)
identifier/identifier_test.go (+1/-1)
launch_helper/helper_finder/helper_finder.go (+1/-1)
launch_helper/helper_finder/helper_finder_test.go (+1/-1)
launch_helper/legacy/legacy.go (+1/-1)
launch_helper/legacy/legacy_test.go (+1/-1)
messaging/messaging.go (+1/-1)
testing/helpers.go (+1/-1)
urldispatcher/curldispatcher/curldispatcher.go (+1/-1)
urldispatcher/urldispatcher.go (+2/-2)
urldispatcher/urldispatcher_test.go (+2/-2)
util/redialer.go (+36/-27)
util/redialer_states.gv (+9/-0)
util/redialer_test.go (+7/-7)
To merge this branch: bzr merge lp:~chipaca/ubuntu-push/flapping-fixes
Reviewer Review Type Date Requested Status
Bret Barker (community) Approve
Review via email: mp+247193@code.launchpad.net

This proposal supersedes a proposal from 2015-01-21.

Commit message

Partially work around the issue in a minimally intrusive way (real fix will have to wait).

Description of the change

Partially work around the issue in a minimally intrusive way (real fix will have to wait).

To post a comment you must log in.
Revision history for this message
Bret Barker (noise) wrote :

LGTM

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (51.7 KiB)

The attempt to merge lp:~chipaca/ubuntu-push/flapping-fixes into lp:ubuntu-push/automatic failed. Below is the output from the failed tests.

scripts/deps.sh ubuntu-push-client.go
scripts/deps.sh server/dev/server.go
scripts/deps.sh server/acceptance/cmd/acceptanceclient.go
/mnt/tarmac/cache/ubuntu-push-automatic/go-ws/bin/godeps -t launchpad.net/ubuntu-push launchpad.net/ubuntu-push/accounts launchpad.net/ubuntu-push/bus launchpad.net/ubuntu-push/bus/connectivity launchpad.net/ubuntu-push/bus/emblemcounter launchpad.net/ubuntu-push/bus/haptic launchpad.net/ubuntu-push/bus/networkmanager launchpad.net/ubuntu-push/bus/notifications launchpad.net/ubuntu-push/bus/polld launchpad.net/ubuntu-push/bus/powerd launchpad.net/ubuntu-push/bus/systemimage launchpad.net/ubuntu-push/bus/testing launchpad.net/ubuntu-push/bus/unitygreeter launchpad.net/ubuntu-push/bus/windowstack launchpad.net/ubuntu-push/click launchpad.net/ubuntu-push/click/cappinfo launchpad.net/ubuntu-push/click/cblacklist launchpad.net/ubuntu-push/click/cclick launchpad.net/ubuntu-push/click/testing launchpad.net/ubuntu-push/client launchpad.net/ubuntu-push/client/gethosts launchpad.net/ubuntu-push/client/service launchpad.net/ubuntu-push/client/session launchpad.net/ubuntu-push/client/session/seenstate launchpad.net/ubuntu-push/config launchpad.net/ubuntu-push/external/murmur3 launchpad.net/ubuntu-push/identifier launchpad.net/ubuntu-push/identifier/testing launchpad.net/ubuntu-push/launch_helper launchpad.net/ubuntu-push/launch_helper/cual launchpad.net/ubuntu-push/launch_helper/helper_finder launchpad.net/ubuntu-push/launch_helper/legacy launchpad.net/ubuntu-push/logger launchpad.net/ubuntu-push/messaging launchpad.net/ubuntu-push/messaging/cmessaging launchpad.net/ubuntu-push/messaging/reply launchpad.net/ubuntu-push/nih launchpad.net/ubuntu-push/nih/cnih launchpad.net/ubuntu-push/poller launchpad.net/ubuntu-push/protocol launchpad.net/ubuntu-push/server launchpad.net/ubuntu-push/server/api launchpad.net/ubuntu-push/server/broker launchpad.net/ubuntu-push/server/broker/simple launchpad.net/ubuntu-push/server/broker/testing launchpad.net/ubuntu-push/server/broker/testsuite launchpad.net/ubuntu-push/server/dev launchpad.net/ubuntu-push/server/listener launchpad.net/ubuntu-push/server/session launchpad.net/ubuntu-push/server/store launchpad.net/ubuntu-push/sounds launchpad.net/ubuntu-push/testing launchpad.net/ubuntu-push/testing/condition launchpad.net/ubuntu-push/urldispatcher launchpad.net/ubuntu-push/urldispatcher/curldispatcher launchpad.net/ubuntu-push/util launchpad.net/ubuntu-push/server/acceptance/cmd/ launchpad.net/ubuntu-push/server/dev/ launchpad.net/ubuntu-push/ 2>/dev/null | cat > dependencies.tsv
rm -f -r /mnt/tarmac/cache/ubuntu-push-automatic/go-ws/pkg
mkdir -p /mnt/tarmac/cache/ubuntu-push-automatic/go-ws/bin
mkdir -p /mnt/tarmac/cache/ubuntu-push-automatic/go-ws/pkg
go get -u launchpad.net/godeps
go get -d -u launchpad.net/gocheck launchpad.net/go-dbus/v1 launchpad.net/go-xdg/v0 code.google.com/p/gosqlite/sqlite3 code.google.com/p/go-uuid/uuid
/mnt/tarmac/cache/ubuntu-push-automatic/go-ws/bin/godeps -u dependencies.tsv
code.google.com/p/go-uuid now at 7dda39b2e7d5e26...

360. By John Lenton

fix a massive data race in session

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bus/connectivity/connectivity.go'
2--- bus/connectivity/connectivity.go 2015-01-22 10:38:04 +0000
3+++ bus/connectivity/connectivity.go 2015-01-22 10:38:04 +0000
4@@ -132,13 +132,17 @@
5 return false, errors.New("got not-OK from StateChanged watch")
6 }
7 cs.webgetCh = nil
8- cs.currentState = v
9- cs.timer.Reset(stabilizingTimeout)
10- log.Debugf("State changed to %s. Assuming disconnect.", v)
11- if cs.lastSent == true {
12- log.Infof("Sending 'disconnected'.")
13- cs.lastSent = false
14- break Loop
15+ if v != networkmanager.Connecting && cs.currentState != v {
16+ cs.currentState = v
17+ cs.timer.Reset(stabilizingTimeout)
18+ log.Debugf("state changed to %s. Assuming disconnect.", v)
19+ if cs.lastSent == true {
20+ log.Debugf("sending 'disconnected'.")
21+ cs.lastSent = false
22+ break Loop
23+ }
24+ } else {
25+ log.Debugf("got State of %s, current is %s, ignoring.", v, cs.currentState)
26 }
27
28 case <-cs.timer.C:
29
30=== modified file 'bus/connectivity/connectivity_test.go'
31--- bus/connectivity/connectivity_test.go 2014-07-04 23:00:42 +0000
32+++ bus/connectivity/connectivity_test.go 2015-01-22 10:38:04 +0000
33@@ -217,20 +217,22 @@
34 f, e := cs.connectedStateStep()
35 c.Check(e, IsNil)
36 c.Check(f, Equals, true)
37- ch <- networkmanager.ConnectedGlobal // a ConnectedGlobal when connected signals trouble
38- f, e = cs.connectedStateStep()
39- c.Check(e, IsNil)
40- c.Check(f, Equals, false) // so we assume a disconnect happened
41- f, e = cs.connectedStateStep()
42- c.Check(e, IsNil)
43- c.Check(f, Equals, true) // and if the web check works, go back to connected
44+ ch <- networkmanager.Disconnected
45+ ch <- networkmanager.ConnectedGlobal
46+ f, e = cs.connectedStateStep()
47+ c.Check(e, IsNil)
48+ c.Check(f, Equals, false)
49+ f, e = cs.connectedStateStep()
50+ c.Check(e, IsNil)
51+ c.Check(f, Equals, true)
52
53 // same scenario, but with failing web check
54 webget_p = condition.Fail2Work(1)
55+ ch <- networkmanager.Disconnected
56 ch <- networkmanager.ConnectedGlobal
57 f, e = cs.connectedStateStep()
58 c.Check(e, IsNil)
59- c.Check(f, Equals, false) // first false is from assuming a Connected signals trouble
60+ c.Check(f, Equals, false) // first false is from the Disconnected
61
62 // the next call to Step will time out
63 _ch := make(chan bool, 1)
64@@ -284,7 +286,6 @@
65
66 endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true),
67 uint32(networkmanager.ConnectedGlobal),
68- uint32(networkmanager.ConnectedGlobal),
69 uint32(networkmanager.Disconnected),
70 )
71
72@@ -303,8 +304,6 @@
73 }{
74 {false, "first state is always false", 0},
75 {true, "then it should be true as per ConnectedGlobal above", 0},
76- {false, "then, false (upon receiving the next ConnectedGlobal)", 2},
77- {true, "then it should be true (webcheck passed)", 0},
78 {false, "then it should be false (Disconnected)", 2},
79 {false, "then it should be false again because it's restarted", 2},
80 }
81
82=== modified file 'bus/endpoint.go'
83--- bus/endpoint.go 2015-01-21 17:21:42 +0000
84+++ bus/endpoint.go 2015-01-22 10:38:04 +0000
85@@ -84,7 +84,7 @@
86 name := endp.addr.Name
87 hasOwner, err := d.NameHasOwner(name)
88 if err != nil {
89- endp.log.Debugf("Unable to determine ownership of %#v: %v", name, err)
90+ endp.log.Debugf("unable to determine ownership of %#v: %v", name, err)
91 bus.Close()
92 return err
93 }
94@@ -126,7 +126,7 @@
95 func (endp *endpoint) WatchSignal(member string, f func(...interface{}), d func()) error {
96 watch, err := endp.proxy.WatchSignal(endp.addr.Interface, member)
97 if err != nil {
98- endp.log.Debugf("Failed to set up the watch: %s", err)
99+ endp.log.Debugf("failed to set up the watch: %s", err)
100 return err
101 }
102
103@@ -167,15 +167,15 @@
104 variantvs := endp.unpackOneMsg(msg, property)
105 switch len(variantvs) {
106 default:
107- return nil, fmt.Errorf("Too many values in Properties.Get response: %d", len(variantvs))
108+ return nil, fmt.Errorf("too many values in Properties.Get response: %d", len(variantvs))
109 case 0:
110- return nil, fmt.Errorf("Not enough values in Properties.Get response: %d", len(variantvs))
111+ return nil, fmt.Errorf("not enough values in Properties.Get response: %d", len(variantvs))
112 case 1:
113 // carry on
114 }
115 variant, ok := variantvs[0].(*dbus.Variant)
116 if !ok {
117- return nil, fmt.Errorf("Response from Properties.Get wasn't a *dbus.Variant")
118+ return nil, fmt.Errorf("response from Properties.Get wasn't a *dbus.Variant")
119 }
120 return variant.Value, nil
121 }
122@@ -324,6 +324,6 @@
123 }
124 f(endp.unpackOneMsg(msg, member)...)
125 }
126- endp.log.Errorf("Got not-OK from %s watch", member)
127+ endp.log.Errorf("got not-OK from %s watch", member)
128 d()
129 }
130
131=== modified file 'bus/networkmanager/networkmanager.go'
132--- bus/networkmanager/networkmanager.go 2014-04-04 12:01:42 +0000
133+++ bus/networkmanager/networkmanager.go 2015-01-22 10:38:04 +0000
134@@ -71,14 +71,14 @@
135 func (nm *networkManager) GetState() State {
136 s, err := nm.bus.GetProperty("state")
137 if err != nil {
138- nm.log.Errorf("Failed gettting current state: %s", err)
139- nm.log.Debugf("Defaulting state to Unknown")
140+ nm.log.Errorf("failed gettting current state: %s", err)
141+ nm.log.Debugf("defaulting state to Unknown")
142 return Unknown
143 }
144
145 v, ok := s.(uint32)
146 if !ok {
147- nm.log.Errorf("Got weird state: %#v", s)
148+ nm.log.Errorf("got weird state: %#v", s)
149 return Unknown
150 }
151
152@@ -110,8 +110,8 @@
153 func (nm *networkManager) GetPrimaryConnection() string {
154 s, err := nm.bus.GetProperty("PrimaryConnection")
155 if err != nil {
156- nm.log.Errorf("Failed gettting current primary connection: %s", err)
157- nm.log.Debugf("Defaulting primary connection to empty")
158+ nm.log.Errorf("failed gettting current primary connection: %s", err)
159+ nm.log.Debugf("defaulting primary connection to empty")
160 return ""
161 }
162
163@@ -146,7 +146,7 @@
164 ch <- string(con)
165 }, func() { close(ch) })
166 if err != nil {
167- nm.log.Debugf("Failed to set up the watch: %s", err)
168+ nm.log.Debugf("failed to set up the watch: %s", err)
169 return nil, err
170 }
171
172
173=== modified file 'bus/notifications/raw.go'
174--- bus/notifications/raw.go 2014-08-15 10:33:04 +0000
175+++ bus/notifications/raw.go 2015-01-22 10:38:04 +0000
176@@ -119,7 +119,7 @@
177 ch <- action
178 }, func() { close(ch) })
179 if err != nil {
180- raw.log.Debugf("Failed to set up the watch: %s", err)
181+ raw.log.Debugf("failed to set up the watch: %s", err)
182 return nil, err
183 }
184 return ch, nil
185
186=== modified file 'client/client.go'
187--- client/client.go 2014-11-03 13:36:00 +0000
188+++ client/client.go 2015-01-22 10:38:04 +0000
189@@ -381,10 +381,9 @@
190 return
191 }
192 client.hasConnectivity = hasConnectivity
193+ client.session.Close()
194 if hasConnectivity {
195 client.session.AutoRedial(client.sessionConnectedCh)
196- } else {
197- client.session.Close()
198 }
199 }
200
201@@ -490,7 +489,7 @@
202 case err := <-client.session.ErrCh:
203 errhandler(err)
204 case count := <-client.sessionConnectedCh:
205- client.log.Debugf("Session connected after %d attempts", count)
206+ client.log.Debugf("session connected after %d attempts", count)
207 case app := <-client.unregisterCh:
208 unregisterhandler(app)
209 }
210
211=== modified file 'client/client_test.go'
212--- client/client_test.go 2014-09-05 10:47:29 +0000
213+++ client/client_test.go 2015-01-22 10:38:04 +0000
214@@ -1135,7 +1135,7 @@
215 // sessionConnectedCh to nothing in particular, but it'll help sync this test
216 cli.sessionConnectedCh <- 42
217 tick()
218- c.Check(cs.log.Captured(), Matches, "(?ms).*Session connected after 42 attempts$")
219+ c.Check(cs.log.Captured(), Matches, "(?msi).*Session connected after 42 attempts$")
220
221 // loop() should have connected:
222 // * connCh to the connectivity checker
223
224=== modified file 'client/service/service.go'
225--- client/service/service.go 2014-11-19 13:58:12 +0000
226+++ client/service/service.go 2015-01-22 10:38:04 +0000
227@@ -149,14 +149,14 @@
228 // errors below here Can't Happen (tm).
229 body, err := ioutil.ReadAll(resp.Body)
230 if err != nil {
231- svc.Log.Errorf("Reading response body: %v", err)
232+ svc.Log.Errorf("during ReadAll() of response body: %v", err)
233 return nil, err
234 }
235
236 var reply registrationReply
237 err = json.Unmarshal(body, &reply)
238 if err != nil {
239- svc.Log.Errorf("Unmarshalling response body: %v", err)
240+ svc.Log.Errorf("during Unmarshal of response body: %v", err)
241 return nil, fmt.Errorf("unable to unmarshal register response: %v", err)
242 }
243
244@@ -181,7 +181,7 @@
245 }
246
247 if !reply.Ok || reply.Token == "" {
248- svc.Log.Errorf("Unexpected response: %#v", reply)
249+ svc.Log.Errorf("unexpected response: %#v", reply)
250 return nil, ErrBadToken
251 }
252
253
254=== modified file 'client/session/session.go'
255--- client/session/session.go 2015-01-21 17:21:42 +0000
256+++ client/session/session.go 2015-01-22 10:38:04 +0000
257@@ -74,8 +74,22 @@
258 Connected
259 Started
260 Running
261+ Unknown
262 )
263
264+func (s ClientSessionState) String() string {
265+ if s >= Unknown {
266+ return fmt.Sprintf("??? (%d)", s)
267+ }
268+ return [Unknown]string{
269+ "Error",
270+ "Disconnected",
271+ "Connected",
272+ "Started",
273+ "Running",
274+ }[s]
275+}
276+
277 type hostGetter interface {
278 Get() (*gethosts.Host, error)
279 }
280@@ -131,6 +145,7 @@
281 proto protocol.Protocol
282 pingInterval time.Duration
283 retrier util.AutoRedialer
284+ retrierLock sync.Mutex
285 cookie string
286 // status
287 stateP *uint32
288@@ -348,6 +363,8 @@
289 }
290
291 func (sess *ClientSession) stopRedial() {
292+ sess.retrierLock.Lock()
293+ defer sess.retrierLock.Unlock()
294 if sess.retrier != nil {
295 sess.retrier.Stop()
296 sess.retrier = nil
297@@ -360,15 +377,30 @@
298 sess.setShouldDelay()
299 }
300 time.Sleep(sess.redialDelay(sess))
301+ sess.retrierLock.Lock()
302+ defer sess.retrierLock.Unlock()
303+ if sess.retrier != nil {
304+ panic("session AutoRedial: unexpected non-nil retrier.")
305+ }
306 sess.retrier = util.NewAutoRedialer(sess)
307 sess.lastAutoRedial = time.Now()
308- go func() { doneCh <- sess.retrier.Redial() }()
309+ go func() {
310+ sess.retrierLock.Lock()
311+ retrier := sess.retrier
312+ sess.retrierLock.Unlock()
313+ if retrier == nil {
314+ sess.Log.Debugf("session autoredialer skipping retry: retrier has been set to nil.")
315+ return
316+ }
317+ doneCh <- retrier.Redial()
318+ }()
319 }
320
321 func (sess *ClientSession) Close() {
322 sess.stopRedial()
323 sess.doClose()
324 }
325+
326 func (sess *ClientSession) doClose() {
327 sess.connLock.Lock()
328 defer sess.connLock.Unlock()
329@@ -593,7 +625,7 @@
330 }
331 sess.proto = proto
332 sess.pingInterval = pingInterval
333- sess.Log.Debugf("Connected %v.", conn.RemoteAddr())
334+ sess.Log.Debugf("connected %v.", conn.RemoteAddr())
335 sess.started() // deals with choosing which host to retry with as well
336 return nil
337 }
338
339=== modified file 'identifier/identifier.go'
340--- identifier/identifier.go 2014-08-04 20:40:50 +0000
341+++ identifier/identifier.go 2015-01-22 10:38:04 +0000
342@@ -48,7 +48,7 @@
343 func New() (Id, error) {
344 value, err := readMachineId()
345 if err != nil {
346- return &Identifier{value: ""}, fmt.Errorf("Failed to read the machine id: %s", err)
347+ return &Identifier{value: ""}, fmt.Errorf("failed to read the machine id: %s", err)
348 }
349 return &Identifier{value: value}, nil
350 }
351
352=== modified file 'identifier/identifier_test.go'
353--- identifier/identifier_test.go 2014-08-12 00:32:32 +0000
354+++ identifier/identifier_test.go 2015-01-22 10:38:04 +0000
355@@ -48,7 +48,7 @@
356 machineIdPath = "/var/lib/dbus/no-such-file"
357 id, err := New()
358 c.Check(err, NotNil)
359- c.Check(err.Error(), Equals, "Failed to read the machine id: open /var/lib/dbus/no-such-file: no such file or directory")
360+ c.Check(err.Error(), Equals, "failed to read the machine id: open /var/lib/dbus/no-such-file: no such file or directory")
361 c.Check(id.String(), HasLen, 0)
362 }
363
364
365=== modified file 'launch_helper/helper_finder/helper_finder.go'
366--- launch_helper/helper_finder/helper_finder.go 2014-07-29 15:36:00 +0000
367+++ launch_helper/helper_finder/helper_finder.go 2015-01-22 10:38:04 +0000
368@@ -72,7 +72,7 @@
369 fInfo, err := os.Stat(helpersDataPath)
370 if err != nil {
371 // cache file is missing, go via the slow route
372- log.Infof("Cache file not found, falling back to .json file lookup")
373+ log.Infof("cache file not found, falling back to .json file lookup")
374 return helperFromHookFile(app)
375 }
376 // get the lock as the map can be changed while we read
377
378=== modified file 'launch_helper/helper_finder/helper_finder_test.go'
379--- launch_helper/helper_finder/helper_finder_test.go 2014-07-29 15:36:00 +0000
380+++ launch_helper/helper_finder/helper_finder_test.go 2015-01-22 10:38:04 +0000
381@@ -139,7 +139,7 @@
382 hid, hex := Helper(app, s.log)
383 c.Check(hid, Equals, "com.example.test_test-helper_1")
384 c.Check(hex, Equals, filepath.Join(s.symlinkPath, "tsthlpr"))
385- c.Check(s.log.Captured(), Matches, ".*Cache file not found, falling back to .json file lookup\n")
386+ c.Check(s.log.Captured(), Matches, ".*(?i)Cache file not found, falling back to .json file lookup\n")
387 }
388
389 func (s *helperSuite) TestHelperFromHookBasic(c *C) {
390
391=== modified file 'launch_helper/legacy/legacy.go'
392--- launch_helper/legacy/legacy.go 2014-11-05 12:07:53 +0000
393+++ launch_helper/legacy/legacy.go 2015-01-22 10:38:04 +0000
394@@ -78,7 +78,7 @@
395 p_err := cmd.Wait()
396 if p_err != nil {
397 // Helper failed or got killed, log output/errors
398- lhl.log.Errorf("Legacy helper failed: appId: %v, helper: %v, pid: %v, error: %v, stdout: %#v, stderr: %#v.",
399+ lhl.log.Errorf("legacy helper failed: appId: %v, helper: %v, pid: %v, error: %v, stdout: %#v, stderr: %#v.",
400 appId, progname, id, p_err, stdout.String(), stderr.String())
401 }
402 lhl.done(id)
403
404=== modified file 'launch_helper/legacy/legacy_test.go'
405--- launch_helper/legacy/legacy_test.go 2014-08-21 18:03:49 +0000
406+++ launch_helper/legacy/legacy_test.go 2015-01-22 10:38:04 +0000
407@@ -104,7 +104,7 @@
408 c.Assert(err, IsNil)
409
410 takeNext(ch, c)
411- c.Check(ls.log.Captured(), Matches, "(?s).*Legacy helper failed.*")
412+ c.Check(ls.log.Captured(), Matches, "(?si).*Legacy helper failed.*")
413 }
414
415 func (ls *legacySuite) TestHelperFailsLog(c *C) {
416
417=== modified file 'messaging/messaging.go'
418--- messaging/messaging.go 2014-07-27 02:54:40 +0000
419+++ messaging/messaging.go 2015-01-22 10:38:04 +0000
420@@ -181,7 +181,7 @@
421 Action: action,
422 })
423 if err != nil {
424- mmu.Log.Errorf("Failed to build action: %s", action)
425+ mmu.Log.Errorf("failed to build action: %s", action)
426 return false
427 }
428 actions[2*i] = string(act)
429
430=== modified file 'testing/helpers.go'
431--- testing/helpers.go 2014-07-11 19:42:57 +0000
432+++ testing/helpers.go 2015-01-22 10:38:04 +0000
433@@ -118,7 +118,7 @@
434
435 idx := strings.LastIndex(dir, sep)
436 if idx == -1 {
437- panic(fmt.Errorf("Unable to find %s in %#v", sep, dir))
438+ panic(fmt.Errorf("unable to find %s in %#v", sep, dir))
439 }
440 idx += len(sep)
441
442
443=== modified file 'urldispatcher/curldispatcher/curldispatcher.go'
444--- urldispatcher/curldispatcher/curldispatcher.go 2014-09-01 13:27:17 +0000
445+++ urldispatcher/curldispatcher/curldispatcher.go 2015-01-22 10:38:04 +0000
446@@ -79,7 +79,7 @@
447 C.dispatch_url(c_url, (C.gpointer)(&payload))
448 success := <-doneCh
449 if !success {
450- return fmt.Errorf("Failed to DispatchURL: %s for %s", url, appPackage)
451+ return fmt.Errorf("failed to DispatchURL: %s for %s", url, appPackage)
452 }
453 return nil
454 }
455
456=== modified file 'urldispatcher/urldispatcher.go'
457--- urldispatcher/urldispatcher.go 2014-09-01 13:27:17 +0000
458+++ urldispatcher/urldispatcher.go 2015-01-22 10:38:04 +0000
459@@ -44,7 +44,7 @@
460 var cTestURL = curldispatcher.TestURL
461
462 func (ud *urlDispatcher) DispatchURL(url string, app *click.AppId) error {
463- ud.log.Debugf("Dispatching %s", url)
464+ ud.log.Debugf("dispatching %s", url)
465 err := cDispatchURL(url, app.DispatchPackage())
466 if err != nil {
467 ud.log.Errorf("DispatchURL failed: %s", err)
468@@ -62,7 +62,7 @@
469 }
470 for _, appId := range appIds {
471 if appId != app.Versioned() {
472- ud.log.Debugf("Notification skipped because of different appid for actions: %v - %s != %s", urls, appId, app.Versioned())
473+ ud.log.Debugf("notification skipped because of different appid for actions: %v - %s != %s", urls, appId, app.Versioned())
474 return false
475 }
476 }
477
478=== modified file 'urldispatcher/urldispatcher_test.go'
479--- urldispatcher/urldispatcher_test.go 2014-08-21 17:45:01 +0000
480+++ urldispatcher/urldispatcher_test.go 2015-01-22 10:38:04 +0000
481@@ -106,7 +106,7 @@
482 appId := clickhelp.MustParseAppId("com.example.test_app_0.99")
483 urls := []string{"potato://test-app"}
484 c.Check(ud.TestURL(appId, urls), Equals, false)
485- c.Check(s.log.Captured(), Matches, `(?sm).*Notification skipped because of different appid for actions: \[potato://test-app\] - com.example.test_test-app_0.1 != com.example.test_app_0.99`)
486+ c.Check(s.log.Captured(), Matches, `(?smi).*notification skipped because of different appid for actions: \[potato://test-app\] - com.example.test_test-app_0.1 != com.example.test_app_0.99`)
487 }
488
489 func (s *UDSuite) TestTestURLOneWrongApp(c *C) {
490@@ -117,7 +117,7 @@
491 appId := clickhelp.MustParseAppId("com.example.test_test-app_0")
492 urls := []string{"potato://test-app", "potato_a://foo"}
493 c.Check(ud.TestURL(appId, urls), Equals, false)
494- c.Check(s.log.Captured(), Matches, `(?sm).*Notification skipped because of different appid for actions: \[potato://test-app potato_a://foo\] - com.example.test_test-app1 != com.example.test_test-app.*`)
495+ c.Check(s.log.Captured(), Matches, `(?smi).*notification skipped because of different appid for actions: \[potato://test-app potato_a://foo\] - com.example.test_test-app1 != com.example.test_test-app.*`)
496 }
497
498 func (s *UDSuite) TestTestURLInvalidURL(c *C) {
499
500=== modified file 'util/redialer.go'
501--- util/redialer.go 2014-03-20 12:15:47 +0000
502+++ util/redialer.go 2015-01-22 10:38:04 +0000
503@@ -19,6 +19,7 @@
504
505 import (
506 "sync"
507+ "sync/atomic"
508 "time"
509 )
510
511@@ -65,30 +66,42 @@
512 Stop() // Stop shuts down the given AutoRedialer, if it is still retrying.
513 }
514
515+type redialerState uint32
516+
517+const (
518+ Unconfigured redialerState = iota
519+ Redialing
520+ Stopped
521+)
522+
523+func (s *redialerState) String() string {
524+ return [3]string{"Unconfigured", "Redialing", "Stopped"}[uint32(*s)]
525+}
526+
527 type autoRedialer struct {
528- stop chan bool
529- lock sync.RWMutex
530+ stateP *redialerState
531 dial func() error
532 jitter func(time.Duration) time.Duration
533 }
534
535+func (ar *autoRedialer) state() redialerState {
536+ return redialerState(atomic.LoadUint32((*uint32)(ar.stateP)))
537+}
538+
539+func (ar *autoRedialer) setState(s redialerState) {
540+ atomic.StoreUint32((*uint32)(ar.stateP), uint32(s))
541+}
542+
543+func (ar *autoRedialer) setStateIfEqual(oldState, newState redialerState) bool {
544+ return atomic.CompareAndSwapUint32((*uint32)(ar.stateP), uint32(oldState), uint32(newState))
545+}
546+
547 func (ar *autoRedialer) Stop() {
548 if ar != nil {
549- ar.lock.RLock()
550- defer ar.lock.RUnlock()
551- if ar.stop != nil {
552- ar.stop <- true
553- }
554+ ar.setState(Stopped)
555 }
556 }
557
558-func (ar *autoRedialer) shutdown() {
559- ar.lock.Lock()
560- defer ar.lock.Unlock()
561- close(ar.stop)
562- ar.stop = nil
563-}
564-
565 // Redial keeps on calling Dial until it stops returning an error. It does
566 // exponential backoff, adding back the output of Jitter at each step.
567 func (ar *autoRedialer) Redial() uint32 {
568@@ -96,20 +109,19 @@
569 // at least it's better than a segfault...
570 panic("you can't Redial a nil AutoRedialer")
571 }
572- if ar.stop == nil {
573- panic("this AutoRedialer has already been shut down")
574+ if !ar.setStateIfEqual(Unconfigured, Redialing) {
575+ // XXX log this
576+ return 0
577 }
578- defer ar.shutdown()
579-
580- ar.lock.RLock()
581- stop := ar.stop
582- ar.lock.RUnlock()
583
584 var timeout time.Duration
585 var dialAttempts uint32 = 0 // unsigned so it can wrap safely ...
586 timeouts := Timeouts()
587 var numTimeouts uint32 = uint32(len(timeouts))
588 for {
589+ if ar.state() != Redialing {
590+ return dialAttempts
591+ }
592 if ar.dial() == nil {
593 return dialAttempts + 1
594 }
595@@ -122,18 +134,15 @@
596 timeout += ar.jitter(timeout)
597 }
598 dialAttempts++
599- select {
600- case <-stop:
601- return dialAttempts
602- case <-time.After(timeout):
603- }
604+ time.Sleep(timeout)
605 }
606 }
607
608 // Returns a stoppable AutoRedialer using the provided Dialer. If the Dialer
609 // is also a Jitterer, the backoff will be jittered.
610 func NewAutoRedialer(dialer Dialer) AutoRedialer {
611- ar := &autoRedialer{stop: make(chan bool), dial: dialer.Dial}
612+ state := Unconfigured
613+ ar := &autoRedialer{stateP: &state, dial: dialer.Dial}
614 jitterer, ok := dialer.(Jitterer)
615 if ok {
616 ar.jitter = jitterer.Jitter
617
618=== added file 'util/redialer_states.gv'
619--- util/redialer_states.gv 1970-01-01 00:00:00 +0000
620+++ util/redialer_states.gv 2015-01-22 10:38:04 +0000
621@@ -0,0 +1,9 @@
622+digraph "redialer" {
623+ "Unconfigured" -> "Redialing" [ label="Redial" ]
624+ "Unconfigured" -> "Stopped" [ label="Stop" ]
625+
626+ "Redialing" -> "Redialing" [ label="Redial" ]
627+ "Redialing" -> "Stopped" [ label="Stop" ]
628+
629+ "Stopped" -> "Stopped" [ label="*" ]
630+}
631
632=== modified file 'util/redialer_test.go'
633--- util/redialer_test.go 2014-02-05 13:02:47 +0000
634+++ util/redialer_test.go 2015-01-22 10:38:04 +0000
635@@ -48,10 +48,10 @@
636 func (s *RedialerSuite) TestWorks(c *C) {
637 endp := testibus.NewTestingEndpoint(condition.Fail2Work(3), nil)
638 ar := NewAutoRedialer(endp)
639- c.Check(ar.(*autoRedialer).stop, NotNil)
640+ // c.Check(ar.(*autoRedialer).stop, NotNil)
641 c.Check(ar.Redial(), Equals, uint32(4))
642 // and on success, the stopper goes away
643- c.Check(ar.(*autoRedialer).stop, IsNil)
644+ // c.Check(ar.(*autoRedialer).stop, IsNil)
645 }
646
647 func (s *RedialerSuite) TestRetryNil(c *C) {
648@@ -63,7 +63,7 @@
649 endp := testibus.NewTestingEndpoint(condition.Work(true), nil)
650 ar := NewAutoRedialer(endp)
651 c.Check(ar.Redial(), Equals, uint32(1))
652- c.Check(ar.Redial, PanicMatches, ".*shut.?down.*")
653+ c.Check(ar.Redial(), Equals, uint32(0))
654 }
655
656 type JitteringEndpoint struct {
657@@ -103,13 +103,13 @@
658 go func() { countCh <- ar.Redial() }()
659 ar.Stop()
660 select {
661- case n := <-countCh:
662- c.Check(n, Equals, uint32(1))
663+ case <-countCh:
664+ // pass
665 case <-time.After(20 * time.Millisecond):
666 c.Fatal("timed out waiting for redial")
667 }
668- // on Stop(), the stopper goes away too
669- c.Check(ar.(*autoRedialer).stop, IsNil)
670+ // on Stop(), the redialer is Stopped
671+ c.Check(ar.(*autoRedialer).state(), Equals, Stopped)
672 // and the next Stop() doesn't panic nor block
673 ar.Stop()
674 }

Subscribers

People subscribed via source and target branches