diff options
Diffstat (limited to 'src/gnunet/service/dht/routingtable.go')
-rw-r--r-- | src/gnunet/service/dht/routingtable.go | 305 |
1 files changed, 200 insertions, 105 deletions
diff --git a/src/gnunet/service/dht/routingtable.go b/src/gnunet/service/dht/routingtable.go index 2933e6a..fe9f956 100644 --- a/src/gnunet/service/dht/routingtable.go +++ b/src/gnunet/service/dht/routingtable.go | |||
@@ -21,10 +21,11 @@ package dht | |||
21 | import ( | 21 | import ( |
22 | "bytes" | 22 | "bytes" |
23 | "context" | 23 | "context" |
24 | "crypto/sha512" | ||
25 | "encoding/hex" | 24 | "encoding/hex" |
25 | "gnunet/config" | ||
26 | "gnunet/crypto" | ||
27 | "gnunet/service/dht/blocks" | ||
26 | "gnunet/util" | 28 | "gnunet/util" |
27 | "math/rand" | ||
28 | "sync" | 29 | "sync" |
29 | "time" | 30 | "time" |
30 | 31 | ||
@@ -32,61 +33,63 @@ import ( | |||
32 | "github.com/bfix/gospel/math" | 33 | "github.com/bfix/gospel/math" |
33 | ) | 34 | ) |
34 | 35 | ||
35 | var ( | 36 | // Routing table constants |
36 | // routing table hash function: defines number of | ||
37 | // buckets and size of peer addresses | ||
38 | rtHash = sha512.New | ||
39 | ) | ||
40 | |||
41 | // Routing table contants (adjust with changing hash function) | ||
42 | const ( | 37 | const ( |
43 | numBuckets = 512 // number of bits of hash function result | 38 | numK = 20 // number of entries per k-bucket |
44 | numK = 20 // number of entries per k-bucket | ||
45 | sizeAddr = 64 // size of peer address in bytes | ||
46 | ) | 39 | ) |
47 | 40 | ||
48 | //====================================================================== | 41 | //====================================================================== |
42 | // Peer address | ||
49 | //====================================================================== | 43 | //====================================================================== |
50 | 44 | ||
51 | // PeerAddress is the identifier for a peer in the DHT network. | 45 | // PeerAddress is the identifier for a peer in the DHT network. |
52 | // It is the SHA-512 hash of the PeerID (public Ed25519 key). | 46 | // It is the SHA-512 hash of the PeerID (public Ed25519 key). |
53 | type PeerAddress struct { | 47 | type PeerAddress struct { |
54 | addr [sizeAddr]byte // hash value as bytes | 48 | Peer *util.PeerID // peer identifier |
55 | connected bool // is peer connected? | 49 | Key *crypto.HashCode // address key is a sha512 hash |
56 | lastSeen util.AbsoluteTime // time the peer was last seen | 50 | lastSeen util.AbsoluteTime // time the peer was last seen |
57 | lastUsed util.AbsoluteTime // time the peer was last used | 51 | lastUsed util.AbsoluteTime // time the peer was last used |
58 | } | 52 | } |
59 | 53 | ||
60 | // NewPeerAddress returns the DHT address of a peer. | 54 | // NewPeerAddress returns the DHT address of a peer. |
61 | func NewPeerAddress(peer *util.PeerID) *PeerAddress { | 55 | func NewPeerAddress(peer *util.PeerID) *PeerAddress { |
62 | r := new(PeerAddress) | 56 | return &PeerAddress{ |
63 | h := rtHash() | 57 | Peer: peer, |
64 | h.Write(peer.Key) | 58 | Key: crypto.Hash(peer.Data), |
65 | copy(r.addr[:], h.Sum(nil)) | 59 | lastSeen: util.AbsoluteTimeNow(), |
66 | r.lastSeen = util.AbsoluteTimeNow() | 60 | lastUsed: util.AbsoluteTimeNow(), |
67 | r.lastUsed = util.AbsoluteTimeNow() | 61 | } |
68 | return r | 62 | } |
63 | |||
64 | // NewQueryAddress returns a wrapped peer address for a query key | ||
65 | func NewQueryAddress(key *crypto.HashCode) *PeerAddress { | ||
66 | return &PeerAddress{ | ||
67 | Peer: nil, | ||
68 | Key: crypto.NewHashCode(key.Bits), | ||
69 | lastSeen: util.AbsoluteTimeNow(), | ||
70 | lastUsed: util.AbsoluteTimeNow(), | ||
71 | } | ||
69 | } | 72 | } |
70 | 73 | ||
71 | // String returns a human-readble representation of an address. | 74 | // String returns a human-readble representation of an address. |
72 | func (addr *PeerAddress) String() string { | 75 | func (addr *PeerAddress) String() string { |
73 | return hex.EncodeToString(addr.addr[:]) | 76 | return hex.EncodeToString(addr.Key.Bits) |
74 | } | 77 | } |
75 | 78 | ||
76 | // Equals returns true if two peer addresses are the same. | 79 | // Equals returns true if two peer addresses are the same. |
77 | func (addr *PeerAddress) Equals(p *PeerAddress) bool { | 80 | func (addr *PeerAddress) Equals(p *PeerAddress) bool { |
78 | return bytes.Equal(addr.addr[:], p.addr[:]) | 81 | return bytes.Equal(addr.Key.Bits, p.Key.Bits) |
79 | } | 82 | } |
80 | 83 | ||
81 | // Distance between two addresses: returns a distance value and a | 84 | // Distance between two addresses: returns a distance value and a |
82 | // bucket index (smaller index = less distant). | 85 | // bucket index (smaller index = less distant). |
83 | func (addr *PeerAddress) Distance(p *PeerAddress) (*math.Int, int) { | 86 | func (addr *PeerAddress) Distance(p *PeerAddress) (*math.Int, int) { |
84 | var d PeerAddress | 87 | d := make([]byte, 64) |
85 | for i := range d.addr { | 88 | for i := range d { |
86 | d.addr[i] = addr.addr[i] ^ p.addr[i] | 89 | d[i] = addr.Key.Bits[i] ^ p.Key.Bits[i] |
87 | } | 90 | } |
88 | r := math.NewIntFromBytes(d.addr[:]) | 91 | r := math.NewIntFromBytes(d) |
89 | return r, numBuckets - r.BitLen() | 92 | return r, 512 - r.BitLen() |
90 | } | 93 | } |
91 | 94 | ||
92 | //====================================================================== | 95 | //====================================================================== |
@@ -98,23 +101,28 @@ func (addr *PeerAddress) Distance(p *PeerAddress) (*math.Int, int) { | |||
98 | // distance to the reference address, so smaller index means | 101 | // distance to the reference address, so smaller index means |
99 | // "nearer" to the reference address. | 102 | // "nearer" to the reference address. |
100 | type RoutingTable struct { | 103 | type RoutingTable struct { |
101 | ref *PeerAddress // reference address for distance | 104 | sync.RWMutex |
102 | buckets []*Bucket // list of buckets | 105 | |
103 | list map[*PeerAddress]struct{} // keep list of peers | 106 | ref *PeerAddress // reference address for distance |
104 | mtx sync.RWMutex // lock for write operations | 107 | buckets []*Bucket // list of buckets |
105 | l2nse float64 // log2 of estimated network size | 108 | list *util.Map[string, *PeerAddress] // keep list of peers |
106 | inProcess bool // flag if Process() is running | 109 | l2nse float64 // log2 of estimated network size |
110 | inProcess bool // flag if Process() is running | ||
111 | cfg *config.RoutingConfig // routing parameters | ||
112 | helloCache *util.Map[string, *blocks.HelloBlock] // HELLO block cache | ||
107 | } | 113 | } |
108 | 114 | ||
109 | // NewRoutingTable creates a new routing table for the reference address. | 115 | // NewRoutingTable creates a new routing table for the reference address. |
110 | func NewRoutingTable(ref *PeerAddress) *RoutingTable { | 116 | func NewRoutingTable(ref *PeerAddress, cfg *config.RoutingConfig) *RoutingTable { |
111 | // create routing table | 117 | // create routing table |
112 | rt := &RoutingTable{ | 118 | rt := &RoutingTable{ |
113 | ref: ref, | 119 | ref: ref, |
114 | list: make(map[*PeerAddress]struct{}), | 120 | list: util.NewMap[string, *PeerAddress](), |
115 | buckets: make([]*Bucket, numBuckets), | 121 | buckets: make([]*Bucket, 512), |
116 | l2nse: 0., | 122 | l2nse: -1, |
117 | inProcess: false, | 123 | inProcess: false, |
124 | cfg: cfg, | ||
125 | helloCache: util.NewMap[string, *blocks.HelloBlock](), | ||
118 | } | 126 | } |
119 | // fill buckets | 127 | // fill buckets |
120 | for i := range rt.buckets { | 128 | for i := range rt.buckets { |
@@ -130,41 +138,69 @@ func NewRoutingTable(ref *PeerAddress) *RoutingTable { | |||
130 | // Add new peer address to routing table. | 138 | // Add new peer address to routing table. |
131 | // Returns true if the entry was added, false otherwise. | 139 | // Returns true if the entry was added, false otherwise. |
132 | func (rt *RoutingTable) Add(p *PeerAddress) bool { | 140 | func (rt *RoutingTable) Add(p *PeerAddress) bool { |
133 | // ensure one write and no readers | 141 | k := p.String() |
134 | rt.lock(false) | 142 | logger.Printf(logger.DBG, "[RT] Add(%s)", k) |
135 | defer rt.unlock(false) | ||
136 | 143 | ||
137 | // check if peer is already known | 144 | // check if peer is already known |
138 | if _, ok := rt.list[p]; ok { | 145 | if px, ok := rt.list.Get(k); ok { |
146 | logger.Println(logger.DBG, "[RT] --> already known") | ||
147 | px.lastSeen = util.AbsoluteTimeNow() | ||
139 | return false | 148 | return false |
140 | } | 149 | } |
141 | 150 | ||
142 | // compute distance (bucket index) and insert address. | 151 | // compute distance (bucket index) and insert address. |
143 | _, idx := p.Distance(rt.ref) | 152 | _, idx := p.Distance(rt.ref) |
144 | if rt.buckets[idx].Add(p) { | 153 | if rt.buckets[idx].Add(p) { |
145 | rt.list[p] = struct{}{} | 154 | logger.Println(logger.DBG, "[RT] --> entry added") |
155 | p.lastUsed = util.AbsoluteTimeNow() | ||
156 | rt.list.Put(k, p) | ||
146 | return true | 157 | return true |
147 | } | 158 | } |
148 | // Full bucket: we did not add the address to the routing table. | 159 | // Full bucket: we did not add the address to the routing table. |
160 | logger.Println(logger.DBG, "[RT] --> bucket full -- discarded") | ||
149 | return false | 161 | return false |
150 | } | 162 | } |
151 | 163 | ||
152 | // Remove peer address from routing table. | 164 | // Remove peer address from routing table. |
153 | // Returns true if the entry was removed, false otherwise. | 165 | // Returns true if the entry was removed, false otherwise. |
154 | func (rt *RoutingTable) Remove(p *PeerAddress) bool { | 166 | func (rt *RoutingTable) Remove(p *PeerAddress) bool { |
155 | // ensure one write and no readers | 167 | k := p.String() |
156 | rt.lock(false) | 168 | logger.Printf(logger.DBG, "[RT] Remove(%s)", k) |
157 | defer rt.unlock(false) | ||
158 | 169 | ||
159 | // compute distance (bucket index) and remove entry from bucket | 170 | // compute distance (bucket index) and remove entry from bucket |
171 | rc := false | ||
160 | _, idx := p.Distance(rt.ref) | 172 | _, idx := p.Distance(rt.ref) |
161 | if rt.buckets[idx].Remove(p) { | 173 | if rt.buckets[idx].Remove(p) { |
162 | delete(rt.list, p) | 174 | logger.Println(logger.DBG, "[RT] --> entry removed from bucket and internal lists") |
163 | return true | 175 | rc = true |
176 | } else { | ||
177 | // remove from internal list | ||
178 | logger.Println(logger.DBG, "[RT] --> entry removed from internal lists only") | ||
164 | } | 179 | } |
165 | // remove from internal list | 180 | rt.list.Delete(k) |
166 | delete(rt.list, p) | 181 | // delete from HELLO cache |
167 | return false | 182 | rt.helloCache.Delete(p.Peer.String()) |
183 | return rc | ||
184 | } | ||
185 | |||
186 | // Contains checks if a peer is available in the routing table | ||
187 | func (rt *RoutingTable) Contains(p *PeerAddress) bool { | ||
188 | k := p.String() | ||
189 | logger.Printf(logger.DBG, "[RT] Contains(%s)?", k) | ||
190 | |||
191 | // check for peer in internal list | ||
192 | px, ok := rt.list.Get(k) | ||
193 | if !ok { | ||
194 | logger.Println(logger.DBG, "[RT] --> NOT found in current list:") | ||
195 | _ = rt.list.ProcessRange(func(key string, val *PeerAddress) error { | ||
196 | logger.Printf(logger.DBG, "[RT] * %s", val) | ||
197 | return nil | ||
198 | }, true) | ||
199 | } else { | ||
200 | logger.Println(logger.DBG, "[RT] --> found in current list") | ||
201 | px.lastSeen = util.AbsoluteTimeNow() | ||
202 | } | ||
203 | return ok | ||
168 | } | 204 | } |
169 | 205 | ||
170 | //---------------------------------------------------------------------- | 206 | //---------------------------------------------------------------------- |
@@ -186,51 +222,53 @@ func (rt *RoutingTable) Process(f func() error, readonly bool) error { | |||
186 | // Routing functions | 222 | // Routing functions |
187 | //---------------------------------------------------------------------- | 223 | //---------------------------------------------------------------------- |
188 | 224 | ||
189 | // SelectClosestPeer for a given peer address and bloomfilter. | 225 | // SelectClosestPeer for a given peer address and peer filter. |
190 | func (rt *RoutingTable) SelectClosestPeer(p *PeerAddress, bf *PeerBloomFilter) (n *PeerAddress) { | 226 | func (rt *RoutingTable) SelectClosestPeer(p *PeerAddress, pf *blocks.PeerFilter) (n *PeerAddress) { |
191 | // no writer allowed | 227 | // no writer allowed |
192 | rt.mtx.RLock() | 228 | rt.RLock() |
193 | defer rt.mtx.RUnlock() | 229 | defer rt.RUnlock() |
194 | 230 | ||
195 | // find closest address | 231 | // find closest peer in routing table |
196 | var dist *math.Int | 232 | var dist *math.Int |
197 | for _, b := range rt.buckets { | 233 | for _, b := range rt.buckets { |
198 | if k, d := b.SelectClosestPeer(p, bf); n == nil || (d != nil && d.Cmp(dist) < 0) { | 234 | if k, d := b.SelectClosestPeer(p, pf); n == nil || (d != nil && d.Cmp(dist) < 0) { |
199 | dist = d | 235 | dist = d |
200 | n = k | 236 | n = k |
201 | } | 237 | } |
202 | } | 238 | } |
203 | // mark peer as used | 239 | // mark peer as used |
204 | n.lastUsed = util.AbsoluteTimeNow() | 240 | if n != nil { |
241 | n.lastUsed = util.AbsoluteTimeNow() | ||
242 | } | ||
205 | return | 243 | return |
206 | } | 244 | } |
207 | 245 | ||
208 | // SelectRandomPeer returns a random address from table (that is not | 246 | // SelectRandomPeer returns a random address from table (that is not |
209 | // included in the bloomfilter) | 247 | // included in the bloomfilter) |
210 | func (rt *RoutingTable) SelectRandomPeer(bf *PeerBloomFilter) *PeerAddress { | 248 | func (rt *RoutingTable) SelectRandomPeer(pf *blocks.PeerFilter) (p *PeerAddress) { |
211 | // no writer allowed | 249 | // no writer allowed |
212 | rt.mtx.RLock() | 250 | rt.RLock() |
213 | defer rt.mtx.RUnlock() | 251 | defer rt.RUnlock() |
214 | 252 | ||
215 | // select random entry from list | 253 | // select random entry from list |
216 | if size := len(rt.list); size > 0 { | 254 | var ok bool |
217 | idx := rand.Intn(size) | 255 | for { |
218 | for k := range rt.list { | 256 | if _, p, ok = rt.list.GetRandom(); !ok { |
219 | if idx == 0 { | 257 | return nil |
220 | // mark peer as used | 258 | } |
221 | k.lastUsed = util.AbsoluteTimeNow() | 259 | if !pf.Contains(p.Peer) { |
222 | return k | 260 | break |
223 | } | ||
224 | idx-- | ||
225 | } | 261 | } |
226 | } | 262 | } |
227 | return nil | 263 | // mark peer as used |
264 | p.lastUsed = util.AbsoluteTimeNow() | ||
265 | return | ||
228 | } | 266 | } |
229 | 267 | ||
230 | // SelectPeer selects a neighbor depending on the number of hops parameter. | 268 | // SelectPeer selects a neighbor depending on the number of hops parameter. |
231 | // If hops < NSE this function MUST return SelectRandomPeer() and | 269 | // If hops < NSE this function MUST return SelectRandomPeer() and |
232 | // SelectClosestpeer() otherwise. | 270 | // SelectClosestpeer() otherwise. |
233 | func (rt *RoutingTable) SelectPeer(p *PeerAddress, hops int, bf *PeerBloomFilter) *PeerAddress { | 271 | func (rt *RoutingTable) SelectPeer(p *PeerAddress, hops int, bf *blocks.PeerFilter) *PeerAddress { |
234 | if float64(hops) < rt.l2nse { | 272 | if float64(hops) < rt.l2nse { |
235 | return rt.SelectRandomPeer(bf) | 273 | return rt.SelectRandomPeer(bf) |
236 | } | 274 | } |
@@ -238,9 +276,24 @@ func (rt *RoutingTable) SelectPeer(p *PeerAddress, hops int, bf *PeerBloomFilter | |||
238 | } | 276 | } |
239 | 277 | ||
240 | // IsClosestPeer returns true if p is the closest peer for k. Peers with a | 278 | // IsClosestPeer returns true if p is the closest peer for k. Peers with a |
241 | // positive test in the Bloom filter are not considered. | 279 | // positive test in the Bloom filter are not considered. If p is nil, our |
242 | func (rt *RoutingTable) IsClosestPeer(p, k *PeerAddress, bf *PeerBloomFilter) bool { | 280 | // reference address is used. |
243 | n := rt.SelectClosestPeer(k, bf) | 281 | func (rt *RoutingTable) IsClosestPeer(p, k *PeerAddress, pf *blocks.PeerFilter) bool { |
282 | // get closest peer in routing table | ||
283 | n := rt.SelectClosestPeer(k, pf) | ||
284 | // check SELF? | ||
285 | if p == nil { | ||
286 | // if no peer in routing table found | ||
287 | if n == nil { | ||
288 | // local peer is closest | ||
289 | return true | ||
290 | } | ||
291 | // check if local distance is smaller than for best peer in routing table | ||
292 | d0, _ := n.Distance(k) | ||
293 | d1, _ := rt.ref.Distance(k) | ||
294 | return d1.Cmp(d0) < 0 | ||
295 | } | ||
296 | // check if p is closest peer | ||
244 | return n.Equals(p) | 297 | return n.Equals(p) |
245 | } | 298 | } |
246 | 299 | ||
@@ -248,7 +301,7 @@ func (rt *RoutingTable) IsClosestPeer(p, k *PeerAddress, bf *PeerBloomFilter) bo | |||
248 | // The arguments are the desired replication level, the hop count of the message so far, | 301 | // The arguments are the desired replication level, the hop count of the message so far, |
249 | // and the base-2 logarithm of the current network size estimate (L2NSE) as provided by the | 302 | // and the base-2 logarithm of the current network size estimate (L2NSE) as provided by the |
250 | // underlay. The result is the non-negative number of next hops to select. | 303 | // underlay. The result is the non-negative number of next hops to select. |
251 | func (rt *RoutingTable) ComputeOutDegree(repl, hop int) int { | 304 | func (rt *RoutingTable) ComputeOutDegree(repl, hop uint16) int { |
252 | hf := float64(hop) | 305 | hf := float64(hop) |
253 | if hf > 4*rt.l2nse { | 306 | if hf > 4*rt.l2nse { |
254 | return 0 | 307 | return 0 |
@@ -271,22 +324,62 @@ func (rt *RoutingTable) ComputeOutDegree(repl, hop int) int { | |||
271 | func (rt *RoutingTable) heartbeat(ctx context.Context) { | 324 | func (rt *RoutingTable) heartbeat(ctx context.Context) { |
272 | 325 | ||
273 | // check for dead or expired peers | 326 | // check for dead or expired peers |
274 | timeout := util.NewRelativeTime(3 * time.Hour) | 327 | logger.Println(logger.DBG, "[dht] RT heartbeat...") |
328 | timeout := util.NewRelativeTime(time.Duration(rt.cfg.PeerTTL) * time.Second) | ||
275 | if err := rt.Process(func() error { | 329 | if err := rt.Process(func() error { |
276 | for addr := range rt.list { | 330 | return rt.list.ProcessRange(func(k string, p *PeerAddress) error { |
277 | if addr.connected { | ||
278 | continue | ||
279 | } | ||
280 | // check if we can/need to drop a peer | 331 | // check if we can/need to drop a peer |
281 | drop := timeout.Compare(addr.lastSeen.Elapsed()) < 0 | 332 | drop := timeout.Compare(p.lastSeen.Elapsed()) < 0 |
282 | if drop || timeout.Compare(addr.lastUsed.Elapsed()) < 0 { | 333 | if drop || timeout.Compare(p.lastUsed.Elapsed()) < 0 { |
283 | rt.Remove(addr) | 334 | logger.Printf(logger.DBG, "[RT] removing %v: %v, %v", p, p.lastSeen.Elapsed(), p.lastUsed.Elapsed()) |
335 | rt.Remove(p) | ||
284 | } | 336 | } |
285 | } | 337 | return nil |
286 | return nil | 338 | }, false) |
287 | }, false); err != nil { | 339 | }, false); err != nil { |
288 | logger.Println(logger.ERROR, "[dht] RT heartbeat: "+err.Error()) | 340 | logger.Println(logger.ERROR, "[dht] RT heartbeat failed: "+err.Error()) |
289 | } | 341 | } |
342 | |||
343 | // drop expired entries from the HELLO cache | ||
344 | _ = rt.helloCache.ProcessRange(func(key string, val *blocks.HelloBlock) error { | ||
345 | if val.Expires.Expired() { | ||
346 | rt.helloCache.Delete(key) | ||
347 | } | ||
348 | return nil | ||
349 | }, false) | ||
350 | |||
351 | // update the estimated network size | ||
352 | // rt.l2nse = ... | ||
353 | } | ||
354 | |||
355 | //---------------------------------------------------------------------- | ||
356 | |||
357 | func (rt *RoutingTable) BestHello(addr *PeerAddress, rf blocks.ResultFilter) (hb *blocks.HelloBlock, dist *math.Int) { | ||
358 | // iterate over cached HELLOs to find (best) match first | ||
359 | _ = rt.helloCache.ProcessRange(func(key string, val *blocks.HelloBlock) error { | ||
360 | // check if block is excluded by result filter | ||
361 | if !rf.Contains(val) { | ||
362 | // check for better match | ||
363 | p := NewPeerAddress(val.PeerID) | ||
364 | d, _ := addr.Distance(p) | ||
365 | if hb == nil || d.Cmp(dist) < 0 { | ||
366 | hb = val | ||
367 | dist = d | ||
368 | } | ||
369 | } | ||
370 | return nil | ||
371 | }, true) | ||
372 | return | ||
373 | } | ||
374 | |||
375 | // CacheHello adds a HELLO block to the list of cached entries. | ||
376 | func (rt *RoutingTable) CacheHello(hb *blocks.HelloBlock) { | ||
377 | rt.helloCache.Put(hb.PeerID.String(), hb) | ||
378 | } | ||
379 | |||
380 | // GetHello returns a HELLO block for key k (if available) | ||
381 | func (rt *RoutingTable) GetHello(k string) (*blocks.HelloBlock, bool) { | ||
382 | return rt.helloCache.Get(k) | ||
290 | } | 383 | } |
291 | 384 | ||
292 | //---------------------------------------------------------------------- | 385 | //---------------------------------------------------------------------- |
@@ -295,9 +388,9 @@ func (rt *RoutingTable) heartbeat(ctx context.Context) { | |||
295 | func (rt *RoutingTable) lock(readonly bool) { | 388 | func (rt *RoutingTable) lock(readonly bool) { |
296 | if !rt.inProcess { | 389 | if !rt.inProcess { |
297 | if readonly { | 390 | if readonly { |
298 | rt.mtx.RLock() | 391 | rt.RLock() |
299 | } else { | 392 | } else { |
300 | rt.mtx.Lock() | 393 | rt.Lock() |
301 | } | 394 | } |
302 | } | 395 | } |
303 | } | 396 | } |
@@ -306,9 +399,9 @@ func (rt *RoutingTable) lock(readonly bool) { | |||
306 | func (rt *RoutingTable) unlock(readonly bool) { | 399 | func (rt *RoutingTable) unlock(readonly bool) { |
307 | if !rt.inProcess { | 400 | if !rt.inProcess { |
308 | if readonly { | 401 | if readonly { |
309 | rt.mtx.RUnlock() | 402 | rt.RUnlock() |
310 | } else { | 403 | } else { |
311 | rt.mtx.Unlock() | 404 | rt.Unlock() |
312 | } | 405 | } |
313 | } | 406 | } |
314 | } | 407 | } |
@@ -319,8 +412,9 @@ func (rt *RoutingTable) unlock(readonly bool) { | |||
319 | 412 | ||
320 | // Bucket holds peer entries with approx. same distance from node | 413 | // Bucket holds peer entries with approx. same distance from node |
321 | type Bucket struct { | 414 | type Bucket struct { |
322 | list []*PeerAddress | 415 | sync.RWMutex |
323 | rwlock sync.RWMutex | 416 | |
417 | list []*PeerAddress // list of peer addresses in bucket. | ||
324 | } | 418 | } |
325 | 419 | ||
326 | // NewBucket creates a new entry list of given size | 420 | // NewBucket creates a new entry list of given size |
@@ -334,8 +428,8 @@ func NewBucket(n int) *Bucket { | |||
334 | // Returns true if entry is added, false otherwise. | 428 | // Returns true if entry is added, false otherwise. |
335 | func (b *Bucket) Add(p *PeerAddress) bool { | 429 | func (b *Bucket) Add(p *PeerAddress) bool { |
336 | // only one writer and no readers | 430 | // only one writer and no readers |
337 | b.rwlock.Lock() | 431 | b.Lock() |
338 | defer b.rwlock.Unlock() | 432 | defer b.Unlock() |
339 | 433 | ||
340 | // check for free space in bucket | 434 | // check for free space in bucket |
341 | if len(b.list) < numK { | 435 | if len(b.list) < numK { |
@@ -343,6 +437,7 @@ func (b *Bucket) Add(p *PeerAddress) bool { | |||
343 | b.list = append(b.list, p) | 437 | b.list = append(b.list, p) |
344 | return true | 438 | return true |
345 | } | 439 | } |
440 | // full bucket: no further additions | ||
346 | return false | 441 | return false |
347 | } | 442 | } |
348 | 443 | ||
@@ -350,8 +445,8 @@ func (b *Bucket) Add(p *PeerAddress) bool { | |||
350 | // Returns true if entry is removed (found), false otherwise. | 445 | // Returns true if entry is removed (found), false otherwise. |
351 | func (b *Bucket) Remove(p *PeerAddress) bool { | 446 | func (b *Bucket) Remove(p *PeerAddress) bool { |
352 | // only one writer and no readers | 447 | // only one writer and no readers |
353 | b.rwlock.Lock() | 448 | b.Lock() |
354 | defer b.rwlock.Unlock() | 449 | defer b.Unlock() |
355 | 450 | ||
356 | for i, pe := range b.list { | 451 | for i, pe := range b.list { |
357 | if pe.Equals(p) { | 452 | if pe.Equals(p) { |
@@ -365,14 +460,14 @@ func (b *Bucket) Remove(p *PeerAddress) bool { | |||
365 | 460 | ||
366 | // SelectClosestPeer returns the entry with minimal distance to the given | 461 | // SelectClosestPeer returns the entry with minimal distance to the given |
367 | // peer address; entries included in the bloom flter are ignored. | 462 | // peer address; entries included in the bloom flter are ignored. |
368 | func (b *Bucket) SelectClosestPeer(p *PeerAddress, bf *PeerBloomFilter) (n *PeerAddress, dist *math.Int) { | 463 | func (b *Bucket) SelectClosestPeer(p *PeerAddress, pf *blocks.PeerFilter) (n *PeerAddress, dist *math.Int) { |
369 | // no writer allowed | 464 | // no writer allowed |
370 | b.rwlock.RLock() | 465 | b.RLock() |
371 | defer b.rwlock.RUnlock() | 466 | defer b.RUnlock() |
372 | 467 | ||
373 | for _, addr := range b.list { | 468 | for _, addr := range b.list { |
374 | // skip addresses in bloomfilter | 469 | // skip addresses in bloomfilter |
375 | if bf.Contains(addr) { | 470 | if pf.Contains(addr.Peer) { |
376 | continue | 471 | continue |
377 | } | 472 | } |
378 | // check for shorter distance | 473 | // check for shorter distance |