@@ -17,6 +17,7 @@ import (
17
17
"github.com/libp2p/go-libp2p/core/peer"
18
18
ma "github.com/multiformats/go-multiaddr"
19
19
mh "github.com/multiformats/go-multihash"
20
+ "go.opentelemetry.io/otel/metric"
20
21
21
22
"github.com/probe-lab/go-libdht/kad/key"
22
23
"github.com/probe-lab/go-libdht/kad/key/bit256"
@@ -67,9 +68,16 @@ type DHTProvider interface {
67
68
68
69
var _ DHTProvider = & SweepingProvider {}
69
70
70
- // maxPrefixSize is the maximum size of a prefix used to define a keyspace
71
- // region.
72
- const maxPrefixSize = 24
71
+ const (
72
+ // maxPrefixSize is the maximum size of a prefix used to define a keyspace
73
+ // region.
74
+ maxPrefixSize = 24
75
+ // individualProvideThreshold is the threshold for the number of keys to
76
+ // trigger a region exploration. If the number of keys to provide for a
77
+ // region is less or equal to the threshold, the keys will be individually
78
+ // provided.
79
+ individualProvideThreshold = 2
80
+ )
73
81
74
82
const loggerName = "dht/SweepingProvider"
75
83
@@ -127,12 +135,13 @@ type SweepingProvider struct {
127
135
msgSender pb.MessageSender
128
136
getSelfAddrs func () []ma.Multiaddr
129
137
addLocalRecord func (mh.Multihash ) error
138
+
139
+ provideCounter metric.Int64Counter
130
140
}
131
141
132
142
// FIXME: remove me
133
143
func (s * SweepingProvider ) SatisfyLinter () {
134
144
s .vanillaProvide ([]byte {})
135
- s .exploreSwarm ("" )
136
145
s .measureInitialPrefixLen ()
137
146
}
138
147
@@ -729,18 +738,108 @@ func (s *SweepingProvider) provideLoop() {
729
738
if ok {
730
739
go func (prefix bitstr.Key , keys []mh.Multihash ) {
731
740
defer s .workerPool .Release (burstWorker )
732
- s .provideForPrefix (prefix , keys )
741
+ s .batchProvide (prefix , keys )
733
742
}(prefix , keys )
734
743
} else {
735
744
s .workerPool .Release (burstWorker )
736
745
}
737
746
}
738
747
}
739
748
740
- func (s * SweepingProvider ) provideForPrefix (prefix bitstr.Key , keys []mh.Multihash ) {
749
+ func (s * SweepingProvider ) batchProvide (prefix bitstr.Key , keys []mh.Multihash ) {
750
+ if len (keys ) == 0 {
751
+ return
752
+ }
753
+ addrInfo , ok := s .selfAddrInfo ()
754
+ if ! ok {
755
+ // Don't provide if the node doesn't have a valid address to include in the
756
+ // provider record.
757
+ return
758
+ }
759
+ if len (keys ) <= individualProvideThreshold {
760
+ // Don't fully explore the region, execute simple DHT provides for these
761
+ // keys. It isn't worth it to fully explore a region for just a few keys.
762
+ s .individualProvide (prefix , keys , false , false )
763
+ return
764
+ }
765
+
766
+ regions , coveredPrefix , err := s .exploreSwarm (prefix )
767
+ if err != nil {
768
+ s .failedProvide (prefix , keys , fmt .Errorf ("reprovide '%s': %w" , prefix , err ))
769
+ return
770
+ }
771
+ logger .Debugf ("provide: requested prefix '%s' (len %d), prefix covered '%s' (len %d)" , prefix , len (prefix ), coveredPrefix , len (coveredPrefix ))
772
+
773
+ // Add any key matching the covered prefix from the provide queue to the
774
+ // current provide batch.
775
+ extraKeys := s .provideQueue .DequeueMatching (coveredPrefix )
776
+ keys = append (keys , extraKeys ... )
777
+ regions = keyspace .AssignKeysToRegions (regions , keys )
778
+
779
+ if ! s .provideRegions (regions , addrInfo ) {
780
+ logger .Errorf ("failed to reprovide any region for prefix %s" , prefix )
781
+ }
782
+ }
783
+
784
+ func (s * SweepingProvider ) failedProvide (prefix bitstr.Key , keys []mh.Multihash , err error ) {
785
+ logger .Error (err )
786
+ // Put keys back to the provide queue.
787
+ s .provideQueue .Enqueue (prefix , keys ... )
788
+
789
+ s .connectivity .TriggerCheck ()
790
+ }
791
+
792
+ // selfAddrInfo returns the current peer.AddrInfo to be used in the provider
793
+ // records sent to remote peers.
794
+ //
795
+ // If the node currently has no valid multiaddress, return an empty AddrInfo
796
+ // and false.
797
+ func (s * SweepingProvider ) selfAddrInfo () (peer.AddrInfo , bool ) {
798
+ addrs := s .getSelfAddrs ()
799
+ if len (addrs ) == 0 {
800
+ logger .Warn ("provider: no self addresses available for providing keys" )
801
+ return peer.AddrInfo {}, false
802
+ }
803
+ return peer.AddrInfo {ID : s .peerid , Addrs : addrs }, true
804
+ }
805
+
806
+ // individualProvide provides the keys sharing the same prefix to the network
807
+ // without exploring the associated keyspace regions. It performs "normal" DHT
808
+ // provides for the supplied keys, handles failures and schedules next
809
+ // reprovide is necessary.
810
+ func (s * SweepingProvider ) individualProvide (prefix bitstr.Key , keys []mh.Multihash , reprovide bool , periodicReprovide bool ) {
741
811
// TODO: implement me
742
812
}
743
813
814
+ // provideRegions contains common logic to batchProvide() and batchReprovide().
815
+ // It iterate over supplied regions, and allocates the regions provider records
816
+ // to the appropriate DHT servers.
817
+ func (s * SweepingProvider ) provideRegions (regions []keyspace.Region , addrInfo peer.AddrInfo ) bool {
818
+ errCount := 0
819
+ for _ , r := range regions {
820
+ nKeys := r .Keys .Size ()
821
+ if nKeys == 0 {
822
+ continue
823
+ }
824
+ // Add keys to local provider store
825
+ for _ , h := range keyspace .AllValues (r .Keys , s .order ) {
826
+ s .addLocalRecord (h )
827
+ }
828
+ keysAllocations := keyspace .AllocateToKClosest (r .Keys , r .Peers , s .replicationFactor )
829
+ err := s .sendProviderRecords (keysAllocations , addrInfo )
830
+ if err != nil {
831
+ errCount ++
832
+ err = fmt .Errorf ("cannot send provider records for region %s: %s" , r .Prefix , err )
833
+ s .failedProvide (r .Prefix , keyspace .AllValues (r .Keys , s .order ), err )
834
+ continue
835
+ }
836
+ s .provideCounter .Add (context .Background (), int64 (nKeys ))
837
+
838
+ }
839
+ // If at least 1 regions was provided, we don't consider it a failure.
840
+ return errCount < len (regions )
841
+ }
842
+
744
843
// ProvideOnce only sends provider records for the given keys out to the DHT
745
844
// swarm. It does NOT take the responsibility to reprovide these keys.
746
845
func (s * SweepingProvider ) ProvideOnce (keys ... mh.Multihash ) {
0 commit comments