From 509e9b4c3b60d666a608b86cff6c7fe77b7c76db Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 27 Feb 2020 18:06:05 +0530 Subject: [PATCH 1/5] export the Option type --- options.go | 16 ++++++++-------- table.go | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/options.go b/options.go index f2bbeaf..5beecf4 100644 --- a/options.go +++ b/options.go @@ -5,8 +5,8 @@ import ( "time" ) -// option is the Routing Table functional option type. -type option func(*options) error +// Option is the Routing Table functional option type. +type Option func(*options) error // options is a structure containing all the functional options that can be used when constructing a Routing Table. type options struct { @@ -19,7 +19,7 @@ type options struct { } // Apply applies the given options to this option. -func (o *options) Apply(opts ...option) error { +func (o *options) Apply(opts ...Option) error { for i, opt := range opts { if err := opt(o); err != nil { return fmt.Errorf("routing table option %d failed: %s", i, err) @@ -30,7 +30,7 @@ func (o *options) Apply(opts ...option) error { // PeerValidationFnc configures the Peer Validation function used for RT cleanup. // Not configuring this disables Routing Table cleanup. -func PeerValidationFnc(f PeerValidationFunc) option { +func PeerValidationFnc(f PeerValidationFunc) Option { return func(o *options) error { o.tableCleanup.peerValidationFnc = f return nil @@ -38,7 +38,7 @@ func PeerValidationFnc(f PeerValidationFunc) option { } // PeersForValidationFnc configures the function that will be used to select the peers that need to be validated during cleanup. -func PeersForValidationFnc(f PeerSelectionFunc) option { +func PeersForValidationFnc(f PeerSelectionFunc) Option { return func(o *options) error { o.tableCleanup.peersForValidationFnc = f return nil @@ -46,7 +46,7 @@ func PeersForValidationFnc(f PeerSelectionFunc) option { } // TableCleanupInterval configures the interval between two runs of the Routing Table cleanup routine. -func TableCleanupInterval(i time.Duration) option { +func TableCleanupInterval(i time.Duration) Option { return func(o *options) error { o.tableCleanup.interval = i return nil @@ -54,7 +54,7 @@ func TableCleanupInterval(i time.Duration) option { } // PeerValidationTimeout sets the timeout for a single peer validation during cleanup. -func PeerValidationTimeout(timeout time.Duration) option { +func PeerValidationTimeout(timeout time.Duration) Option { return func(o *options) error { o.tableCleanup.peerValidationTimeout = timeout return nil @@ -79,4 +79,4 @@ var Defaults = func(o *options) error { } return nil -} +} \ No newline at end of file diff --git a/table.go b/table.go index 0e1cfa9..13c1d18 100644 --- a/table.go +++ b/table.go @@ -87,10 +87,10 @@ type RoutingTable struct { // NewRoutingTable creates a new routing table with a given bucketsize, local ID, and latency tolerance. // Passing a nil PeerValidationFunc disables periodic table cleanup. func NewRoutingTable(bucketsize int, localID ID, latency time.Duration, m peerstore.Metrics, - opts ...option) (*RoutingTable, error) { + opts ...Option) (*RoutingTable, error) { var cfg options - if err := cfg.Apply(append([]option{Defaults}, opts...)...); err != nil { + if err := cfg.Apply(append([]Option{Defaults}, opts...)...); err != nil { return nil, err } From 1b4a7cbe7c7296ea8bf66ab85624189a09de3545 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 27 Feb 2020 19:24:26 +0530 Subject: [PATCH 2/5] fix error in Print --- table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/table.go b/table.go index 13c1d18..ca73763 100644 --- a/table.go +++ b/table.go @@ -459,7 +459,7 @@ func (rt *RoutingTable) Print() { fmt.Printf("\tbucket: %d\n", i) for e := b.list.Front(); e != nil; e = e.Next() { - p := e.Value.(peer.ID) + p := e.Value.(*PeerInfo).Id fmt.Printf("\t\t- %s %s\n", p.Pretty(), rt.metrics.LatencyEWMA(p).String()) } } From 552cb4a10f6bbfd78813bc03122d8e88ddc3e281 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 27 Feb 2020 19:26:09 +0530 Subject: [PATCH 3/5] go fmt --- options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options.go b/options.go index 5beecf4..c4aae83 100644 --- a/options.go +++ b/options.go @@ -79,4 +79,4 @@ var Defaults = func(o *options) error { } return nil -} \ No newline at end of file +} From 7dd9040cd7840bc10918de7710d819e25f0f670d Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 27 Feb 2020 21:26:01 +0530 Subject: [PATCH 4/5] bucket size fncs --- table.go | 28 ++++++++++++++++++++++++++++ table_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/table.go b/table.go index ca73763..27dcdaa 100644 --- a/table.go +++ b/table.go @@ -196,6 +196,34 @@ func (rt *RoutingTable) peersToValidate() []PeerInfo { return rt.peersForValidationFnc(peers) } +// NPeersForCPL returns the number of peers we have for a given Cpl +func (rt *RoutingTable) NPeersForCpl(cpl uint) int { + rt.tabLock.RLock() + defer rt.tabLock.RUnlock() + + // it's in the last bucket + if int(cpl) >= len(rt.buckets)-1 { + count := 0 + b := rt.buckets[len(rt.buckets)-1] + for _, p := range b.peerIds() { + if CommonPrefixLen(rt.local, ConvertPeerID(p)) == int(cpl) { + count++ + } + } + return count + } else { + return rt.buckets[cpl].len() + } +} + +// IsBucketFull returns true if the Logical bucket for a given Cpl is full +func (rt *RoutingTable) IsBucketFull(cpl uint) bool { + rt.tabLock.RLock() + defer rt.tabLock.RUnlock() + + return rt.NPeersForCpl(cpl) == rt.bucketsize +} + // GetTrackedCplsForRefresh returns the Cpl's we are tracking for refresh. // Caller is free to modify the returned slice as it is a defensive copy. func (rt *RoutingTable) GetTrackedCplsForRefresh() []CplRefresh { diff --git a/table_test.go b/table_test.go index c72d289..9d4d789 100644 --- a/table_test.go +++ b/table_test.go @@ -90,6 +90,42 @@ func TestGenRandPeerID(t *testing.T) { } } +func TestNPeersForCpl(t *testing.T) { + t.Parallel() + local := test.RandPeerIDFatal(t) + m := pstore.NewMetrics() + rt, err := NewRoutingTable(2, ConvertPeerID(local), time.Hour, m, PeerValidationFnc(PeerAlwaysValidFnc)) + require.NoError(t, err) + + require.Equal(t, 0, rt.NPeersForCpl(0)) + require.Equal(t, 0, rt.NPeersForCpl(1)) + + // one peer with cpl 1 + p, _ := rt.GenRandPeerID(1) + rt.HandlePeerAlive(p) + require.Equal(t, 0, rt.NPeersForCpl(0)) + require.Equal(t, 1, rt.NPeersForCpl(1)) + require.Equal(t, 0, rt.NPeersForCpl(2)) + + // one peer with cpl 0 + p, _ = rt.GenRandPeerID(0) + rt.HandlePeerAlive(p) + require.Equal(t, 1, rt.NPeersForCpl(0)) + require.Equal(t, 1, rt.NPeersForCpl(1)) + require.Equal(t, 0, rt.NPeersForCpl(2)) + + // split the bucket with a peer with cpl 1 + p, _ = rt.GenRandPeerID(1) + rt.HandlePeerAlive(p) + require.Equal(t, 1, rt.NPeersForCpl(0)) + require.Equal(t, 2, rt.NPeersForCpl(1)) + require.Equal(t, 0, rt.NPeersForCpl(2)) + + p, _ = rt.GenRandPeerID(0) + rt.HandlePeerAlive(p) + require.Equal(t, 2, rt.NPeersForCpl(0)) +} + func TestRefreshAndGetTrackedCpls(t *testing.T) { t.Parallel() local := test.RandPeerIDFatal(t) From c91e40808524752702144c20ea1e1ee6197e21c0 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Fri, 28 Feb 2020 13:07:57 +0530 Subject: [PATCH 5/5] changes as per review --- options.go | 4 ++-- table.go | 2 +- table_test.go | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/options.go b/options.go index c4aae83..23f699d 100644 --- a/options.go +++ b/options.go @@ -18,8 +18,8 @@ type options struct { } } -// Apply applies the given options to this option. -func (o *options) Apply(opts ...Option) error { +// apply applies the given options to this option. +func (o *options) apply(opts ...Option) error { for i, opt := range opts { if err := opt(o); err != nil { return fmt.Errorf("routing table option %d failed: %s", i, err) diff --git a/table.go b/table.go index 27dcdaa..7166ebc 100644 --- a/table.go +++ b/table.go @@ -90,7 +90,7 @@ func NewRoutingTable(bucketsize int, localID ID, latency time.Duration, m peerst opts ...Option) (*RoutingTable, error) { var cfg options - if err := cfg.Apply(append([]Option{Defaults}, opts...)...); err != nil { + if err := cfg.apply(append([]Option{Defaults}, opts...)...); err != nil { return nil, err } diff --git a/table_test.go b/table_test.go index 9d4d789..4318583 100644 --- a/table_test.go +++ b/table_test.go @@ -18,6 +18,15 @@ var PeerAlwaysValidFnc = func(ctx context.Context, p peer.ID) bool { return true } +func TestPrint(t *testing.T) { + t.Parallel() + local := test.RandPeerIDFatal(t) + m := pstore.NewMetrics() + rt, err := NewRoutingTable(1, ConvertPeerID(local), time.Hour, m, PeerValidationFnc(PeerAlwaysValidFnc)) + require.NoError(t, err) + rt.Print() +} + // Test basic features of the bucket struct func TestBucket(t *testing.T) { t.Parallel()