Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
dms3
go-unixfs
Commits
bade1aa2
Commit
bade1aa2
authored
10 years ago
by
Jeromy
Committed by
Juan Batiz-Benet
10 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tests for kbucket and some code cleanup
parent
35a4086e
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
249 additions
and
127 deletions
+249
-127
routing/dht/bucket.go
routing/dht/bucket.go
+63
-0
routing/dht/table.go
routing/dht/table.go
+16
-127
routing/dht/table_test.go
routing/dht/table_test.go
+92
-0
routing/dht/util.go
routing/dht/util.go
+78
-0
No files found.
routing/dht/bucket.go
0 → 100644
View file @
bade1aa2
package
dht
import
(
"container/list"
peer
"github.com/jbenet/go-ipfs/peer"
)
// Bucket holds a list of peers.
type
Bucket
list
.
List
func
(
b
*
Bucket
)
Find
(
id
peer
.
ID
)
*
list
.
Element
{
bucket_list
:=
(
*
list
.
List
)(
b
)
for
e
:=
bucket_list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
if
e
.
Value
.
(
*
peer
.
Peer
)
.
ID
.
Equal
(
id
)
{
return
e
}
}
return
nil
}
func
(
b
*
Bucket
)
MoveToFront
(
e
*
list
.
Element
)
{
bucket_list
:=
(
*
list
.
List
)(
b
)
bucket_list
.
MoveToFront
(
e
)
}
func
(
b
*
Bucket
)
PushFront
(
p
*
peer
.
Peer
)
{
bucket_list
:=
(
*
list
.
List
)(
b
)
bucket_list
.
PushFront
(
p
)
}
func
(
b
*
Bucket
)
PopBack
()
*
peer
.
Peer
{
bucket_list
:=
(
*
list
.
List
)(
b
)
last
:=
bucket_list
.
Back
()
bucket_list
.
Remove
(
last
)
return
last
.
Value
.
(
*
peer
.
Peer
)
}
func
(
b
*
Bucket
)
Len
()
int
{
bucket_list
:=
(
*
list
.
List
)(
b
)
return
bucket_list
.
Len
()
}
// Splits a buckets peers into two buckets, the methods receiver will have
// peers with CPL equal to cpl, the returned bucket will have peers with CPL
// greater than cpl (returned bucket has closer peers)
func
(
b
*
Bucket
)
Split
(
cpl
int
,
target
ID
)
*
Bucket
{
bucket_list
:=
(
*
list
.
List
)(
b
)
out
:=
list
.
New
()
e
:=
bucket_list
.
Front
()
for
e
!=
nil
{
peer_id
:=
convertPeerID
(
e
.
Value
.
(
*
peer
.
Peer
)
.
ID
)
peer_cpl
:=
xor
(
peer_id
,
target
)
.
commonPrefixLen
()
if
peer_cpl
>
cpl
{
cur
:=
e
out
.
PushBack
(
e
.
Value
)
e
=
e
.
Next
()
bucket_list
.
Remove
(
cur
)
continue
}
e
=
e
.
Next
()
}
return
(
*
Bucket
)(
out
)
}
This diff is collapsed.
Click to expand it.
routing/dht/table.go
View file @
bade1aa2
package
dht
import
(
"bytes"
"container/list"
"sort"
"crypto/sha256"
peer
"github.com/jbenet/go-ipfs/peer"
u
"github.com/jbenet/go-ipfs/util"
)
// ID for IpfsDHT should be a byte slice, to allow for simpler operations
// (xor). DHT ids are based on the peer.IDs.
//
// NOTE: peer.IDs are biased because they are multihashes (first bytes
// biased). Thus, may need to re-hash keys (uniform dist). TODO(jbenet)
type
ID
[]
byte
// Bucket holds a list of peers.
type
Bucket
list
.
List
func
(
b
*
Bucket
)
Find
(
id
peer
.
ID
)
*
list
.
Element
{
bucket_list
:=
(
*
list
.
List
)(
b
)
for
e
:=
bucket_list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
if
e
.
Value
.
(
*
peer
.
Peer
)
.
ID
.
Equal
(
id
)
{
return
e
}
}
return
nil
}
func
(
b
*
Bucket
)
MoveToFront
(
e
*
list
.
Element
)
{
bucket_list
:=
(
*
list
.
List
)(
b
)
bucket_list
.
MoveToFront
(
e
)
}
func
(
b
*
Bucket
)
PushFront
(
p
*
peer
.
Peer
)
{
bucket_list
:=
(
*
list
.
List
)(
b
)
bucket_list
.
PushFront
(
p
)
}
func
(
b
*
Bucket
)
PopBack
()
*
peer
.
Peer
{
bucket_list
:=
(
*
list
.
List
)(
b
)
last
:=
bucket_list
.
Back
()
bucket_list
.
Remove
(
last
)
return
last
.
Value
.
(
*
peer
.
Peer
)
}
func
(
b
*
Bucket
)
Len
()
int
{
bucket_list
:=
(
*
list
.
List
)(
b
)
return
bucket_list
.
Len
()
}
func
(
b
*
Bucket
)
Split
(
cpl
int
,
target
ID
)
*
Bucket
{
bucket_list
:=
(
*
list
.
List
)(
b
)
out
:=
list
.
New
()
e
:=
bucket_list
.
Front
()
for
e
!=
nil
{
peer_id
:=
convertPeerID
(
e
.
Value
.
(
*
peer
.
Peer
)
.
ID
)
peer_cpl
:=
xor
(
peer_id
,
target
)
.
commonPrefixLen
()
if
peer_cpl
>
cpl
{
cur
:=
e
out
.
PushBack
(
e
.
Value
)
e
=
e
.
Next
()
bucket_list
.
Remove
(
cur
)
continue
}
}
return
(
*
Bucket
)(
out
)
}
// RoutingTable defines the routing table.
type
RoutingTable
struct
{
...
...
@@ -82,14 +18,12 @@ type RoutingTable struct {
bucketsize
int
}
func
convertPeerID
(
id
peer
.
ID
)
ID
{
hash
:=
sha256
.
Sum256
(
id
)
return
hash
[
:
]
}
func
convertKey
(
id
u
.
Key
)
ID
{
hash
:=
sha256
.
Sum256
([]
byte
(
id
))
return
hash
[
:
]
func
NewRoutingTable
(
bucketsize
int
,
local_id
ID
)
*
RoutingTable
{
rt
:=
new
(
RoutingTable
)
rt
.
Buckets
=
[]
*
Bucket
{
new
(
Bucket
)}
rt
.
bucketsize
=
bucketsize
rt
.
local
=
local_id
return
rt
}
// Update adds or moves the given peer to the front of its respective bucket
...
...
@@ -114,6 +48,10 @@ func (rt *RoutingTable) Update(p *peer.Peer) *peer.Peer {
if
b_id
==
len
(
rt
.
Buckets
)
-
1
{
new_bucket
:=
bucket
.
Split
(
b_id
,
rt
.
local
)
rt
.
Buckets
=
append
(
rt
.
Buckets
,
new_bucket
)
if
new_bucket
.
Len
()
>
rt
.
bucketsize
{
// This is another very rare and annoying case
panic
(
"Case not handled."
)
}
// If all elements were on left side of split...
if
bucket
.
Len
()
>
rt
.
bucketsize
{
...
...
@@ -139,20 +77,23 @@ type peerDistance struct {
p
*
peer
.
Peer
distance
ID
}
// peerSorterArr implements sort.Interface to sort peers by xor distance
type
peerSorterArr
[]
*
peerDistance
func
(
p
peerSorterArr
)
Len
()
int
{
return
len
(
p
)}
func
(
p
peerSorterArr
)
Swap
(
a
,
b
int
)
{
p
[
a
],
p
[
b
]
=
p
[
b
],
p
[
a
]}
func
(
p
peerSorterArr
)
Less
(
a
,
b
int
)
bool
{
return
p
[
a
]
.
distance
.
Less
(
p
[
b
])
return
p
[
a
]
.
distance
.
Less
(
p
[
b
]
.
distance
)
}
//
// Returns a single peer that is nearest to the given ID
func
(
rt
*
RoutingTable
)
NearestPeer
(
id
ID
)
*
peer
.
Peer
{
peers
:=
rt
.
NearestPeers
(
id
,
1
)
return
peers
[
0
]
}
//
TODO: make this accept an ID, requires method of converting keys to
ID
s
//
Returns a list of the 'count' closest peers to the given
ID
func
(
rt
*
RoutingTable
)
NearestPeers
(
id
ID
,
count
int
)
[]
*
peer
.
Peer
{
cpl
:=
xor
(
id
,
rt
.
local
)
.
commonPrefixLen
()
...
...
@@ -170,7 +111,6 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []*peer.Peer {
}
var
peerArr
peerSorterArr
plist
:=
(
*
list
.
List
)(
bucket
)
for
e
:=
plist
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
e
.
Value
.
(
*
peer
.
Peer
)
...
...
@@ -182,6 +122,7 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []*peer.Peer {
peerArr
=
append
(
peerArr
,
&
pd
)
}
// Sort by distance to local peer
sort
.
Sort
(
peerArr
)
var
out
[]
*
peer
.
Peer
...
...
@@ -191,55 +132,3 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []*peer.Peer {
return
out
}
func
(
id
ID
)
Equal
(
other
ID
)
bool
{
return
bytes
.
Equal
(
id
,
other
)
}
func
(
id
ID
)
Less
(
other
interface
{})
bool
{
a
,
b
:=
equalizeSizes
(
id
,
other
.
(
ID
))
for
i
:=
0
;
i
<
len
(
a
);
i
++
{
if
a
[
i
]
!=
b
[
i
]
{
return
a
[
i
]
<
b
[
i
]
}
}
return
len
(
a
)
<
len
(
b
)
}
func
(
id
ID
)
commonPrefixLen
()
int
{
for
i
:=
0
;
i
<
len
(
id
);
i
++
{
for
j
:=
0
;
j
<
8
;
j
++
{
if
(
id
[
i
]
>>
uint8
(
7
-
j
))
&
0x1
!=
0
{
return
i
*
8
+
j
}
}
}
return
len
(
id
)
*
8
-
1
}
func
xor
(
a
,
b
ID
)
ID
{
a
,
b
=
equalizeSizes
(
a
,
b
)
c
:=
make
(
ID
,
len
(
a
))
for
i
:=
0
;
i
<
len
(
a
);
i
++
{
c
[
i
]
=
a
[
i
]
^
b
[
i
]
}
return
c
}
func
equalizeSizes
(
a
,
b
ID
)
(
ID
,
ID
)
{
la
:=
len
(
a
)
lb
:=
len
(
b
)
if
la
<
lb
{
na
:=
make
([]
byte
,
lb
)
copy
(
na
,
a
)
a
=
na
}
else
if
lb
<
la
{
nb
:=
make
([]
byte
,
la
)
copy
(
nb
,
b
)
b
=
nb
}
return
a
,
b
}
This diff is collapsed.
Click to expand it.
routing/dht/table_test.go
0 → 100644
View file @
bade1aa2
package
dht
import
(
crand
"crypto/rand"
"crypto/sha256"
"math/rand"
"container/list"
"testing"
peer
"github.com/jbenet/go-ipfs/peer"
)
func
_randPeer
()
*
peer
.
Peer
{
p
:=
new
(
peer
.
Peer
)
p
.
ID
=
make
(
peer
.
ID
,
16
)
crand
.
Read
(
p
.
ID
)
return
p
}
func
_randID
()
ID
{
buf
:=
make
([]
byte
,
16
)
crand
.
Read
(
buf
)
hash
:=
sha256
.
Sum256
(
buf
)
return
ID
(
hash
[
:
])
}
// Test basic features of the bucket struct
func
TestBucket
(
t
*
testing
.
T
)
{
b
:=
new
(
Bucket
)
peers
:=
make
([]
*
peer
.
Peer
,
100
)
for
i
:=
0
;
i
<
100
;
i
++
{
peers
[
i
]
=
_randPeer
()
b
.
PushFront
(
peers
[
i
])
}
local
:=
_randPeer
()
local_id
:=
convertPeerID
(
local
.
ID
)
i
:=
rand
.
Intn
(
len
(
peers
))
e
:=
b
.
Find
(
peers
[
i
]
.
ID
)
if
e
==
nil
{
t
.
Errorf
(
"Failed to find peer: %v"
,
peers
[
i
])
}
spl
:=
b
.
Split
(
0
,
convertPeerID
(
local
.
ID
))
llist
:=
(
*
list
.
List
)(
b
)
for
e
:=
llist
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
convertPeerID
(
e
.
Value
.
(
*
peer
.
Peer
)
.
ID
)
cpl
:=
xor
(
p
,
local_id
)
.
commonPrefixLen
()
if
cpl
>
0
{
t
.
Fatalf
(
"Split failed. found id with cpl > 0 in 0 bucket"
)
}
}
rlist
:=
(
*
list
.
List
)(
spl
)
for
e
:=
rlist
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
convertPeerID
(
e
.
Value
.
(
*
peer
.
Peer
)
.
ID
)
cpl
:=
xor
(
p
,
local_id
)
.
commonPrefixLen
()
if
cpl
==
0
{
t
.
Fatalf
(
"Split failed. found id with cpl == 0 in non 0 bucket"
)
}
}
}
// Right now, this just makes sure that it doesnt hang or crash
func
TestTableUpdate
(
t
*
testing
.
T
)
{
local
:=
_randPeer
()
rt
:=
NewRoutingTable
(
10
,
convertPeerID
(
local
.
ID
))
peers
:=
make
([]
*
peer
.
Peer
,
100
)
for
i
:=
0
;
i
<
100
;
i
++
{
peers
[
i
]
=
_randPeer
()
}
// Testing Update
for
i
:=
0
;
i
<
10000
;
i
++
{
p
:=
rt
.
Update
(
peers
[
rand
.
Intn
(
len
(
peers
))])
if
p
!=
nil
{
t
.
Log
(
"evicted peer."
)
}
}
for
i
:=
0
;
i
<
100
;
i
++
{
id
:=
_randID
()
ret
:=
rt
.
NearestPeers
(
id
,
5
)
if
len
(
ret
)
==
0
{
t
.
Fatal
(
"Failed to find node near ID."
)
}
}
}
This diff is collapsed.
Click to expand it.
routing/dht/util.go
0 → 100644
View file @
bade1aa2
package
dht
import
(
"bytes"
"crypto/sha256"
peer
"github.com/jbenet/go-ipfs/peer"
u
"github.com/jbenet/go-ipfs/util"
)
// ID for IpfsDHT should be a byte slice, to allow for simpler operations
// (xor). DHT ids are based on the peer.IDs.
//
// NOTE: peer.IDs are biased because they are multihashes (first bytes
// biased). Thus, may need to re-hash keys (uniform dist). TODO(jbenet)
type
ID
[]
byte
func
(
id
ID
)
Equal
(
other
ID
)
bool
{
return
bytes
.
Equal
(
id
,
other
)
}
func
(
id
ID
)
Less
(
other
interface
{})
bool
{
a
,
b
:=
equalizeSizes
(
id
,
other
.
(
ID
))
for
i
:=
0
;
i
<
len
(
a
);
i
++
{
if
a
[
i
]
!=
b
[
i
]
{
return
a
[
i
]
<
b
[
i
]
}
}
return
len
(
a
)
<
len
(
b
)
}
func
(
id
ID
)
commonPrefixLen
()
int
{
for
i
:=
0
;
i
<
len
(
id
);
i
++
{
for
j
:=
0
;
j
<
8
;
j
++
{
if
(
id
[
i
]
>>
uint8
(
7
-
j
))
&
0x1
!=
0
{
return
i
*
8
+
j
}
}
}
return
len
(
id
)
*
8
-
1
}
func
xor
(
a
,
b
ID
)
ID
{
a
,
b
=
equalizeSizes
(
a
,
b
)
c
:=
make
(
ID
,
len
(
a
))
for
i
:=
0
;
i
<
len
(
a
);
i
++
{
c
[
i
]
=
a
[
i
]
^
b
[
i
]
}
return
c
}
func
equalizeSizes
(
a
,
b
ID
)
(
ID
,
ID
)
{
la
:=
len
(
a
)
lb
:=
len
(
b
)
if
la
<
lb
{
na
:=
make
([]
byte
,
lb
)
copy
(
na
,
a
)
a
=
na
}
else
if
lb
<
la
{
nb
:=
make
([]
byte
,
la
)
copy
(
nb
,
b
)
b
=
nb
}
return
a
,
b
}
func
convertPeerID
(
id
peer
.
ID
)
ID
{
hash
:=
sha256
.
Sum256
(
id
)
return
hash
[
:
]
}
func
convertKey
(
id
u
.
Key
)
ID
{
hash
:=
sha256
.
Sum256
([]
byte
(
id
))
return
hash
[
:
]
}
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment