Merge lp:~dimitern/juju-core/001-upgrade-charm-filter-restart-watchers into lp:~juju/juju-core/trunk

Proposed by Dimiter Naydenov
Status: Merged
Merged at revision: 922
Proposed branch: lp:~dimitern/juju-core/001-upgrade-charm-filter-restart-watchers
Merge into: lp:~juju/juju-core/trunk
Diff against target: 103 lines (+38/-16)
2 files modified
worker/uniter/filter.go (+33/-16)
worker/uniter/filter_test.go (+5/-0)
To merge this branch: bzr merge lp:~dimitern/juju-core/001-upgrade-charm-filter-restart-watchers
Reviewer Review Type Date Requested Status
The Go Language Gophers Pending
Review via email: mp+149910@code.launchpad.net

Description of the change

uniter: WantAllRelationsEvents() filter

This is the first CL in preparation for the
implementation of upgrade-charm. Here, we'll
prepare the Uniter to handle upgrades better,
by restarting the relations watcher in the
filter, when requested with WantAllRelationsEvents().

https://codereview.appspot.com/7373046/

To post a comment you must log in.
Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Reviewers: mp+149910_code.launchpad.net,

Message:
Please take a look.

Description:
uniter: restart filter relations watcher

This is the first CL in preparation for the
implementation of upgrade-charm. Here, we'll
prepare the Uniter to handle upgrades better,
by restarting the relations watcher in the
filter, when we detect an upgrade.

https://code.launchpad.net/~dimitern/juju-core/001-upgrade-charm-filter-restart-watchers/+merge/149910

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/7373046/

Affected files:
   A [revision details]
   M state/service.go
   M worker/uniter/filter.go

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision:
<email address hidden>

Index: state/service.go
=== modified file 'state/service.go'
--- state/service.go 2013-02-20 13:27:51 +0000
+++ state/service.go 2013-02-21 19:02:04 +0000
@@ -267,6 +267,11 @@
  // SetCharm changes the charm for the service. New units will be started
with
  // this charm, and existing units will be upgraded to use it. If force is
true,
  // units will be upgraded even if they are in an error state.
