aboutsummaryrefslogtreecommitdiff
path: root/dht/routing_table.go
diff options
context:
space:
mode:
authorFelix Hanley <felix@userspace.com.au>2018-02-15 11:42:34 +0000
committerFelix Hanley <felix@userspace.com.au>2018-02-15 11:42:40 +0000
commit32a655f042a3752d93c4507b4c128b21bf6aa602 (patch)
tree224c0d7e51efccac3b32dc5d0662baa2ab7304a5 /dht/routing_table.go
parent2ded0704c8f675c3d92cf2b4874a32c65faf2553 (diff)
downloaddhtsearch-32a655f042a3752d93c4507b4c128b21bf6aa602.tar.gz
dhtsearch-32a655f042a3752d93c4507b4c128b21bf6aa602.tar.bz2
Refactor DHT code into separate package
Diffstat (limited to 'dht/routing_table.go')
-rw-r--r--dht/routing_table.go116
1 files changed, 89 insertions, 27 deletions
diff --git a/dht/routing_table.go b/dht/routing_table.go
index 0252519..3c1f2d2 100644
--- a/dht/routing_table.go
+++ b/dht/routing_table.go
@@ -1,57 +1,119 @@
package dht
import (
- "net"
+ "container/heap"
"sync"
)
-// Keep it simple for now
+type rItem struct {
+ value *remoteNode
+ distance int
+ index int // Index in heap
+}
+
+type priorityQueue []*rItem
+
type routingTable struct {
- id Infohash
- address net.UDPAddr
- nodes []*remoteNode
- max int
+ id Infohash
+ max int
+ items priorityQueue
+ addresses map[string]*remoteNode
sync.Mutex
}
-func newRoutingTable(id Infohash) *routingTable {
- k := &routingTable{id: id, max: 4000}
- k.refresh()
- return k
+func newRoutingTable(id Infohash, max int) (*routingTable, error) {
+ k := &routingTable{
+ id: id,
+ max: max,
+ }
+ k.flush()
+ heap.Init(&k.items)
+ return k, nil
}
-func (k *routingTable) add(rn *remoteNode) {
- k.Lock()
- defer k.Unlock()
+// Len implements sort.Interface
+func (pq priorityQueue) Len() int { return len(pq) }
+
+// Less implements sort.Interface
+func (pq priorityQueue) Less(i, j int) bool {
+ return pq[i].distance > pq[j].distance
+}
+
+// Swap implements sort.Interface
+func (pq priorityQueue) Swap(i, j int) {
+ pq[i], pq[j] = pq[j], pq[i]
+ pq[i].index = i
+ pq[j].index = j
+}
+
+// Push implements heap.Interface
+func (pq *priorityQueue) Push(x interface{}) {
+ n := len(*pq)
+ item := x.(*rItem)
+ item.index = n
+ *pq = append(*pq, item)
+}
+
+// Pop implements heap.Interface
+func (pq *priorityQueue) Pop() interface{} {
+ old := *pq
+ n := len(old)
+ item := old[n-1]
+ item.index = -1 // for safety
+ *pq = old[0 : n-1]
+ return item
+}
+func (k *routingTable) add(rn *remoteNode) {
// Check IP and ports are valid and not self
- if (rn.address.String() == k.address.String() && rn.address.Port == k.address.Port) || !rn.id.Valid() || rn.id.Equal(k.id) {
+ if !rn.id.Valid() || rn.id.Equal(k.id) {
return
}
- k.nodes = append(k.nodes, rn)
-}
-func (k *routingTable) getNodes() []*remoteNode {
k.Lock()
defer k.Unlock()
- return k.nodes
+
+ if _, ok := k.addresses[rn.address.String()]; ok {
+ return
+ }
+ k.addresses[rn.address.String()] = rn
+
+ item := &rItem{
+ value: rn,
+ distance: k.id.Distance(rn.id),
+ }
+
+ heap.Push(&k.items, item)
+
+ if len(k.items) > k.max {
+ for i := k.max - 1; i < len(k.items); i++ {
+ old := k.items[i]
+ delete(k.addresses, old.value.address.String())
+ heap.Remove(&k.items, i)
+ }
+ }
}
-func (k *routingTable) isEmpty() bool {
- k.Lock()
- defer k.Unlock()
- return len(k.nodes) == 0
+func (k *routingTable) get(n int) (out []*remoteNode) {
+ if n == 0 {
+ n = len(k.items)
+ }
+ for i := 0; i < n && i < len(k.items); i++ {
+ out = append(out, k.items[i].value)
+ }
+ return out
}
-func (k *routingTable) isFull() bool {
+func (k *routingTable) flush() {
k.Lock()
defer k.Unlock()
- return len(k.nodes) >= k.max
+
+ k.items = make(priorityQueue, 0)
+ k.addresses = make(map[string]*remoteNode, k.max)
}
-// For now
-func (k *routingTable) refresh() {
+func (k *routingTable) isEmpty() bool {
k.Lock()
defer k.Unlock()
- k.nodes = make([]*remoteNode, 0)
+ return len(k.items) == 0
}