Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit 4d5134c

Browse files
committed
refactor(general): extract components to packages
Extract session manager from bitswap Extract session manager & want manager to package Move want manager message queue to seperate file Move Message Queue to subpackage Respond to PR Comments
1 parent c5b071d commit 4d5134c

File tree

7 files changed

+535
-446
lines changed

7 files changed

+535
-446
lines changed

bitswap.go

+13-26
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package bitswap
55
import (
66
"context"
77
"errors"
8-
"math"
98
"sync"
109
"sync/atomic"
1110
"time"
@@ -14,6 +13,8 @@ import (
1413
bsmsg "github.com/ipfs/go-bitswap/message"
1514
bsnet "github.com/ipfs/go-bitswap/network"
1615
notifications "github.com/ipfs/go-bitswap/notifications"
16+
bssm "github.com/ipfs/go-bitswap/sessionmanager"
17+
bswm "github.com/ipfs/go-bitswap/wantmanager"
1718

1819
blocks "github.com/ipfs/go-block-format"
1920
cid "github.com/ipfs/go-cid"
@@ -42,8 +43,6 @@ const (
4243
providerRequestTimeout = time.Second * 10
4344
provideTimeout = time.Second * 15
4445
sizeBatchRequestChan = 32
45-
// kMaxPriority is the max priority as defined by the bitswap protocol
46-
kMaxPriority = math.MaxInt32
4746
)
4847

4948
var (
@@ -101,7 +100,8 @@ func New(parent context.Context, network bsnet.BitSwapNetwork,
101100
process: px,
102101
newBlocks: make(chan cid.Cid, HasBlockBufferSize),
103102
provideKeys: make(chan cid.Cid, provideKeysBufferSize),
104-
wm: NewWantManager(ctx, network),
103+
wm: bswm.New(ctx, network),
104+
sm: bssm.New(),
105105
counters: new(counters),
106106

107107
dupMetric: dupHist,
@@ -128,7 +128,7 @@ func New(parent context.Context, network bsnet.BitSwapNetwork,
128128
type Bitswap struct {
129129
// the peermanager manages sending messages to peers in a way that
130130
// wont block bitswap operation
131-
wm *WantManager
131+
wm *bswm.WantManager
132132

133133
// the engine is the bit of logic that decides who to send which blocks to
134134
engine *decision.Engine
@@ -163,12 +163,8 @@ type Bitswap struct {
163163
dupMetric metrics.Histogram
164164
allMetric metrics.Histogram
165165

166-
// Sessions
167-
sessions []*Session
168-
sessLk sync.Mutex
169-
170-
sessID uint64
171-
sessIDLk sync.Mutex
166+
// the sessionmanager manages tracking sessions
167+
sm *bssm.SessionManager
172168
}
173169

174170
type counters struct {
@@ -229,7 +225,7 @@ func (bs *Bitswap) GetBlocks(ctx context.Context, keys []cid.Cid) (<-chan blocks
229225
log.Event(ctx, "Bitswap.GetBlockRequest.Start", k)
230226
}
231227

232-
mses := bs.getNextSessionID()
228+
mses := bs.sm.GetNextSessionID()
233229

234230
bs.wm.WantBlocks(ctx, keys, nil, mses)
235231

@@ -294,13 +290,6 @@ func (bs *Bitswap) GetBlocks(ctx context.Context, keys []cid.Cid) (<-chan blocks
294290
return out, nil
295291
}
296292

297-
func (bs *Bitswap) getNextSessionID() uint64 {
298-
bs.sessIDLk.Lock()
299-
defer bs.sessIDLk.Unlock()
300-
bs.sessID++
301-
return bs.sessID
302-
}
303-
304293
// CancelWant removes a given key from the wantlist
305294
func (bs *Bitswap) CancelWants(cids []cid.Cid, ses uint64) {
306295
if len(cids) == 0 {
@@ -359,15 +348,13 @@ func (bs *Bitswap) receiveBlockFrom(blk blocks.Block, from peer.ID) error {
359348

360349
// SessionsForBlock returns a slice of all sessions that may be interested in the given cid
361350
func (bs *Bitswap) SessionsForBlock(c cid.Cid) []*Session {
362-
bs.sessLk.Lock()
363-
defer bs.sessLk.Unlock()
364-
365351
var out []*Session
366-
for _, s := range bs.sessions {
352+
bs.sm.IterateSessions(func(session exchange.Fetcher) {
353+
s := session.(*Session)
367354
if s.interestedIn(c) {
368355
out = append(out, s)
369356
}
370-
}
357+
})
371358
return out
372359
}
373360

@@ -398,7 +385,7 @@ func (bs *Bitswap) ReceiveMessage(ctx context.Context, p peer.ID, incoming bsmsg
398385
log.Debugf("got block %s from %s", b, p)
399386

400387
// skip received blocks that are not in the wantlist
401-
if _, contains := bs.wm.wl.Contains(b.Cid()); !contains {
388+
if !bs.wm.IsWanted(b.Cid()) {
402389
return
403390
}
404391

@@ -461,7 +448,7 @@ func (bs *Bitswap) Close() error {
461448
}
462449

463450
func (bs *Bitswap) GetWantlist() []cid.Cid {
464-
entries := bs.wm.wl.Entries()
451+
entries := bs.wm.CurrentWants()
465452
out := make([]cid.Cid, 0, len(entries))
466453
for _, e := range entries {
467454
out = append(out, e.Cid)

messagequeue/messagequeue.go

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package messagequeue
2+
3+
import (
4+
"context"
5+
"sync"
6+
"time"
7+
8+
bsmsg "github.com/ipfs/go-bitswap/message"
9+
bsnet "github.com/ipfs/go-bitswap/network"
10+
wantlist "github.com/ipfs/go-bitswap/wantlist"
11+
logging "github.com/ipfs/go-log"
12+
peer "github.com/libp2p/go-libp2p-peer"
13+
)
14+
15+
var log = logging.Logger("bitswap")
16+
17+
type MessageQueue struct {
18+
p peer.ID
19+
20+
outlk sync.Mutex
21+
out bsmsg.BitSwapMessage
22+
network bsnet.BitSwapNetwork
23+
wl *wantlist.ThreadSafe
24+
25+
sender bsnet.MessageSender
26+
27+
refcnt int
28+
29+
work chan struct{}
30+
done chan struct{}
31+
}
32+
33+
func New(p peer.ID, network bsnet.BitSwapNetwork) *MessageQueue {
34+
return &MessageQueue{
35+
done: make(chan struct{}),
36+
work: make(chan struct{}, 1),
37+
wl: wantlist.NewThreadSafe(),
38+
network: network,
39+
p: p,
40+
refcnt: 1,
41+
}
42+
}
43+
44+
func (mq *MessageQueue) RefIncrement() {
45+
mq.refcnt++
46+
}
47+
48+
func (mq *MessageQueue) RefDecrement() bool {
49+
mq.refcnt--
50+
return mq.refcnt > 0
51+
}
52+
53+
func (mq *MessageQueue) AddMessage(entries []*bsmsg.Entry, ses uint64) {
54+
var work bool
55+
mq.outlk.Lock()
56+
defer func() {
57+
mq.outlk.Unlock()
58+
if !work {
59+
return
60+
}
61+
select {
62+
case mq.work <- struct{}{}:
63+
default:
64+
}
65+
}()
66+
67+
// if we have no message held allocate a new one
68+
if mq.out == nil {
69+
mq.out = bsmsg.New(false)
70+
}
71+
72+
// TODO: add a msg.Combine(...) method
73+
// otherwise, combine the one we are holding with the
74+
// one passed in
75+
for _, e := range entries {
76+
if e.Cancel {
77+
if mq.wl.Remove(e.Cid, ses) {
78+
work = true
79+
mq.out.Cancel(e.Cid)
80+
}
81+
} else {
82+
if mq.wl.Add(e.Cid, e.Priority, ses) {
83+
work = true
84+
mq.out.AddEntry(e.Cid, e.Priority)
85+
}
86+
}
87+
}
88+
}
89+
90+
func (mq *MessageQueue) Startup(ctx context.Context, initialEntries []*wantlist.Entry) {
91+
92+
// new peer, we will want to give them our full wantlist
93+
fullwantlist := bsmsg.New(true)
94+
for _, e := range initialEntries {
95+
for k := range e.SesTrk {
96+
mq.wl.AddEntry(e, k)
97+
}
98+
fullwantlist.AddEntry(e.Cid, e.Priority)
99+
}
100+
mq.out = fullwantlist
101+
mq.work <- struct{}{}
102+
103+
go mq.runQueue(ctx)
104+
}
105+
106+
func (mq *MessageQueue) Shutdown() {
107+
close(mq.done)
108+
}
109+
func (mq *MessageQueue) runQueue(ctx context.Context) {
110+
for {
111+
select {
112+
case <-mq.work: // there is work to be done
113+
mq.doWork(ctx)
114+
case <-mq.done:
115+
if mq.sender != nil {
116+
mq.sender.Close()
117+
}
118+
return
119+
case <-ctx.Done():
120+
if mq.sender != nil {
121+
mq.sender.Reset()
122+
}
123+
return
124+
}
125+
}
126+
}
127+
128+
func (mq *MessageQueue) doWork(ctx context.Context) {
129+
// grab outgoing message
130+
mq.outlk.Lock()
131+
wlm := mq.out
132+
if wlm == nil || wlm.Empty() {
133+
mq.outlk.Unlock()
134+
return
135+
}
136+
mq.out = nil
137+
mq.outlk.Unlock()
138+
139+
// NB: only open a stream if we actually have data to send
140+
if mq.sender == nil {
141+
err := mq.openSender(ctx)
142+
if err != nil {
143+
log.Infof("cant open message sender to peer %s: %s", mq.p, err)
144+
// TODO: cant connect, what now?
145+
return
146+
}
147+
}
148+
149+
// send wantlist updates
150+
for { // try to send this message until we fail.
151+
err := mq.sender.SendMsg(ctx, wlm)
152+
if err == nil {
153+
return
154+
}
155+
156+
log.Infof("bitswap send error: %s", err)
157+
mq.sender.Reset()
158+
mq.sender = nil
159+
160+
select {
161+
case <-mq.done:
162+
return
163+
case <-ctx.Done():
164+
return
165+
case <-time.After(time.Millisecond * 100):
166+
// wait 100ms in case disconnect notifications are still propogating
167+
log.Warning("SendMsg errored but neither 'done' nor context.Done() were set")
168+
}
169+
170+
err = mq.openSender(ctx)
171+
if err != nil {
172+
log.Infof("couldnt open sender again after SendMsg(%s) failed: %s", mq.p, err)
173+
// TODO(why): what do we do now?
174+
// I think the *right* answer is to probably put the message we're
175+
// trying to send back, and then return to waiting for new work or
176+
// a disconnect.
177+
return
178+
}
179+
180+
// TODO: Is this the same instance for the remote peer?
181+
// If its not, we should resend our entire wantlist to them
182+
/*
183+
if mq.sender.InstanceID() != mq.lastSeenInstanceID {
184+
wlm = mq.getFullWantlistMessage()
185+
}
186+
*/
187+
}
188+
}
189+
190+
func (mq *MessageQueue) openSender(ctx context.Context) error {
191+
// allow ten minutes for connections this includes looking them up in the
192+
// dht dialing them, and handshaking
193+
conctx, cancel := context.WithTimeout(ctx, time.Minute*10)
194+
defer cancel()
195+
196+
err := mq.network.ConnectTo(conctx, mq.p)
197+
if err != nil {
198+
return err
199+
}
200+
201+
nsender, err := mq.network.NewMessageSender(ctx, mq.p)
202+
if err != nil {
203+
return err
204+
}
205+
206+
mq.sender = nsender
207+
return nil
208+
}

session.go

+3-14
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,15 @@ func (bs *Bitswap) NewSession(ctx context.Context) exchange.Fetcher {
6666
notif: notifications.New(),
6767
uuid: loggables.Uuid("GetBlockRequest"),
6868
baseTickDelay: time.Millisecond * 500,
69-
id: bs.getNextSessionID(),
69+
id: bs.sm.GetNextSessionID(),
7070
}
7171

7272
s.tag = fmt.Sprint("bs-ses-", s.id)
7373

7474
cache, _ := lru.New(2048)
7575
s.interest = cache
7676

77-
bs.sessLk.Lock()
78-
bs.sessions = append(bs.sessions, s)
79-
bs.sessLk.Unlock()
80-
77+
bs.sm.AddSession(s)
8178
go s.run(ctx)
8279

8380
return s
@@ -92,15 +89,7 @@ func (bs *Bitswap) removeSession(s *Session) {
9289
}
9390
bs.CancelWants(live, s.id)
9491

95-
bs.sessLk.Lock()
96-
defer bs.sessLk.Unlock()
97-
for i := 0; i < len(bs.sessions); i++ {
98-
if bs.sessions[i] == s {
99-
bs.sessions[i] = bs.sessions[len(bs.sessions)-1]
100-
bs.sessions = bs.sessions[:len(bs.sessions)-1]
101-
return
102-
}
103-
}
92+
bs.sm.RemoveSession(s)
10493
}
10594

10695
type blkRecv struct {

0 commit comments

Comments
 (0)