@@ -97,6 +97,9 @@ const (
9797// startTask is used to check whether an op is already going on.
9898// If rollup is going on, we cancel and wait for rollup to complete
9999// before we return. If the same task is already going, we return error.
100+ // You should only call Done() on the returned closer. Calling other
101+ // functions (such as SignalAndWait) for closer could result in panics.
102+ // For more details, see GitHub issue #5034.
100103func (n * node ) startTask (id op ) (* y.Closer , error ) {
101104 n .opsLock .Lock ()
102105 defer n .opsLock .Unlock ()
@@ -126,6 +129,8 @@ func (n *node) startTask(id op) (*y.Closer, error) {
126129 case opSnapshot , opIndexing :
127130 for otherId , otherCloser := range n .ops {
128131 if otherId == opRollup {
132+ // We set to nil so that stopAllTasks doesn't call SignalAndWait again.
133+ n .ops [opRollup ] = nil
129134 otherCloser .SignalAndWait ()
130135 } else {
131136 return nil , errors .Errorf ("operation %s is already running" , otherId )
@@ -159,14 +164,12 @@ func (n *node) stopAllTasks() {
159164 defer n .closer .Done () // CLOSER:1
160165 <- n .closer .HasBeenClosed ()
161166
162- var closers []* y.Closer
163167 n .opsLock .Lock ()
168+ defer n .opsLock .Unlock ()
164169 for _ , closer := range n .ops {
165- closers = append (closers , closer )
166- }
167- n .opsLock .Unlock ()
168-
169- for _ , closer := range closers {
170+ if closer == nil {
171+ continue
172+ }
170173 closer .SignalAndWait ()
171174 }
172175 glog .Infof ("Stopped all ongoing registered tasks." )
0 commit comments