+//
+// A sanity check is performed:
+// * The new charm must still implement the local endpoints of every
+// relation the service is in, otherwise return an error.
+//
  func (s *Service) SetCharm(ch *Charm, force bool) (err error) {
   ops := []txn.Op{{
    C: s.st.services.Name,

Index: worker/uniter/filter.go
=== modified file 'worker/uniter/filter.go'
--- worker/uniter/filter.go 2013-01-16 17:04:22 +0000
+++ worker/uniter/filter.go 2013-02-21 19:02:04 +0000
@@ -179,7 +179,8 @@
   configw := f.service.WatchConfig()
   defer watcher.Stop(configw, &f.tomb)
   relationsw := f.service.WatchRelations()
- defer watcher.Stop(relationsw, &f.tomb)
+ // relationsw can be recreated when sending upgrades
+ defer func() { watcher.Stop(relationsw, &f.tomb) }()

   // Config events cannot be meaningfully discarded until one is available;
   // once we receive the initial change, we unblock discard requests by
@@ -218,8 +219,11 @@
     discardConfig = f.discardConfig
    case ids, ok := <-relationsw.Changes():
     log.Debugf("filter: got relations change")
- if !ok {
- return watcher.MustErr(relationsw)
+ if !ok && relationsw.Err() == nil {
+ // It was stopped cleanly, so restart it
+ relationsw = f.service.WatchRelations()
+ } else {
+ return relationsw.Err()
     }
     f.relationsChanged(ids)

@@ -228,6 +232,10 @@
     log.Debugf("worker/uniter/filter: sent upgrade event")
     f.upgradeRequested.url = f.upgrade.URL()
     f.outUpgrade = nil
+ // To avoid missing any changes to relations, we need
+ // to restart the watcher after an upgrade is triggered
+ // (it'll get recreated above).
+ relationsw.Stop()
    case f.outResolved <- f.resolved:
     log.Debugf("worker/uniter/filter: sent resolved event")
     f.outResolved = nil

Revision history for this message
Dimiter Naydenov (dimitern) wrote :
Revision history for this message
William Reade (fwereade) wrote :

On reflection, as discussed online, too much magic. I recommend a
WantAllRelationsEvents method for clarity's sake.

https://codereview.appspot.com/7373046/diff/3001/worker/uniter/filter.go
File worker/uniter/filter.go (right):

https://codereview.appspot.com/7373046/diff/3001/worker/uniter/filter.go#newcode226
worker/uniter/filter.go:226: return relationsw.Err()
I think this bit is equivalent to "if ok {return nil}". Don't you need:

if !ok {
   if err := relationsw.Err(); err != nil {
     return err
   }
   relationsw = f.service.WatchRelations()
}

https://codereview.appspot.com/7373046/

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Please take a look.

https://codereview.appspot.com/7373046/diff/3001/worker/uniter/filter.go
File worker/uniter/filter.go (right):

https://codereview.appspot.com/7373046/diff/3001/worker/uniter/filter.go#newcode226
worker/uniter/filter.go:226: return relationsw.Err()
On 2013/02/22 10:25:28, fwereade wrote:
> I think this bit is equivalent to "if ok {return nil}". Don't you
need:

> if !ok {
> if err := relationsw.Err(); err != nil {
> return err
> }
> relationsw = f.service.WatchRelations()
> }

As discussed, changed as it was.

https://codereview.appspot.com/7373046/

Revision history for this message
William Reade (fwereade) wrote :

LGTM, one trivial

https://codereview.appspot.com/7373046/diff/8001/worker/uniter/filter.go
File worker/uniter/filter.go (right):

https://codereview.appspot.com/7373046/diff/8001/worker/uniter/filter.go#newcode144
worker/uniter/filter.go:144: // pending relation changes.
...should send an event for every known relation.

https://codereview.appspot.com/7373046/

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Please take a look.

https://codereview.appspot.com/7373046/diff/8001/worker/uniter/filter.go
File worker/uniter/filter.go (right):

https://codereview.appspot.com/7373046/diff/8001/worker/uniter/filter.go#newcode144
worker/uniter/filter.go:144: // pending relation changes.
On 2013/02/22 11:25:33, fwereade wrote:
> ...should send an event for every known relation.

Done.

https://codereview.appspot.com/7373046/diff/8001/worker/uniter/filter.go#newcode268
worker/uniter/filter.go:268: // restart the relations watcher
On 2013/02/22 11:41:23, TheMue wrote:
> Maybe too pedantic, but like a correct style here: "Restart the
relations
> watcher.". See the "Send events ..." comment above.

Done.

https://codereview.appspot.com/7373046/

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

*** Submitted:

uniter: WantAllRelationsEvents() filter

This is the first CL in preparation for the
implementation of upgrade-charm. Here, we'll
prepare the Uniter to handle upgrades better,
by restarting the relations watcher in the
filter, when requested with WantAllRelationsEvents().

R=fwereade, TheMue
CC=
https://codereview.appspot.com/7373046

https://codereview.appspot.com/7373046/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'worker/uniter/filter.go'
2--- worker/uniter/filter.go 2013-01-16 17:04:22 +0000
3+++ worker/uniter/filter.go 2013-02-22 14:13:22 +0000
4@@ -36,8 +36,9 @@
5
6 // The want* chans are used to indicate that the filter should send
7 // events if it has them available.
8- wantUpgrade chan serviceCharm
9- wantResolved chan struct{}
10+ wantUpgrade chan serviceCharm
11+ wantResolved chan struct{}
12+ wantAllRelations chan struct{}
13
14 // discardConfig is used to indicate that any pending config event
15 // should be discarded.
16@@ -59,19 +60,20 @@
17 // supplied unit.
18 func newFilter(st *state.State, unitName string) (*filter, error) {
19 f := &filter{
20- st: st,
21- outUnitDying: make(chan struct{}),
22- outConfig: make(chan struct{}),
23- outConfigOn: make(chan struct{}),
24- outUpgrade: make(chan *state.Charm),
25- outUpgradeOn: make(chan *state.Charm),
26- outResolved: make(chan state.ResolvedMode),
27- outResolvedOn: make(chan state.ResolvedMode),
28- outRelations: make(chan []int),
29- outRelationsOn: make(chan []int),
30- wantResolved: make(chan struct{}),
31- wantUpgrade: make(chan serviceCharm),
32- discardConfig: make(chan struct{}),
33+ st: st,
34+ outUnitDying: make(chan struct{}),
35+ outConfig: make(chan struct{}),
36+ outConfigOn: make(chan struct{}),
37+ outUpgrade: make(chan *state.Charm),
38+ outUpgradeOn: make(chan *state.Charm),
39+ outResolved: make(chan state.ResolvedMode),
40+ outResolvedOn: make(chan state.ResolvedMode),
41+ outRelations: make(chan []int),
42+ outRelationsOn: make(chan []int),
43+ wantResolved: make(chan struct{}),
44+ wantAllRelations: make(chan struct{}),
45+ wantUpgrade: make(chan serviceCharm),
46+ discardConfig: make(chan struct{}),
47 }
48 go func() {
49 defer f.tomb.Done()
50@@ -138,6 +140,15 @@
51 }
52 }
53
54+// WantAllRelationsEvents indicates that the filter should send an
55+// event for every known relation.
56+func (f *filter) WantAllRelationsEvents() {
57+ select {
58+ case <-f.tomb.Dying():
59+ case f.wantAllRelations <- nothing:
60+ }
61+}
62+
63 // WantResolvedEvent indicates that the filter should send a resolved event
64 // if one is available.
65 func (f *filter) WantResolvedEvent() {
66@@ -179,7 +190,8 @@
67 configw := f.service.WatchConfig()
68 defer watcher.Stop(configw, &f.tomb)
69 relationsw := f.service.WatchRelations()
70- defer watcher.Stop(relationsw, &f.tomb)
71+ // relationsw can get restarted, so we need to bind its current value here
72+ defer func() { watcher.Stop(relationsw, &f.tomb) }()
73
74 // Config events cannot be meaningfully discarded until one is available;
75 // once we receive the initial change, we unblock discard requests by
76@@ -251,6 +263,11 @@
77 if f.resolved != state.ResolvedNone {
78 f.outResolved = f.outResolvedOn
79 }
80+ case <-f.wantAllRelations:
81+ log.Debugf("worker/uniter/filter: want all relations events")
82+ // Restart the relations watcher.
83+ watcher.Stop(relationsw, &f.tomb)
84+ relationsw = f.service.WatchRelations()
85 case <-discardConfig:
86 log.Debugf("filter: discarded config event")
87 f.outConfig = nil
88
89=== modified file 'worker/uniter/filter_test.go'
90--- worker/uniter/filter_test.go 2013-01-25 18:33:16 +0000
91+++ worker/uniter/filter_test.go 2013-02-22 14:13:22 +0000
92@@ -327,6 +327,11 @@
93 assertChange([]int{0, 1})
94 assertNoChange()
95
96+ // Request all relations events; no changes should happen
97+ f.WantAllRelationsEvents()
98+ assertChange([]int{0, 1})
99+ assertNoChange()
100+
101 // Add another relation, and change another's Life (by entering scope before
102 // Destroy, thereby setting the relation to Dying); check event.
103 s.addRelation(c)

Subscribers

People subscribed via source and target branches