generated from ipfs/ipfs-repository-template
-
Notifications
You must be signed in to change notification settings - Fork 95
/
blockpresencemanager.go
121 lines (101 loc) · 2.87 KB
/
blockpresencemanager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package blockpresencemanager
import (
"sync"
cid "github.com/ipfs/go-cid"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// BlockPresenceManager keeps track of which peers have indicated that they
// have or explicitly don't have a block
type BlockPresenceManager struct {
sync.RWMutex
presence map[cid.Cid]map[peer.ID]bool
}
func New() *BlockPresenceManager {
return &BlockPresenceManager{
presence: make(map[cid.Cid]map[peer.ID]bool),
}
}
// ReceiveFrom is called when a peer sends us information about which blocks
// it has and does not have
func (bpm *BlockPresenceManager) ReceiveFrom(p peer.ID, haves []cid.Cid, dontHaves []cid.Cid) {
bpm.Lock()
defer bpm.Unlock()
for _, c := range haves {
bpm.updateBlockPresence(p, c, true)
}
for _, c := range dontHaves {
bpm.updateBlockPresence(p, c, false)
}
}
func (bpm *BlockPresenceManager) updateBlockPresence(p peer.ID, c cid.Cid, present bool) {
_, ok := bpm.presence[c]
if !ok {
bpm.presence[c] = make(map[peer.ID]bool)
}
// Make sure not to change HAVE to DONT_HAVE
has, pok := bpm.presence[c][p]
if pok && has {
return
}
bpm.presence[c][p] = present
}
// PeerHasBlock indicates whether the given peer has sent a HAVE for the given
// cid
func (bpm *BlockPresenceManager) PeerHasBlock(p peer.ID, c cid.Cid) bool {
bpm.RLock()
defer bpm.RUnlock()
return bpm.presence[c][p]
}
// PeerDoesNotHaveBlock indicates whether the given peer has sent a DONT_HAVE
// for the given cid
func (bpm *BlockPresenceManager) PeerDoesNotHaveBlock(p peer.ID, c cid.Cid) bool {
bpm.RLock()
defer bpm.RUnlock()
have, known := bpm.presence[c][p]
return known && !have
}
// Filters the keys such that all the given peers have received a DONT_HAVE
// for a key.
// This allows us to know if we've exhausted all possibilities of finding
// the key with the peers we know about.
func (bpm *BlockPresenceManager) AllPeersDoNotHaveBlock(peers []peer.ID, ks []cid.Cid) []cid.Cid {
bpm.RLock()
defer bpm.RUnlock()
var res []cid.Cid
for _, c := range ks {
if bpm.allDontHave(peers, c) {
res = append(res, c)
}
}
return res
}
func (bpm *BlockPresenceManager) allDontHave(peers []peer.ID, c cid.Cid) bool {
// Check if we know anything about the cid's block presence
ps, cok := bpm.presence[c]
if !cok {
return false
}
// Check if we explicitly know that all the given peers do not have the cid
for _, p := range peers {
if has, pok := ps[p]; !pok || has {
return false
}
}
return true
}
// RemoveKeys cleans up the given keys from the block presence map
func (bpm *BlockPresenceManager) RemoveKeys(ks []cid.Cid) {
bpm.Lock()
defer bpm.Unlock()
for _, c := range ks {
delete(bpm.presence, c)
}
}
// HasKey indicates whether the BlockPresenceManager is tracking the given key
// (used by the tests)
func (bpm *BlockPresenceManager) HasKey(c cid.Cid) bool {
bpm.Lock()
defer bpm.Unlock()
_, ok := bpm.presence[c]
return ok
}