p2p/peer: addressbook can now clear addrs
Juan Batiz-Benet committed
Jan 26, 2015 at 12:06 UTC
56d900fa1058a357599236b5434ec83d2019b923
4 files changed
+194
-19
p2p/peer/addr/addrsrcs.go
new
+70
@@ -0,0 +1,70 @@
1
+// Package addr provides utility functions to handle peer addresses.
2
+package addr
3
+
4
+import (
5
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
6
+)
7
+
8
+// AddrSource is a source of addresses. It allows clients to retrieve
9
+// a set of addresses at a last possible moment in time. It is used
10
+// to query a set of addresses that may change over time, as a result
11
+// of the network changing interfaces or mappings.
12
+type Source interface {
13
+ Addrs() []ma.Multiaddr
14
+}
15
+
16
+// CombineSources returns a new AddrSource which is the
17
+// concatenation of all input AddrSources:
18
+//
19
+// combined := CombinedSources(a, b)
20
+// combined.Addrs() // append(a.Addrs(), b.Addrs()...)
21
+//
22
+func CombineSources(srcs ...Source) Source {
23
+ return combinedAS(srcs)
24
+}
25
+
26
+type combinedAS []Source
27
+
28
+func (cas combinedAS) Addrs() []ma.Multiaddr {
29
+ var addrs []ma.Multiaddr
30
+ for _, s := range cas {
31
+ addrs = append(addrs, s.Addrs()...)
32
+ }
33
+ return addrs
34
+}
35
+
36
+// UniqueSource returns a new AddrSource which omits duplicate
37
+// addresses from the inputs:
38
+//
39
+// unique := UniqueSource(a, b)
40
+// unique.Addrs() // append(a.Addrs(), b.Addrs()...)
41
+// // but only adds each addr once.
42
+//
43
+func UniqueSource(srcs ...Source) Source {
44
+ return uniqueAS(srcs)
45
+}
46
+
47
+type uniqueAS []Source
48
+
49
+func (uas uniqueAS) Addrs() []ma.Multiaddr {
50
+ seen := make(map[string]struct{})
51
+ var addrs []ma.Multiaddr
52
+ for _, s := range uas {
53
+ for _, a := range s.Addrs() {
54
+ s := a.String()
55
+ if _, found := seen[s]; !found {
56
+ addrs = append(addrs, a)
57
+ seen[s] = struct{}{}
58
+ }
59
+ }
60
+ }
61
+ return addrs
62
+}
63
+
64
+// Slice is a simple slice of addresses that implements
65
+// the AddrSource interface.
66
+type Slice []ma.Multiaddr
67
+
68
+func (as Slice) Addrs() []ma.Multiaddr {
69
+ return as
70
+}
p2p/peer/addr/addrsrcs_test.go
new
+78
@@ -0,0 +1,78 @@
1
+package addr
2
+
3
+import (
4
+ "fmt"
5
+ "testing"
6
+
7
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8
+)
9
+
10
+func newAddrOrFatal(t *testing.T, s string) ma.Multiaddr {
11
+ a, err := ma.NewMultiaddr(s)
12
+ if err != nil {
13
+ t.Fatal("error parsing multiaddr", err)
14
+ }
15
+ return a
16
+}
17
+
18
+func newAddrs(t *testing.T, n int) []ma.Multiaddr {
19
+ addrs := make([]ma.Multiaddr, n)
20
+ for i := 0; i < n; i++ {
21
+ s := fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i)
22
+ addrs[i] = newAddrOrFatal(t, s)
23
+ }
24
+ return addrs
25
+}
26
+
27
+func addrSetsSame(a, b []ma.Multiaddr) bool {
28
+ if len(a) != len(b) {
29
+ return false
30
+ }
31
+ for i, aa := range a {
32
+ bb := b[i]
33
+ if !aa.Equal(bb) {
34
+ return false
35
+ }
36
+ }
37
+ return true
38
+}
39
+
40
+func addrSourcesSame(a, b Source) bool {
41
+ return addrSetsSame(a.Addrs(), b.Addrs())
42
+}
43
+
44
+func TestAddrCombine(t *testing.T) {
45
+ addrs := newAddrs(t, 30)
46
+ a := Slice(addrs[0:10])
47
+ b := Slice(addrs[10:20])
48
+ c := Slice(addrs[20:30])
49
+ d := CombineSources(a, b, c)
50
+ if !addrSetsSame(addrs, d.Addrs()) {
51
+ t.Error("addrs differ")
52
+ }
53
+ if !addrSourcesSame(Slice(addrs), d) {
54
+ t.Error("addrs differ")
55
+ }
56
+}
57
+
58
+func TestAddrUnique(t *testing.T) {
59
+
60
+ addrs := newAddrs(t, 40)
61
+ a := Slice(addrs[0:20])
62
+ b := Slice(addrs[10:30])
63
+ c := Slice(addrs[20:40])
64
+ d := CombineSources(a, b, c)
65
+ e := UniqueSource(a, b, c)
66
+ if addrSetsSame(addrs, d.Addrs()) {
67
+ t.Error("addrs same")
68
+ }
69
+ if addrSourcesSame(Slice(addrs), d) {
70
+ t.Error("addrs same")
71
+ }
72
+ if !addrSetsSame(addrs, e.Addrs()) {
73
+ t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n")
74
+ }
75
+ if !addrSourcesSame(Slice(addrs), e) {
76
+ t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n")
77
+ }
78
+}
p2p/peer/peerstore.go
+18
-12
@@ -38,9 +38,10 @@ type Peerstore interface {
38
39
// AddressBook tracks the addresses of Peers
40
type AddressBook interface {
41
- Addresses(ID) []ma.Multiaddr
42
- AddAddress(ID, ma.Multiaddr)
43
- AddAddresses(ID, []ma.Multiaddr)
41
+ Addresses(ID) []ma.Multiaddr // returns addresses for ID
42
+ AddAddress(ID, ma.Multiaddr) // Adds given addr for ID
43
+ AddAddresses(ID, []ma.Multiaddr) // Adds given addrs for ID
44
+ SetAddresses(ID, []ma.Multiaddr) // Sets given addrs for ID (clears previously stored)
45
}
46
47
type addressMap map[string]ma.Multiaddr
@@ -81,27 +82,32 @@ func (ab *addressbook) Addresses(p ID) []ma.Multiaddr {
82
}
83
84
func (ab *addressbook) AddAddress(p ID, m ma.Multiaddr) {
85
+ ab.AddAddresses(p, []ma.Multiaddr{m})
86
+}
87
+
88
+func (ab *addressbook) AddAddresses(p ID, ms []ma.Multiaddr) {
89
ab.Lock()
90
defer ab.Unlock()
91
87
- _, found := ab.addrs[p]
92
+ amap, found := ab.addrs[p]
93
if !found {
89
- ab.addrs[p] = addressMap{}
94
+ amap = addressMap{}
95
+ ab.addrs[p] = amap
96
+ }
97
+ for _, m := range ms {
98
+ amap[m.String()] = m
99
}
91
- ab.addrs[p][m.String()] = m
100
}
101
94
-func (ab *addressbook) AddAddresses(p ID, ms []ma.Multiaddr) {
102
+func (ab *addressbook) SetAddresses(p ID, ms []ma.Multiaddr) {
103
ab.Lock()
104
defer ab.Unlock()
105
106
+ amap := addressMap{}
107
for _, m := range ms {
99
- _, found := ab.addrs[p]
100
- if !found {
101
- ab.addrs[p] = addressMap{}
102
- }
103
- ab.addrs[p][m.String()] = m
108
+ amap[m.String()] = m
109
}
110
+ ab.addrs[p] = amap // clear what was there before
111
}
112
113
// KeyBook tracks the Public keys of Peers.
p2p/peer/peerstore_test.go
+28
-7
@@ -29,20 +29,37 @@ func TestAddresses(t *testing.T) {
29
id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
30
id2 := IDS(t, "QmRmPL3FDZKE3Qiwv1RosLdwdvbvg17b2hB39QPScgWKKZ")
31
id3 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ6Kn")
32
+ id4 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Kn")
33
+ id5 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Km")
34
35
ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
34
- ma21 := MA(t, "/ip4/1.2.3.2/tcp/1111")
35
- ma22 := MA(t, "/ip4/1.2.3.2/tcp/2222")
36
- ma31 := MA(t, "/ip4/1.2.3.3/tcp/1111")
37
- ma32 := MA(t, "/ip4/1.2.3.3/tcp/2222")
38
- ma33 := MA(t, "/ip4/1.2.3.3/tcp/3333")
36
+ ma21 := MA(t, "/ip4/2.2.3.2/tcp/1111")
37
+ ma22 := MA(t, "/ip4/2.2.3.2/tcp/2222")
38
+ ma31 := MA(t, "/ip4/3.2.3.3/tcp/1111")
39
+ ma32 := MA(t, "/ip4/3.2.3.3/tcp/2222")
40
+ ma33 := MA(t, "/ip4/3.2.3.3/tcp/3333")
41
+ ma41 := MA(t, "/ip4/4.2.3.3/tcp/1111")
42
+ ma42 := MA(t, "/ip4/4.2.3.3/tcp/2222")
43
+ ma43 := MA(t, "/ip4/4.2.3.3/tcp/3333")
44
+ ma44 := MA(t, "/ip4/4.2.3.3/tcp/4444")
45
+ ma51 := MA(t, "/ip4/5.2.3.3/tcp/1111")
46
+ ma52 := MA(t, "/ip4/5.2.3.3/tcp/2222")
47
+ ma53 := MA(t, "/ip4/5.2.3.3/tcp/3333")
48
+ ma54 := MA(t, "/ip4/5.2.3.3/tcp/4444")
49
+ ma55 := MA(t, "/ip4/5.2.3.3/tcp/5555")
50
51
ps.AddAddress(id1, ma11)
41
- ps.AddAddress(id2, ma21)
42
- ps.AddAddress(id2, ma22)
52
+ ps.AddAddresses(id2, []ma.Multiaddr{ma21, ma22})
53
+ ps.AddAddresses(id2, []ma.Multiaddr{ma21, ma22}) // idempotency
54
ps.AddAddress(id3, ma31)
55
ps.AddAddress(id3, ma32)
56
ps.AddAddress(id3, ma33)
57
+ ps.AddAddress(id3, ma33) // idempotency
58
+ ps.AddAddress(id3, ma33)
59
+ ps.AddAddresses(id4, []ma.Multiaddr{ma41, ma42, ma43, ma44}) // multiple
60
+ ps.AddAddresses(id5, []ma.Multiaddr{ma21, ma22}) // clearing
61
+ ps.AddAddresses(id5, []ma.Multiaddr{ma41, ma42, ma43, ma44}) // clearing
62
+ ps.SetAddresses(id5, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}) // clearing
63
64
test := func(exp, act []ma.Multiaddr) {
65
if len(exp) != len(act) {
@@ -69,9 +86,13 @@ func TestAddresses(t *testing.T) {
86
test([]ma.Multiaddr{ma11}, ps.Addresses(id1))
87
test([]ma.Multiaddr{ma21, ma22}, ps.Addresses(id2))
88
test([]ma.Multiaddr{ma31, ma32, ma33}, ps.Addresses(id3))
89
+ test([]ma.Multiaddr{ma41, ma42, ma43, ma44}, ps.Addresses(id4))
90
+ test([]ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, ps.Addresses(id5))
91
92
// test also the PeerInfo return
93
test([]ma.Multiaddr{ma11}, ps.PeerInfo(id1).Addrs)
94
test([]ma.Multiaddr{ma21, ma22}, ps.PeerInfo(id2).Addrs)
95
test([]ma.Multiaddr{ma31, ma32, ma33}, ps.PeerInfo(id3).Addrs)
96
+ test([]ma.Multiaddr{ma41, ma42, ma43, ma44}, ps.PeerInfo(id4).Addrs)
97
+ test([]ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, ps.PeerInfo(id5).Addrs)
98
}