@@ -61,7 +61,7 @@ type waitingCh struct {
61
61
// Dialler throttling (e.g. FD limit exceeded) is a concern, as we can easily spin up more workers to compensate, and
62
62
// end up adding fuel to the fire. Since we have no deterministic way to detect this for now, we hard-limit concurrency
63
63
// to DialQueueMaxParallelism.
64
- func newDialQueue (ctx context.Context , target string , in * queue.ChanQueue , dialFn func (context.Context , peer.ID ) error , nConsumers int ) * dialQueue {
64
+ func newDialQueue (ctx context.Context , target string , in * queue.ChanQueue , dialFn func (context.Context , peer.ID ) error ) * dialQueue {
65
65
sq := & dialQueue {
66
66
ctx : ctx ,
67
67
dialFn : dialFn ,
@@ -71,9 +71,9 @@ func newDialQueue(ctx context.Context, target string, in *queue.ChanQueue, dialF
71
71
in : in ,
72
72
out : queue .NewChanQueue (ctx , queue .NewXORDistancePQ (target )),
73
73
74
- growCh : make (chan struct {}, nConsumers ),
74
+ growCh : make (chan struct {}, 1 ),
75
75
shrinkCh : make (chan struct {}, 1 ),
76
- waitingCh : make (chan waitingCh , nConsumers ),
76
+ waitingCh : make (chan waitingCh ),
77
77
dieCh : make (chan struct {}, DialQueueMaxParallelism ),
78
78
}
79
79
for i := 0 ; i < DialQueueMinParallelism ; i ++ {
@@ -85,22 +85,16 @@ func newDialQueue(ctx context.Context, target string, in *queue.ChanQueue, dialF
85
85
86
86
func (dq * dialQueue ) control () {
87
87
var (
88
- p peer.ID
89
- dialled = dq .out .DeqChan
90
- resp waitingCh
91
- waiting <- chan waitingCh
88
+ dialled <- chan peer.ID
89
+ waiting []waitingCh
92
90
lastScalingEvt = time .Now ()
93
91
)
94
92
95
93
defer func () {
96
- // close channels.
97
- if resp .ch != nil {
98
- close (resp .ch )
99
- }
100
- close (dq .waitingCh )
101
- for w := range dq .waitingCh {
94
+ for _ , w := range waiting {
102
95
close (w .ch )
103
96
}
97
+ waiting = nil
104
98
}()
105
99
106
100
for {
@@ -109,16 +103,23 @@ func (dq *dialQueue) control() {
109
103
select {
110
104
case <- dq .ctx .Done ():
111
105
return
112
- case p = <- dialled :
113
- dialled , waiting = nil , dq .waitingCh
106
+ case w := <- dq .waitingCh :
107
+ waiting = append (waiting , w )
108
+ dialled = dq .out .DeqChan
114
109
continue // onto the top.
115
- case resp = <- waiting :
116
- // got a channel that's waiting for a peer.
117
- log .Debugf ("delivering dialled peer to DHT; took %dms." , time .Now ().Sub (resp .ts )/ time .Millisecond )
118
- resp .ch <- p
119
- close (resp .ch )
120
- dialled , waiting = dq .out .DeqChan , nil // stop consuming waiting jobs until we've cleared a peer.
121
- resp .ch = nil
110
+ case p , ok := <- dialled :
111
+ if ! ok {
112
+ return // we're done if the ChanQueue is closed, which happens when the context is closed.
113
+ }
114
+ w := waiting [0 ]
115
+ log .Debugf ("delivering dialled peer to DHT; took %dms." , time .Since (w .ts )/ time .Millisecond )
116
+ w .ch <- p
117
+ close (w .ch )
118
+ waiting = waiting [1 :]
119
+ if len (waiting ) == 0 {
120
+ // no more waiters, so stop consuming dialled jobs.
121
+ dialled = nil
122
+ }
122
123
continue // onto the top.
123
124
default :
124
125
// there's nothing to process, so proceed onto the main select block.
@@ -127,23 +128,30 @@ func (dq *dialQueue) control() {
127
128
select {
128
129
case <- dq .ctx .Done ():
129
130
return
130
- case p = <- dialled :
131
- dialled , waiting = nil , dq .waitingCh
132
- case resp = <- waiting :
133
- // got a channel that's waiting for a peer.
134
- log .Debugf ("delivering dialled peer to DHT; took %dms." , time .Now ().Sub (resp .ts )/ time .Millisecond )
135
- resp .ch <- p
136
- close (resp .ch )
137
- dialled , waiting = dq .out .DeqChan , nil // stop consuming waiting jobs until we've cleared a peer.
138
- resp .ch = nil
131
+ case w := <- dq .waitingCh :
132
+ waiting = append (waiting , w )
133
+ dialled = dq .out .DeqChan
134
+ case p , ok := <- dialled :
135
+ if ! ok {
136
+ return // we're done if the ChanQueue is closed, which happens when the context is closed.
137
+ }
138
+ w := waiting [0 ]
139
+ log .Debugf ("delivering dialled peer to DHT; took %dms." , time .Since (w .ts )/ time .Millisecond )
140
+ w .ch <- p
141
+ close (w .ch )
142
+ waiting = waiting [1 :]
143
+ if len (waiting ) == 0 {
144
+ // no more waiters, so stop consuming dialled jobs.
145
+ dialled = nil
146
+ }
139
147
case <- dq .growCh :
140
- if time .Now (). Sub (lastScalingEvt ) < DialQueueScalingMutePeriod {
148
+ if time .Since (lastScalingEvt ) < DialQueueScalingMutePeriod {
141
149
continue
142
150
}
143
151
dq .grow ()
144
152
lastScalingEvt = time .Now ()
145
153
case <- dq .shrinkCh :
146
- if time .Now (). Sub (lastScalingEvt ) < DialQueueScalingMutePeriod {
154
+ if time .Since (lastScalingEvt ) < DialQueueScalingMutePeriod {
147
155
continue
148
156
}
149
157
dq .shrink ()
@@ -176,13 +184,11 @@ func (dq *dialQueue) Consume() <-chan peer.ID {
176
184
177
185
// park the channel until a dialled peer becomes available.
178
186
select {
187
+ case dq .waitingCh <- waitingCh {ch , time .Now ()}:
188
+ // all good
179
189
case <- dq .ctx .Done ():
180
190
// return a closed channel with no value if we're done.
181
191
close (ch )
182
- return ch
183
- case dq .waitingCh <- waitingCh {ch , time .Now ()}:
184
- default :
185
- panic ("detected more consuming goroutines than declared upfront" )
186
192
}
187
193
return ch
188
194
}
@@ -268,7 +274,7 @@ func (dq *dialQueue) worker() {
268
274
log .Debugf ("discarding dialled peer because of error: %v" , err )
269
275
continue
270
276
}
271
- log .Debugf ("dialling %v took %dms (as observed by the dht subsystem)." , p , time .Now (). Sub (t )/ time .Millisecond )
277
+ log .Debugf ("dialling %v took %dms (as observed by the dht subsystem)." , p , time .Since (t )/ time .Millisecond )
272
278
waiting := len (dq .waitingCh )
273
279
dq .out .EnqChan <- p
274
280
if waiting > 0 {
0 commit comments