@cryptotaxi247 / kubo / commits / 35a4086e0

rough kbucket implementation, tests and cleanup to follow

Jeromy committed Aug 3, 2014 at 13:37 UTC 35a4086e066b2602f9c8d3ae28e6ec957e606242
3 files changed +170 -8
peer/peer.go
+2 -2
@@ -12,8 +12,8 @@ import (
12 type ID mh.Multihash
13
14 // Utililty function for comparing two peer ID's
15 -func (id *ID) Equal(other *ID) bool {
16 - return bytes.Equal(*id, *other)
15 +func (id ID) Equal(other ID) bool {
16 + return bytes.Equal(id, other)
17 }
18
19 // Map maps Key (string) : *Peer (slices are not comparable).
routing/dht/routing.go
+2 -2
@@ -21,7 +21,7 @@ func GenerateMessageID() uint64 {
21 // PutValue adds value corresponding to given Key.
22 func (s *IpfsDHT) PutValue(key u.Key, value []byte) error {
23 var p *peer.Peer
24 - p = s.routes.NearestNode(key)
24 + p = s.routes.NearestPeer(convertKey(key))
25
26 pmes_type := DHTMessage_PUT_VALUE
27 str_key := string(key)
@@ -44,7 +44,7 @@ func (s *IpfsDHT) PutValue(key u.Key, value []byte) error {
44 // GetValue searches for the value corresponding to given Key.
45 func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
46 var p *peer.Peer
47 - p = s.routes.NearestNode(key)
47 + p = s.routes.NearestPeer(convertKey(key))
48
49 str_key := string(key)
50 mes_type := DHTMessage_GET_VALUE
routing/dht/table.go
+166 -4
@@ -3,6 +3,9 @@ package dht
3 import (
4 "bytes"
5 "container/list"
6 + "sort"
7 +
8 + "crypto/sha256"
9
10 peer "github.com/jbenet/go-ipfs/peer"
11 u "github.com/jbenet/go-ipfs/util"
@@ -16,18 +19,177 @@ import (
19 type ID []byte
20
21 // Bucket holds a list of peers.
19 -type Bucket []*list.List
22 +type Bucket list.List
23 +
24 +func (b *Bucket) Find(id peer.ID) *list.Element {
25 + bucket_list := (*list.List)(b)
26 + for e := bucket_list.Front(); e != nil; e = e.Next() {
27 + if e.Value.(*peer.Peer).ID.Equal(id) {
28 + return e
29 + }
30 + }
31 + return nil
32 +}
33 +
34 +func (b *Bucket) MoveToFront(e *list.Element) {
35 + bucket_list := (*list.List)(b)
36 + bucket_list.MoveToFront(e)
37 +}
38 +
39 +func (b *Bucket) PushFront(p *peer.Peer) {
40 + bucket_list := (*list.List)(b)
41 + bucket_list.PushFront(p)
42 +}
43 +
44 +func (b *Bucket) PopBack() *peer.Peer {
45 + bucket_list := (*list.List)(b)
46 + last := bucket_list.Back()
47 + bucket_list.Remove(last)
48 + return last.Value.(*peer.Peer)
49 +}
50 +
51 +func (b *Bucket) Len() int {
52 + bucket_list := (*list.List)(b)
53 + return bucket_list.Len()
54 +}
55 +
56 +func (b *Bucket) Split(cpl int, target ID) *Bucket {
57 + bucket_list := (*list.List)(b)
58 + out := list.New()
59 + e := bucket_list.Front()
60 + for e != nil {
61 + peer_id := convertPeerID(e.Value.(*peer.Peer).ID)
62 + peer_cpl := xor(peer_id, target).commonPrefixLen()
63 + if peer_cpl > cpl {
64 + cur := e
65 + out.PushBack(e.Value)
66 + e = e.Next()
67 + bucket_list.Remove(cur)
68 + continue
69 + }
70 + }
71 + return (*Bucket)(out)
72 +}
73
74 // RoutingTable defines the routing table.
75 type RoutingTable struct {
76
77 + // ID of the local peer
78 + local ID
79 +
80 // kBuckets define all the fingers to other nodes.
25 - Buckets []Bucket
81 + Buckets []*Bucket
82 + bucketsize int
83 +}
84 +
85 +func convertPeerID(id peer.ID) ID {
86 + hash := sha256.Sum256(id)
87 + return hash[:]
88 +}
89 +
90 +func convertKey(id u.Key) ID {
91 + hash := sha256.Sum256([]byte(id))
92 + return hash[:]
93 +}
94 +
95 +// Update adds or moves the given peer to the front of its respective bucket
96 +// If a peer gets removed from a bucket, it is returned
97 +func (rt *RoutingTable) Update(p *peer.Peer) *peer.Peer {
98 + peer_id := convertPeerID(p.ID)
99 + cpl := xor(peer_id, rt.local).commonPrefixLen()
100 +
101 + b_id := cpl
102 + if b_id >= len(rt.Buckets) {
103 + b_id = len(rt.Buckets) - 1
104 + }
105 +
106 + bucket := rt.Buckets[b_id]
107 + e := bucket.Find(p.ID)
108 + if e == nil {
109 + // New peer, add to bucket
110 + bucket.PushFront(p)
111 +
112 + // Are we past the max bucket size?
113 + if bucket.Len() > rt.bucketsize {
114 + if b_id == len(rt.Buckets) - 1 {
115 + new_bucket := bucket.Split(b_id, rt.local)
116 + rt.Buckets = append(rt.Buckets, new_bucket)
117 +
118 + // If all elements were on left side of split...
119 + if bucket.Len() > rt.bucketsize {
120 + return bucket.PopBack()
121 + }
122 + } else {
123 + // If the bucket cant split kick out least active node
124 + return bucket.PopBack()
125 + }
126 + }
127 + return nil
128 + } else {
129 + // If the peer is already in the table, move it to the front.
130 + // This signifies that it it "more active" and the less active nodes
131 + // Will as a result tend towards the back of the list
132 + bucket.MoveToFront(e)
133 + return nil
134 + }
135 +}
136 +
137 +// A helper struct to sort peers by their distance to the local node
138 +type peerDistance struct {
139 + p *peer.Peer
140 + distance ID
141 +}
142 +type peerSorterArr []*peerDistance
143 +func (p peerSorterArr) Len() int {return len(p)}
144 +func (p peerSorterArr) Swap(a, b int) {p[a],p[b] = p[b],p[a]}
145 +func (p peerSorterArr) Less(a, b int) bool {
146 + return p[a].distance.Less(p[b])
147 +}
148 +//
149 +
150 +func (rt *RoutingTable) NearestPeer(id ID) *peer.Peer {
151 + peers := rt.NearestPeers(id, 1)
152 + return peers[0]
153 }
154
155 //TODO: make this accept an ID, requires method of converting keys to IDs
29 -func (rt *RoutingTable) NearestNode(key u.Key) *peer.Peer {
30 - panic("Function not implemented.")
156 +func (rt *RoutingTable) NearestPeers(id ID, count int) []*peer.Peer {
157 + cpl := xor(id, rt.local).commonPrefixLen()
158 +
159 + // Get bucket at cpl index or last bucket
160 + var bucket *Bucket
161 + if cpl >= len(rt.Buckets) {
162 + bucket = rt.Buckets[len(rt.Buckets) - 1]
163 + } else {
164 + bucket = rt.Buckets[cpl]
165 + }
166 +
167 + if bucket.Len() == 0 {
168 + // This can happen, very rarely.
169 + panic("Case not yet implemented.")
170 + }
171 +
172 + var peerArr peerSorterArr
173 +
174 + plist := (*list.List)(bucket)
175 + for e := plist.Front();e != nil; e = e.Next() {
176 + p := e.Value.(*peer.Peer)
177 + p_id := convertPeerID(p.ID)
178 + pd := peerDistance{
179 + p: p,
180 + distance: xor(rt.local, p_id),
181 + }
182 + peerArr = append(peerArr, &pd)
183 + }
184 +
185 + sort.Sort(peerArr)
186 +
187 + var out []*peer.Peer
188 + for i := 0; i < count && i < peerArr.Len(); i++ {
189 + out = append(out, peerArr[i].p)
190 + }
191 +
192 + return out
193 }
194
195 func (id ID) Equal(other ID) bool {