@@ -2,7 +2,6 @@ package messagequeue
2
2
3
3
import (
4
4
"context"
5
- "sync"
6
5
"time"
7
6
8
7
bsmsg "github.com/ipfs/go-bitswap/message"
@@ -23,86 +22,99 @@ type MessageNetwork interface {
23
22
NewMessageSender (context.Context , peer.ID ) (bsnet.MessageSender , error )
24
23
}
25
24
25
+ type request interface {
26
+ handle (mq * MessageQueue )
27
+ }
28
+
26
29
// MessageQueue implements queue of want messages to send to peers.
27
30
type MessageQueue struct {
28
- p peer.ID
29
-
30
- outlk sync.Mutex
31
- out bsmsg.BitSwapMessage
31
+ ctx context.Context
32
+ p peer.ID
32
33
network MessageNetwork
33
- wl * wantlist.ThreadSafe
34
34
35
- sender bsnet.MessageSender
35
+ newRequests chan request
36
+ outgoingMessages chan bsmsg.BitSwapMessage
37
+ done chan struct {}
38
+
39
+ // do not touch out of run loop
40
+ wl * wantlist.SessionTrackedWantlist
41
+ nextMessage bsmsg.BitSwapMessage
42
+ sender bsnet.MessageSender
43
+ }
44
+
45
+ type messageRequest struct {
46
+ entries []* bsmsg.Entry
47
+ ses uint64
48
+ }
36
49
37
- work chan struct {}
38
- done chan struct {}
50
+ type wantlistRequest struct {
51
+ wl * wantlist. SessionTrackedWantlist
39
52
}
40
53
41
54
// New creats a new MessageQueue.
42
- func New (p peer.ID , network MessageNetwork ) * MessageQueue {
55
+ func New (ctx context. Context , p peer.ID , network MessageNetwork ) * MessageQueue {
43
56
return & MessageQueue {
44
- done : make (chan struct {}),
45
- work : make (chan struct {}, 1 ),
46
- wl : wantlist .NewThreadSafe (),
47
- network : network ,
48
- p : p ,
57
+ ctx : ctx ,
58
+ wl : wantlist .NewSessionTrackedWantlist (),
59
+ network : network ,
60
+ p : p ,
61
+ newRequests : make (chan request , 16 ),
62
+ outgoingMessages : make (chan bsmsg.BitSwapMessage ),
63
+ done : make (chan struct {}),
49
64
}
50
65
}
51
66
52
67
// AddMessage adds new entries to an outgoing message for a given session.
53
68
func (mq * MessageQueue ) AddMessage (entries []* bsmsg.Entry , ses uint64 ) {
54
- if ! mq .addEntries (entries , ses ) {
55
- return
56
- }
57
69
select {
58
- case mq .work <- struct {}{ }:
59
- default :
70
+ case mq .newRequests <- & messageRequest { entries , ses }:
71
+ case <- mq . ctx . Done () :
60
72
}
61
73
}
62
74
63
75
// AddWantlist adds a complete session tracked want list to a message queue
64
- func (mq * MessageQueue ) AddWantlist (initialEntries []* wantlist.Entry ) {
65
- if len (initialEntries ) > 0 {
66
- if mq .out == nil {
67
- mq .out = bsmsg .New (false )
68
- }
76
+ func (mq * MessageQueue ) AddWantlist (initialWants * wantlist.SessionTrackedWantlist ) {
77
+ wl := wantlist .NewSessionTrackedWantlist ()
78
+ initialWants .CopyWants (wl )
69
79
70
- for _ , e := range initialEntries {
71
- for k := range e .SesTrk {
72
- mq .wl .AddEntry (e , k )
73
- }
74
- mq .out .AddEntry (e .Cid , e .Priority )
75
- }
76
-
77
- select {
78
- case mq .work <- struct {}{}:
79
- default :
80
- }
80
+ select {
81
+ case mq .newRequests <- & wantlistRequest {wl }:
82
+ case <- mq .ctx .Done ():
81
83
}
82
84
}
83
85
84
86
// Startup starts the processing of messages, and creates an initial message
85
87
// based on the given initial wantlist.
86
- func (mq * MessageQueue ) Startup (ctx context.Context ) {
87
- go mq .runQueue (ctx )
88
+ func (mq * MessageQueue ) Startup () {
89
+ go mq .runQueue ()
90
+ go mq .sendMessages ()
88
91
}
89
92
90
93
// Shutdown stops the processing of messages for a message queue.
91
94
func (mq * MessageQueue ) Shutdown () {
92
95
close (mq .done )
93
96
}
94
97
95
- func (mq * MessageQueue ) runQueue (ctx context.Context ) {
98
+ func (mq * MessageQueue ) runQueue () {
99
+ outgoingMessages := func () chan bsmsg.BitSwapMessage {
100
+ if mq .nextMessage == nil {
101
+ return nil
102
+ }
103
+ return mq .outgoingMessages
104
+ }
105
+
96
106
for {
97
107
select {
98
- case <- mq .work : // there is work to be done
99
- mq .doWork (ctx )
108
+ case newRequest := <- mq .newRequests :
109
+ newRequest .handle (mq )
110
+ case outgoingMessages () <- mq .nextMessage :
111
+ mq .nextMessage = nil
100
112
case <- mq .done :
101
113
if mq .sender != nil {
102
114
mq .sender .Close ()
103
115
}
104
116
return
105
- case <- ctx .Done ():
117
+ case <- mq . ctx .Done ():
106
118
if mq .sender != nil {
107
119
mq .sender .Reset ()
108
120
}
@@ -111,72 +123,86 @@ func (mq *MessageQueue) runQueue(ctx context.Context) {
111
123
}
112
124
}
113
125
114
- func (mq * MessageQueue ) addEntries (entries []* bsmsg.Entry , ses uint64 ) bool {
115
- var work bool
116
- mq .outlk .Lock ()
117
- defer mq .outlk .Unlock ()
118
- // if we have no message held allocate a new one
119
- if mq .out == nil {
120
- mq .out = bsmsg .New (false )
126
+ func (mr * messageRequest ) handle (mq * MessageQueue ) {
127
+ mq .addEntries (mr .entries , mr .ses )
128
+ }
129
+
130
+ func (wr * wantlistRequest ) handle (mq * MessageQueue ) {
131
+ initialWants := wr .wl
132
+ initialWants .CopyWants (mq .wl )
133
+ if initialWants .Len () > 0 {
134
+ if mq .nextMessage == nil {
135
+ mq .nextMessage = bsmsg .New (false )
136
+ }
137
+ for _ , e := range initialWants .Entries () {
138
+ mq .nextMessage .AddEntry (e .Cid , e .Priority )
139
+ }
121
140
}
141
+ }
122
142
123
- // TODO: add a msg.Combine(...) method
124
- // otherwise, combine the one we are holding with the
125
- // one passed in
143
+ func (mq * MessageQueue ) addEntries (entries []* bsmsg.Entry , ses uint64 ) {
126
144
for _ , e := range entries {
127
145
if e .Cancel {
128
146
if mq .wl .Remove (e .Cid , ses ) {
129
- work = true
130
- mq .out .Cancel (e .Cid )
147
+ if mq .nextMessage == nil {
148
+ mq .nextMessage = bsmsg .New (false )
149
+ }
150
+ mq .nextMessage .Cancel (e .Cid )
131
151
}
132
152
} else {
133
153
if mq .wl .Add (e .Cid , e .Priority , ses ) {
134
- work = true
135
- mq .out .AddEntry (e .Cid , e .Priority )
154
+ if mq .nextMessage == nil {
155
+ mq .nextMessage = bsmsg .New (false )
156
+ }
157
+ mq .nextMessage .AddEntry (e .Cid , e .Priority )
136
158
}
137
159
}
138
160
}
139
-
140
- return work
141
161
}
142
162
143
- func (mq * MessageQueue ) doWork (ctx context.Context ) {
144
-
145
- wlm := mq .extractOutgoingMessage ()
146
- if wlm == nil || wlm .Empty () {
147
- return
163
+ func (mq * MessageQueue ) sendMessages () {
164
+ for {
165
+ select {
166
+ case nextMessage := <- mq .outgoingMessages :
167
+ mq .sendMessage (nextMessage )
168
+ case <- mq .done :
169
+ return
170
+ case <- mq .ctx .Done ():
171
+ return
172
+ }
148
173
}
174
+ }
175
+
176
+ func (mq * MessageQueue ) sendMessage (message bsmsg.BitSwapMessage ) {
149
177
150
- // NB: only open a stream if we actually have data to send
151
- err := mq .initializeSender (ctx )
178
+ err := mq .initializeSender ()
152
179
if err != nil {
153
180
log .Infof ("cant open message sender to peer %s: %s" , mq .p , err )
154
181
// TODO: cant connect, what now?
155
182
return
156
183
}
157
184
158
- // send wantlist updates
159
185
for i := 0 ; i < maxRetries ; i ++ { // try to send this message until we fail.
160
- if mq .attemptSendAndRecovery (ctx , wlm ) {
186
+ if mq .attemptSendAndRecovery (message ) {
161
187
return
162
188
}
163
189
}
164
190
}
165
191
166
- func (mq * MessageQueue ) initializeSender (ctx context. Context ) error {
192
+ func (mq * MessageQueue ) initializeSender () error {
167
193
if mq .sender != nil {
168
194
return nil
169
195
}
170
- nsender , err := openSender (ctx , mq .network , mq .p )
196
+ nsender , err := openSender (mq . ctx , mq .network , mq .p )
171
197
if err != nil {
172
198
return err
173
199
}
174
200
mq .sender = nsender
175
201
return nil
176
202
}
177
203
178
- func (mq * MessageQueue ) attemptSendAndRecovery (ctx context. Context , wlm bsmsg.BitSwapMessage ) bool {
179
- err := mq .sender .SendMsg (ctx , wlm )
204
+ func (mq * MessageQueue ) attemptSendAndRecovery (message bsmsg.BitSwapMessage ) bool {
205
+ err := mq .sender .SendMsg (mq . ctx , message )
180
206
if err == nil {
181
207
return true
182
208
}
@@ -188,14 +214,14 @@ func (mq *MessageQueue) attemptSendAndRecovery(ctx context.Context, wlm bsmsg.Bi
188
214
select {
189
215
case <- mq .done :
190
216
return true
191
- case <- ctx .Done ():
217
+ case <- mq . ctx .Done ():
192
218
return true
193
219
case <- time .After (time .Millisecond * 100 ):
194
220
// wait 100ms in case disconnect notifications are still propogating
195
221
log .Warning ("SendMsg errored but neither 'done' nor context.Done() were set" )
196
222
}
197
223
198
- err = mq .initializeSender (ctx )
224
+ err = mq .initializeSender ()
199
225
if err != nil {
200
226
log .Infof ("couldnt open sender again after SendMsg(%s) failed: %s" , mq .p , err )
201
227
// TODO(why): what do we do now?
@@ -215,15 +241,6 @@ func (mq *MessageQueue) attemptSendAndRecovery(ctx context.Context, wlm bsmsg.Bi
215
241
return false
216
242
}
217
243
218
- func (mq * MessageQueue ) extractOutgoingMessage () bsmsg.BitSwapMessage {
219
- // grab outgoing message
220
- mq .outlk .Lock ()
221
- wlm := mq .out
222
- mq .out = nil
223
- mq .outlk .Unlock ()
224
- return wlm
225
- }
226
-
227
244
func openSender (ctx context.Context , network MessageNetwork , p peer.ID ) (bsnet.MessageSender , error ) {
228
245
// allow ten minutes for connections this includes looking them up in the
229
246
// dht dialing them, and handshaking
0 commit comments