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
p2p
go-p2p-kbucket
Commits
ee7b926e
Unverified
Commit
ee7b926e
authored
Apr 02, 2020
by
Steven Allen
Committed by
GitHub
Apr 02, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #69 from libp2p/feat/expose-peerinfo
Get Peer Infos
parents
3d3bf8ce
0779168b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
82 additions
and
37 deletions
+82
-37
bucket.go
bucket.go
+15
-15
sorting.go
sorting.go
+1
-1
table.go
table.go
+26
-12
table_test.go
table_test.go
+40
-9
No files found.
bucket.go
View file @
ee7b926e
...
...
@@ -9,12 +9,12 @@ import (
"github.com/libp2p/go-libp2p-core/peer"
)
//
p
eerInfo holds all related information for a peer in the K-Bucket.
type
p
eerInfo
struct
{
//
P
eerInfo holds all related information for a peer in the K-Bucket.
type
P
eerInfo
struct
{
Id
peer
.
ID
//
l
astSuccessfulOutboundQuery is the time instant when we last made a successful
//
L
astSuccessfulOutboundQuery is the time instant when we last made a successful
// outbound query to this peer
l
astSuccessfulOutboundQuery
time
.
Time
L
astSuccessfulOutboundQuery
time
.
Time
// Id of the peer in the DHT XOR keyspace
dhtId
ID
...
...
@@ -37,10 +37,10 @@ func newBucket() *bucket {
// returns all peers in the bucket
// it is safe for the caller to modify the returned objects as it is a defensive copy
func
(
b
*
bucket
)
peers
()
[]
p
eerInfo
{
var
ps
[]
p
eerInfo
func
(
b
*
bucket
)
peers
()
[]
P
eerInfo
{
var
ps
[]
P
eerInfo
for
e
:=
b
.
list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
e
.
Value
.
(
*
p
eerInfo
)
p
:=
e
.
Value
.
(
*
P
eerInfo
)
ps
=
append
(
ps
,
*
p
)
}
return
ps
...
...
@@ -50,7 +50,7 @@ func (b *bucket) peers() []peerInfo {
func
(
b
*
bucket
)
peerIds
()
[]
peer
.
ID
{
ps
:=
make
([]
peer
.
ID
,
0
,
b
.
list
.
Len
())
for
e
:=
b
.
list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
e
.
Value
.
(
*
p
eerInfo
)
p
:=
e
.
Value
.
(
*
P
eerInfo
)
ps
=
append
(
ps
,
p
.
Id
)
}
return
ps
...
...
@@ -58,10 +58,10 @@ func (b *bucket) peerIds() []peer.ID {
// returns the peer with the given Id if it exists
// returns nil if the peerId does not exist
func
(
b
*
bucket
)
getPeer
(
p
peer
.
ID
)
*
p
eerInfo
{
func
(
b
*
bucket
)
getPeer
(
p
peer
.
ID
)
*
P
eerInfo
{
for
e
:=
b
.
list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
if
e
.
Value
.
(
*
p
eerInfo
)
.
Id
==
p
{
return
e
.
Value
.
(
*
p
eerInfo
)
if
e
.
Value
.
(
*
P
eerInfo
)
.
Id
==
p
{
return
e
.
Value
.
(
*
P
eerInfo
)
}
}
return
nil
...
...
@@ -71,7 +71,7 @@ func (b *bucket) getPeer(p peer.ID) *peerInfo {
// returns true if successful, false otherwise.
func
(
b
*
bucket
)
remove
(
id
peer
.
ID
)
bool
{
for
e
:=
b
.
list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
if
e
.
Value
.
(
*
p
eerInfo
)
.
Id
==
id
{
if
e
.
Value
.
(
*
P
eerInfo
)
.
Id
==
id
{
b
.
list
.
Remove
(
e
)
return
true
}
...
...
@@ -82,13 +82,13 @@ func (b *bucket) remove(id peer.ID) bool {
func
(
b
*
bucket
)
moveToFront
(
id
peer
.
ID
)
{
for
e
:=
b
.
list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
if
e
.
Value
.
(
*
p
eerInfo
)
.
Id
==
id
{
if
e
.
Value
.
(
*
P
eerInfo
)
.
Id
==
id
{
b
.
list
.
MoveToFront
(
e
)
}
}
}
func
(
b
*
bucket
)
pushFront
(
p
*
p
eerInfo
)
{
func
(
b
*
bucket
)
pushFront
(
p
*
P
eerInfo
)
{
b
.
list
.
PushFront
(
p
)
}
...
...
@@ -105,7 +105,7 @@ func (b *bucket) split(cpl int, target ID) *bucket {
newbuck
.
list
=
out
e
:=
b
.
list
.
Front
()
for
e
!=
nil
{
pDhtId
:=
e
.
Value
.
(
*
p
eerInfo
)
.
dhtId
pDhtId
:=
e
.
Value
.
(
*
P
eerInfo
)
.
dhtId
peerCPL
:=
CommonPrefixLen
(
pDhtId
,
target
)
if
peerCPL
>
cpl
{
cur
:=
e
...
...
sorting.go
View file @
ee7b926e
...
...
@@ -38,7 +38,7 @@ func (pds *peerDistanceSorter) appendPeer(p peer.ID, pDhtId ID) {
// Append the peer.ID values in the list to the sorter's slice. It may no longer be sorted.
func
(
pds
*
peerDistanceSorter
)
appendPeersFromList
(
l
*
list
.
List
)
{
for
e
:=
l
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
pds
.
appendPeer
(
e
.
Value
.
(
*
p
eerInfo
)
.
Id
,
e
.
Value
.
(
*
p
eerInfo
)
.
dhtId
)
pds
.
appendPeer
(
e
.
Value
.
(
*
P
eerInfo
)
.
Id
,
e
.
Value
.
(
*
P
eerInfo
)
.
dhtId
)
}
}
...
...
table.go
View file @
ee7b926e
...
...
@@ -49,7 +49,7 @@ type RoutingTable struct {
PeerRemoved
func
(
peer
.
ID
)
PeerAdded
func
(
peer
.
ID
)
// maxLastSuccessfulOutboundThreshold is the max threshold/upper limit for the value of "
l
astSuccessfulOutboundQuery"
// maxLastSuccessfulOutboundThreshold is the max threshold/upper limit for the value of "
L
astSuccessfulOutboundQuery"
// of the peer in the bucket above which we will evict it to make place for a new peer if the bucket
// is full
maxLastSuccessfulOutboundThreshold
float64
...
...
@@ -87,12 +87,12 @@ func (rt *RoutingTable) Close() error {
}
// TryAddPeer tries to add a peer to the Routing table. If the peer ALREADY exists in the Routing Table, this call is a no-op.
// If the peer is a queryPeer i.e. we queried it or it queried us, we set the
l
astSuccessfulOutboundQuery to the current time.
// If the peer is a queryPeer i.e. we queried it or it queried us, we set the
L
astSuccessfulOutboundQuery to the current time.
// If the peer is just a peer that we connect to/it connected to us without any DHT query, we consider it as having
// no
l
astSuccessfulOutboundQuery.
// no
L
astSuccessfulOutboundQuery.
//
// If the logical bucket to which the peer belongs is full and it's not the last bucket, we try to replace an existing peer
// whose
l
astSuccessfulOutboundQuery is above the maximum allowed threshold in that bucket with the new peer.
// whose
L
astSuccessfulOutboundQuery is above the maximum allowed threshold in that bucket with the new peer.
// If no such peer exists in that bucket, we do NOT add the peer to the Routing Table and return error "ErrPeerRejectedNoCapacity".
// It returns a boolean value set to true if the peer was newly added to the Routing Table, false otherwise.
...
...
@@ -129,7 +129,7 @@ func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) {
// We have enough space in the bucket (whether spawned or grouped).
if
bucket
.
len
()
<
rt
.
bucketsize
{
bucket
.
pushFront
(
&
p
eerInfo
{
p
,
lastSuccessfulOutboundQuery
,
ConvertPeerID
(
p
)})
bucket
.
pushFront
(
&
P
eerInfo
{
p
,
lastSuccessfulOutboundQuery
,
ConvertPeerID
(
p
)})
rt
.
PeerAdded
(
p
)
return
true
,
nil
}
...
...
@@ -143,20 +143,20 @@ func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) {
// push the peer only if the bucket isn't overflowing after slitting
if
bucket
.
len
()
<
rt
.
bucketsize
{
bucket
.
pushFront
(
&
p
eerInfo
{
p
,
lastSuccessfulOutboundQuery
,
ConvertPeerID
(
p
)})
bucket
.
pushFront
(
&
P
eerInfo
{
p
,
lastSuccessfulOutboundQuery
,
ConvertPeerID
(
p
)})
rt
.
PeerAdded
(
p
)
return
true
,
nil
}
}
// the bucket to which the peer belongs is full. Let's try to find a peer
// in that bucket with a
l
astSuccessfulOutboundQuery value above the maximum threshold and replace it.
// in that bucket with a
L
astSuccessfulOutboundQuery value above the maximum threshold and replace it.
allPeers
:=
bucket
.
peers
()
for
_
,
pc
:=
range
allPeers
{
if
float64
(
time
.
Since
(
pc
.
l
astSuccessfulOutboundQuery
))
>
rt
.
maxLastSuccessfulOutboundThreshold
{
if
float64
(
time
.
Since
(
pc
.
L
astSuccessfulOutboundQuery
))
>
rt
.
maxLastSuccessfulOutboundThreshold
{
// let's evict it and add the new peer
if
bucket
.
remove
(
pc
.
Id
)
{
bucket
.
pushFront
(
&
p
eerInfo
{
p
,
lastSuccessfulOutboundQuery
,
ConvertPeerID
(
p
)})
bucket
.
pushFront
(
&
P
eerInfo
{
p
,
lastSuccessfulOutboundQuery
,
ConvertPeerID
(
p
)})
rt
.
PeerAdded
(
p
)
return
true
,
nil
}
...
...
@@ -166,7 +166,21 @@ func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) {
return
false
,
ErrPeerRejectedNoCapacity
}
// UpdateLastSuccessfulOutboundQuery updates the lastSuccessfulOutboundQuery time of the peer
// GetPeerInfos returns the peer information that we've stored in the buckets
func
(
rt
*
RoutingTable
)
GetPeerInfos
()
[]
PeerInfo
{
rt
.
tabLock
.
RLock
()
defer
rt
.
tabLock
.
RUnlock
()
var
pis
[]
PeerInfo
for
_
,
b
:=
range
rt
.
buckets
{
for
_
,
p
:=
range
b
.
peers
()
{
pis
=
append
(
pis
,
p
)
}
}
return
pis
}
// UpdateLastSuccessfulOutboundQuery updates the LastSuccessfulOutboundQuery time of the peer
// Returns true if the update was successful, false otherwise.
func
(
rt
*
RoutingTable
)
UpdateLastSuccessfulOutboundQuery
(
p
peer
.
ID
,
t
time
.
Time
)
bool
{
rt
.
tabLock
.
Lock
()
...
...
@@ -176,7 +190,7 @@ func (rt *RoutingTable) UpdateLastSuccessfulOutboundQuery(p peer.ID, t time.Time
bucket
:=
rt
.
buckets
[
bucketID
]
if
pc
:=
bucket
.
getPeer
(
p
);
pc
!=
nil
{
pc
.
l
astSuccessfulOutboundQuery
=
t
pc
.
L
astSuccessfulOutboundQuery
=
t
return
true
}
return
false
...
...
@@ -334,7 +348,7 @@ func (rt *RoutingTable) Print() {
fmt
.
Printf
(
"
\t
bucket: %d
\n
"
,
i
)
for
e
:=
b
.
list
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
e
.
Value
.
(
*
p
eerInfo
)
.
Id
p
:=
e
.
Value
.
(
*
P
eerInfo
)
.
Id
fmt
.
Printf
(
"
\t\t
- %s %s
\n
"
,
p
.
Pretty
(),
rt
.
metrics
.
LatencyEWMA
(
p
)
.
String
())
}
}
...
...
table_test.go
View file @
ee7b926e
...
...
@@ -33,7 +33,7 @@ func TestBucket(t *testing.T) {
peers
:=
make
([]
peer
.
ID
,
100
)
for
i
:=
0
;
i
<
100
;
i
++
{
peers
[
i
]
=
test
.
RandPeerIDFatal
(
t
)
b
.
pushFront
(
&
p
eerInfo
{
peers
[
i
],
testTime1
,
ConvertPeerID
(
peers
[
i
])})
b
.
pushFront
(
&
P
eerInfo
{
peers
[
i
],
testTime1
,
ConvertPeerID
(
peers
[
i
])})
}
local
:=
test
.
RandPeerIDFatal
(
t
)
...
...
@@ -47,19 +47,19 @@ func TestBucket(t *testing.T) {
require
.
NotNil
(
t
,
p
)
require
.
Equal
(
t
,
peers
[
i
],
p
.
Id
)
require
.
Equal
(
t
,
ConvertPeerID
(
peers
[
i
]),
p
.
dhtId
)
require
.
EqualValues
(
t
,
testTime1
,
p
.
l
astSuccessfulOutboundQuery
)
require
.
EqualValues
(
t
,
testTime1
,
p
.
L
astSuccessfulOutboundQuery
)
// mark as missing
t2
:=
time
.
Now
()
.
Add
(
1
*
time
.
Hour
)
p
.
l
astSuccessfulOutboundQuery
=
t2
p
.
L
astSuccessfulOutboundQuery
=
t2
p
=
b
.
getPeer
(
peers
[
i
])
require
.
NotNil
(
t
,
p
)
require
.
EqualValues
(
t
,
t2
,
p
.
l
astSuccessfulOutboundQuery
)
require
.
EqualValues
(
t
,
t2
,
p
.
L
astSuccessfulOutboundQuery
)
spl
:=
b
.
split
(
0
,
ConvertPeerID
(
local
))
llist
:=
b
.
list
for
e
:=
llist
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
ConvertPeerID
(
e
.
Value
.
(
*
p
eerInfo
)
.
Id
)
p
:=
ConvertPeerID
(
e
.
Value
.
(
*
P
eerInfo
)
.
Id
)
cpl
:=
CommonPrefixLen
(
p
,
localID
)
if
cpl
>
0
{
t
.
Fatalf
(
"split failed. found id with cpl > 0 in 0 bucket"
)
...
...
@@ -68,7 +68,7 @@ func TestBucket(t *testing.T) {
rlist
:=
spl
.
list
for
e
:=
rlist
.
Front
();
e
!=
nil
;
e
=
e
.
Next
()
{
p
:=
ConvertPeerID
(
e
.
Value
.
(
*
p
eerInfo
)
.
Id
)
p
:=
ConvertPeerID
(
e
.
Value
.
(
*
P
eerInfo
)
.
Id
)
cpl
:=
CommonPrefixLen
(
p
,
localID
)
if
cpl
==
0
{
t
.
Fatalf
(
"split failed. found id with cpl == 0 in non 0 bucket"
)
...
...
@@ -218,7 +218,7 @@ func TestUpdateLastSuccessfulOutboundQuery(t *testing.T) {
rt
.
tabLock
.
Lock
()
pi
:=
rt
.
buckets
[
0
]
.
getPeer
(
p
)
require
.
NotNil
(
t
,
pi
)
require
.
EqualValues
(
t
,
t2
,
pi
.
l
astSuccessfulOutboundQuery
)
require
.
EqualValues
(
t
,
t2
,
pi
.
L
astSuccessfulOutboundQuery
)
rt
.
tabLock
.
Unlock
()
}
...
...
@@ -257,7 +257,7 @@ func TestTryAddPeer(t *testing.T) {
require
.
True
(
t
,
b
)
require
.
Equal
(
t
,
p4
,
rt
.
Find
(
p4
))
// adding a peer with cpl 0 works if an existing peer has
l
astSuccessfulOutboundQuery above the max threshold
// adding a peer with cpl 0 works if an existing peer has
L
astSuccessfulOutboundQuery above the max threshold
// because that existing peer will get replaced
require
.
True
(
t
,
rt
.
UpdateLastSuccessfulOutboundQuery
(
p2
,
time
.
Now
()
.
AddDate
(
0
,
0
,
-
1
)))
b
,
err
=
rt
.
TryAddPeer
(
p3
,
true
)
...
...
@@ -285,7 +285,7 @@ func TestTryAddPeer(t *testing.T) {
rt
.
tabLock
.
Lock
()
pi
:=
rt
.
buckets
[
rt
.
bucketIdForPeer
(
p6
)]
.
getPeer
(
p6
)
require
.
NotNil
(
t
,
p6
)
require
.
True
(
t
,
pi
.
l
astSuccessfulOutboundQuery
.
IsZero
())
require
.
True
(
t
,
pi
.
L
astSuccessfulOutboundQuery
.
IsZero
())
rt
.
tabLock
.
Unlock
()
}
...
...
@@ -399,6 +399,37 @@ func TestTableMultithreaded(t *testing.T) {
<-
done
}
func
TestGetPeerInfos
(
t
*
testing
.
T
)
{
local
:=
test
.
RandPeerIDFatal
(
t
)
m
:=
pstore
.
NewMetrics
()
rt
,
err
:=
NewRoutingTable
(
10
,
ConvertPeerID
(
local
),
time
.
Hour
,
m
,
NoOpThreshold
)
require
.
NoError
(
t
,
err
)
require
.
Empty
(
t
,
rt
.
GetPeerInfos
())
p1
:=
test
.
RandPeerIDFatal
(
t
)
p2
:=
test
.
RandPeerIDFatal
(
t
)
b
,
err
:=
rt
.
TryAddPeer
(
p1
,
false
)
require
.
True
(
t
,
b
)
require
.
NoError
(
t
,
err
)
b
,
err
=
rt
.
TryAddPeer
(
p2
,
true
)
require
.
True
(
t
,
b
)
require
.
NoError
(
t
,
err
)
ps
:=
rt
.
GetPeerInfos
()
require
.
Len
(
t
,
ps
,
2
)
ms
:=
make
(
map
[
peer
.
ID
]
PeerInfo
)
for
_
,
p
:=
range
ps
{
ms
[
p
.
Id
]
=
p
}
require
.
Equal
(
t
,
p1
,
ms
[
p1
]
.
Id
)
require
.
True
(
t
,
ms
[
p1
]
.
LastSuccessfulOutboundQuery
.
IsZero
())
require
.
Equal
(
t
,
p2
,
ms
[
p2
]
.
Id
)
require
.
False
(
t
,
ms
[
p2
]
.
LastSuccessfulOutboundQuery
.
IsZero
())
}
func
BenchmarkAddPeer
(
b
*
testing
.
B
)
{
b
.
StopTimer
()
local
:=
ConvertKey
(
"localKey"
)
...
...
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