Merge lp:~jonas-drange/ubuntu-push/poller-checks-send-recv into lp:ubuntu-push/automatic

Proposed by Jonas G. Drange
Status: Merged
Approved by: John Lenton
Approved revision: 426
Merged at revision: 412
Proposed branch: lp:~jonas-drange/ubuntu-push/poller-checks-send-recv
Merge into: lp:ubuntu-push/automatic
Diff against target: 291 lines (+44/-39)
4 files modified
client/client.go (+6/-1)
client/client_test.go (+7/-0)
poller/poller.go (+23/-26)
poller/poller_test.go (+8/-12)
To merge this branch: bzr merge lp:~jonas-drange/ubuntu-push/poller-checks-send-recv
Reviewer Review Type Date Requested Status
John Lenton (community) Approve
Samuele Pedroni Abstain
Review via email: mp+272927@code.launchpad.net

Commit message

Fix lp:1469398 by using the connectivity state. Fix case where a failed powerd wakeup request would deadlock step().

Description of the change

Fix lp:1469398 by using the connectivity state. Fix case where a failed powerd wakeup request would deadlock step().

To post a comment you must log in.
Revision history for this message
Samuele Pedroni (pedronis) wrote :

see comment below

Revision history for this message
Samuele Pedroni (pedronis) wrote :

another one

review: Approve
Revision history for this message
Samuele Pedroni (pedronis) :
review: Abstain
Revision history for this message
Samuele Pedroni (pedronis) wrote :

as discussed the new

p.requestedWakeupErrCh <- err

can probably be

filteredWakeUpCh <- true

without need new channels

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

You were right, Samuele. That did indeed work.

Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

Voting does not meet specified criteria. Required: Approve >= 1, Disapprove == 0, Needs Fixing == 0, Needs Information == 0, Resubmit == 0, Pending == 0. Got: .

Revision history for this message
John Lenton (chipaca) wrote :

LGTM!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'client/client.go'
2--- client/client.go 2015-04-01 17:43:20 +0000
3+++ client/client.go 2015-10-07 12:15:39 +0000
4@@ -442,6 +442,11 @@
5 return nil
6 }
7
8+func (client *PushClient) handeConnNotification(conn bool) {
9+ client.session.HasConnectivity(conn)
10+ client.poller.HasConnectivity(conn)
11+}
12+
13 // doLoop connects events with their handlers
14 func (client *PushClient) doLoop(connhandler func(bool), bcasthandler func(*session.BroadcastNotification) error, ucasthandler func(session.AddressedNotification) error, unregisterhandler func(*click.AppId), accountshandler func()) {
15 for {
16@@ -475,7 +480,7 @@
17
18 // Loop calls doLoop with the "real" handlers
19 func (client *PushClient) Loop() {
20- client.doLoop(client.session.HasConnectivity,
21+ client.doLoop(client.handeConnNotification,
22 client.handleBroadcastNotification,
23 client.handleUnicastNotification,
24 client.handleUnregister,
25
26=== modified file 'client/client_test.go'
27--- client/client_test.go 2015-04-01 16:02:31 +0000
28+++ client/client_test.go 2015-10-07 12:15:39 +0000
29@@ -1032,6 +1032,7 @@
30 ******************************************************************/
31
32 type loopSession struct{ hasConn bool }
33+type loopPoller struct{}
34
35 func (s *loopSession) ResetCookie() {}
36 func (s *loopSession) State() session.ClientSessionState {
37@@ -1045,6 +1046,11 @@
38 func (s *loopSession) KeepConnection() error { return nil }
39 func (s *loopSession) StopKeepConnection() {}
40
41+func (p *loopPoller) HasConnectivity(hasConn bool) {}
42+func (p *loopPoller) IsConnected() bool { return false }
43+func (p *loopPoller) Start() error { return nil }
44+func (p *loopPoller) Run() error { return nil }
45+
46 func (cs *clientSuite) TestLoop(c *C) {
47 cli := NewPushClient(cs.configPath, cs.leveldbPath)
48 cli.connCh = make(chan bool)
49@@ -1070,6 +1076,7 @@
50 c.Assert(cli.session, NotNil)
51 cli.session.StopKeepConnection()
52 cli.session = &loopSession{}
53+ cli.poller = &loopPoller{}
54
55 go cli.Loop()
56
57
58=== modified file 'poller/poller.go'
59--- poller/poller.go 2015-09-28 08:24:51 +0000
60+++ poller/poller.go 2015-10-07 12:15:39 +0000
61@@ -25,7 +25,6 @@
62 "time"
63
64 "launchpad.net/ubuntu-push/bus"
65- "launchpad.net/ubuntu-push/bus/networkmanager"
66 "launchpad.net/ubuntu-push/bus/polld"
67 "launchpad.net/ubuntu-push/bus/powerd"
68 "launchpad.net/ubuntu-push/client/session"
69@@ -56,6 +55,7 @@
70 IsConnected() bool
71 Start() error
72 Run() error
73+ HasConnectivity(bool)
74 }
75
76 type PollerSetup struct {
77@@ -69,9 +69,9 @@
78 log logger.Logger
79 powerd powerd.Powerd
80 polld polld.Polld
81- nm networkmanager.NetworkManager
82 cookie string
83 sessionState stater
84+ connCh chan bool
85 requestWakeupCh chan struct{}
86 requestedWakeupErrCh chan error
87 holdsWakeLockCh chan bool
88@@ -84,6 +84,7 @@
89 powerd: nil,
90 polld: nil,
91 sessionState: setup.SessionStateGetter,
92+ connCh: make(chan bool),
93 requestWakeupCh: make(chan struct{}),
94 requestedWakeupErrCh: make(chan error),
95 holdsWakeLockCh: make(chan bool),
96@@ -94,6 +95,10 @@
97 return p.sessionState.State() == session.Running
98 }
99
100+func (p *poller) HasConnectivity(hasConn bool) {
101+ p.connCh <- hasConn
102+}
103+
104 func (p *poller) Start() error {
105 if p.log == nil {
106 return ErrUnconfigured
107@@ -104,10 +109,9 @@
108
109 powerdEndp := bus.SystemBus.Endpoint(powerd.BusAddress, p.log)
110 polldEndp := bus.SessionBus.Endpoint(polld.BusAddress, p.log)
111- nmEndp := bus.SystemBus.Endpoint(networkmanager.BusAddress, p.log)
112
113 var wg sync.WaitGroup
114- wg.Add(3)
115+ wg.Add(2)
116 go func() {
117 n := util.NewAutoRedialer(powerdEndp).Redial()
118 p.log.Debugf("powerd dialed on try %d", n)
119@@ -118,16 +122,10 @@
120 p.log.Debugf("polld dialed in on try %d", n)
121 wg.Done()
122 }()
123- go func() {
124- n := util.NewAutoRedialer(nmEndp).Redial()
125- p.log.Debugf("NetworkManager dialed on try %d", n)
126- wg.Done()
127- }()
128 wg.Wait()
129
130 p.powerd = powerd.New(powerdEndp, p.log)
131 p.polld = polld.New(polldEndp, p.log)
132- p.nm = networkmanager.New(nmEndp, p.log)
133
134 // busy sleep loop to workaround go's timer/sleep
135 // not accounting for time when the system is suspended
136@@ -150,7 +148,7 @@
137 if p.log == nil {
138 return ErrUnconfigured
139 }
140- if p.powerd == nil || p.polld == nil || p.nm == nil {
141+ if p.powerd == nil || p.polld == nil {
142 return ErrNotStarted
143 }
144 wakeupCh, err := p.powerd.WatchWakeups()
145@@ -161,13 +159,8 @@
146 if err != nil {
147 return err
148 }
149- nmState := p.nm.GetState()
150- nmStateCh, _, err := p.nm.WatchState()
151- if err != nil {
152- return err
153- }
154 filteredWakeUpCh := make(chan bool)
155- go p.control(wakeupCh, filteredWakeUpCh, nmState, nmStateCh)
156+ go p.control(wakeupCh, filteredWakeUpCh)
157 go p.run(filteredWakeUpCh, doneCh)
158 return nil
159 }
160@@ -185,10 +178,10 @@
161 return t, cookie, err
162 }
163
164-func (p *poller) control(wakeupCh <-chan bool, filteredWakeUpCh chan<- bool, nmState networkmanager.State, nmStateCh <-chan networkmanager.State) {
165- connected := nmState == networkmanager.ConnectedGlobal
166+func (p *poller) control(wakeupCh <-chan bool, filteredWakeUpCh chan<- bool) {
167+ // Assume a connection, and poll immediately.
168+ connected := true
169 dontPoll := !connected
170- p.log.Debugf("nmState: %v, networkmanager.ConnectedGlobal: %v", nmState, networkmanager.ConnectedGlobal)
171 var t time.Time
172 cookie := ""
173 holdsWakeLock := false
174@@ -225,11 +218,12 @@
175 filteredWakeUpCh <- true
176 }
177 }
178- case nmState = <-nmStateCh:
179- connected = nmState == networkmanager.ConnectedGlobal
180+ case state := <-p.connCh:
181+ connected = state
182+ p.log.Debugf("control: connected:%v", state)
183 }
184 newDontPoll := !connected
185- p.log.Debugf("control: nmState:%v prevDontPoll:%v dontPoll:%v wakeupReq:%v holdsWakeLock:%v", nmState, dontPoll, newDontPoll, !t.IsZero(), holdsWakeLock)
186+ p.log.Debugf("control: prevDontPoll:%v dontPoll:%v wakeupReq:%v holdsWakeLock:%v", dontPoll, newDontPoll, !t.IsZero(), holdsWakeLock)
187 if newDontPoll != dontPoll {
188 if dontPoll = newDontPoll; dontPoll {
189 if !t.IsZero() {
190@@ -245,7 +239,12 @@
191 } else {
192 if t.IsZero() && !holdsWakeLock {
193 // reschedule soon
194- t, cookie, _ = p.doRequestWakeup(p.times.NetworkWait / 20)
195+ var err error
196+ t, cookie, err = p.doRequestWakeup(p.times.NetworkWait / 20)
197+ if err != nil {
198+ // Make sure we break a potential deadlock by trying again.
199+ filteredWakeUpCh <- true
200+ }
201 }
202 }
203 }
204@@ -281,8 +280,6 @@
205 if lockCookie != "" {
206 if err := p.powerd.ClearWakelock(lockCookie); err != nil {
207 p.log.Errorf("ClearWakelock(%#v) got %v", lockCookie, err)
208- } else {
209- p.log.Debugf("cleared wakelock cookie %s.", lockCookie)
210 }
211 lockCookie = ""
212 }
213
214=== modified file 'poller/poller_test.go'
215--- poller/poller_test.go 2015-09-28 08:24:51 +0000
216+++ poller/poller_test.go 2015-10-07 12:15:39 +0000
217@@ -21,7 +21,6 @@
218
219 . "launchpad.net/gocheck"
220
221- "launchpad.net/ubuntu-push/bus/networkmanager"
222 "launchpad.net/ubuntu-push/client/session"
223 helpers "launchpad.net/ubuntu-push/testing"
224 )
225@@ -91,11 +90,6 @@
226 s.myd = &myD{}
227 }
228
229-const (
230- connectedGlobal = networkmanager.ConnectedGlobal
231- disconnectedGlobal = networkmanager.Disconnected
232-)
233-
234 func (s *PrSuite) TestStep(c *C) {
235 p := &poller{
236 times: Times{},
237@@ -106,6 +100,7 @@
238 requestWakeupCh: make(chan struct{}),
239 requestedWakeupErrCh: make(chan error),
240 holdsWakeLockCh: make(chan bool),
241+ connCh: make(chan bool),
242 }
243 s.myd.reqLockCookie = "wakelock cookie"
244 s.myd.stateState = session.Running
245@@ -117,7 +112,7 @@
246 ch := make(chan string)
247 // now, run
248 filteredWakeUpCh := make(chan bool)
249- go p.control(wakeupCh, filteredWakeUpCh, connectedGlobal, nil)
250+ go p.control(wakeupCh, filteredWakeUpCh)
251 go func() { ch <- p.step(filteredWakeUpCh, doneCh, "old cookie") }()
252 select {
253 case s := <-ch:
254@@ -139,14 +134,15 @@
255 requestWakeupCh: make(chan struct{}),
256 requestedWakeupErrCh: make(chan error),
257 holdsWakeLockCh: make(chan bool),
258+ connCh: make(chan bool),
259 }
260 wakeUpCh := make(chan bool)
261 filteredWakeUpCh := make(chan bool)
262 s.myd.watchWakeCh = make(chan bool, 1)
263- nmStateCh := make(chan networkmanager.State)
264- go p.control(wakeUpCh, filteredWakeUpCh, connectedGlobal, nmStateCh)
265+ go p.control(wakeUpCh, filteredWakeUpCh)
266
267 // works
268+ p.HasConnectivity(true)
269 err := p.requestWakeup()
270 c.Assert(err, IsNil)
271 c.Check(<-s.myd.watchWakeCh, Equals, true)
272@@ -160,17 +156,17 @@
273 wakeUpCh <- true
274 <-filteredWakeUpCh
275
276- nmStateCh <- disconnectedGlobal
277+ p.HasConnectivity(false)
278 err = p.requestWakeup()
279 c.Assert(err, IsNil)
280 c.Check(s.myd.watchWakeCh, HasLen, 0)
281
282 // connected
283- nmStateCh <- connectedGlobal
284+ p.HasConnectivity(true)
285 c.Check(<-s.myd.watchWakeCh, Equals, true)
286
287 // disconnected
288- nmStateCh <- disconnectedGlobal
289+ p.HasConnectivity(false)
290 // pending wakeup was cleared
291 c.Check(<-s.myd.watchWakeCh, Equals, false)
292

Subscribers

People subscribed via source and target branches