diff --git a/README.md b/README.md index 0a30098..540283f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# DEPRECATION NOTICE + +This package has moved into go-libp2p as a sub-package, `github.com/libp2p/go-libp2p/p2p/host/resource-manager`. + # The libp2p Network Resource Manager This package contains the canonical implementation of the libp2p diff --git a/allowlist.go b/allowlist.go index fd72af0..493f5b4 100644 --- a/allowlist.go +++ b/allowlist.go @@ -1,215 +1,16 @@ package rcmgr import ( - "bytes" - "errors" - "fmt" - "net" - "sync" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" - "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr/net" ) -type Allowlist struct { - mu sync.RWMutex - // a simple structure of lists of networks. There is probably a faster way - // to check if an IP address is in this network than iterating over this - // list, but this is good enough for small numbers of networks (<1_000). - // Analyze the benchmark before trying to optimize this. - - // Any peer with these IPs are allowed - allowedNetworks []*net.IPNet - - // Only the specified peers can use these IPs - allowedPeerByNetwork map[peer.ID][]*net.IPNet -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.Allowlist instead +type Allowlist = rcmgr.Allowlist // WithAllowlistedMultiaddrs sets the multiaddrs to be in the allowlist +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.WithAllowlistedMultiaddrs instead func WithAllowlistedMultiaddrs(mas []multiaddr.Multiaddr) Option { - return func(rm *resourceManager) error { - for _, ma := range mas { - err := rm.allowlist.Add(ma) - if err != nil { - return err - } - } - return nil - } -} - -func newAllowlist() Allowlist { - return Allowlist{ - allowedPeerByNetwork: make(map[peer.ID][]*net.IPNet), - } -} - -func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) { - var ipString string - var mask string - var allowedPeerStr string - var allowedPeer peer.ID - var isIPV4 bool - - multiaddr.ForEach(ma, func(c multiaddr.Component) bool { - if c.Protocol().Code == multiaddr.P_IP4 || c.Protocol().Code == multiaddr.P_IP6 { - isIPV4 = c.Protocol().Code == multiaddr.P_IP4 - ipString = c.Value() - } - if c.Protocol().Code == multiaddr.P_IPCIDR { - mask = c.Value() - } - if c.Protocol().Code == multiaddr.P_P2P { - allowedPeerStr = c.Value() - } - return ipString == "" || mask == "" || allowedPeerStr == "" - }) - - if ipString == "" { - return nil, allowedPeer, errors.New("missing ip address") - } - - if allowedPeerStr != "" { - var err error - allowedPeer, err = peer.Decode(allowedPeerStr) - if err != nil { - return nil, allowedPeer, fmt.Errorf("failed to decode allowed peer: %w", err) - } - } - - if mask == "" { - ip := net.ParseIP(ipString) - if ip == nil { - return nil, allowedPeer, errors.New("invalid ip address") - } - var mask net.IPMask - if isIPV4 { - mask = net.CIDRMask(32, 32) - } else { - mask = net.CIDRMask(128, 128) - } - - net := &net.IPNet{IP: ip, Mask: mask} - return net, allowedPeer, nil - } - - _, ipnet, err := net.ParseCIDR(ipString + "/" + mask) - return ipnet, allowedPeer, err - -} - -// Add takes a multiaddr and adds it to the allowlist. The multiaddr should be -// an ip address of the peer with or without a `/p2p` protocol. -// e.g. /ip4/1.2.3.4/p2p/QmFoo, /ip4/1.2.3.4, and /ip4/1.2.3.0/ipcidr/24 are valid. -// /p2p/QmFoo is not valid. -func (al *Allowlist) Add(ma multiaddr.Multiaddr) error { - ipnet, allowedPeer, err := toIPNet(ma) - if err != nil { - return err - } - al.mu.Lock() - defer al.mu.Unlock() - - if allowedPeer != peer.ID("") { - // We have a peerID constraint - if al.allowedPeerByNetwork == nil { - al.allowedPeerByNetwork = make(map[peer.ID][]*net.IPNet) - } - al.allowedPeerByNetwork[allowedPeer] = append(al.allowedPeerByNetwork[allowedPeer], ipnet) - } else { - al.allowedNetworks = append(al.allowedNetworks, ipnet) - } - return nil -} - -func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error { - ipnet, allowedPeer, err := toIPNet(ma) - if err != nil { - return err - } - al.mu.Lock() - defer al.mu.Unlock() - - ipNetList := al.allowedNetworks - - if allowedPeer != "" { - // We have a peerID constraint - ipNetList = al.allowedPeerByNetwork[allowedPeer] - } - - if ipNetList == nil { - return nil - } - - i := len(ipNetList) - for i > 0 { - i-- - if ipNetList[i].IP.Equal(ipnet.IP) && bytes.Equal(ipNetList[i].Mask, ipnet.Mask) { - // swap remove - ipNetList[i] = ipNetList[len(ipNetList)-1] - ipNetList = ipNetList[:len(ipNetList)-1] - // We only remove one thing - break - } - } - - if allowedPeer != "" { - al.allowedPeerByNetwork[allowedPeer] = ipNetList - } else { - al.allowedNetworks = ipNetList - } - - return nil -} - -func (al *Allowlist) Allowed(ma multiaddr.Multiaddr) bool { - ip, err := manet.ToIP(ma) - if err != nil { - return false - } - al.mu.RLock() - defer al.mu.RUnlock() - - for _, network := range al.allowedNetworks { - if network.Contains(ip) { - return true - } - } - - for _, allowedNetworks := range al.allowedPeerByNetwork { - for _, network := range allowedNetworks { - if network.Contains(ip) { - return true - } - } - } - - return false -} - -func (al *Allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multiaddr) bool { - ip, err := manet.ToIP(ma) - if err != nil { - return false - } - al.mu.RLock() - defer al.mu.RUnlock() - - for _, network := range al.allowedNetworks { - if network.Contains(ip) { - // We found a match that isn't constrained by a peerID - return true - } - } - - if expectedNetworks, ok := al.allowedPeerByNetwork[peerID]; ok { - for _, expectedNetwork := range expectedNetworks { - if expectedNetwork.Contains(ip) { - return true - } - } - } - - return false + return rcmgr.WithAllowlistedMultiaddrs(mas) } diff --git a/allowlist_test.go b/allowlist_test.go deleted file mode 100644 index 2e8ce3f..0000000 --- a/allowlist_test.go +++ /dev/null @@ -1,287 +0,0 @@ -package rcmgr - -import ( - "crypto/rand" - "fmt" - "net" - "testing" - - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/test" - "github.com/multiformats/go-multiaddr" -) - -func ExampleWithAllowlistedMultiaddrs() { - somePeer, err := test.RandPeerID() - if err != nil { - panic("Failed to generate somePeer") - } - - limits := DefaultLimits.AutoScale() - rcmgr, err := NewResourceManager(NewFixedLimiter(limits), WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{ - // Any peer connecting from this IP address - multiaddr.StringCast("/ip4/1.2.3.4"), - // Only the specified peer from this address - multiaddr.StringCast("/ip4/2.2.3.4/p2p/" + peer.Encode(somePeer)), - // Only peers from this 1.2.3.0/24 IP address range - multiaddr.StringCast("/ip4/1.2.3.0/ipcidr/24"), - })) - if err != nil { - panic("Failed to start resource manager") - } - - // Use rcmgr as before - _ = rcmgr -} - -func TestAllowedSimple(t *testing.T) { - allowlist := newAllowlist() - ma := multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234") - err := allowlist.Add(ma) - if err != nil { - t.Fatalf("failed to add ip4: %s", err) - } - - if !allowlist.Allowed(ma) { - t.Fatalf("addr should be allowed") - } -} - -func TestAllowedWithPeer(t *testing.T) { - type testcase struct { - name string - allowlist []string - endpoint multiaddr.Multiaddr - peer peer.ID - // Is this endpoint allowed? (We don't have peer info yet) - isConnAllowed bool - // Is this peer + endpoint allowed? - isAllowedWithPeer bool - } - - peerA := test.RandPeerIDFatal(t) - peerB := test.RandPeerIDFatal(t) - multiaddrA := multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234") - multiaddrB := multiaddr.StringCast("/ip4/2.2.3.4/tcp/1234") - - testcases := []testcase{ - { - name: "Blocked", - isConnAllowed: false, - isAllowedWithPeer: false, - allowlist: []string{"/ip4/1.2.3.1"}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "Blocked wrong peer", - isConnAllowed: true, - isAllowedWithPeer: false, - allowlist: []string{"/ip4/1.2.3.4" + "/p2p/" + peer.Encode(peerB)}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "allowed on network", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "Blocked peer not on network", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, - endpoint: multiaddrA, - peer: peerA, - }, { - name: "allowed. right network, right peer", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerA)}, - endpoint: multiaddrA, - peer: peerA, - }, { - name: "allowed. right network, no peer", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "Blocked. right network, wrong peer", - isConnAllowed: true, - isAllowedWithPeer: false, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerB)}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "allowed peer any ip", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/0.0.0.0/ipcidr/0"}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "allowed peer multiple ips in allowlist", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.4/p2p/" + peer.Encode(peerA), "/ip4/2.2.3.4/p2p/" + peer.Encode(peerA)}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "allowed peer multiple ips in allowlist", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.4/p2p/" + peer.Encode(peerA), "/ip4/1.2.3.4/p2p/" + peer.Encode(peerA)}, - endpoint: multiaddrA, - peer: peerA, - }, - { - name: "allowed peer multiple ips in allowlist", - isConnAllowed: true, - isAllowedWithPeer: true, - allowlist: []string{"/ip4/1.2.3.4/p2p/" + peer.Encode(peerA), "/ip4/2.2.3.4/p2p/" + peer.Encode(peerA)}, - endpoint: multiaddrB, - peer: peerA, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - allowlist := newAllowlist() - for _, maStr := range tc.allowlist { - ma, err := multiaddr.NewMultiaddr(maStr) - if err != nil { - fmt.Printf("failed to parse multiaddr: %s", err) - } - allowlist.Add(ma) - } - - if allowlist.Allowed(tc.endpoint) != tc.isConnAllowed { - t.Fatalf("%v: expected %v", !tc.isConnAllowed, tc.isConnAllowed) - } - - if allowlist.AllowedPeerAndMultiaddr(tc.peer, tc.endpoint) != tc.isAllowedWithPeer { - t.Fatalf("%v: expected %v", !tc.isAllowedWithPeer, tc.isAllowedWithPeer) - } - }) - } - -} - -func TestRemoved(t *testing.T) { - type testCase struct { - name string - allowedMA string - } - peerA := test.RandPeerIDFatal(t) - maA := multiaddr.StringCast("/ip4/1.2.3.4") - - testCases := []testCase{ - {name: "ip4", allowedMA: "/ip4/1.2.3.4"}, - {name: "ip4 with peer", allowedMA: "/ip4/1.2.3.4/p2p/" + peer.Encode(peerA)}, - {name: "ip4 network", allowedMA: "/ip4/0.0.0.0/ipcidr/0"}, - {name: "ip4 network with peer", allowedMA: "/ip4/0.0.0.0/ipcidr/0/p2p/" + peer.Encode(peerA)}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - allowlist := newAllowlist() - ma := multiaddr.StringCast(tc.allowedMA) - - err := allowlist.Add(ma) - if err != nil { - t.Fatalf("failed to add ip4: %s", err) - } - - if !allowlist.AllowedPeerAndMultiaddr(peerA, maA) { - t.Fatalf("addr should be allowed") - } - - allowlist.Remove((ma)) - - if allowlist.AllowedPeerAndMultiaddr(peerA, maA) { - t.Fatalf("addr should not be allowed") - } - }) - } -} - -// BenchmarkAllowlistCheck benchmarks the allowlist with plausible conditions. -func BenchmarkAllowlistCheck(b *testing.B) { - allowlist := newAllowlist() - - // How often do we expect a peer to be specified? 1 in N - ratioOfSpecifiedPeers := 10 - - // How often do we expect an allowlist hit? 1 in N - ratioOfAllowlistHit := 100 - - // How many multiaddrs in our allowlist? - howManyMultiaddrsInAllowList := 1_000 - - // How often is the IP addr an IPV6? 1 in N - ratioOfIPV6 := 20 - - countOfTotalPeersForTest := 100_000 - - mas := make([]multiaddr.Multiaddr, countOfTotalPeersForTest) - for i := 0; i < countOfTotalPeersForTest; i++ { - - ip := make([]byte, 16) - n, err := rand.Reader.Read(ip) - if err != nil || n != 16 { - b.Fatalf("Failed to generate IP address") - } - - var ipString string - - if i%ratioOfIPV6 == 0 { - // IPv6 - ip6 := net.IP(ip) - ipString = "/ip6/" + ip6.String() - } else { - // IPv4 - ip4 := net.IPv4(ip[0], ip[1], ip[2], ip[3]) - ipString = "/ip4/" + ip4.String() - } - - var ma multiaddr.Multiaddr - if i%ratioOfSpecifiedPeers == 0 { - ma = multiaddr.StringCast(ipString + "/p2p/" + peer.Encode(test.RandPeerIDFatal(b))) - } else { - ma = multiaddr.StringCast(ipString) - } - if err != nil { - b.Fatalf("Failed to generate multiaddr: %v", ipString) - } - - mas[i] = ma - } - - for _, ma := range mas[:howManyMultiaddrsInAllowList] { - err := allowlist.Add(ma) - if err != nil { - b.Fatalf("Failed to add multiaddr") - } - } - - masInAllowList := mas[:howManyMultiaddrsInAllowList] - masNotInAllowList := mas[howManyMultiaddrsInAllowList:] - - b.ResetTimer() - for n := 0; n < b.N; n++ { - if n%ratioOfAllowlistHit == 0 { - allowlist.Allowed(masInAllowList[n%len(masInAllowList)]) - } else { - allowlist.Allowed(masNotInAllowList[n%len(masNotInAllowList)]) - } - } -} diff --git a/docs/allowlist.md b/docs/allowlist.md deleted file mode 100644 index 4ada09c..0000000 --- a/docs/allowlist.md +++ /dev/null @@ -1,54 +0,0 @@ -# Allowlist - -Imagine you have a node that is getting overloaded by possibly malicious -incoming connections. This node won't be able to accept incoming connections -from peers it _knows_ to be good. This node would effectively be _eclipsed_ from -the network since no other nodes will be able to connect to it. - -This is the problem that the Allowlist is designed to solve. - -## Design Goals - -- We should not fail to allocate a resource for an allowlisted peer because the - normal transient and system scopes are at their limits. This is the minimum - bar to avoid eclipse attacks. -- Minimal changes to resource manager and existing code (e.g. go-libp2p). -- The allowlist scope itself is limited to avoid giving an allowlisted peer the - ability to DoS a node. -- PeerIDs can optionally be fed into the allowlist. This will give an extra - step of verification before continuing to allow the peer to open streams. - - A peer may be able to open a connection, but after the handshake, if it's - not an expected peer id we move it to the normal system scope. -- We can have multiple PeerIDs for a given IP addr. -- No extra cost for the happy path when we are still below system and transient - limits. - -## Proposed change - -Add a change to `ResourceManager.OpenConnection` so that it accepts a multiaddr -parameter of the endpoint the connection is for. - -Add a change to `ResourceManager` to initialize it with a set of allowlisted -multiaddrs. This set can be modified at runtime as well for dynamic updating. - -For example, an allowlist set could look like: -``` -/ip4/1.1.1.1 -/ip6/2345:0425:2CA1::0567:5673:23b5 -/ip4/192.168.1.1/p2p/qmFoo -/ip4/192.168.1.1/p2p/qmBar -/ip4/1.2.3.0/ipcidr/24 -``` - -When a new connection is opened, the resource manager tries to allocate with the -normal system and transient resource scopes. If that fails, it checks if the -multiaddr matches an item in the set of allowlisted multiaddrs. If so, it -creates the connection resource scope using the allowlisted specific system and -transient resource scopes. If it wasn't an allowlisted multiaddr it fails as -before. - -When an allowlisted connection is tied to a peer id and transfered with -`ConnManagementScope.SetPeer`, we check if that peer id matches the expected -value in the allowlist (if it exists). If it does not match, we attempt to -transfer this resource to the normal system and peer scope. If that transfer -fails we close the connection. diff --git a/error.go b/error.go deleted file mode 100644 index 1ccc86f..0000000 --- a/error.go +++ /dev/null @@ -1,81 +0,0 @@ -package rcmgr - -import ( - "errors" - - "github.com/libp2p/go-libp2p-core/network" -) - -type errStreamOrConnLimitExceeded struct { - current, attempted, limit int - err error -} - -func (e *errStreamOrConnLimitExceeded) Error() string { return e.err.Error() } -func (e *errStreamOrConnLimitExceeded) Unwrap() error { return e.err } - -// edge may be "" if this is not an edge error -func logValuesStreamLimit(scope, edge string, dir network.Direction, stat network.ScopeStat, err error) []interface{} { - logValues := make([]interface{}, 0, 2*8) - logValues = append(logValues, "scope", scope) - if edge != "" { - logValues = append(logValues, "edge", edge) - } - logValues = append(logValues, "direction", dir) - var e *errStreamOrConnLimitExceeded - if errors.As(err, &e) { - logValues = append(logValues, - "current", e.current, - "attempted", e.attempted, - "limit", e.limit, - ) - } - return append(logValues, "stat", stat, "error", err) -} - -// edge may be "" if this is not an edge error -func logValuesConnLimit(scope, edge string, dir network.Direction, usefd bool, stat network.ScopeStat, err error) []interface{} { - logValues := make([]interface{}, 0, 2*9) - logValues = append(logValues, "scope", scope) - if edge != "" { - logValues = append(logValues, "edge", edge) - } - logValues = append(logValues, "direction", dir, "usefd", usefd) - var e *errStreamOrConnLimitExceeded - if errors.As(err, &e) { - logValues = append(logValues, - "current", e.current, - "attempted", e.attempted, - "limit", e.limit, - ) - } - return append(logValues, "stat", stat, "error", err) -} - -type errMemoryLimitExceeded struct { - current, attempted, limit int64 - priority uint8 - err error -} - -func (e *errMemoryLimitExceeded) Error() string { return e.err.Error() } -func (e *errMemoryLimitExceeded) Unwrap() error { return e.err } - -// edge may be "" if this is not an edge error -func logValuesMemoryLimit(scope, edge string, stat network.ScopeStat, err error) []interface{} { - logValues := make([]interface{}, 0, 2*8) - logValues = append(logValues, "scope", scope) - if edge != "" { - logValues = append(logValues, "edge", edge) - } - var e *errMemoryLimitExceeded - if errors.As(err, &e) { - logValues = append(logValues, - "current", e.current, - "attempted", e.attempted, - "priority", e.priority, - "limit", e.limit, - ) - } - return append(logValues, "stat", stat, "error", err) -} diff --git a/extapi.go b/extapi.go index 92605c8..1bb69d9 100644 --- a/extapi.go +++ b/extapi.go @@ -1,147 +1,16 @@ package rcmgr import ( - "bytes" - "sort" - "strings" - - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) // ResourceScopeLimiter is a trait interface that allows you to access scope limits. -type ResourceScopeLimiter interface { - Limit() Limit - SetLimit(Limit) -} - -var _ ResourceScopeLimiter = (*resourceScope)(nil) - -// ResourceManagerStat is a trait that allows you to access resource manager state. -type ResourceManagerState interface { - ListServices() []string - ListProtocols() []protocol.ID - ListPeers() []peer.ID - - Stat() ResourceManagerStat -} - -type ResourceManagerStat struct { - System network.ScopeStat - Transient network.ScopeStat - Services map[string]network.ScopeStat - Protocols map[protocol.ID]network.ScopeStat - Peers map[peer.ID]network.ScopeStat -} - -var _ ResourceManagerState = (*resourceManager)(nil) - -func (s *resourceScope) Limit() Limit { - s.Lock() - defer s.Unlock() - - return s.rc.limit -} - -func (s *resourceScope) SetLimit(limit Limit) { - s.Lock() - defer s.Unlock() - - s.rc.limit = limit -} - -func (s *protocolScope) SetLimit(limit Limit) { - s.rcmgr.setStickyProtocol(s.proto) - s.resourceScope.SetLimit(limit) -} - -func (s *peerScope) SetLimit(limit Limit) { - s.rcmgr.setStickyPeer(s.peer) - s.resourceScope.SetLimit(limit) -} - -func (r *resourceManager) ListServices() []string { - r.mx.Lock() - defer r.mx.Unlock() - - result := make([]string, 0, len(r.svc)) - for svc := range r.svc { - result = append(result, svc) - } - - sort.Slice(result, func(i, j int) bool { - return strings.Compare(result[i], result[j]) < 0 - }) - - return result -} - -func (r *resourceManager) ListProtocols() []protocol.ID { - r.mx.Lock() - defer r.mx.Unlock() - - result := make([]protocol.ID, 0, len(r.proto)) - for p := range r.proto { - result = append(result, p) - } - - sort.Slice(result, func(i, j int) bool { - return strings.Compare(string(result[i]), string(result[j])) < 0 - }) - - return result -} - -func (r *resourceManager) ListPeers() []peer.ID { - r.mx.Lock() - defer r.mx.Unlock() - - result := make([]peer.ID, 0, len(r.peer)) - for p := range r.peer { - result = append(result, p) - } - - sort.Slice(result, func(i, j int) bool { - return bytes.Compare([]byte(result[i]), []byte(result[j])) < 0 - }) - - return result -} - -func (r *resourceManager) Stat() (result ResourceManagerStat) { - r.mx.Lock() - svcs := make([]*serviceScope, 0, len(r.svc)) - for _, svc := range r.svc { - svcs = append(svcs, svc) - } - protos := make([]*protocolScope, 0, len(r.proto)) - for _, proto := range r.proto { - protos = append(protos, proto) - } - peers := make([]*peerScope, 0, len(r.peer)) - for _, peer := range r.peer { - peers = append(peers, peer) - } - r.mx.Unlock() +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ResourceScopeLimiter instead +type ResourceScopeLimiter = rcmgr.ResourceScopeLimiter - // Note: there is no global lock, so the system is updating while we are dumping its state... - // as such stats might not exactly add up to the system level; we take the system stat - // last nonetheless so that this is the most up-to-date snapshot - result.Peers = make(map[peer.ID]network.ScopeStat, len(peers)) - for _, peer := range peers { - result.Peers[peer.peer] = peer.Stat() - } - result.Protocols = make(map[protocol.ID]network.ScopeStat, len(protos)) - for _, proto := range protos { - result.Protocols[proto.proto] = proto.Stat() - } - result.Services = make(map[string]network.ScopeStat, len(svcs)) - for _, svc := range svcs { - result.Services[svc.service] = svc.Stat() - } - result.Transient = r.transient.Stat() - result.System = r.system.Stat() +// ResourceManagerState is a trait that allows you to access resource manager state. +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ResourceManagerState instead +type ResourceManagerState = rcmgr.ResourceManagerState - return result -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ResourceManagerStat instead +type ResourceManagerStat = rcmgr.ResourceManagerStat diff --git a/go.mod b/go.mod index 047a6df..a81414d 100644 --- a/go.mod +++ b/go.mod @@ -3,41 +3,37 @@ module github.com/libp2p/go-libp2p-resource-manager go 1.17 require ( - github.com/ipfs/go-log/v2 v2.5.1 - github.com/libp2p/go-libp2p-core v0.19.0 + github.com/libp2p/go-libp2p v0.22.0 github.com/multiformats/go-multiaddr v0.6.0 - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 - github.com/stretchr/testify v1.8.0 - go.opencensus.io v0.23.0 - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c ) require ( - github.com/btcsuite/btcd v0.22.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/gogo/protobuf v1.3.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/ipfs/go-cid v0.2.0 // indirect - github.com/klauspost/cpuid/v2 v2.0.4 // indirect - github.com/libp2p/go-buffer-pool v0.0.2 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/klauspost/cpuid/v2 v2.1.0 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/libp2p/go-openssl v0.1.0 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-pointer v0.0.1 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base32 v0.0.4 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multicodec v0.4.1 // indirect - github.com/multiformats/go-multihash v0.0.15 // indirect + github.com/multiformats/go-multibase v0.1.1 // indirect + github.com/multiformats/go-multicodec v0.5.0 // indirect + github.com/multiformats/go-multihash v0.2.1 // indirect github.com/multiformats/go-varint v0.0.6 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.19.1 // indirect - golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + go.opencensus.io v0.23.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.22.0 // indirect + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + lukechampine.com/blake3 v1.1.7 // indirect ) diff --git a/go.sum b/go.sum index 7205f7d..addb0c2 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,66 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= @@ -21,207 +72,801 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= +github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= +github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek= +github.com/ipfs/go-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= +github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p-core v0.19.0 h1:KDw7hanmh0EuVdZqsHCAzmkdiYMk5uR5h0UGSCVTxSU= +github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= +github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= +github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= +github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= github.com/libp2p/go-libp2p-core v0.19.0/go.mod h1:AkA+FUKQfYt1FLNef5fOPlo/naAWjKy/RCjkcPjqzYg= +github.com/libp2p/go-libp2p-testing v0.11.0/go.mod h1:qG4sF27dfKFoK9KlVzK2y52LQKhp0VEmLjV5aDqr1Hg= +github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= +github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= +github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= +github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= +github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= +github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= +github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= +github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= +github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= +github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= +github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= +github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= +github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= +github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= +github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg= github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4= +github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= +github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= +github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= +github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= +github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= +github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= +go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -231,18 +876,45 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= +lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/limit.go b/limit.go index 21dffb7..e836c68 100644 --- a/limit.go +++ b/limit.go @@ -10,255 +10,41 @@ allocating the resource. package rcmgr import ( - "encoding/json" "io" - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) // Limit is an object that specifies basic resource limits. -type Limit interface { - // GetMemoryLimit returns the (current) memory limit. - GetMemoryLimit() int64 - // GetStreamLimit returns the stream limit, for inbound or outbound streams. - GetStreamLimit(network.Direction) int - // GetStreamTotalLimit returns the total stream limit - GetStreamTotalLimit() int - // GetConnLimit returns the connection limit, for inbound or outbound connections. - GetConnLimit(network.Direction) int - // GetConnTotalLimit returns the total connection limit - GetConnTotalLimit() int - // GetFDLimit returns the file descriptor limit. - GetFDLimit() int -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.Limit instead +type Limit = rcmgr.Limit // Limiter is the interface for providing limits to the resource manager. -type Limiter interface { - GetSystemLimits() Limit - GetTransientLimits() Limit - GetAllowlistedSystemLimits() Limit - GetAllowlistedTransientLimits() Limit - GetServiceLimits(svc string) Limit - GetServicePeerLimits(svc string) Limit - GetProtocolLimits(proto protocol.ID) Limit - GetProtocolPeerLimits(proto protocol.ID) Limit - GetPeerLimits(p peer.ID) Limit - GetStreamLimits(p peer.ID) Limit - GetConnLimits() Limit -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.Limiter instead +type Limiter = rcmgr.Limiter // NewDefaultLimiterFromJSON creates a new limiter by parsing a json configuration, // using the default limits for fallback. +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.NewDefaultLimiterFromJSON instead func NewDefaultLimiterFromJSON(in io.Reader) (Limiter, error) { - return NewLimiterFromJSON(in, DefaultLimits.AutoScale()) + return rcmgr.NewDefaultLimiterFromJSON(in) } // NewLimiterFromJSON creates a new limiter by parsing a json configuration. +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.NewLimiterFromJSON instead func NewLimiterFromJSON(in io.Reader, defaults LimitConfig) (Limiter, error) { - cfg, err := readLimiterConfigFromJSON(in, defaults) - if err != nil { - return nil, err - } - return &fixedLimiter{cfg}, nil -} - -func readLimiterConfigFromJSON(in io.Reader, defaults LimitConfig) (LimitConfig, error) { - var cfg LimitConfig - if err := json.NewDecoder(in).Decode(&cfg); err != nil { - return LimitConfig{}, err - } - cfg.Apply(defaults) - return cfg, nil -} - -// fixedLimiter is a limiter with fixed limits. -type fixedLimiter struct { - LimitConfig + return rcmgr.NewLimiterFromJSON(in, defaults) } -var _ Limiter = (*fixedLimiter)(nil) - +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.NewFixedLimiter instead func NewFixedLimiter(conf LimitConfig) Limiter { - log.Debugw("initializing new limiter with config", "limits", conf) - return &fixedLimiter{LimitConfig: conf} + return rcmgr.NewFixedLimiter(conf) } // BaseLimit is a mixin type for basic resource limits. -type BaseLimit struct { - Streams int - StreamsInbound int - StreamsOutbound int - Conns int - ConnsInbound int - ConnsOutbound int - FD int - Memory int64 -} - -// Apply overwrites all zero-valued limits with the values of l2 -// Must not use a pointer receiver. -func (l *BaseLimit) Apply(l2 BaseLimit) { - if l.Streams == 0 { - l.Streams = l2.Streams - } - if l.StreamsInbound == 0 { - l.StreamsInbound = l2.StreamsInbound - } - if l.StreamsOutbound == 0 { - l.StreamsOutbound = l2.StreamsOutbound - } - if l.Conns == 0 { - l.Conns = l2.Conns - } - if l.ConnsInbound == 0 { - l.ConnsInbound = l2.ConnsInbound - } - if l.ConnsOutbound == 0 { - l.ConnsOutbound = l2.ConnsOutbound - } - if l.Memory == 0 { - l.Memory = l2.Memory - } - if l.FD == 0 { - l.FD = l2.FD - } -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.BaseLimit instead +type BaseLimit = rcmgr.BaseLimit // BaseLimitIncrease is the increase per GB of system memory. -type BaseLimitIncrease struct { - Streams int - StreamsInbound int - StreamsOutbound int - Conns int - ConnsInbound int - ConnsOutbound int - Memory int64 - FDFraction float64 -} - -// Apply overwrites all zero-valued limits with the values of l2 -// Must not use a pointer receiver. -func (l *BaseLimitIncrease) Apply(l2 BaseLimitIncrease) { - if l.Streams == 0 { - l.Streams = l2.Streams - } - if l.StreamsInbound == 0 { - l.StreamsInbound = l2.StreamsInbound - } - if l.StreamsOutbound == 0 { - l.StreamsOutbound = l2.StreamsOutbound - } - if l.Conns == 0 { - l.Conns = l2.Conns - } - if l.ConnsInbound == 0 { - l.ConnsInbound = l2.ConnsInbound - } - if l.ConnsOutbound == 0 { - l.ConnsOutbound = l2.ConnsOutbound - } - if l.Memory == 0 { - l.Memory = l2.Memory - } - if l.FDFraction == 0 { - l.FDFraction = l2.FDFraction - } -} - -func (l *BaseLimit) GetStreamLimit(dir network.Direction) int { - if dir == network.DirInbound { - return l.StreamsInbound - } else { - return l.StreamsOutbound - } -} - -func (l *BaseLimit) GetStreamTotalLimit() int { - return l.Streams -} - -func (l *BaseLimit) GetConnLimit(dir network.Direction) int { - if dir == network.DirInbound { - return l.ConnsInbound - } else { - return l.ConnsOutbound - } -} - -func (l *BaseLimit) GetConnTotalLimit() int { - return l.Conns -} - -func (l *BaseLimit) GetFDLimit() int { - return l.FD -} - -func (l *BaseLimit) GetMemoryLimit() int64 { - return l.Memory -} - -func (l *fixedLimiter) GetSystemLimits() Limit { - return &l.System -} - -func (l *fixedLimiter) GetTransientLimits() Limit { - return &l.Transient -} - -func (l *fixedLimiter) GetAllowlistedSystemLimits() Limit { - return &l.AllowlistedSystem -} - -func (l *fixedLimiter) GetAllowlistedTransientLimits() Limit { - return &l.AllowlistedTransient -} - -func (l *fixedLimiter) GetServiceLimits(svc string) Limit { - sl, ok := l.Service[svc] - if !ok { - return &l.ServiceDefault - } - return &sl -} - -func (l *fixedLimiter) GetServicePeerLimits(svc string) Limit { - pl, ok := l.ServicePeer[svc] - if !ok { - return &l.ServicePeerDefault - } - return &pl -} - -func (l *fixedLimiter) GetProtocolLimits(proto protocol.ID) Limit { - pl, ok := l.Protocol[proto] - if !ok { - return &l.ProtocolDefault - } - return &pl -} - -func (l *fixedLimiter) GetProtocolPeerLimits(proto protocol.ID) Limit { - pl, ok := l.ProtocolPeer[proto] - if !ok { - return &l.ProtocolPeerDefault - } - return &pl -} - -func (l *fixedLimiter) GetPeerLimits(p peer.ID) Limit { - pl, ok := l.Peer[p] - if !ok { - return &l.PeerDefault - } - return &pl -} - -func (l *fixedLimiter) GetStreamLimits(_ peer.ID) Limit { - return &l.Stream -} - -func (l *fixedLimiter) GetConnLimits() Limit { - return &l.Conn -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.BaseLimitIncrease instead +type BaseLimitIncrease = rcmgr.BaseLimitIncrease diff --git a/limit_config_test.go b/limit_config_test.go deleted file mode 100644 index 1330d4b..0000000 --- a/limit_config_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package rcmgr - -import ( - "bytes" - "encoding/json" - "os" - "testing" - - "github.com/libp2p/go-libp2p-core/peer" - - "github.com/stretchr/testify/require" -) - -func withMemoryLimit(l BaseLimit, m int64) BaseLimit { - l2 := l - l2.Memory = m - return l2 -} - -func TestLimitConfigParser(t *testing.T) { - in, err := os.Open("limit_config_test.json") - require.NoError(t, err) - defer in.Close() - - DefaultLimits.AddServiceLimit("C", DefaultLimits.ServiceBaseLimit, BaseLimitIncrease{}) - DefaultLimits.AddProtocolPeerLimit("C", DefaultLimits.ServiceBaseLimit, BaseLimitIncrease{}) - defaults := DefaultLimits.AutoScale() - cfg, err := readLimiterConfigFromJSON(in, defaults) - require.NoError(t, err) - - require.Equal(t, int64(65536), cfg.System.Memory) - require.Equal(t, defaults.System.Streams, cfg.System.Streams) - require.Equal(t, defaults.System.StreamsInbound, cfg.System.StreamsInbound) - require.Equal(t, defaults.System.StreamsOutbound, cfg.System.StreamsOutbound) - require.Equal(t, 16, cfg.System.Conns) - require.Equal(t, 8, cfg.System.ConnsInbound) - require.Equal(t, 16, cfg.System.ConnsOutbound) - require.Equal(t, 16, cfg.System.FD) - - require.Equal(t, defaults.Transient, cfg.Transient) - require.Equal(t, int64(8765), cfg.ServiceDefault.Memory) - - require.Contains(t, cfg.Service, "A") - require.Equal(t, withMemoryLimit(cfg.ServiceDefault, 8192), cfg.Service["A"]) - require.Contains(t, cfg.Service, "B") - require.Equal(t, cfg.ServiceDefault, cfg.Service["B"]) - require.Contains(t, cfg.Service, "C") - require.Equal(t, defaults.Service["C"], cfg.Service["C"]) - - require.Equal(t, int64(4096), cfg.PeerDefault.Memory) - peerID, err := peer.Decode("12D3KooWPFH2Bx2tPfw6RLxN8k2wh47GRXgkt9yrAHU37zFwHWzS") - require.NoError(t, err) - require.Contains(t, cfg.Peer, peerID) - require.Equal(t, int64(4097), cfg.Peer[peerID].Memory) - - // Roundtrip - jsonBytes, err := json.Marshal(&cfg) - require.NoError(t, err) - cfgAfterRoundTrip, err := readLimiterConfigFromJSON(bytes.NewReader(jsonBytes), defaults) - require.NoError(t, err) - require.Equal(t, cfg, cfgAfterRoundTrip) -} diff --git a/limit_config_test.json b/limit_config_test.json deleted file mode 100644 index b7758ba..0000000 --- a/limit_config_test.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "System": { - "Memory": 65536, - "Conns": 16, - "ConnsInbound": 8, - "ConnsOutbound": 16, - "FD": 16 - }, - "ServiceDefault": { - "Memory": 8765 - }, - "Service": { - "A": { - "Memory": 8192 - }, - "B": {} - }, - "ServicePeerDefault": { - "Memory": 2048 - }, - "ServicePeer": { - "A": { - "Memory": 4096 - } - }, - "ProtocolDefault": { - "Memory": 2048 - }, - "ProtocolPeerDefault": { - "Memory": 1024 - }, - "Protocol": { - "/A": { - "Memory": 8192 - } - }, - "PeerDefault": { - "Memory": 4096 - }, - "Peer": { - "12D3KooWPFH2Bx2tPfw6RLxN8k2wh47GRXgkt9yrAHU37zFwHWzS": { - "Memory": 4097 - } - } -} diff --git a/limit_defaults.go b/limit_defaults.go index bb10b7c..814df23 100644 --- a/limit_defaults.go +++ b/limit_defaults.go @@ -1,548 +1,23 @@ package rcmgr import ( - "encoding/json" - "math" - - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/protocol" - - "github.com/pbnjay/memory" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) -type baseLimitConfig struct { - BaseLimit BaseLimit - BaseLimitIncrease BaseLimitIncrease -} - // ScalingLimitConfig is a struct for configuring default limits. // {}BaseLimit is the limits that Apply for a minimal node (128 MB of memory for libp2p) and 256 file descriptors. // {}LimitIncrease is the additional limit granted for every additional 1 GB of RAM. -type ScalingLimitConfig struct { - SystemBaseLimit BaseLimit - SystemLimitIncrease BaseLimitIncrease - - TransientBaseLimit BaseLimit - TransientLimitIncrease BaseLimitIncrease - - AllowlistedSystemBaseLimit BaseLimit - AllowlistedSystemLimitIncrease BaseLimitIncrease - - AllowlistedTransientBaseLimit BaseLimit - AllowlistedTransientLimitIncrease BaseLimitIncrease - - ServiceBaseLimit BaseLimit - ServiceLimitIncrease BaseLimitIncrease - ServiceLimits map[string]baseLimitConfig // use AddServiceLimit to modify - - ServicePeerBaseLimit BaseLimit - ServicePeerLimitIncrease BaseLimitIncrease - ServicePeerLimits map[string]baseLimitConfig // use AddServicePeerLimit to modify - - ProtocolBaseLimit BaseLimit - ProtocolLimitIncrease BaseLimitIncrease - ProtocolLimits map[protocol.ID]baseLimitConfig // use AddProtocolLimit to modify - - ProtocolPeerBaseLimit BaseLimit - ProtocolPeerLimitIncrease BaseLimitIncrease - ProtocolPeerLimits map[protocol.ID]baseLimitConfig // use AddProtocolPeerLimit to modify - - PeerBaseLimit BaseLimit - PeerLimitIncrease BaseLimitIncrease - PeerLimits map[peer.ID]baseLimitConfig // use AddPeerLimit to modify - - ConnBaseLimit BaseLimit - ConnLimitIncrease BaseLimitIncrease - - StreamBaseLimit BaseLimit - StreamLimitIncrease BaseLimitIncrease -} - -func (cfg *ScalingLimitConfig) AddServiceLimit(svc string, base BaseLimit, inc BaseLimitIncrease) { - if cfg.ServiceLimits == nil { - cfg.ServiceLimits = make(map[string]baseLimitConfig) - } - cfg.ServiceLimits[svc] = baseLimitConfig{ - BaseLimit: base, - BaseLimitIncrease: inc, - } -} - -func (cfg *ScalingLimitConfig) AddProtocolLimit(proto protocol.ID, base BaseLimit, inc BaseLimitIncrease) { - if cfg.ProtocolLimits == nil { - cfg.ProtocolLimits = make(map[protocol.ID]baseLimitConfig) - } - cfg.ProtocolLimits[proto] = baseLimitConfig{ - BaseLimit: base, - BaseLimitIncrease: inc, - } -} - -func (cfg *ScalingLimitConfig) AddPeerLimit(p peer.ID, base BaseLimit, inc BaseLimitIncrease) { - if cfg.PeerLimits == nil { - cfg.PeerLimits = make(map[peer.ID]baseLimitConfig) - } - cfg.PeerLimits[p] = baseLimitConfig{ - BaseLimit: base, - BaseLimitIncrease: inc, - } -} - -func (cfg *ScalingLimitConfig) AddServicePeerLimit(svc string, base BaseLimit, inc BaseLimitIncrease) { - if cfg.ServicePeerLimits == nil { - cfg.ServicePeerLimits = make(map[string]baseLimitConfig) - } - cfg.ServicePeerLimits[svc] = baseLimitConfig{ - BaseLimit: base, - BaseLimitIncrease: inc, - } -} - -func (cfg *ScalingLimitConfig) AddProtocolPeerLimit(proto protocol.ID, base BaseLimit, inc BaseLimitIncrease) { - if cfg.ProtocolPeerLimits == nil { - cfg.ProtocolPeerLimits = make(map[protocol.ID]baseLimitConfig) - } - cfg.ProtocolPeerLimits[proto] = baseLimitConfig{ - BaseLimit: base, - BaseLimitIncrease: inc, - } -} - -type LimitConfig struct { - System BaseLimit `json:",omitempty"` - Transient BaseLimit `json:",omitempty"` - - // Limits that are applied to resources with an allowlisted multiaddr. - // These will only be used if the normal System & Transient limits are - // reached. - AllowlistedSystem BaseLimit `json:",omitempty"` - AllowlistedTransient BaseLimit `json:",omitempty"` - - ServiceDefault BaseLimit `json:",omitempty"` - Service map[string]BaseLimit `json:",omitempty"` - - ServicePeerDefault BaseLimit `json:",omitempty"` - ServicePeer map[string]BaseLimit `json:",omitempty"` - - ProtocolDefault BaseLimit `json:",omitempty"` - Protocol map[protocol.ID]BaseLimit `json:",omitempty"` - - ProtocolPeerDefault BaseLimit `json:",omitempty"` - ProtocolPeer map[protocol.ID]BaseLimit `json:",omitempty"` - - PeerDefault BaseLimit `json:",omitempty"` - Peer map[peer.ID]BaseLimit `json:",omitempty"` - - Conn BaseLimit `json:",omitempty"` - Stream BaseLimit `json:",omitempty"` -} - -func (cfg *LimitConfig) MarshalJSON() ([]byte, error) { - // we want to marshal the encoded peer id - encodedPeerMap := make(map[string]BaseLimit, len(cfg.Peer)) - for p, v := range cfg.Peer { - encodedPeerMap[peer.Encode(p)] = v - } - - type Alias LimitConfig - return json.Marshal(&struct { - *Alias - Peer map[string]BaseLimit `json:",omitempty"` - }{ - Alias: (*Alias)(cfg), - Peer: encodedPeerMap, - }) -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ScalingLimitConfig instead +type ScalingLimitConfig = rcmgr.ScalingLimitConfig -func (cfg *LimitConfig) Apply(c LimitConfig) { - cfg.System.Apply(c.System) - cfg.Transient.Apply(c.Transient) - cfg.AllowlistedSystem.Apply(c.AllowlistedSystem) - cfg.AllowlistedTransient.Apply(c.AllowlistedTransient) - cfg.ServiceDefault.Apply(c.ServiceDefault) - cfg.ProtocolDefault.Apply(c.ProtocolDefault) - cfg.ProtocolPeerDefault.Apply(c.ProtocolPeerDefault) - cfg.PeerDefault.Apply(c.PeerDefault) - cfg.Conn.Apply(c.Conn) - cfg.Stream.Apply(c.Stream) - - // TODO: the following could be solved a lot nicer, if only we could use generics - for s, l := range cfg.Service { - r := cfg.ServiceDefault - if l2, ok := c.Service[s]; ok { - r = l2 - } - l.Apply(r) - cfg.Service[s] = l - } - if c.Service != nil && cfg.Service == nil { - cfg.Service = make(map[string]BaseLimit) - } - for s, l := range c.Service { - if _, ok := cfg.Service[s]; !ok { - cfg.Service[s] = l - } - } - - for s, l := range cfg.ServicePeer { - r := cfg.ServicePeerDefault - if l2, ok := c.ServicePeer[s]; ok { - r = l2 - } - l.Apply(r) - cfg.ServicePeer[s] = l - } - if c.ServicePeer != nil && cfg.ServicePeer == nil { - cfg.ServicePeer = make(map[string]BaseLimit) - } - for s, l := range c.ServicePeer { - if _, ok := cfg.ServicePeer[s]; !ok { - cfg.ServicePeer[s] = l - } - } - - for s, l := range cfg.Protocol { - r := cfg.ProtocolDefault - if l2, ok := c.Protocol[s]; ok { - r = l2 - } - l.Apply(r) - cfg.Protocol[s] = l - } - if c.Protocol != nil && cfg.Protocol == nil { - cfg.Protocol = make(map[protocol.ID]BaseLimit) - } - for s, l := range c.Protocol { - if _, ok := cfg.Protocol[s]; !ok { - cfg.Protocol[s] = l - } - } - - for s, l := range cfg.ProtocolPeer { - r := cfg.ProtocolPeerDefault - if l2, ok := c.ProtocolPeer[s]; ok { - r = l2 - } - l.Apply(r) - cfg.ProtocolPeer[s] = l - } - if c.ProtocolPeer != nil && cfg.ProtocolPeer == nil { - cfg.ProtocolPeer = make(map[protocol.ID]BaseLimit) - } - for s, l := range c.ProtocolPeer { - if _, ok := cfg.ProtocolPeer[s]; !ok { - cfg.ProtocolPeer[s] = l - } - } - - for s, l := range cfg.Peer { - r := cfg.PeerDefault - if l2, ok := c.Peer[s]; ok { - r = l2 - } - l.Apply(r) - cfg.Peer[s] = l - } - if c.Peer != nil && cfg.Peer == nil { - cfg.Peer = make(map[peer.ID]BaseLimit) - } - for s, l := range c.Peer { - if _, ok := cfg.Peer[s]; !ok { - cfg.Peer[s] = l - } - } -} - -// Scale scales up a limit configuration. -// memory is the amount of memory that the stack is allowed to consume, -// for a full it's recommended to use 1/8 of the installed system memory. -// If memory is smaller than 128 MB, the base configuration will be used. -// -func (cfg *ScalingLimitConfig) Scale(memory int64, numFD int) LimitConfig { - var scaleFactor int - if memory > 128<<20 { - scaleFactor = int((memory - 128<<20) >> 20) - } - lc := LimitConfig{ - System: scale(cfg.SystemBaseLimit, cfg.SystemLimitIncrease, scaleFactor, numFD), - Transient: scale(cfg.TransientBaseLimit, cfg.TransientLimitIncrease, scaleFactor, numFD), - AllowlistedSystem: scale(cfg.AllowlistedSystemBaseLimit, cfg.AllowlistedSystemLimitIncrease, scaleFactor, numFD), - AllowlistedTransient: scale(cfg.AllowlistedTransientBaseLimit, cfg.AllowlistedTransientLimitIncrease, scaleFactor, numFD), - ServiceDefault: scale(cfg.ServiceBaseLimit, cfg.ServiceLimitIncrease, scaleFactor, numFD), - ServicePeerDefault: scale(cfg.ServicePeerBaseLimit, cfg.ServicePeerLimitIncrease, scaleFactor, numFD), - ProtocolDefault: scale(cfg.ProtocolBaseLimit, cfg.ProtocolLimitIncrease, scaleFactor, numFD), - ProtocolPeerDefault: scale(cfg.ProtocolPeerBaseLimit, cfg.ProtocolPeerLimitIncrease, scaleFactor, numFD), - PeerDefault: scale(cfg.PeerBaseLimit, cfg.PeerLimitIncrease, scaleFactor, numFD), - Conn: scale(cfg.ConnBaseLimit, cfg.ConnLimitIncrease, scaleFactor, numFD), - Stream: scale(cfg.StreamBaseLimit, cfg.ConnLimitIncrease, scaleFactor, numFD), - } - if cfg.ServiceLimits != nil { - lc.Service = make(map[string]BaseLimit) - for svc, l := range cfg.ServiceLimits { - lc.Service[svc] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD) - } - } - if cfg.ProtocolLimits != nil { - lc.Protocol = make(map[protocol.ID]BaseLimit) - for proto, l := range cfg.ProtocolLimits { - lc.Protocol[proto] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD) - } - } - if cfg.PeerLimits != nil { - lc.Peer = make(map[peer.ID]BaseLimit) - for p, l := range cfg.PeerLimits { - lc.Peer[p] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD) - } - } - if cfg.ServicePeerLimits != nil { - lc.ServicePeer = make(map[string]BaseLimit) - for svc, l := range cfg.ServicePeerLimits { - lc.ServicePeer[svc] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD) - } - } - if cfg.ProtocolPeerLimits != nil { - lc.ProtocolPeer = make(map[protocol.ID]BaseLimit) - for p, l := range cfg.ProtocolPeerLimits { - lc.ProtocolPeer[p] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD) - } - } - return lc -} - -func (cfg *ScalingLimitConfig) AutoScale() LimitConfig { - return cfg.Scale( - int64(memory.TotalMemory())/8, - getNumFDs()/2, - ) -} - -// factor is the number of MBs above the minimum (128 MB) -func scale(base BaseLimit, inc BaseLimitIncrease, factor int, numFD int) BaseLimit { - l := BaseLimit{ - StreamsInbound: base.StreamsInbound + (inc.StreamsInbound*factor)>>10, - StreamsOutbound: base.StreamsOutbound + (inc.StreamsOutbound*factor)>>10, - Streams: base.Streams + (inc.Streams*factor)>>10, - ConnsInbound: base.ConnsInbound + (inc.ConnsInbound*factor)>>10, - ConnsOutbound: base.ConnsOutbound + (inc.ConnsOutbound*factor)>>10, - Conns: base.Conns + (inc.Conns*factor)>>10, - Memory: base.Memory + (inc.Memory*int64(factor))>>10, - FD: base.FD, - } - if inc.FDFraction > 0 && numFD > 0 { - l.FD = int(inc.FDFraction * float64(numFD)) - } - return l -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.LimitConfig instead +type LimitConfig = rcmgr.LimitConfig // DefaultLimits are the limits used by the default limiter constructors. -var DefaultLimits = ScalingLimitConfig{ - SystemBaseLimit: BaseLimit{ - ConnsInbound: 64, - ConnsOutbound: 128, - Conns: 128, - StreamsInbound: 64 * 16, - StreamsOutbound: 128 * 16, - Streams: 128 * 16, - Memory: 128 << 20, - FD: 256, - }, - - SystemLimitIncrease: BaseLimitIncrease{ - ConnsInbound: 64, - ConnsOutbound: 128, - Conns: 128, - StreamsInbound: 64 * 16, - StreamsOutbound: 128 * 16, - Streams: 128 * 16, - Memory: 1 << 30, - FDFraction: 1, - }, - - TransientBaseLimit: BaseLimit{ - ConnsInbound: 32, - ConnsOutbound: 64, - Conns: 64, - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 256, - Memory: 32 << 20, - FD: 64, - }, - - TransientLimitIncrease: BaseLimitIncrease{ - ConnsInbound: 16, - ConnsOutbound: 32, - Conns: 32, - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 256, - Memory: 128 << 20, - FDFraction: 0.25, - }, - - // Setting the allowlisted limits to be the same as the normal limits. The - // allowlist only activates when you reach your normal system/transient - // limits. So it's okay if these limits err on the side of being too big, - // since most of the time you won't even use any of these. Tune these down - // if you want to manage your resources against an allowlisted endpoint. - AllowlistedSystemBaseLimit: BaseLimit{ - ConnsInbound: 64, - ConnsOutbound: 128, - Conns: 128, - StreamsInbound: 64 * 16, - StreamsOutbound: 128 * 16, - Streams: 128 * 16, - Memory: 128 << 20, - FD: 256, - }, - - AllowlistedSystemLimitIncrease: BaseLimitIncrease{ - ConnsInbound: 64, - ConnsOutbound: 128, - Conns: 128, - StreamsInbound: 64 * 16, - StreamsOutbound: 128 * 16, - Streams: 128 * 16, - Memory: 1 << 30, - FDFraction: 1, - }, - - AllowlistedTransientBaseLimit: BaseLimit{ - ConnsInbound: 32, - ConnsOutbound: 64, - Conns: 64, - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 256, - Memory: 32 << 20, - FD: 64, - }, - - AllowlistedTransientLimitIncrease: BaseLimitIncrease{ - ConnsInbound: 16, - ConnsOutbound: 32, - Conns: 32, - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 256, - Memory: 128 << 20, - FDFraction: 0.25, - }, - - ServiceBaseLimit: BaseLimit{ - StreamsInbound: 1024, - StreamsOutbound: 4096, - Streams: 4096, - Memory: 64 << 20, - }, - - ServiceLimitIncrease: BaseLimitIncrease{ - StreamsInbound: 512, - StreamsOutbound: 2048, - Streams: 2048, - Memory: 128 << 20, - }, - - ServicePeerBaseLimit: BaseLimit{ - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 256, - Memory: 16 << 20, - }, - - ServicePeerLimitIncrease: BaseLimitIncrease{ - StreamsInbound: 4, - StreamsOutbound: 8, - Streams: 8, - Memory: 4 << 20, - }, - - ProtocolBaseLimit: BaseLimit{ - StreamsInbound: 512, - StreamsOutbound: 2048, - Streams: 2048, - Memory: 64 << 20, - }, - - ProtocolLimitIncrease: BaseLimitIncrease{ - StreamsInbound: 256, - StreamsOutbound: 512, - Streams: 512, - Memory: 164 << 20, - }, - - ProtocolPeerBaseLimit: BaseLimit{ - StreamsInbound: 64, - StreamsOutbound: 128, - Streams: 256, - Memory: 16 << 20, - }, - - ProtocolPeerLimitIncrease: BaseLimitIncrease{ - StreamsInbound: 4, - StreamsOutbound: 8, - Streams: 16, - Memory: 4, - }, - - PeerBaseLimit: BaseLimit{ - ConnsInbound: 4, - ConnsOutbound: 8, - Conns: 8, - StreamsInbound: 256, - StreamsOutbound: 512, - Streams: 512, - Memory: 64 << 20, - FD: 4, - }, - - PeerLimitIncrease: BaseLimitIncrease{ - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 256, - Memory: 128 << 20, - FDFraction: 1.0 / 64, - }, - - ConnBaseLimit: BaseLimit{ - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - Memory: 1 << 20, - }, - - StreamBaseLimit: BaseLimit{ - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - Memory: 16 << 20, - }, -} - -var infiniteBaseLimit = BaseLimit{ - Streams: math.MaxInt, - StreamsInbound: math.MaxInt, - StreamsOutbound: math.MaxInt, - Conns: math.MaxInt, - ConnsInbound: math.MaxInt, - ConnsOutbound: math.MaxInt, - FD: math.MaxInt, - Memory: math.MaxInt64, -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.DefaultLimits instead +var DefaultLimits = rcmgr.DefaultLimits // InfiniteLimits are a limiter configuration that uses infinite limits, thus effectively not limiting anything. // Keep in mind that the operating system limits the number of file descriptors that an application can use. -var InfiniteLimits = LimitConfig{ - System: infiniteBaseLimit, - Transient: infiniteBaseLimit, - AllowlistedSystem: infiniteBaseLimit, - AllowlistedTransient: infiniteBaseLimit, - ServiceDefault: infiniteBaseLimit, - ServicePeerDefault: infiniteBaseLimit, - ProtocolDefault: infiniteBaseLimit, - ProtocolPeerDefault: infiniteBaseLimit, - PeerDefault: infiniteBaseLimit, - Conn: infiniteBaseLimit, - Stream: infiniteBaseLimit, -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.InfiniteLimits instead +var InfiniteLimits = rcmgr.InfiniteLimits diff --git a/limit_test.go b/limit_test.go deleted file mode 100644 index e772632..0000000 --- a/limit_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package rcmgr - -import ( - "runtime" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestFileDescriptorCounting(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("can't read file descriptors on Windows") - } - n := getNumFDs() - require.NotZero(t, n) - require.Less(t, n, int(1e7)) -} - -func TestScaling(t *testing.T) { - base := BaseLimit{ - Streams: 100, - StreamsInbound: 200, - StreamsOutbound: 400, - Conns: 10, - ConnsInbound: 20, - ConnsOutbound: 40, - FD: 1, - Memory: 1 << 20, - } - - t.Run("no scaling if no increase is defined", func(t *testing.T) { - cfg := ScalingLimitConfig{ServiceBaseLimit: base} - scaled := cfg.Scale(8<<30, 100) - require.Equal(t, base, scaled.ServiceDefault) - }) - - t.Run("scaling", func(t *testing.T) { - cfg := ScalingLimitConfig{ - TransientBaseLimit: base, - TransientLimitIncrease: BaseLimitIncrease{ - Streams: 1, - StreamsInbound: 2, - StreamsOutbound: 3, - Conns: 4, - ConnsInbound: 5, - ConnsOutbound: 6, - Memory: 7, - FDFraction: 0.5, - }, - } - scaled := cfg.Scale(128<<20+4<<30, 1000) - require.Equal(t, 500, scaled.Transient.FD) - require.Equal(t, base.Streams+4, scaled.Transient.Streams) - require.Equal(t, base.StreamsInbound+4*2, scaled.Transient.StreamsInbound) - require.Equal(t, base.StreamsOutbound+4*3, scaled.Transient.StreamsOutbound) - require.Equal(t, base.Conns+4*4, scaled.Transient.Conns) - require.Equal(t, base.ConnsInbound+4*5, scaled.Transient.ConnsInbound) - require.Equal(t, base.ConnsOutbound+4*6, scaled.Transient.ConnsOutbound) - require.Equal(t, base.Memory+4*7, scaled.Transient.Memory) - }) - - t.Run("scaling limits in maps", func(t *testing.T) { - cfg := ScalingLimitConfig{ - ServiceLimits: map[string]baseLimitConfig{ - "A": { - BaseLimit: BaseLimit{Streams: 10, Memory: 100, FD: 9}, - }, - "B": { - BaseLimit: BaseLimit{Streams: 20, Memory: 200, FD: 10}, - BaseLimitIncrease: BaseLimitIncrease{Streams: 2, Memory: 3, FDFraction: 0.4}, - }, - }, - } - scaled := cfg.Scale(128<<20+4<<30, 1000) - - require.Len(t, scaled.Service, 2) - require.Contains(t, scaled.Service, "A") - require.Equal(t, 10, scaled.Service["A"].Streams) - require.Equal(t, int64(100), scaled.Service["A"].Memory) - require.Equal(t, 9, scaled.Service["A"].FD) - - require.Contains(t, scaled.Service, "B") - require.Equal(t, 20+4*2, scaled.Service["B"].Streams) - require.Equal(t, int64(200+4*3), scaled.Service["B"].Memory) - require.Equal(t, 400, scaled.Service["B"].FD) - - }) -} diff --git a/metrics.go b/metrics.go index a875415..869a8ad 100644 --- a/metrics.go +++ b/metrics.go @@ -1,168 +1,19 @@ package rcmgr import ( - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) // MetricsReporter is an interface for collecting metrics from resource manager actions -type MetricsReporter interface { - // AllowConn is invoked when opening a connection is allowed - AllowConn(dir network.Direction, usefd bool) - // BlockConn is invoked when opening a connection is blocked - BlockConn(dir network.Direction, usefd bool) - - // AllowStream is invoked when opening a stream is allowed - AllowStream(p peer.ID, dir network.Direction) - // BlockStream is invoked when opening a stream is blocked - BlockStream(p peer.ID, dir network.Direction) - - // AllowPeer is invoked when attaching ac onnection to a peer is allowed - AllowPeer(p peer.ID) - // BlockPeer is invoked when attaching ac onnection to a peer is blocked - BlockPeer(p peer.ID) - - // AllowProtocol is invoked when setting the protocol for a stream is allowed - AllowProtocol(proto protocol.ID) - // BlockProtocol is invoked when setting the protocol for a stream is blocked - BlockProtocol(proto protocol.ID) - // BlockProtocolPeer is invoked when setting the protocol for a stream is blocked at the per protocol peer scope - BlockProtocolPeer(proto protocol.ID, p peer.ID) - - // AllowService is invoked when setting the protocol for a stream is allowed - AllowService(svc string) - // BlockService is invoked when setting the protocol for a stream is blocked - BlockService(svc string) - // BlockServicePeer is invoked when setting the service for a stream is blocked at the per service peer scope - BlockServicePeer(svc string, p peer.ID) - - // AllowMemory is invoked when a memory reservation is allowed - AllowMemory(size int) - // BlockMemory is invoked when a memory reservation is blocked - BlockMemory(size int) -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.MetricsReporter instead +type MetricsReporter = rcmgr.MetricsReporter type metrics struct { reporter MetricsReporter } // WithMetrics is a resource manager option to enable metrics collection +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.WithMetrics instead func WithMetrics(reporter MetricsReporter) Option { - return func(r *resourceManager) error { - r.metrics = &metrics{reporter: reporter} - return nil - } -} - -func (m *metrics) AllowConn(dir network.Direction, usefd bool) { - if m == nil { - return - } - - m.reporter.AllowConn(dir, usefd) -} - -func (m *metrics) BlockConn(dir network.Direction, usefd bool) { - if m == nil { - return - } - - m.reporter.BlockConn(dir, usefd) -} - -func (m *metrics) AllowStream(p peer.ID, dir network.Direction) { - if m == nil { - return - } - - m.reporter.AllowStream(p, dir) -} - -func (m *metrics) BlockStream(p peer.ID, dir network.Direction) { - if m == nil { - return - } - - m.reporter.BlockStream(p, dir) -} - -func (m *metrics) AllowPeer(p peer.ID) { - if m == nil { - return - } - - m.reporter.AllowPeer(p) -} - -func (m *metrics) BlockPeer(p peer.ID) { - if m == nil { - return - } - - m.reporter.BlockPeer(p) -} - -func (m *metrics) AllowProtocol(proto protocol.ID) { - if m == nil { - return - } - - m.reporter.AllowProtocol(proto) -} - -func (m *metrics) BlockProtocol(proto protocol.ID) { - if m == nil { - return - } - - m.reporter.BlockProtocol(proto) -} - -func (m *metrics) BlockProtocolPeer(proto protocol.ID, p peer.ID) { - if m == nil { - return - } - - m.reporter.BlockProtocolPeer(proto, p) -} - -func (m *metrics) AllowService(svc string) { - if m == nil { - return - } - - m.reporter.AllowService(svc) -} - -func (m *metrics) BlockService(svc string) { - if m == nil { - return - } - - m.reporter.BlockService(svc) -} - -func (m *metrics) BlockServicePeer(svc string, p peer.ID) { - if m == nil { - return - } - - m.reporter.BlockServicePeer(svc, p) -} - -func (m *metrics) AllowMemory(size int) { - if m == nil { - return - } - - m.reporter.AllowMemory(size) -} - -func (m *metrics) BlockMemory(size int) { - if m == nil { - return - } - - m.reporter.BlockMemory(size) + return rcmgr.WithMetrics(reporter) } diff --git a/obs/grafana-dashboards/README.md b/obs/grafana-dashboards/README.md deleted file mode 100644 index dfa7265..0000000 --- a/obs/grafana-dashboards/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Ready to go Grafana Dashboard - -Here are some prebuilt dashboards that you can add to your Grafana instance. To -import follow the Grafana docs [here](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard) - -## Setup - -To make sure you're emitting the correct metrics you'll have to hook up the -Opencensus views that `stats.go` exports. For Prometheus this looks like: - -``` go -import ( - // ... - ocprom "contrib.go.opencensus.io/exporter/prometheus" - - rcmgr "github.com/libp2p/go-libp2p-resource-manager" - rcmgrObs "github.com/libp2p/go-libp2p-resource-manager/obs" - - "github.com/prometheus/client_golang/prometheus" - "go.opencensus.io/stats/view" -) - - func SetupResourceManager() (network.ResourceManager, error) { - // Hook up the trace reporter metrics. This will expose all opencensus - // stats via the default prometheus registry. See https://opencensus.io/exporters/supported-exporters/go/prometheus/ for other options. - view.Register(rcmgrObs.DefaultViews...) - ocprom.NewExporter(ocprom.Options{ - Registry: prometheus.DefaultRegisterer.(*prometheus.Registry), - }) - - str, err := rcmgrObs.NewStatsTraceReporter() - if err != nil { - return nil, err - } - - return rcmgr.NewResourceManager(limiter, rcmgr.WithTraceReporter(str)) - } -``` - -It should be fairly similar for other exporters. See the [OpenCensus -docs](https://opencensus.io/exporters/supported-exporters/go/) to see how to -export to another exporter. - -## Updating Dashboard json - -Use the share functionality on an existing dashboard, and make sure to toggle -"Export for sharing externally". See the [Grafana -Docs](https://grafana.com/docs/grafana/latest/dashboards/export-import/#exporting-a-dashboard) -for more details. \ No newline at end of file diff --git a/obs/grafana-dashboards/resource-manager.json b/obs/grafana-dashboards/resource-manager.json deleted file mode 100644 index 0b29c6c..0000000 --- a/obs/grafana-dashboards/resource-manager.json +++ /dev/null @@ -1,1818 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__elements": [], - "__requires": [ - { - "type": "panel", - "id": "bargauge", - "name": "Bar gauge", - "version": "" - }, - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.5.6" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "text", - "name": "Text", - "version": "" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": null, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 65, - "panels": [], - "title": "Blocked Resources", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "This should be empty. If it's large you are running into your resource manager limits.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 67, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rate(rcmgr_blocked_resources[$__rate_interval])", - "interval": "", - "legendFormat": "", - "refId": "A" - } - ], - "title": "Number of blocked resource requests", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 9 - }, - "id": 42, - "panels": [], - "title": "Streams", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 10 - }, - "id": 48, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_streams{scope=\"system\"}", - "interval": "", - "legendFormat": "{{dir}} {{instance}}", - "refId": "A" - } - ], - "title": "System Streams", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 10 - }, - "id": 44, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_streams{scope=\"transient\"}", - "interval": "", - "legendFormat": "{{dir}} {{instance}}", - "refId": "A" - } - ], - "title": "Transient Streams", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "How many streams does each service have open", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 24, - "x": 0, - "y": 18 - }, - "id": 43, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_streams{scope=\"service\"}", - "interval": "", - "legendFormat": "{{dir}} {{service}} {{instance}}", - "refId": "A" - } - ], - "title": "Streams by service", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "How many streams does each protocol have open.\n\nA protocol is similiar to a service except there may be many protocols for a single service. A service may have \nmultiple protocols for backwards compatibility. For example, bitswap the service is a single entity, but it supports bitswap protocols v1.1 and v1.2.\n\nA service is attached to a stream manually by the protocol developer. A service may be missing if there is no `StreamScope.SetService` call.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 24, - "x": 0, - "y": 27 - }, - "id": 52, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_streams{scope=\"protocol\"}", - "interval": "", - "legendFormat": "{{dir}} {{protocol}} {{instance}}", - "refId": "A" - } - ], - "title": "Streams by protocol", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 36 - }, - "id": 35, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(0.50, (rcmgr_peer_streams_bucket - rcmgr_peer_streams_negative_bucket)) - 0.1", - "interval": "", - "legendFormat": "p50 {{dir}} streams per peer – {{instance}}", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(0.90, (rcmgr_peer_streams_bucket - rcmgr_peer_streams_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "p90 {{dir}} streams per peer – {{instance}}", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(1, (rcmgr_peer_streams_bucket - rcmgr_peer_streams_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "max {{dir}} streams per peer – {{instance}}", - "refId": "C" - } - ], - "title": "Streams per peer, aggregated", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "How many peers have N-0.1 streams open", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 46 - }, - "id": 46, - "options": { - "displayMode": "gradient", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "8.4.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": false, - "expr": "sum without (instance) (rcmgr_peer_streams_bucket{dir=\"inbound\"}-rcmgr_peer_streams_negative_bucket{dir=\"inbound\"})", - "format": "heatmap", - "hide": false, - "interval": "", - "legendFormat": "{{le}}", - "refId": "A" - } - ], - "title": "Current inbound streams per peer histogram. Across all instances", - "type": "bargauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "How many peers have N-0.1 streams open", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 46 - }, - "id": 47, - "options": { - "displayMode": "gradient", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "8.4.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": false, - "expr": "sum without (instance) (rcmgr_peer_streams_bucket{dir=\"outbound\"}-rcmgr_peer_streams_negative_bucket{dir=\"outbound\"})", - "format": "heatmap", - "hide": false, - "interval": "", - "legendFormat": "{{le}}", - "refId": "A" - } - ], - "title": "Current outbound streams per peer histogram. Across all instances", - "type": "bargauge" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 54 - }, - "id": 29, - "panels": [], - "title": "Connections", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "gridPos": { - "h": 9, - "w": 24, - "x": 0, - "y": 55 - }, - "id": 31, - "options": { - "content": "# Libp2p Connections\n\nBroken down by [Resource Scope](https://github.com/libp2p/go-libp2p-resource-manager#resource-scopes). \nScopes represent what is imposing limits on this resource. For connections, we have three main scopes:\n\n1. System. The total number of connections owned by the process. Includes both application usable connections + the number of transient connections.\n2. Transient. The total number of connections that are being upgraded into usable connections in the process.\n3. Peer. The total number of connections associated with this peer. When a connection has this scope it is usable by the application.\n\nAn example of a System connection is a connection you can open a libp2p stream on and send data.\nA transient connection is not yet usable for application data since it may be negotiating \na security handshake or a multiplexer.\n\nConnections start in the transient scope and move over to the System and Peer scopes once they are ready to be used.\n\nIt would be unusual to see a lot of transient connections. It would also be unusal to see a peer with a lot of connections.", - "mode": "markdown" - }, - "pluginVersion": "8.4.5", - "title": "libp2p Connections", - "type": "text" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 64 - }, - "id": 33, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_connections{scope=\"system\"}", - "interval": "", - "legendFormat": "{{dir}} {{instance}}", - "refId": "A" - } - ], - "title": "System Connections", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 64 - }, - "id": 36, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_connections{scope=\"transient\"}", - "interval": "", - "legendFormat": "{{dir}} {{instance}}", - "refId": "A" - } - ], - "title": "Transient Connections", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "gridPos": { - "h": 3, - "w": 24, - "x": 0, - "y": 72 - }, - "id": 38, - "options": { - "content": "These are aggregated stats. They are grouped by buckets. Each bucket represents how many peers have N number of connections.\n\nDue to a quirk in [opencensus](https://github.com/census-instrumentation/opencensus-go/blob/v0.23.0/stats/view/aggregation_data.go#L195) the bucket values have to be a bit bigger than the integer values.\nSo subtract 0.1 from the number to get the true number of connections. e.g. If a peer has 3 connections, it'll be put in the 3.1 bucket. \n", - "mode": "markdown" - }, - "pluginVersion": "8.4.5", - "title": "Connections per Peer", - "type": "text" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 75 - }, - "id": 45, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(0.50, (rcmgr_peer_connections_bucket - rcmgr_peer_connections_negative_bucket)) - 0.1", - "interval": "", - "legendFormat": "p50 {{dir}} connections per peer – {{instance}}", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(0.90, (rcmgr_peer_connections_bucket - rcmgr_peer_connections_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "p90 {{dir}} connections per peer – {{instance}}", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(1, (rcmgr_peer_connections_bucket - rcmgr_peer_connections_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "max {{dir}} connections per peer – {{instance}}", - "refId": "C" - } - ], - "title": "Connections per peer, aggregated", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "How many peers have N-0.1 connections open", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 85 - }, - "id": 39, - "options": { - "displayMode": "gradient", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "8.4.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": false, - "expr": "sum without (instance) (rcmgr_peer_connections_bucket{dir=\"inbound\"}-rcmgr_peer_connections_negative_bucket{dir=\"inbound\"})", - "format": "heatmap", - "hide": false, - "interval": "", - "legendFormat": "{{le}}", - "refId": "A" - } - ], - "title": "Current inbound connections per peer histogram. Across all instances", - "type": "bargauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "How many peers have N-0.1 connections open", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 85 - }, - "id": 40, - "options": { - "displayMode": "gradient", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "8.4.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": false, - "expr": "sum without (instance) (rcmgr_peer_connections_bucket{dir=\"outbound\"}-rcmgr_peer_connections_negative_bucket{dir=\"outbound\"})", - "format": "heatmap", - "hide": false, - "interval": "", - "legendFormat": "{{le}}", - "refId": "A" - } - ], - "title": "Curent outbound connections per peer histogram. Across all instances", - "type": "bargauge" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 93 - }, - "id": 54, - "panels": [], - "title": "Memory", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "As reported to Resource Manager", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 24, - "x": 0, - "y": 94 - }, - "id": 56, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_memory{scope=\"system\"}", - "interval": "", - "legendFormat": "Bytes Reserved", - "refId": "A" - } - ], - "title": "System memory reservations", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "As reported to Resource Manager", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 103 - }, - "id": 57, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_memory{scope=\"protocol\"}", - "interval": "", - "legendFormat": "{{protocol}} {{instance}}", - "refId": "A" - } - ], - "title": "Memory reservations by protocol", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "As reported to Resource Manager", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 103 - }, - "id": 58, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_memory{scope=\"service\"}", - "interval": "", - "legendFormat": "{{service}} {{instance}}", - "refId": "A" - } - ], - "title": "Memory reservations by service", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "As reported to the resource manager", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Number of peers aggregated" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-purple", - "mode": "fixed" - } - }, - { - "id": "custom.axisPlacement", - "value": "right" - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 111 - }, - "id": 59, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(0.50, sum by (le) (rcmgr_peer_memory_bucket - rcmgr_peer_memory_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "p50 memory usage per peer", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(0.90, sum by (le) (rcmgr_peer_memory_bucket - rcmgr_peer_memory_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "p90 memory usage per peer", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "histogram_quantile(1, sum by (le) (rcmgr_peer_memory_bucket - rcmgr_peer_memory_negative_bucket)) - 0.1", - "hide": false, - "interval": "", - "legendFormat": "max memory usage per peer", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": true, - "expr": "sum(rcmgr_peer_memory_count-rcmgr_peer_memory_negative_count)", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "Number of peers aggregated", - "range": true, - "refId": "D" - } - ], - "title": "Memory reservations per peer, aggregated across all instances", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 121 - }, - "id": 62, - "panels": [], - "title": "File Descriptors", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "As reported to the resource manager", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 122 - }, - "id": 60, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "exemplar": true, - "expr": "rcmgr_fds", - "interval": "", - "legendFormat": "{{scope}} {{instance}}", - "refId": "A" - } - ], - "title": "FDs in use", - "type": "timeseries" - } - ], - "refresh": false, - "schemaVersion": 36, - "style": "dark", - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "Resource Manager", - "uid": "MgmGIjjnk", - "version": 1, - "weekStart": "" -} \ No newline at end of file diff --git a/obs/stats.go b/obs/stats.go index b3f2877..cd3fc9d 100644 --- a/obs/stats.go +++ b/obs/stats.go @@ -1,343 +1,48 @@ +// Deprecated: This package has moved into go-libp2p as a sub-package: github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs. package obs import ( - "context" - "strings" - - rcmgr "github.com/libp2p/go-libp2p-resource-manager" - "go.opencensus.io/stats" - "go.opencensus.io/stats/view" - "go.opencensus.io/tag" -) - -var ( - metricNamespace = "rcmgr/" - conns = stats.Int64(metricNamespace+"connections", "Number of Connections", stats.UnitDimensionless) - - peerConns = stats.Int64(metricNamespace+"peer/connections", "Number of connections this peer has", stats.UnitDimensionless) - peerConnsNegative = stats.Int64(metricNamespace+"peer/connections_negative", "Number of connections this peer had. This is used to get the current connection number per peer histogram by subtracting this from the peer/connections histogram", stats.UnitDimensionless) - - streams = stats.Int64(metricNamespace+"streams", "Number of Streams", stats.UnitDimensionless) - - peerStreams = stats.Int64(metricNamespace+"peer/streams", "Number of streams this peer has", stats.UnitDimensionless) - peerStreamsNegative = stats.Int64(metricNamespace+"peer/streams_negative", "Number of streams this peer had. This is used to get the current streams number per peer histogram by subtracting this from the peer/streams histogram", stats.UnitDimensionless) - - memory = stats.Int64(metricNamespace+"memory", "Amount of memory reserved as reported to the Resource Manager", stats.UnitDimensionless) - peerMemory = stats.Int64(metricNamespace+"peer/memory", "Amount of memory currently reseved for peer", stats.UnitDimensionless) - peerMemoryNegative = stats.Int64(metricNamespace+"peer/memory_negative", "Amount of memory previously reseved for peer. This is used to get the current memory per peer histogram by subtracting this from the peer/memory histogram", stats.UnitDimensionless) - - connMemory = stats.Int64(metricNamespace+"conn/memory", "Amount of memory currently reseved for the connection", stats.UnitDimensionless) - connMemoryNegative = stats.Int64(metricNamespace+"conn/memory_negative", "Amount of memory previously reseved for the connection. This is used to get the current memory per connection histogram by subtracting this from the conn/memory histogram", stats.UnitDimensionless) - - fds = stats.Int64(metricNamespace+"fds", "Number of fds as reported to the Resource Manager", stats.UnitDimensionless) - - blockedResources = stats.Int64(metricNamespace+"blocked_resources", "Number of resource requests blocked", stats.UnitDimensionless) + "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" ) var ( - directionTag, _ = tag.NewKey("dir") - scopeTag, _ = tag.NewKey("scope") - serviceTag, _ = tag.NewKey("service") - protocolTag, _ = tag.NewKey("protocol") - resourceTag, _ = tag.NewKey("resource") -) - -var ( - ConnView = &view.View{Measure: conns, Aggregation: view.Sum(), TagKeys: []tag.Key{directionTag, scopeTag}} - - oneTenThenExpDistribution = []float64{ - 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 16.1, 32.1, 64.1, 128.1, 256.1, - } - - PeerConnsView = &view.View{ - Measure: peerConns, - Aggregation: view.Distribution(oneTenThenExpDistribution...), - TagKeys: []tag.Key{directionTag}, - } - PeerConnsNegativeView = &view.View{ - Measure: peerConnsNegative, - Aggregation: view.Distribution(oneTenThenExpDistribution...), - TagKeys: []tag.Key{directionTag}, - } - - StreamView = &view.View{Measure: streams, Aggregation: view.Sum(), TagKeys: []tag.Key{directionTag, scopeTag, serviceTag, protocolTag}} - PeerStreamsView = &view.View{Measure: peerStreams, Aggregation: view.Distribution(oneTenThenExpDistribution...), TagKeys: []tag.Key{directionTag}} - PeerStreamNegativeView = &view.View{Measure: peerStreamsNegative, Aggregation: view.Distribution(oneTenThenExpDistribution...), TagKeys: []tag.Key{directionTag}} - - MemoryView = &view.View{Measure: memory, Aggregation: view.Sum(), TagKeys: []tag.Key{scopeTag, serviceTag, protocolTag}} - - memDistribution = []float64{ - 1 << 10, // 1KB - 4 << 10, // 4KB - 32 << 10, // 32KB - 1 << 20, // 1MB - 32 << 20, // 32MB - 256 << 20, // 256MB - 512 << 20, // 512MB - 1 << 30, // 1GB - 2 << 30, // 2GB - 4 << 30, // 4GB - } - PeerMemoryView = &view.View{ - Measure: peerMemory, - Aggregation: view.Distribution(memDistribution...), - } - PeerMemoryNegativeView = &view.View{ - Measure: peerMemoryNegative, - Aggregation: view.Distribution(memDistribution...), - } - + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.ConnView instead + ConnView = obs.ConnView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.PeerConnsView instead + PeerConnsView = obs.PeerConnsView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.PeerConnsNegativeView instead + PeerConnsNegativeView = obs.PeerConnsNegativeView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.StreamView instead + StreamView = obs.StreamView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.PeerStreamsView instead + PeerStreamsView = obs.PeerStreamsView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.PeerStreamNegativeView instead + PeerStreamNegativeView = obs.PeerStreamNegativeView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.MemoryView instead + MemoryView = obs.MemoryView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.PeerMemoryView instead + PeerMemoryView = obs.PeerMemoryView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.PeerMemoryNegativeView instead + PeerMemoryNegativeView = obs.PeerMemoryNegativeView // Not setup yet. Memory isn't attached to a given connection. - ConnMemoryView = &view.View{ - Measure: connMemory, - Aggregation: view.Distribution(memDistribution...), - } - ConnMemoryNegativeView = &view.View{ - Measure: connMemoryNegative, - Aggregation: view.Distribution(memDistribution...), - } - - FDsView = &view.View{Measure: fds, Aggregation: view.Sum(), TagKeys: []tag.Key{scopeTag}} - - BlockedResourcesView = &view.View{ - Measure: blockedResources, - Aggregation: view.Sum(), - TagKeys: []tag.Key{scopeTag, resourceTag}, - } + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.ConnMemoryView instead + ConnMemoryView = obs.ConnMemoryView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.ConnMemoryNegativeView instead + ConnMemoryNegativeView = obs.ConnMemoryNegativeView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.FDsView instead + FDsView = obs.FDsView + // Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.BlockedResourcesView instead + BlockedResourcesView = obs.BlockedResourcesView ) -var DefaultViews []*view.View = []*view.View{ - ConnView, - PeerConnsView, - PeerConnsNegativeView, - FDsView, - - StreamView, - PeerStreamsView, - PeerStreamNegativeView, - - MemoryView, - PeerMemoryView, - PeerMemoryNegativeView, - - BlockedResourcesView, -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.DefaultViews instead +var DefaultViews = obs.DefaultViews // StatsTraceReporter reports stats on the resource manager using its traces. -type StatsTraceReporter struct{} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.StatsTraceReporter instead +type StatsTraceReporter = obs.StatsTraceReporter +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs.NewStatsTraceReporter instead func NewStatsTraceReporter() (StatsTraceReporter, error) { - // TODO tell prometheus the system limits - return StatsTraceReporter{}, nil -} - -func (r StatsTraceReporter) ConsumeEvent(evt rcmgr.TraceEvt) { - ctx := context.Background() - - switch evt.Type { - case rcmgr.TraceAddStreamEvt, rcmgr.TraceRemoveStreamEvt: - if p := rcmgr.ParsePeerScopeName(evt.Name); p.Validate() == nil { - // Aggregated peer stats. Counts how many peers have N number of streams open. - // Uses two buckets aggregations. One to count how many streams the - // peer has now. The other to count the negative value, or how many - // streams did the peer use to have. When looking at the data you - // take the difference from the two. - - oldStreamsOut := int64(evt.StreamsOut - evt.DeltaOut) - peerStreamsOut := int64(evt.StreamsOut) - if oldStreamsOut != peerStreamsOut { - if oldStreamsOut != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "outbound")}, peerStreamsNegative.M(oldStreamsOut)) - } - if peerStreamsOut != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "outbound")}, peerStreams.M(peerStreamsOut)) - } - } - - oldStreamsIn := int64(evt.StreamsIn - evt.DeltaIn) - peerStreamsIn := int64(evt.StreamsIn) - if oldStreamsIn != peerStreamsIn { - if oldStreamsIn != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "inbound")}, peerStreamsNegative.M(oldStreamsIn)) - } - if peerStreamsIn != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "inbound")}, peerStreams.M(peerStreamsIn)) - } - } - } else { - var tags []tag.Mutator - if rcmgr.IsSystemScope(evt.Name) || rcmgr.IsTransientScope(evt.Name) { - tags = append(tags, tag.Upsert(scopeTag, evt.Name)) - } else if svc := rcmgr.ParseServiceScopeName(evt.Name); svc != "" { - tags = append(tags, tag.Upsert(scopeTag, "service"), tag.Upsert(serviceTag, svc)) - } else if proto := rcmgr.ParseProtocolScopeName(evt.Name); proto != "" { - tags = append(tags, tag.Upsert(scopeTag, "protocol"), tag.Upsert(protocolTag, proto)) - } else { - // Not measuring connscope, servicepeer and protocolpeer. Lots of data, and - // you can use aggregated peer stats + service stats to infer - // this. - break - } - - if evt.DeltaOut != 0 { - stats.RecordWithTags( - ctx, - append([]tag.Mutator{tag.Upsert(directionTag, "outbound")}, tags...), - streams.M(int64(evt.DeltaOut)), - ) - } - - if evt.DeltaIn != 0 { - stats.RecordWithTags( - ctx, - append([]tag.Mutator{tag.Upsert(directionTag, "inbound")}, tags...), - streams.M(int64(evt.DeltaIn)), - ) - } - } - - case rcmgr.TraceAddConnEvt, rcmgr.TraceRemoveConnEvt: - if p := rcmgr.ParsePeerScopeName(evt.Name); p.Validate() == nil { - // Aggregated peer stats. Counts how many peers have N number of connections. - // Uses two buckets aggregations. One to count how many streams the - // peer has now. The other to count the negative value, or how many - // conns did the peer use to have. When looking at the data you - // take the difference from the two. - - oldConnsOut := int64(evt.ConnsOut - evt.DeltaOut) - connsOut := int64(evt.ConnsOut) - if oldConnsOut != connsOut { - if oldConnsOut != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "outbound")}, peerConnsNegative.M(oldConnsOut)) - } - if connsOut != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "outbound")}, peerConns.M(connsOut)) - } - } - - oldConnsIn := int64(evt.ConnsIn - evt.DeltaIn) - connsIn := int64(evt.ConnsIn) - if oldConnsIn != connsIn { - if oldConnsIn != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "inbound")}, peerConnsNegative.M(oldConnsIn)) - } - if connsIn != 0 { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(directionTag, "inbound")}, peerConns.M(connsIn)) - } - } - } else { - var tags []tag.Mutator - if rcmgr.IsSystemScope(evt.Name) || rcmgr.IsTransientScope(evt.Name) { - tags = append(tags, tag.Upsert(scopeTag, evt.Name)) - } else if rcmgr.IsConnScope(evt.Name) { - // Not measuring this. I don't think it's useful. - break - } else { - // This could be a span - break - } - - if evt.DeltaOut != 0 { - stats.RecordWithTags( - ctx, - append([]tag.Mutator{tag.Upsert(directionTag, "outbound")}, tags...), - conns.M(int64(evt.DeltaOut)), - ) - } - - if evt.DeltaIn != 0 { - stats.RecordWithTags( - ctx, - append([]tag.Mutator{tag.Upsert(directionTag, "inbound")}, tags...), - conns.M(int64(evt.DeltaIn)), - ) - } - - // Represents the delta in fds - if evt.Delta != 0 { - stats.RecordWithTags( - ctx, - tags, - fds.M(int64(evt.Delta)), - ) - } - } - case rcmgr.TraceReserveMemoryEvt, rcmgr.TraceReleaseMemoryEvt: - if p := rcmgr.ParsePeerScopeName(evt.Name); p.Validate() == nil { - oldMem := evt.Memory - evt.Delta - if oldMem != evt.Memory { - if oldMem != 0 { - stats.Record(ctx, peerMemoryNegative.M(oldMem)) - } - if evt.Memory != 0 { - stats.Record(ctx, peerMemory.M(evt.Memory)) - } - } - } else if rcmgr.IsConnScope(evt.Name) { - oldMem := evt.Memory - evt.Delta - if oldMem != evt.Memory { - if oldMem != 0 { - stats.Record(ctx, connMemoryNegative.M(oldMem)) - } - if evt.Memory != 0 { - stats.Record(ctx, connMemory.M(evt.Memory)) - } - } - } else { - var tags []tag.Mutator - if rcmgr.IsSystemScope(evt.Name) || rcmgr.IsTransientScope(evt.Name) { - tags = append(tags, tag.Upsert(scopeTag, evt.Name)) - } else if svc := rcmgr.ParseServiceScopeName(evt.Name); svc != "" { - tags = append(tags, tag.Upsert(scopeTag, "service"), tag.Upsert(serviceTag, svc)) - } else if proto := rcmgr.ParseProtocolScopeName(evt.Name); proto != "" { - tags = append(tags, tag.Upsert(scopeTag, "protocol"), tag.Upsert(protocolTag, proto)) - } else { - // Not measuring connscope, servicepeer and protocolpeer. Lots of data, and - // you can use aggregated peer stats + service stats to infer - // this. - break - } - - if evt.Delta != 0 { - stats.RecordWithTags(ctx, tags, memory.M(int64(evt.Delta))) - } - } - - case rcmgr.TraceBlockAddConnEvt, rcmgr.TraceBlockAddStreamEvt, rcmgr.TraceBlockReserveMemoryEvt: - var resource string - if evt.Type == rcmgr.TraceBlockAddConnEvt { - resource = "connection" - } else if evt.Type == rcmgr.TraceBlockAddStreamEvt { - resource = "stream" - } else { - resource = "memory" - } - - // Only the top scopeName. We don't want to get the peerid here. - scopeName := strings.SplitN(evt.Name, ":", 2)[0] - // Drop the connection or stream id - scopeName = strings.SplitN(scopeName, "-", 2)[0] - - // If something else gets added here, make sure to update the size hint - // below when we make `tagsWithDir`. - tags := []tag.Mutator{tag.Upsert(scopeTag, scopeName), tag.Upsert(resourceTag, resource)} - - if evt.DeltaIn != 0 { - tagsWithDir := make([]tag.Mutator, 0, 3) - tagsWithDir = append(tagsWithDir, tag.Insert(directionTag, "inbound")) - tagsWithDir = append(tagsWithDir, tags...) - stats.RecordWithTags(ctx, tagsWithDir[0:], blockedResources.M(int64(1))) - } - - if evt.DeltaOut != 0 { - tagsWithDir := make([]tag.Mutator, 0, 3) - tagsWithDir = append(tagsWithDir, tag.Insert(directionTag, "outbound")) - tagsWithDir = append(tagsWithDir, tags...) - stats.RecordWithTags(ctx, tagsWithDir, blockedResources.M(int64(1))) - } - - if evt.Delta != 0 { - stats.RecordWithTags(ctx, tags, blockedResources.M(1)) - } - } + return obs.NewStatsTraceReporter() } diff --git a/obs/stats_test.go b/obs/stats_test.go deleted file mode 100644 index 990e216..0000000 --- a/obs/stats_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package obs_test - -import ( - "testing" - "time" - - rcmgr "github.com/libp2p/go-libp2p-resource-manager" - "github.com/libp2p/go-libp2p-resource-manager/obs" - "go.opencensus.io/stats/view" -) - -func TestTraceReporterStartAndClose(t *testing.T) { - rcmgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale()), rcmgr.WithTraceReporter(obs.StatsTraceReporter{})) - if err != nil { - t.Fatal(err) - } - defer rcmgr.Close() -} - -func TestConsumeEvent(t *testing.T) { - evt := rcmgr.TraceEvt{ - Type: rcmgr.TraceBlockAddStreamEvt, - Name: "conn-1", - DeltaOut: 1, - Time: time.Now().Format(time.RFC3339Nano), - } - - err := view.Register(obs.DefaultViews...) - if err != nil { - t.Fatal(err) - } - - str, err := obs.NewStatsTraceReporter() - if err != nil { - t.Fatal(err) - } - - str.ConsumeEvent(evt) -} diff --git a/rcmgr.go b/rcmgr.go index b2cd18c..11cc47d 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -1,874 +1,59 @@ +// Deprecated: This package has moved into go-libp2p as a sub-package: github.com/libp2p/go-libp2p/p2p/host/resource-manager. package rcmgr import ( - "context" - "fmt" - "strings" - "sync" - "time" - - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/protocol" - "github.com/multiformats/go-multiaddr" - - logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) -var log = logging.Logger("rcmgr") - -type resourceManager struct { - limits Limiter - - trace *trace - metrics *metrics - - allowlist *Allowlist - - system *systemScope - transient *transientScope - - allowlistedSystem *systemScope - allowlistedTransient *transientScope - - cancelCtx context.Context - cancel func() - wg sync.WaitGroup - - mx sync.Mutex - svc map[string]*serviceScope - proto map[protocol.ID]*protocolScope - peer map[peer.ID]*peerScope - - stickyProto map[protocol.ID]struct{} - stickyPeer map[peer.ID]struct{} - - connId, streamId int64 -} - -var _ network.ResourceManager = (*resourceManager)(nil) - -type systemScope struct { - *resourceScope -} - -var _ network.ResourceScope = (*systemScope)(nil) - -type transientScope struct { - *resourceScope - - system *systemScope -} - -var _ network.ResourceScope = (*transientScope)(nil) - -type serviceScope struct { - *resourceScope - - service string - rcmgr *resourceManager - - peers map[peer.ID]*resourceScope -} - -var _ network.ServiceScope = (*serviceScope)(nil) - -type protocolScope struct { - *resourceScope - - proto protocol.ID - rcmgr *resourceManager - - peers map[peer.ID]*resourceScope -} - -var _ network.ProtocolScope = (*protocolScope)(nil) - -type peerScope struct { - *resourceScope - - peer peer.ID - rcmgr *resourceManager -} - -var _ network.PeerScope = (*peerScope)(nil) - -type connectionScope struct { - *resourceScope - - dir network.Direction - usefd bool - isAllowlisted bool - rcmgr *resourceManager - peer *peerScope - endpoint multiaddr.Multiaddr -} - -var _ network.ConnScope = (*connectionScope)(nil) -var _ network.ConnManagementScope = (*connectionScope)(nil) - -type streamScope struct { - *resourceScope - - dir network.Direction - rcmgr *resourceManager - peer *peerScope - svc *serviceScope - proto *protocolScope - - peerProtoScope *resourceScope - peerSvcScope *resourceScope -} - -var _ network.StreamScope = (*streamScope)(nil) -var _ network.StreamManagementScope = (*streamScope)(nil) - -type Option func(*resourceManager) error +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.Option instead +type Option = rcmgr.Option +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.NewResourceManager instead func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager, error) { - allowlist := newAllowlist() - r := &resourceManager{ - limits: limits, - allowlist: &allowlist, - svc: make(map[string]*serviceScope), - proto: make(map[protocol.ID]*protocolScope), - peer: make(map[peer.ID]*peerScope), - } - - for _, opt := range opts { - if err := opt(r); err != nil { - return nil, err - } - } - - if err := r.trace.Start(limits); err != nil { - return nil, err - } - - r.system = newSystemScope(limits.GetSystemLimits(), r, "system") - r.system.IncRef() - r.transient = newTransientScope(limits.GetTransientLimits(), r, "transient", r.system.resourceScope) - r.transient.IncRef() - - r.allowlistedSystem = newSystemScope(limits.GetAllowlistedSystemLimits(), r, "allowlistedSystem") - r.allowlistedSystem.IncRef() - r.allowlistedTransient = newTransientScope(limits.GetAllowlistedTransientLimits(), r, "allowlistedTransient", r.allowlistedSystem.resourceScope) - r.allowlistedTransient.IncRef() - - r.cancelCtx, r.cancel = context.WithCancel(context.Background()) - - r.wg.Add(1) - go r.background() - - return r, nil -} - -func (r *resourceManager) GetAllowlist() *Allowlist { - return r.allowlist + return rcmgr.NewResourceManager(limits, opts...) } // GetAllowlist tries to get the allowlist from the given resourcemanager // interface by checking to see if its concrete type is a resourceManager. // Returns nil if it fails to get the allowlist. -func GetAllowlist(rcmgr network.ResourceManager) *Allowlist { - r, ok := rcmgr.(*resourceManager) - if !ok { - return nil - } - - return r.allowlist -} - -func (r *resourceManager) ViewSystem(f func(network.ResourceScope) error) error { - return f(r.system) -} - -func (r *resourceManager) ViewTransient(f func(network.ResourceScope) error) error { - return f(r.transient) -} - -func (r *resourceManager) ViewService(srv string, f func(network.ServiceScope) error) error { - s := r.getServiceScope(srv) - defer s.DecRef() - - return f(s) -} - -func (r *resourceManager) ViewProtocol(proto protocol.ID, f func(network.ProtocolScope) error) error { - s := r.getProtocolScope(proto) - defer s.DecRef() - - return f(s) -} - -func (r *resourceManager) ViewPeer(p peer.ID, f func(network.PeerScope) error) error { - s := r.getPeerScope(p) - defer s.DecRef() - - return f(s) -} - -func (r *resourceManager) getServiceScope(svc string) *serviceScope { - r.mx.Lock() - defer r.mx.Unlock() - - s, ok := r.svc[svc] - if !ok { - s = newServiceScope(svc, r.limits.GetServiceLimits(svc), r) - r.svc[svc] = s - } - - s.IncRef() - return s -} - -func (r *resourceManager) getProtocolScope(proto protocol.ID) *protocolScope { - r.mx.Lock() - defer r.mx.Unlock() - - s, ok := r.proto[proto] - if !ok { - s = newProtocolScope(proto, r.limits.GetProtocolLimits(proto), r) - r.proto[proto] = s - } - - s.IncRef() - return s -} - -func (r *resourceManager) setStickyProtocol(proto protocol.ID) { - r.mx.Lock() - defer r.mx.Unlock() - - if r.stickyProto == nil { - r.stickyProto = make(map[protocol.ID]struct{}) - } - r.stickyProto[proto] = struct{}{} -} - -func (r *resourceManager) getPeerScope(p peer.ID) *peerScope { - r.mx.Lock() - defer r.mx.Unlock() - - s, ok := r.peer[p] - if !ok { - s = newPeerScope(p, r.limits.GetPeerLimits(p), r) - r.peer[p] = s - } - - s.IncRef() - return s -} - -func (r *resourceManager) setStickyPeer(p peer.ID) { - r.mx.Lock() - defer r.mx.Unlock() - - if r.stickyPeer == nil { - r.stickyPeer = make(map[peer.ID]struct{}) - } - - r.stickyPeer[p] = struct{}{} -} - -func (r *resourceManager) nextConnId() int64 { - r.mx.Lock() - defer r.mx.Unlock() - - r.connId++ - return r.connId -} - -func (r *resourceManager) nextStreamId() int64 { - r.mx.Lock() - defer r.mx.Unlock() - - r.streamId++ - return r.streamId -} - -func (r *resourceManager) OpenConnection(dir network.Direction, usefd bool, endpoint multiaddr.Multiaddr) (network.ConnManagementScope, error) { - var conn *connectionScope - conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r, endpoint) - - err := conn.AddConn(dir, usefd) - if err != nil { - // Try again if this is an allowlisted connection - // Failed to open connection, let's see if this was allowlisted and try again - allowed := r.allowlist.Allowed(endpoint) - if allowed { - conn.Done() - conn = newAllowListedConnectionScope(dir, usefd, r.limits.GetConnLimits(), r, endpoint) - err = conn.AddConn(dir, usefd) - } - } - - if err != nil { - conn.Done() - r.metrics.BlockConn(dir, usefd) - return nil, err - } - - r.metrics.AllowConn(dir, usefd) - return conn, nil -} - -func (r *resourceManager) OpenStream(p peer.ID, dir network.Direction) (network.StreamManagementScope, error) { - peer := r.getPeerScope(p) - stream := newStreamScope(dir, r.limits.GetStreamLimits(p), peer, r) - peer.DecRef() // we have the reference in edges - - err := stream.AddStream(dir) - if err != nil { - stream.Done() - r.metrics.BlockStream(p, dir) - return nil, err - } - - r.metrics.AllowStream(p, dir) - return stream, nil -} - -func (r *resourceManager) Close() error { - r.cancel() - r.wg.Wait() - r.trace.Close() - - return nil -} - -func (r *resourceManager) background() { - defer r.wg.Done() - - // periodically garbage collects unused peer and protocol scopes - ticker := time.NewTicker(time.Minute) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - r.gc() - case <-r.cancelCtx.Done(): - return - } - } -} - -func (r *resourceManager) gc() { - r.mx.Lock() - defer r.mx.Unlock() - - for proto, s := range r.proto { - _, sticky := r.stickyProto[proto] - if sticky { - continue - } - if s.IsUnused() { - s.Done() - delete(r.proto, proto) - } - } - - var deadPeers []peer.ID - for p, s := range r.peer { - _, sticky := r.stickyPeer[p] - if sticky { - continue - } - - if s.IsUnused() { - s.Done() - delete(r.peer, p) - deadPeers = append(deadPeers, p) - } - } - - for _, s := range r.svc { - s.Lock() - for _, p := range deadPeers { - ps, ok := s.peers[p] - if ok { - ps.Done() - delete(s.peers, p) - } - } - s.Unlock() - } - - for _, s := range r.proto { - s.Lock() - for _, p := range deadPeers { - ps, ok := s.peers[p] - if ok { - ps.Done() - delete(s.peers, p) - } - } - s.Unlock() - } -} - -func newSystemScope(limit Limit, rcmgr *resourceManager, name string) *systemScope { - return &systemScope{ - resourceScope: newResourceScope(limit, nil, name, rcmgr.trace, rcmgr.metrics), - } -} - -func newTransientScope(limit Limit, rcmgr *resourceManager, name string, systemScope *resourceScope) *transientScope { - return &transientScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{systemScope}, - name, rcmgr.trace, rcmgr.metrics), - system: rcmgr.system, - } -} - -func newServiceScope(service string, limit Limit, rcmgr *resourceManager) *serviceScope { - return &serviceScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{rcmgr.system.resourceScope}, - fmt.Sprintf("service:%s", service), rcmgr.trace, rcmgr.metrics), - service: service, - rcmgr: rcmgr, - } -} - -func newProtocolScope(proto protocol.ID, limit Limit, rcmgr *resourceManager) *protocolScope { - return &protocolScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{rcmgr.system.resourceScope}, - fmt.Sprintf("protocol:%s", proto), rcmgr.trace, rcmgr.metrics), - proto: proto, - rcmgr: rcmgr, - } -} - -func newPeerScope(p peer.ID, limit Limit, rcmgr *resourceManager) *peerScope { - return &peerScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{rcmgr.system.resourceScope}, - peerScopeName(p), rcmgr.trace, rcmgr.metrics), - peer: p, - rcmgr: rcmgr, - } -} - -func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager, endpoint multiaddr.Multiaddr) *connectionScope { - return &connectionScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{rcmgr.transient.resourceScope, rcmgr.system.resourceScope}, - connScopeName(rcmgr.nextConnId()), rcmgr.trace, rcmgr.metrics), - dir: dir, - usefd: usefd, - rcmgr: rcmgr, - endpoint: endpoint, - } -} - -func newAllowListedConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager, endpoint multiaddr.Multiaddr) *connectionScope { - return &connectionScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{rcmgr.allowlistedTransient.resourceScope, rcmgr.allowlistedSystem.resourceScope}, - connScopeName(rcmgr.nextConnId()), rcmgr.trace, rcmgr.metrics), - dir: dir, - usefd: usefd, - rcmgr: rcmgr, - endpoint: endpoint, - isAllowlisted: true, - } -} - -func newStreamScope(dir network.Direction, limit Limit, peer *peerScope, rcmgr *resourceManager) *streamScope { - return &streamScope{ - resourceScope: newResourceScope(limit, - []*resourceScope{peer.resourceScope, rcmgr.transient.resourceScope, rcmgr.system.resourceScope}, - streamScopeName(rcmgr.nextStreamId()), rcmgr.trace, rcmgr.metrics), - dir: dir, - rcmgr: peer.rcmgr, - peer: peer, - } +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.GetAllowlist instead +func GetAllowlist(mgr network.ResourceManager) *Allowlist { + return rcmgr.GetAllowlist(mgr) } +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.IsSystemScope instead func IsSystemScope(name string) bool { - return name == "system" + return rcmgr.IsSystemScope(name) } +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.IsTransientScope instead func IsTransientScope(name string) bool { - return name == "transient" -} - -func streamScopeName(streamId int64) string { - return fmt.Sprintf("stream-%d", streamId) -} - -func IsStreamScope(name string) bool { - return strings.HasPrefix(name, "stream-") && !IsSpan(name) -} - -func connScopeName(streamId int64) string { - return fmt.Sprintf("conn-%d", streamId) + return rcmgr.IsTransientScope(name) } +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.IsConnScope instead func IsConnScope(name string) bool { - return strings.HasPrefix(name, "conn-") && !IsSpan(name) -} - -func peerScopeName(p peer.ID) string { - return fmt.Sprintf("peer:%s", p) + return rcmgr.IsConnScope(name) } // ParsePeerScopeName returns "" if name is not a peerScopeName +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ParsePeerScopeName instead func ParsePeerScopeName(name string) peer.ID { - if !strings.HasPrefix(name, "peer:") || IsSpan(name) { - return "" - } - parts := strings.SplitN(name, "peer:", 2) - if len(parts) != 2 { - return "" - } - p, err := peer.Decode(parts[1]) - if err != nil { - return "" - } - return p + return rcmgr.ParsePeerScopeName(name) } // ParseServiceScopeName returns the service name if name is a serviceScopeName. // Otherwise returns "" +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ParseServiceScopeName instead func ParseServiceScopeName(name string) string { - if strings.HasPrefix(name, "service:") && !IsSpan(name) { - if strings.Contains(name, "peer:") { - // This is a service peer scope - return "" - } - parts := strings.SplitN(name, ":", 2) - if len(parts) != 2 { - return "" - } - - return parts[1] - } - return "" + return rcmgr.ParseServiceScopeName(name) } // ParseProtocolScopeName returns the service name if name is a serviceScopeName. // Otherwise returns "" +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ParseProtocolScopeName instead func ParseProtocolScopeName(name string) string { - if strings.HasPrefix(name, "protocol:") && !IsSpan(name) { - if strings.Contains(name, "peer:") { - // This is a protocol peer scope - return "" - } - parts := strings.SplitN(name, ":", 2) - if len(parts) != 2 { - return ("") - } - - return parts[1] - } - return "" -} - -func (s *serviceScope) Name() string { - return s.service -} - -func (s *serviceScope) getPeerScope(p peer.ID) *resourceScope { - s.Lock() - defer s.Unlock() - - ps, ok := s.peers[p] - if ok { - ps.IncRef() - return ps - } - - l := s.rcmgr.limits.GetServicePeerLimits(s.service) - - if s.peers == nil { - s.peers = make(map[peer.ID]*resourceScope) - } - - ps = newResourceScope(l, nil, fmt.Sprintf("%s.peer:%s", s.name, p), s.rcmgr.trace, s.rcmgr.metrics) - s.peers[p] = ps - - ps.IncRef() - return ps -} - -func (s *protocolScope) Protocol() protocol.ID { - return s.proto -} - -func (s *protocolScope) getPeerScope(p peer.ID) *resourceScope { - s.Lock() - defer s.Unlock() - - ps, ok := s.peers[p] - if ok { - ps.IncRef() - return ps - } - - l := s.rcmgr.limits.GetProtocolPeerLimits(s.proto) - - if s.peers == nil { - s.peers = make(map[peer.ID]*resourceScope) - } - - ps = newResourceScope(l, nil, fmt.Sprintf("%s.peer:%s", s.name, p), s.rcmgr.trace, s.rcmgr.metrics) - s.peers[p] = ps - - ps.IncRef() - return ps -} - -func (s *peerScope) Peer() peer.ID { - return s.peer -} - -func (s *connectionScope) PeerScope() network.PeerScope { - s.Lock() - defer s.Unlock() - - // avoid nil is not nil footgun; go.... - if s.peer == nil { - return nil - } - - return s.peer -} - -// transferAllowedToStandard transfers this connection scope from being part of -// the allowlist set of scopes to being part of the standard set of scopes. -// Happens when we first allowlisted this connection due to its IP, but later -// discovered that the peer id not what we expected. -func (s *connectionScope) transferAllowedToStandard() (err error) { - - systemScope := s.rcmgr.system.resourceScope - transientScope := s.rcmgr.transient.resourceScope - - stat := s.resourceScope.rc.stat() - - for _, scope := range s.edges { - scope.ReleaseForChild(stat) - scope.DecRef() // removed from edges - } - s.edges = nil - - if err := systemScope.ReserveForChild(stat); err != nil { - return err - } - systemScope.IncRef() - - // Undo this if we fail later - defer func() { - if err != nil { - systemScope.ReleaseForChild(stat) - systemScope.DecRef() - } - }() - - if err := transientScope.ReserveForChild(stat); err != nil { - return err - } - transientScope.IncRef() - - // Update edges - s.edges = []*resourceScope{ - systemScope, - transientScope, - } - return nil -} - -func (s *connectionScope) SetPeer(p peer.ID) error { - s.Lock() - defer s.Unlock() - - if s.peer != nil { - return fmt.Errorf("connection scope already attached to a peer") - } - - system := s.rcmgr.system - transient := s.rcmgr.transient - - if s.isAllowlisted { - system = s.rcmgr.allowlistedSystem - transient = s.rcmgr.allowlistedTransient - - if !s.rcmgr.allowlist.AllowedPeerAndMultiaddr(p, s.endpoint) { - s.isAllowlisted = false - - // This is not an allowed peer + multiaddr combination. We need to - // transfer this connection to the general scope. We'll do this first by - // transferring the connection to the system and transient scopes, then - // continue on with this function. The idea is that a connection - // shouldn't get the benefit of evading the transient scope because it - // was _almost_ an allowlisted connection. - if err := s.transferAllowedToStandard(); err != nil { - // Failed to transfer this connection to the standard scopes - return err - } - - // set the system and transient scopes to the non-allowlisted ones - system = s.rcmgr.system - transient = s.rcmgr.transient - } - } - - s.peer = s.rcmgr.getPeerScope(p) - - // juggle resources from transient scope to peer scope - stat := s.resourceScope.rc.stat() - if err := s.peer.ReserveForChild(stat); err != nil { - s.peer.DecRef() - s.peer = nil - s.rcmgr.metrics.BlockPeer(p) - return err - } - - transient.ReleaseForChild(stat) - transient.DecRef() // removed from edges - - // update edges - edges := []*resourceScope{ - s.peer.resourceScope, - system.resourceScope, - } - s.resourceScope.edges = edges - - s.rcmgr.metrics.AllowPeer(p) - return nil -} - -func (s *streamScope) ProtocolScope() network.ProtocolScope { - s.Lock() - defer s.Unlock() - - // avoid nil is not nil footgun; go.... - if s.proto == nil { - return nil - } - - return s.proto -} - -func (s *streamScope) SetProtocol(proto protocol.ID) error { - s.Lock() - defer s.Unlock() - - if s.proto != nil { - return fmt.Errorf("stream scope already attached to a protocol") - } - - s.proto = s.rcmgr.getProtocolScope(proto) - - // juggle resources from transient scope to protocol scope - stat := s.resourceScope.rc.stat() - if err := s.proto.ReserveForChild(stat); err != nil { - s.proto.DecRef() - s.proto = nil - s.rcmgr.metrics.BlockProtocol(proto) - return err - } - - s.peerProtoScope = s.proto.getPeerScope(s.peer.peer) - if err := s.peerProtoScope.ReserveForChild(stat); err != nil { - s.proto.ReleaseForChild(stat) - s.proto.DecRef() - s.proto = nil - s.peerProtoScope.DecRef() - s.peerProtoScope = nil - s.rcmgr.metrics.BlockProtocolPeer(proto, s.peer.peer) - return err - } - - s.rcmgr.transient.ReleaseForChild(stat) - s.rcmgr.transient.DecRef() // removed from edges - - // update edges - edges := []*resourceScope{ - s.peer.resourceScope, - s.peerProtoScope, - s.proto.resourceScope, - s.rcmgr.system.resourceScope, - } - s.resourceScope.edges = edges - - s.rcmgr.metrics.AllowProtocol(proto) - return nil -} - -func (s *streamScope) ServiceScope() network.ServiceScope { - s.Lock() - defer s.Unlock() - - // avoid nil is not nil footgun; go.... - if s.svc == nil { - return nil - } - - return s.svc -} - -func (s *streamScope) SetService(svc string) error { - s.Lock() - defer s.Unlock() - - if s.svc != nil { - return fmt.Errorf("stream scope already attached to a service") - } - if s.proto == nil { - return fmt.Errorf("stream scope not attached to a protocol") - } - - s.svc = s.rcmgr.getServiceScope(svc) - - // reserve resources in service - stat := s.resourceScope.rc.stat() - if err := s.svc.ReserveForChild(stat); err != nil { - s.svc.DecRef() - s.svc = nil - s.rcmgr.metrics.BlockService(svc) - return err - } - - // get the per peer service scope constraint, if any - s.peerSvcScope = s.svc.getPeerScope(s.peer.peer) - if err := s.peerSvcScope.ReserveForChild(stat); err != nil { - s.svc.ReleaseForChild(stat) - s.svc.DecRef() - s.svc = nil - s.peerSvcScope.DecRef() - s.peerSvcScope = nil - s.rcmgr.metrics.BlockServicePeer(svc, s.peer.peer) - return err - } - - // update edges - edges := []*resourceScope{ - s.peer.resourceScope, - s.peerProtoScope, - s.peerSvcScope, - s.proto.resourceScope, - s.svc.resourceScope, - s.rcmgr.system.resourceScope, - } - s.resourceScope.edges = edges - - s.rcmgr.metrics.AllowService(svc) - return nil -} - -func (s *streamScope) PeerScope() network.PeerScope { - s.Lock() - defer s.Unlock() - - // avoid nil is not nil footgun; go.... - if s.peer == nil { - return nil - } - - return s.peer + return rcmgr.ParseProtocolScopeName(name) } diff --git a/rcmgr_test.go b/rcmgr_test.go deleted file mode 100644 index de41cf6..0000000 --- a/rcmgr_test.go +++ /dev/null @@ -1,1052 +0,0 @@ -package rcmgr - -import ( - "testing" - - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/protocol" - "github.com/libp2p/go-libp2p-core/test" - "github.com/multiformats/go-multiaddr" -) - -var dummyMA = multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234") - -func TestResourceManager(t *testing.T) { - peerA := peer.ID("A") - peerB := peer.ID("B") - protoA := protocol.ID("/A") - protoB := protocol.ID("/B") - svcA := "A.svc" - svcB := "B.svc" - nmgr, err := NewResourceManager( - NewFixedLimiter(LimitConfig{ - System: BaseLimit{ - Memory: 16384, - StreamsInbound: 3, - StreamsOutbound: 3, - Streams: 6, - ConnsInbound: 3, - ConnsOutbound: 3, - Conns: 6, - FD: 2, - }, - Transient: BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 2, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 2, - FD: 1, - }, - ServiceDefault: BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 2, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 2, - FD: 1, - }, - ServicePeerDefault: BaseLimit{ - Memory: 4096, - StreamsInbound: 5, - StreamsOutbound: 5, - Streams: 10, - }, - Service: map[string]BaseLimit{ - svcA: { - Memory: 8192, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 4, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 4, - FD: 1, - }, - svcB: { - Memory: 8192, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 4, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 4, - FD: 1, - }, - }, - ServicePeer: map[string]BaseLimit{ - svcB: { - Memory: 8192, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 2, - }, - }, - ProtocolDefault: BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 2, - }, - Protocol: map[protocol.ID]BaseLimit{ - protoA: { - Memory: 8192, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 2, - }, - }, - ProtocolPeer: map[protocol.ID]BaseLimit{ - protoB: { - Memory: 8192, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 2, - }, - }, - PeerDefault: BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 2, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 2, - FD: 1, - }, - ProtocolPeerDefault: BaseLimit{ - Memory: 4096, - StreamsInbound: 5, - StreamsOutbound: 5, - Streams: 10, - }, - Peer: map[peer.ID]BaseLimit{ - peerA: { - Memory: 8192, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 4, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 4, - FD: 1, - }, - }, - Conn: BaseLimit{ - Memory: 4096, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }, - Stream: BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - }, - }), - ) - - if err != nil { - t.Fatal(err) - } - - mgr := nmgr.(*resourceManager) - defer mgr.Close() - - checkRefCnt := func(s *resourceScope, count int) { - t.Helper() - if refCnt := s.refCnt; refCnt != count { - t.Fatalf("expected refCnt of %d, got %d", count, refCnt) - } - } - checkSystem := func(check func(s *resourceScope)) { - if err := mgr.ViewSystem(func(s network.ResourceScope) error { - check(s.(*systemScope).resourceScope) - return nil - }); err != nil { - t.Fatal(err) - } - } - checkTransient := func(check func(s *resourceScope)) { - if err := mgr.ViewTransient(func(s network.ResourceScope) error { - check(s.(*transientScope).resourceScope) - return nil - }); err != nil { - t.Fatal(err) - } - } - checkService := func(svc string, check func(s *resourceScope)) { - if err := mgr.ViewService(svc, func(s network.ServiceScope) error { - check(s.(*serviceScope).resourceScope) - return nil - }); err != nil { - t.Fatal(err) - } - } - checkProtocol := func(p protocol.ID, check func(s *resourceScope)) { - if err := mgr.ViewProtocol(p, func(s network.ProtocolScope) error { - check(s.(*protocolScope).resourceScope) - return nil - }); err != nil { - t.Fatal(err) - } - } - checkPeer := func(p peer.ID, check func(s *resourceScope)) { - if err := mgr.ViewPeer(p, func(s network.PeerScope) error { - check(s.(*peerScope).resourceScope) - return nil - }); err != nil { - t.Fatal(err) - } - } - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // open an inbound connection, using an fd - conn, err := mgr.OpenConnection(network.DirInbound, true, dummyMA) - if err != nil { - t.Fatal(err) - } - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - - // the connection is transient, we shouldn't be able to open a second one - if _, err := mgr.OpenConnection(network.DirInbound, true, dummyMA); err == nil { - t.Fatal("expected OpenConnection to fail") - } - if _, err := mgr.OpenConnection(network.DirInbound, false, dummyMA); err == nil { - t.Fatal("expected OpenConnection to fail") - } - - // close it to check resources are reclaimed - conn.Done() - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // open another inbound connection, using an fd - conn1, err := mgr.OpenConnection(network.DirInbound, true, dummyMA) - if err != nil { - t.Fatal(err) - } - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - - // check nility of current peer scope - if conn1.PeerScope() != nil { - t.Fatal("peer scope should be nil") - } - - // attach to a peer - if err := conn1.SetPeer(peerA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 4) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // we should be able to open a second transient connection now - conn2, err := mgr.OpenConnection(network.DirInbound, true, dummyMA) - if err != nil { - t.Fatal(err) - } - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - - // but we shouldn't be able to attach it to the same peer due to the fd limit - if err := conn2.SetPeer(peerA); err == nil { - t.Fatal("expected SetPeer to fail") - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - }) - - // close it and reopen without using an FD -- we should be able to attach now - conn2.Done() - - conn2, err = mgr.OpenConnection(network.DirInbound, false, dummyMA) - if err != nil { - t.Fatal(err) - } - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 0}) - }) - - if err := conn2.SetPeer(peerA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // open a stream - stream, err := mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 4) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 6) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - // the stream is transient we shouldn't be able to open a second one - if _, err := mgr.OpenStream(peerA, network.DirInbound); err == nil { - t.Fatal("expected OpenStream to fail") - } - - // close the stream to check resource reclamation - stream.Done() - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // open another stream, but this time attach it to a protocol - stream1, err := mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 4) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 6) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - // check nility of protocol scope - if stream1.ProtocolScope() != nil { - t.Fatal("protocol scope should be nil") - } - - if err := stream1.SetProtocol(protoA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 4) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 7) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // and now we should be able to open another stream and attach it to the protocol - stream2, err := mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 8) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - if err := stream2.SetProtocol(protoA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 8) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // open a 3rd stream, and try to attach it to the same protocol - stream3, err := mgr.OpenStream(peerB, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 10) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - if err := stream3.SetProtocol(protoA); err == nil { - t.Fatal("expected SetProtocol to fail") - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 10) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - // but we should be able to set to another protocol - if err := stream3.SetProtocol(protoB); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 11) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // check nility of current service scope - if stream1.ServiceScope() != nil { - t.Fatal("service scope should be nil") - } - - // we should be able to attach stream1 and stream2 to svcA, but stream3 should fail due to limit - if err := stream1.SetService(svcA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkService(svcA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 12) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - if err := stream2.SetService(svcA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkService(svcA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 12) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - if err := stream3.SetService(svcA); err == nil { - t.Fatal("expected SetService to fail") - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkService(svcA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 12) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // and now let's reclaim our resources to make sure we can gc unused peer and proto scopes - // but first check internal refs - mgr.mx.Lock() - _, okProtoA := mgr.proto[protoA] - _, okProtoB := mgr.proto[protoB] - _, okPeerA := mgr.peer[peerA] - _, okPeerB := mgr.peer[peerB] - mgr.mx.Unlock() - - if !okProtoA { - t.Fatal("protocol scope is not stored") - } - if !okProtoB { - t.Fatal("protocol scope is not stored") - } - if !okPeerA { - t.Fatal("peer scope is not stored") - } - if !okPeerB { - t.Fatal("peer scope is not stored") - } - - // ok, reclaim - stream1.Done() - stream2.Done() - stream3.Done() - conn1.Done() - conn2.Done() - - // check everything released - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkPeer(peerB, func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkService(svcA, func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 7) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - mgr.gc() - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - mgr.mx.Lock() - lenProto := len(mgr.proto) - lenPeer := len(mgr.peer) - mgr.mx.Unlock() - - if lenProto != 0 { - t.Fatal("protocols were not gc'ed") - } - if lenPeer != 0 { - t.Fatal("perrs were not gc'ed") - } - - // check that per protocol peer scopes work as intended - stream1, err = mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 5) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - if err := stream1.SetProtocol(protoB); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 6) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - stream2, err = mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 7) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - if err := stream2.SetProtocol(protoB); err == nil { - t.Fatal("expected SetProtocol to fail") - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 7) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - stream1.Done() - stream2.Done() - - // check that per service peer scopes work as intended - stream1, err = mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 6) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - if err := stream1.SetProtocol(protoA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 7) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - stream2, err = mgr.OpenStream(peerA, network.DirInbound) - if err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 8) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - - if err := stream2.SetProtocol(protoA); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 8) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - if err := stream1.SetService(svcB); err != nil { - t.Fatal(err) - } - - checkPeer(peerA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkService(svcB, func(s *resourceScope) { - checkRefCnt(s, 2) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - }) - checkProtocol(protoA, func(s *resourceScope) { - checkRefCnt(s, 3) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 9) - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - // now we should fail to set the service for stream2 to svcB because of the service peer limit - if err := stream2.SetService(svcB); err == nil { - t.Fatal("expected SetService to fail") - } - - // now release resources and check interior gc of per service peer scopes - stream1.Done() - stream2.Done() - - mgr.gc() - - checkSystem(func(s *resourceScope) { - checkRefCnt(s, 4) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - checkTransient(func(s *resourceScope) { - checkRefCnt(s, 1) - checkResources(t, &s.rc, network.ScopeStat{}) - }) - - mgr.mx.Lock() - lenProto = len(mgr.proto) - lenPeer = len(mgr.peer) - mgr.mx.Unlock() - - svc := mgr.svc[svcB] - svc.Lock() - lenSvcPeer := len(svc.peers) - svc.Unlock() - - if lenProto != 0 { - t.Fatal("protocols were not gc'ed") - } - if lenPeer != 0 { - t.Fatal("peers were not gc'ed") - } - if lenSvcPeer != 0 { - t.Fatal("service peers were not gc'ed") - } - -} - -func TestResourceManagerWithAllowlist(t *testing.T) { - peerA := test.RandPeerIDFatal(t) - - limits := DefaultLimits.AutoScale() - limits.System.Conns = 0 - limits.Transient.Conns = 0 - - baseLimit := BaseLimit{ - Conns: 2, - ConnsInbound: 2, - ConnsOutbound: 1, - } - baseLimit.Apply(limits.AllowlistedSystem) - limits.AllowlistedSystem = baseLimit - - baseLimit = BaseLimit{ - Conns: 1, - ConnsInbound: 1, - ConnsOutbound: 1, - } - baseLimit.Apply(limits.AllowlistedTransient) - limits.AllowlistedTransient = baseLimit - - rcmgr, err := NewResourceManager(NewFixedLimiter(limits), WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{ - multiaddr.StringCast("/ip4/1.2.3.4"), - multiaddr.StringCast("/ip4/4.3.2.1/p2p/" + peerA.String()), - })) - if err != nil { - t.Fatal(err) - } - defer rcmgr.Close() - - ableToGetAllowlist := GetAllowlist(rcmgr) - if ableToGetAllowlist == nil { - t.Fatal("Expected to be able to get the allowlist") - } - - // A connection comes in from a non-allowlisted ip address - _, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/1.2.3.5")) - if err == nil { - t.Fatalf("Expected this to fail. err=%v", err) - } - - // A connection comes in from an allowlisted ip address - connScope, err := rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/1.2.3.4")) - if err != nil { - t.Fatal(err) - } - - err = connScope.SetPeer(test.RandPeerIDFatal(t)) - if err != nil { - t.Fatal(err) - } - - // A connection comes in that looks like it should be allowlisted, but then has the wrong peer id. - connScope, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/4.3.2.1")) - if err != nil { - t.Fatal(err) - } - - err = connScope.SetPeer(test.RandPeerIDFatal(t)) - if err == nil { - t.Fatalf("Expected this to fail. err=%v", err) - } - - // A connection comes in that looks like it should be allowlisted, and it has the allowlisted peer id - connScope, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/4.3.2.1")) - if err != nil { - t.Fatal(err) - } - - err = connScope.SetPeer(peerA) - if err != nil { - t.Fatal(err) - } -} diff --git a/scope.go b/scope.go index 2190527..9ab03ad 100644 --- a/scope.go +++ b/scope.go @@ -1,771 +1,11 @@ package rcmgr import ( - "fmt" - "strings" - "sync" - - "github.com/libp2p/go-libp2p-core/network" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) -// resources tracks the current state of resource consumption -type resources struct { - limit Limit - - nconnsIn, nconnsOut int - nstreamsIn, nstreamsOut int - nfd int - - memory int64 -} - -// A resourceScope can be a DAG, where a downstream node is not allowed to outlive an upstream node -// (ie cannot call Done in the upstream node before the downstream node) and account for resources -// using a linearized parent set. -// A resourceScope can be a span scope, where it has a specific owner; span scopes create a tree rooted -// at the owner (which can be a DAG scope) and can outlive their parents -- this is important because -// span scopes are the main *user* interface for memory management, and the user may call -// Done in a span scope after the system has closed the root of the span tree in some background -// goroutine. -// If we didn't make this distinction we would have a double release problem in that case. -type resourceScope struct { - sync.Mutex - done bool - refCnt int - - spanID int - - rc resources - owner *resourceScope // set in span scopes, which define trees - edges []*resourceScope // set in DAG scopes, it's the linearized parent set - - name string // for debugging purposes - trace *trace // debug tracing - metrics *metrics // metrics collection -} - -var _ network.ResourceScope = (*resourceScope)(nil) -var _ network.ResourceScopeSpan = (*resourceScope)(nil) - -func newResourceScope(limit Limit, edges []*resourceScope, name string, trace *trace, metrics *metrics) *resourceScope { - for _, e := range edges { - e.IncRef() - } - r := &resourceScope{ - rc: resources{limit: limit}, - edges: edges, - name: name, - trace: trace, - metrics: metrics, - } - r.trace.CreateScope(name, limit) - return r -} - -func newResourceScopeSpan(owner *resourceScope, id int) *resourceScope { - r := &resourceScope{ - rc: resources{limit: owner.rc.limit}, - owner: owner, - name: fmt.Sprintf("%s.span-%d", owner.name, id), - trace: owner.trace, - metrics: owner.metrics, - } - r.trace.CreateScope(r.name, r.rc.limit) - return r -} - // IsSpan will return true if this name was created by newResourceScopeSpan +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.IsSpan instead func IsSpan(name string) bool { - return strings.Contains(name, ".span-") -} - -// Resources implementation -func (rc *resources) checkMemory(rsvp int64, prio uint8) error { - // overflow check; this also has the side effect that we cannot reserve negative memory. - newmem := rc.memory + rsvp - limit := rc.limit.GetMemoryLimit() - threshold := (1 + int64(prio)) * limit / 256 - - if newmem > threshold { - return &errMemoryLimitExceeded{ - current: rc.memory, - attempted: rsvp, - limit: limit, - priority: prio, - err: network.ErrResourceLimitExceeded, - } - } - return nil -} - -func (rc *resources) reserveMemory(size int64, prio uint8) error { - if err := rc.checkMemory(size, prio); err != nil { - return err - } - - rc.memory += size - return nil -} - -func (rc *resources) releaseMemory(size int64) { - rc.memory -= size - - // sanity check for bugs upstream - if rc.memory < 0 { - log.Warn("BUG: too much memory released") - rc.memory = 0 - } -} - -func (rc *resources) addStream(dir network.Direction) error { - if dir == network.DirInbound { - return rc.addStreams(1, 0) - } - return rc.addStreams(0, 1) -} - -func (rc *resources) addStreams(incount, outcount int) error { - if incount > 0 { - limit := rc.limit.GetStreamLimit(network.DirInbound) - if rc.nstreamsIn+incount > limit { - return &errStreamOrConnLimitExceeded{ - current: rc.nstreamsIn, - attempted: incount, - limit: limit, - err: fmt.Errorf("cannot reserve inbound stream: %w", network.ErrResourceLimitExceeded), - } - } - } - if outcount > 0 { - limit := rc.limit.GetStreamLimit(network.DirOutbound) - if rc.nstreamsOut+outcount > limit { - return &errStreamOrConnLimitExceeded{ - current: rc.nstreamsOut, - attempted: outcount, - limit: limit, - err: fmt.Errorf("cannot reserve outbound stream: %w", network.ErrResourceLimitExceeded), - } - } - } - - if limit := rc.limit.GetStreamTotalLimit(); rc.nstreamsIn+incount+rc.nstreamsOut+outcount > limit { - return &errStreamOrConnLimitExceeded{ - current: rc.nstreamsIn + rc.nstreamsOut, - attempted: incount + outcount, - limit: limit, - err: fmt.Errorf("cannot reserve stream: %w", network.ErrResourceLimitExceeded), - } - } - - rc.nstreamsIn += incount - rc.nstreamsOut += outcount - return nil -} - -func (rc *resources) removeStream(dir network.Direction) { - if dir == network.DirInbound { - rc.removeStreams(1, 0) - } else { - rc.removeStreams(0, 1) - } -} - -func (rc *resources) removeStreams(incount, outcount int) { - rc.nstreamsIn -= incount - rc.nstreamsOut -= outcount - - if rc.nstreamsIn < 0 { - log.Warn("BUG: too many inbound streams released") - rc.nstreamsIn = 0 - } - if rc.nstreamsOut < 0 { - log.Warn("BUG: too many outbound streams released") - rc.nstreamsOut = 0 - } -} - -func (rc *resources) addConn(dir network.Direction, usefd bool) error { - var fd int - if usefd { - fd = 1 - } - - if dir == network.DirInbound { - return rc.addConns(1, 0, fd) - } - - return rc.addConns(0, 1, fd) -} - -func (rc *resources) addConns(incount, outcount, fdcount int) error { - if incount > 0 { - limit := rc.limit.GetConnLimit(network.DirInbound) - if rc.nconnsIn+incount > limit { - return &errStreamOrConnLimitExceeded{ - current: rc.nconnsIn, - attempted: incount, - limit: limit, - err: fmt.Errorf("cannot reserve inbound connection: %w", network.ErrResourceLimitExceeded), - } - } - } - if outcount > 0 { - limit := rc.limit.GetConnLimit(network.DirOutbound) - if rc.nconnsOut+outcount > limit { - return &errStreamOrConnLimitExceeded{ - current: rc.nconnsOut, - attempted: outcount, - limit: limit, - err: fmt.Errorf("cannot reserve outbound connection: %w", network.ErrResourceLimitExceeded), - } - } - } - - if connLimit := rc.limit.GetConnTotalLimit(); rc.nconnsIn+incount+rc.nconnsOut+outcount > connLimit { - return &errStreamOrConnLimitExceeded{ - current: rc.nconnsIn + rc.nconnsOut, - attempted: incount + outcount, - limit: connLimit, - err: fmt.Errorf("cannot reserve connection: %w", network.ErrResourceLimitExceeded), - } - } - if fdcount > 0 { - limit := rc.limit.GetFDLimit() - if rc.nfd+fdcount > limit { - return &errStreamOrConnLimitExceeded{ - current: rc.nfd, - attempted: fdcount, - limit: limit, - err: fmt.Errorf("cannot reserve file descriptor: %w", network.ErrResourceLimitExceeded), - } - } - } - - rc.nconnsIn += incount - rc.nconnsOut += outcount - rc.nfd += fdcount - return nil -} - -func (rc *resources) removeConn(dir network.Direction, usefd bool) { - var fd int - if usefd { - fd = 1 - } - - if dir == network.DirInbound { - rc.removeConns(1, 0, fd) - } else { - rc.removeConns(0, 1, fd) - } -} - -func (rc *resources) removeConns(incount, outcount, fdcount int) { - rc.nconnsIn -= incount - rc.nconnsOut -= outcount - rc.nfd -= fdcount - - if rc.nconnsIn < 0 { - log.Warn("BUG: too many inbound connections released") - rc.nconnsIn = 0 - } - if rc.nconnsOut < 0 { - log.Warn("BUG: too many outbound connections released") - rc.nconnsOut = 0 - } - if rc.nfd < 0 { - log.Warn("BUG: too many file descriptors released") - rc.nfd = 0 - } -} - -func (rc *resources) stat() network.ScopeStat { - return network.ScopeStat{ - Memory: rc.memory, - NumStreamsInbound: rc.nstreamsIn, - NumStreamsOutbound: rc.nstreamsOut, - NumConnsInbound: rc.nconnsIn, - NumConnsOutbound: rc.nconnsOut, - NumFD: rc.nfd, - } -} - -// resourceScope implementation -func (s *resourceScope) wrapError(err error) error { - return fmt.Errorf("%s: %w", s.name, err) -} - -func (s *resourceScope) ReserveMemory(size int, prio uint8) error { - s.Lock() - defer s.Unlock() - - if s.done { - return s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.reserveMemory(int64(size), prio); err != nil { - log.Debugw("blocked memory reservation", logValuesMemoryLimit(s.name, "", s.rc.stat(), err)...) - s.trace.BlockReserveMemory(s.name, prio, int64(size), s.rc.memory) - s.metrics.BlockMemory(size) - return s.wrapError(err) - } - - if err := s.reserveMemoryForEdges(size, prio); err != nil { - s.rc.releaseMemory(int64(size)) - s.metrics.BlockMemory(size) - return s.wrapError(err) - } - - s.trace.ReserveMemory(s.name, prio, int64(size), s.rc.memory) - s.metrics.AllowMemory(size) - return nil -} - -func (s *resourceScope) reserveMemoryForEdges(size int, prio uint8) error { - if s.owner != nil { - return s.owner.ReserveMemory(size, prio) - } - - var reserved int - var err error - for _, e := range s.edges { - var stat network.ScopeStat - stat, err = e.ReserveMemoryForChild(int64(size), prio) - if err != nil { - log.Debugw("blocked memory reservation from constraining edge", logValuesMemoryLimit(s.name, e.name, stat, err)...) - break - } - - reserved++ - } - - if err != nil { - // we failed because of a constraint; undo memory reservations - for _, e := range s.edges[:reserved] { - e.ReleaseMemoryForChild(int64(size)) - } - } - - return err -} - -func (s *resourceScope) releaseMemoryForEdges(size int) { - if s.owner != nil { - s.owner.ReleaseMemory(size) - return - } - - for _, e := range s.edges { - e.ReleaseMemoryForChild(int64(size)) - } -} - -func (s *resourceScope) ReserveMemoryForChild(size int64, prio uint8) (network.ScopeStat, error) { - s.Lock() - defer s.Unlock() - - if s.done { - return s.rc.stat(), s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.reserveMemory(size, prio); err != nil { - s.trace.BlockReserveMemory(s.name, prio, size, s.rc.memory) - return s.rc.stat(), s.wrapError(err) - } - - s.trace.ReserveMemory(s.name, prio, size, s.rc.memory) - return network.ScopeStat{}, nil -} - -func (s *resourceScope) ReleaseMemory(size int) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.releaseMemory(int64(size)) - s.releaseMemoryForEdges(size) - s.trace.ReleaseMemory(s.name, int64(size), s.rc.memory) -} - -func (s *resourceScope) ReleaseMemoryForChild(size int64) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.releaseMemory(size) - s.trace.ReleaseMemory(s.name, size, s.rc.memory) -} - -func (s *resourceScope) AddStream(dir network.Direction) error { - s.Lock() - defer s.Unlock() - - if s.done { - return s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.addStream(dir); err != nil { - log.Debugw("blocked stream", logValuesStreamLimit(s.name, "", dir, s.rc.stat(), err)...) - s.trace.BlockAddStream(s.name, dir, s.rc.nstreamsIn, s.rc.nstreamsOut) - return s.wrapError(err) - } - - if err := s.addStreamForEdges(dir); err != nil { - s.rc.removeStream(dir) - return s.wrapError(err) - } - - s.trace.AddStream(s.name, dir, s.rc.nstreamsIn, s.rc.nstreamsOut) - return nil -} - -func (s *resourceScope) addStreamForEdges(dir network.Direction) error { - if s.owner != nil { - return s.owner.AddStream(dir) - } - - var err error - var reserved int - for _, e := range s.edges { - var stat network.ScopeStat - stat, err = e.AddStreamForChild(dir) - if err != nil { - log.Debugw("blocked stream from constraining edge", logValuesStreamLimit(s.name, e.name, dir, stat, err)...) - break - } - reserved++ - } - - if err != nil { - for _, e := range s.edges[:reserved] { - e.RemoveStreamForChild(dir) - } - } - - return err -} - -func (s *resourceScope) AddStreamForChild(dir network.Direction) (network.ScopeStat, error) { - s.Lock() - defer s.Unlock() - - if s.done { - return s.rc.stat(), s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.addStream(dir); err != nil { - s.trace.BlockAddStream(s.name, dir, s.rc.nstreamsIn, s.rc.nstreamsOut) - return s.rc.stat(), s.wrapError(err) - } - - s.trace.AddStream(s.name, dir, s.rc.nstreamsIn, s.rc.nstreamsOut) - return network.ScopeStat{}, nil -} - -func (s *resourceScope) RemoveStream(dir network.Direction) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.removeStream(dir) - s.removeStreamForEdges(dir) - s.trace.RemoveStream(s.name, dir, s.rc.nstreamsIn, s.rc.nstreamsOut) -} - -func (s *resourceScope) removeStreamForEdges(dir network.Direction) { - if s.owner != nil { - s.owner.RemoveStream(dir) - return - } - - for _, e := range s.edges { - e.RemoveStreamForChild(dir) - } -} - -func (s *resourceScope) RemoveStreamForChild(dir network.Direction) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.removeStream(dir) - s.trace.RemoveStream(s.name, dir, s.rc.nstreamsIn, s.rc.nstreamsOut) -} - -func (s *resourceScope) AddConn(dir network.Direction, usefd bool) error { - s.Lock() - defer s.Unlock() - - if s.done { - return s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.addConn(dir, usefd); err != nil { - log.Debugw("blocked connection", logValuesConnLimit(s.name, "", dir, usefd, s.rc.stat(), err)...) - s.trace.BlockAddConn(s.name, dir, usefd, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) - return s.wrapError(err) - } - - if err := s.addConnForEdges(dir, usefd); err != nil { - s.rc.removeConn(dir, usefd) - return s.wrapError(err) - } - - s.trace.AddConn(s.name, dir, usefd, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) - return nil -} - -func (s *resourceScope) addConnForEdges(dir network.Direction, usefd bool) error { - if s.owner != nil { - return s.owner.AddConn(dir, usefd) - } - - var err error - var reserved int - for _, e := range s.edges { - var stat network.ScopeStat - stat, err = e.AddConnForChild(dir, usefd) - if err != nil { - log.Debugw("blocked connection from constraining edge", logValuesConnLimit(s.name, e.name, dir, usefd, stat, err)...) - break - } - reserved++ - } - - if err != nil { - for _, e := range s.edges[:reserved] { - e.RemoveConnForChild(dir, usefd) - } - } - - return err -} - -func (s *resourceScope) AddConnForChild(dir network.Direction, usefd bool) (network.ScopeStat, error) { - s.Lock() - defer s.Unlock() - - if s.done { - return s.rc.stat(), s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.addConn(dir, usefd); err != nil { - s.trace.BlockAddConn(s.name, dir, usefd, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) - return s.rc.stat(), s.wrapError(err) - } - - s.trace.AddConn(s.name, dir, usefd, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) - return network.ScopeStat{}, nil -} - -func (s *resourceScope) RemoveConn(dir network.Direction, usefd bool) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.removeConn(dir, usefd) - s.removeConnForEdges(dir, usefd) - s.trace.RemoveConn(s.name, dir, usefd, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) -} - -func (s *resourceScope) removeConnForEdges(dir network.Direction, usefd bool) { - if s.owner != nil { - s.owner.RemoveConn(dir, usefd) - } - - for _, e := range s.edges { - e.RemoveConnForChild(dir, usefd) - } -} - -func (s *resourceScope) RemoveConnForChild(dir network.Direction, usefd bool) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.removeConn(dir, usefd) - s.trace.RemoveConn(s.name, dir, usefd, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) -} - -func (s *resourceScope) ReserveForChild(st network.ScopeStat) error { - s.Lock() - defer s.Unlock() - - if s.done { - return s.wrapError(network.ErrResourceScopeClosed) - } - - if err := s.rc.reserveMemory(st.Memory, network.ReservationPriorityAlways); err != nil { - s.trace.BlockReserveMemory(s.name, 255, st.Memory, s.rc.memory) - return s.wrapError(err) - } - - if err := s.rc.addStreams(st.NumStreamsInbound, st.NumStreamsOutbound); err != nil { - s.trace.BlockAddStreams(s.name, st.NumStreamsInbound, st.NumStreamsOutbound, s.rc.nstreamsIn, s.rc.nstreamsOut) - s.rc.releaseMemory(st.Memory) - return s.wrapError(err) - } - - if err := s.rc.addConns(st.NumConnsInbound, st.NumConnsOutbound, st.NumFD); err != nil { - s.trace.BlockAddConns(s.name, st.NumConnsInbound, st.NumConnsOutbound, st.NumFD, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) - - s.rc.releaseMemory(st.Memory) - s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound) - return s.wrapError(err) - } - - s.trace.ReserveMemory(s.name, 255, st.Memory, s.rc.memory) - s.trace.AddStreams(s.name, st.NumStreamsInbound, st.NumStreamsOutbound, s.rc.nstreamsIn, s.rc.nstreamsOut) - s.trace.AddConns(s.name, st.NumConnsInbound, st.NumConnsOutbound, st.NumFD, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) - - return nil -} - -func (s *resourceScope) ReleaseForChild(st network.ScopeStat) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.releaseMemory(st.Memory) - s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound) - s.rc.removeConns(st.NumConnsInbound, st.NumConnsOutbound, st.NumFD) - - s.trace.ReleaseMemory(s.name, st.Memory, s.rc.memory) - s.trace.RemoveStreams(s.name, st.NumStreamsInbound, st.NumStreamsOutbound, s.rc.nstreamsIn, s.rc.nstreamsOut) - s.trace.RemoveConns(s.name, st.NumConnsInbound, st.NumConnsOutbound, st.NumFD, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) -} - -func (s *resourceScope) ReleaseResources(st network.ScopeStat) { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - s.rc.releaseMemory(st.Memory) - s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound) - s.rc.removeConns(st.NumConnsInbound, st.NumConnsOutbound, st.NumFD) - - if s.owner != nil { - s.owner.ReleaseResources(st) - } else { - for _, e := range s.edges { - e.ReleaseForChild(st) - } - } - - s.trace.ReleaseMemory(s.name, st.Memory, s.rc.memory) - s.trace.RemoveStreams(s.name, st.NumStreamsInbound, st.NumStreamsOutbound, s.rc.nstreamsIn, s.rc.nstreamsOut) - s.trace.RemoveConns(s.name, st.NumConnsInbound, st.NumConnsOutbound, st.NumFD, s.rc.nconnsIn, s.rc.nconnsOut, s.rc.nfd) -} - -func (s *resourceScope) nextSpanID() int { - s.spanID++ - return s.spanID -} - -func (s *resourceScope) BeginSpan() (network.ResourceScopeSpan, error) { - s.Lock() - defer s.Unlock() - - if s.done { - return nil, s.wrapError(network.ErrResourceScopeClosed) - } - - s.refCnt++ - return newResourceScopeSpan(s, s.nextSpanID()), nil -} - -func (s *resourceScope) Done() { - s.Lock() - defer s.Unlock() - - if s.done { - return - } - - stat := s.rc.stat() - if s.owner != nil { - s.owner.ReleaseResources(stat) - s.owner.DecRef() - } else { - for _, e := range s.edges { - e.ReleaseForChild(stat) - e.DecRef() - } - } - - s.rc.nstreamsIn = 0 - s.rc.nstreamsOut = 0 - s.rc.nconnsIn = 0 - s.rc.nconnsOut = 0 - s.rc.nfd = 0 - s.rc.memory = 0 - - s.done = true - - s.trace.DestroyScope(s.name) -} - -func (s *resourceScope) Stat() network.ScopeStat { - s.Lock() - defer s.Unlock() - - return s.rc.stat() -} - -func (s *resourceScope) IncRef() { - s.Lock() - defer s.Unlock() - - s.refCnt++ -} - -func (s *resourceScope) DecRef() { - s.Lock() - defer s.Unlock() - - s.refCnt-- -} - -func (s *resourceScope) IsUnused() bool { - s.Lock() - defer s.Unlock() - - if s.done { - return true - } - - if s.refCnt > 0 { - return false - } - - st := s.rc.stat() - return st.NumStreamsInbound == 0 && - st.NumStreamsOutbound == 0 && - st.NumConnsInbound == 0 && - st.NumConnsOutbound == 0 && - st.NumFD == 0 + return rcmgr.IsSpan(name) } diff --git a/scope_test.go b/scope_test.go deleted file mode 100644 index 3743068..0000000 --- a/scope_test.go +++ /dev/null @@ -1,1200 +0,0 @@ -package rcmgr - -import ( - "testing" - - "github.com/libp2p/go-libp2p-core/network" -) - -func checkResources(t *testing.T, rc *resources, st network.ScopeStat) { - t.Helper() - - if rc.nconnsIn != st.NumConnsInbound { - t.Fatalf("expected %d inbound conns, got %d", st.NumConnsInbound, rc.nconnsIn) - } - if rc.nconnsOut != st.NumConnsOutbound { - t.Fatalf("expected %d outbound conns, got %d", st.NumConnsOutbound, rc.nconnsOut) - } - if rc.nstreamsIn != st.NumStreamsInbound { - t.Fatalf("expected %d inbound streams, got %d", st.NumStreamsInbound, rc.nstreamsIn) - } - if rc.nstreamsOut != st.NumStreamsOutbound { - t.Fatalf("expected %d outbound streams, got %d", st.NumStreamsOutbound, rc.nstreamsOut) - } - if rc.nfd != st.NumFD { - t.Fatalf("expected %d file descriptors, got %d", st.NumFD, rc.nfd) - } - if rc.memory != st.Memory { - t.Fatalf("expected %d reserved bytes of memory, got %d", st.Memory, rc.memory) - } -} - -func TestResources(t *testing.T) { - rc := resources{limit: &BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }} - - checkResources(t, &rc, network.ScopeStat{}) - - // test checkMemory - if err := rc.checkMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(2048, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(3072, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(4096, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(8192, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected memory check to fail") - } - - if err := rc.checkMemory(1024, network.ReservationPriorityLow); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(2048, network.ReservationPriorityLow); err == nil { - t.Fatal("expected memory check to fail") - } - - if err := rc.checkMemory(2048, network.ReservationPriorityMedium); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(3072, network.ReservationPriorityMedium); err == nil { - t.Fatal("expected memory check to fail") - } - - if err := rc.checkMemory(3072, network.ReservationPriorityHigh); err != nil { - t.Fatal(err) - } - - if err := rc.checkMemory(3584, network.ReservationPriorityHigh); err == nil { - t.Fatal("expected memory check to fail") - } - - // test reserveMemory - if err := rc.reserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 1024}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 2048}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 3072}) - - if err := rc.reserveMemory(512, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 3584}) - - if err := rc.reserveMemory(4096, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected memory reservation to fail") - } - checkResources(t, &rc, network.ScopeStat{Memory: 3584}) - - rc.releaseMemory(2560) - checkResources(t, &rc, network.ScopeStat{Memory: 1024}) - - if err := rc.reserveMemory(2048, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 3072}) - - rc.releaseMemory(3072) - checkResources(t, &rc, network.ScopeStat{}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityLow); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 1024}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityLow); err == nil { - t.Fatal("expected memory check to fail") - } - checkResources(t, &rc, network.ScopeStat{Memory: 1024}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityMedium); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 2048}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityMedium); err == nil { - t.Fatal("expected memory check to fail") - } - checkResources(t, &rc, network.ScopeStat{Memory: 2048}) - - if err := rc.reserveMemory(1024, network.ReservationPriorityHigh); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 3072}) - - if err := rc.reserveMemory(512, network.ReservationPriorityHigh); err == nil { - t.Fatal("expected memory check to fail") - } - checkResources(t, &rc, network.ScopeStat{Memory: 3072}) - - if err := rc.reserveMemory(512, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{Memory: 3584}) - - rc.releaseMemory(3584) - checkResources(t, &rc, network.ScopeStat{}) - - // test addStream - if err := rc.addStream(network.DirInbound); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{NumStreamsInbound: 1}) - - if err := rc.addStream(network.DirInbound); err == nil { - t.Fatal("expected addStream to fail") - } - checkResources(t, &rc, network.ScopeStat{NumStreamsInbound: 1}) - - if err := rc.addStream(network.DirOutbound); err == nil { - t.Fatal("expected addStream to fail") - } - checkResources(t, &rc, network.ScopeStat{NumStreamsInbound: 1}) - - rc.removeStream(network.DirInbound) - checkResources(t, &rc, network.ScopeStat{}) - - if err := rc.addStream(network.DirOutbound); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{NumStreamsOutbound: 1}) - - if err := rc.addStream(network.DirOutbound); err == nil { - t.Fatal("expected addStream to fail") - } - checkResources(t, &rc, network.ScopeStat{NumStreamsOutbound: 1}) - - if err := rc.addStream(network.DirInbound); err == nil { - t.Fatal("expected addStream to fail") - } - checkResources(t, &rc, network.ScopeStat{NumStreamsOutbound: 1}) - - rc.removeStream(network.DirOutbound) - checkResources(t, &rc, network.ScopeStat{}) - - // test addConn - if err := rc.addConn(network.DirInbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{NumConnsInbound: 1}) - - if err := rc.addConn(network.DirInbound, false); err == nil { - t.Fatal("expected addConn to fail") - } - checkResources(t, &rc, network.ScopeStat{NumConnsInbound: 1}) - - rc.removeConn(network.DirInbound, false) - checkResources(t, &rc, network.ScopeStat{}) - - if err := rc.addConn(network.DirOutbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{NumConnsOutbound: 1}) - - if err := rc.addConn(network.DirOutbound, false); err == nil { - t.Fatal("expected addConn to fail") - } - checkResources(t, &rc, network.ScopeStat{NumConnsOutbound: 1}) - - rc.removeConn(network.DirOutbound, false) - checkResources(t, &rc, network.ScopeStat{}) - - if err := rc.addConn(network.DirInbound, true); err != nil { - t.Fatal(err) - } - checkResources(t, &rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - - if err := rc.addConn(network.DirOutbound, true); err == nil { - t.Fatal("expected addConn to fail") - } - checkResources(t, &rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - - rc.removeConn(network.DirInbound, true) - checkResources(t, &rc, network.ScopeStat{}) -} - -func TestResourceScopeSimple(t *testing.T) { - s := newResourceScope( - &BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }, - nil, "test", nil, nil, - ) - - s.IncRef() - if s.refCnt != 1 { - t.Fatal("expected refcnt of 1") - } - s.DecRef() - if s.refCnt != 0 { - t.Fatal("expected refcnt of 0") - } - - testResourceScopeBasic(t, s) -} - -func testResourceScopeBasic(t *testing.T, s *resourceScope) { - if err := s.ReserveMemory(2048, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{Memory: 2048}) - - if err := s.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{Memory: 3072}) - - if err := s.ReserveMemory(512, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{Memory: 3584}) - - if err := s.ReserveMemory(512, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{Memory: 4096}) - - if err := s.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - checkResources(t, &s.rc, network.ScopeStat{Memory: 4096}) - - s.ReleaseMemory(4096) - checkResources(t, &s.rc, network.ScopeStat{}) - - if err := s.AddStream(network.DirInbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - - if err := s.AddStream(network.DirInbound); err == nil { - t.Fatal("expected AddStream to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - - if err := s.AddStream(network.DirOutbound); err == nil { - t.Fatal("expected AddStream to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1}) - - s.RemoveStream(network.DirInbound) - checkResources(t, &s.rc, network.ScopeStat{}) - - if err := s.AddStream(network.DirOutbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{NumStreamsOutbound: 1}) - - if err := s.AddStream(network.DirOutbound); err == nil { - t.Fatal("expected AddStream to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumStreamsOutbound: 1}) - - if err := s.AddStream(network.DirInbound); err == nil { - t.Fatal("expected AddStream to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumStreamsOutbound: 1}) - - s.RemoveStream(network.DirOutbound) - checkResources(t, &s.rc, network.ScopeStat{}) - - if err := s.AddConn(network.DirInbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1}) - - if err := s.AddConn(network.DirInbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1}) - - s.RemoveConn(network.DirInbound, false) - checkResources(t, &s.rc, network.ScopeStat{}) - - if err := s.AddConn(network.DirOutbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{NumConnsOutbound: 1}) - - if err := s.AddConn(network.DirOutbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumConnsOutbound: 1}) - - s.RemoveConn(network.DirOutbound, false) - checkResources(t, &s.rc, network.ScopeStat{}) - - if err := s.AddConn(network.DirInbound, true); err != nil { - t.Fatal(err) - } - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - - if err := s.AddConn(network.DirOutbound, true); err == nil { - t.Fatal("expected AddConn to fail") - } - checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - - s.RemoveConn(network.DirInbound, true) - checkResources(t, &s.rc, network.ScopeStat{}) -} - -func TestResourceScopeTxnBasic(t *testing.T) { - s := newResourceScope( - &BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }, - nil, "test", nil, nil, - ) - - txn, err := s.BeginSpan() - if err != nil { - t.Fatal(err) - } - - testResourceScopeBasic(t, txn.(*resourceScope)) - checkResources(t, &s.rc, network.ScopeStat{}) - - // check constraint propagation - if err := txn.ReserveMemory(4096, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &txn.(*resourceScope).rc, network.ScopeStat{Memory: 4096}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 4096}) - txn.Done() - checkResources(t, &s.rc, network.ScopeStat{}) - txn.Done() // idempotent - checkResources(t, &s.rc, network.ScopeStat{}) -} - -func TestResourceScopeTxnZombie(t *testing.T) { - s := newResourceScope( - &BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }, - nil, "test", nil, nil, - ) - - txn1, err := s.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn2, err := txn1.BeginSpan() - if err != nil { - t.Fatal(err) - } - - if err := txn2.ReserveMemory(4096, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &txn2.(*resourceScope).rc, network.ScopeStat{Memory: 4096}) - checkResources(t, &txn1.(*resourceScope).rc, network.ScopeStat{Memory: 4096}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 4096}) - - txn1.Done() - checkResources(t, &s.rc, network.ScopeStat{}) - if err := txn2.ReserveMemory(4096, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - - txn2.Done() - checkResources(t, &s.rc, network.ScopeStat{}) -} - -func TestResourceScopeTxnTree(t *testing.T) { - s := newResourceScope( - &BaseLimit{ - Memory: 4096, - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }, - nil, "test", nil, nil, - ) - - txn1, err := s.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn2, err := txn1.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn3, err := txn1.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn4, err := txn2.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn5, err := txn2.BeginSpan() - if err != nil { - t.Fatal(err) - } - - if err := txn3.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &txn3.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn1.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 1024}) - - if err := txn4.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &txn4.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn3.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn2.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn1.(*resourceScope).rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 2048}) - - if err := txn5.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &txn5.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn4.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn3.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn2.(*resourceScope).rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &txn1.(*resourceScope).rc, network.ScopeStat{Memory: 3072}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 3072}) - - if err := txn1.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &txn5.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn4.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn3.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn2.(*resourceScope).rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &txn1.(*resourceScope).rc, network.ScopeStat{Memory: 4096}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 4096}) - - if err := txn5.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - if err := txn4.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - if err := txn3.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - if err := txn2.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - checkResources(t, &txn5.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn4.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn3.(*resourceScope).rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &txn2.(*resourceScope).rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &txn1.(*resourceScope).rc, network.ScopeStat{Memory: 4096}) - checkResources(t, &s.rc, network.ScopeStat{Memory: 4096}) - - txn1.Done() - checkResources(t, &s.rc, network.ScopeStat{}) -} - -func TestResourceScopeDAG(t *testing.T) { - // A small DAG of scopes - // s1 - // +---> s2 - // +------------> s5 - // +---- - // +---> s3 +. \ - // | \ -----+-> s4 (a diamond!) - // | ------/ - // \ - // ------> s6 - s1 := newResourceScope( - &BaseLimit{ - Memory: 4096, - StreamsInbound: 4, - StreamsOutbound: 4, - Streams: 4, - ConnsInbound: 4, - ConnsOutbound: 4, - Conns: 4, - FD: 4, - }, - nil, "test", nil, nil, - ) - s2 := newResourceScope( - &BaseLimit{ - Memory: 2048, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 2, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 2, - FD: 2, - }, - []*resourceScope{s1}, "test", nil, nil, - ) - s3 := newResourceScope( - &BaseLimit{ - Memory: 2048, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 2, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 2, - FD: 2, - }, - []*resourceScope{s1}, "test", nil, nil, - ) - s4 := newResourceScope( - &BaseLimit{ - Memory: 2048, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 2, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 2, - FD: 2, - }, - []*resourceScope{s2, s3, s1}, "test", nil, nil, - ) - s5 := newResourceScope( - &BaseLimit{ - Memory: 2048, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 2, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 2, - FD: 2, - }, - []*resourceScope{s2, s1}, "test", nil, nil, - ) - s6 := newResourceScope( - &BaseLimit{ - Memory: 2048, - StreamsInbound: 2, - StreamsOutbound: 2, - Streams: 2, - ConnsInbound: 2, - ConnsOutbound: 2, - Conns: 2, - FD: 2, - }, - []*resourceScope{s3, s1}, "test", nil, nil, - ) - - if err := s4.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 1024}) - - if err := s5.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 2048}) - - if err := s6.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 3072}) - - if err := s4.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expcted ReserveMemory to fail") - } - if err := s5.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expcted ReserveMemory to fail") - } - if err := s6.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expcted ReserveMemory to fail") - } - - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 3072}) - - s4.ReleaseMemory(1024) - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 2048}) - - s5.ReleaseMemory(1024) - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 1024}) - - s6.ReleaseMemory(1024) - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) - - if err := s4.AddStream(network.DirInbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsInbound: 1}) - - if err := s5.AddStream(network.DirInbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsInbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsInbound: 2}) - - if err := s6.AddStream(network.DirInbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsInbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsInbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsInbound: 3}) - - if err := s4.AddStream(network.DirInbound); err == nil { - t.Fatal("expected AddStream to fail") - } - if err := s5.AddStream(network.DirInbound); err == nil { - t.Fatal("expected AddStream to fail") - } - if err := s6.AddStream(network.DirInbound); err == nil { - t.Fatal("expected AddStream to fail") - } - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsInbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsInbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsInbound: 3}) - - s4.RemoveStream(network.DirInbound) - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsInbound: 2}) - - s5.RemoveStream(network.DirInbound) - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsInbound: 1}) - - s6.RemoveStream(network.DirInbound) - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) - - if err := s4.AddStream(network.DirOutbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsOutbound: 1}) - - if err := s5.AddStream(network.DirOutbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsOutbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsOutbound: 2}) - - if err := s6.AddStream(network.DirOutbound); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsOutbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsOutbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsOutbound: 3}) - - if err := s4.AddStream(network.DirOutbound); err == nil { - t.Fatal("expected AddStream to fail") - } - if err := s5.AddStream(network.DirOutbound); err == nil { - t.Fatal("expected AddStream to fail") - } - if err := s6.AddStream(network.DirOutbound); err == nil { - t.Fatal("expected AddStream to fail") - } - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsOutbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsOutbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsOutbound: 3}) - - s4.RemoveStream(network.DirOutbound) - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsOutbound: 2}) - - s5.RemoveStream(network.DirOutbound) - checkResources(t, &s6.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumStreamsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{NumStreamsOutbound: 1}) - - s6.RemoveStream(network.DirOutbound) - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) - - if err := s4.AddConn(network.DirInbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 1}) - - if err := s5.AddConn(network.DirInbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 2}) - - if err := s6.AddConn(network.DirInbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 3}) - - if err := s4.AddConn(network.DirInbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - if err := s5.AddConn(network.DirInbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - if err := s6.AddConn(network.DirInbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 3}) - - s4.RemoveConn(network.DirInbound, false) - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 2}) - - s5.RemoveConn(network.DirInbound, false) - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 1}) - - s6.RemoveConn(network.DirInbound, false) - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) - - if err := s4.AddConn(network.DirOutbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsOutbound: 1}) - - if err := s5.AddConn(network.DirOutbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsOutbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsOutbound: 2}) - - if err := s6.AddConn(network.DirOutbound, false); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsOutbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsOutbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsOutbound: 3}) - - if err := s4.AddConn(network.DirOutbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - if err := s5.AddConn(network.DirOutbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - if err := s6.AddConn(network.DirOutbound, false); err == nil { - t.Fatal("expected AddConn to fail") - } - checkResources(t, &s6.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsOutbound: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsOutbound: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsOutbound: 3}) - - s4.RemoveConn(network.DirOutbound, false) - checkResources(t, &s6.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsOutbound: 2}) - - s5.RemoveConn(network.DirOutbound, false) - checkResources(t, &s6.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsOutbound: 1}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsOutbound: 1}) - - s6.RemoveConn(network.DirOutbound, false) - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) - - if err := s4.AddConn(network.DirInbound, true); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - - if err := s5.AddConn(network.DirInbound, true); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - - if err := s6.AddConn(network.DirInbound, true); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 3, NumFD: 3}) - - if err := s4.AddConn(network.DirOutbound, true); err == nil { - t.Fatal("expected AddConn to fail") - } - if err := s5.AddConn(network.DirOutbound, true); err == nil { - t.Fatal("expected AddConn to fail") - } - if err := s6.AddConn(network.DirOutbound, true); err == nil { - t.Fatal("expected AddConn to fail") - } - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s4.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 3, NumFD: 3}) - - s4.RemoveConn(network.DirInbound, true) - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s5.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s2.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2}) - - s5.RemoveConn(network.DirInbound, true) - checkResources(t, &s6.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1}) - - s6.RemoveConn(network.DirInbound, true) - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) -} - -func TestResourceScopeDAGTxn(t *testing.T) { - // A small DAG of scopes - // s1 - // +---> s2 - // +------------> s5 - // +---- - // +---> s3 +. \ - // | \ -----+-> s4 (a diamond!) - // | ------/ - // \ - // ------> s6 - s1 := newResourceScope( - &BaseLimit{Memory: 8192}, - nil, "test", nil, nil, - ) - s2 := newResourceScope( - &BaseLimit{Memory: 4096 + 2048}, - []*resourceScope{s1}, "test", nil, nil, - ) - s3 := newResourceScope( - &BaseLimit{Memory: 4096 + 2048}, - []*resourceScope{s1}, "test", nil, nil, - ) - s4 := newResourceScope( - &BaseLimit{Memory: 4096 + 1024}, - []*resourceScope{s2, s3, s1}, "test", nil, nil, - ) - s5 := newResourceScope( - &BaseLimit{Memory: 4096 + 1024}, - []*resourceScope{s2, s1}, "test", nil, nil, - ) - s6 := newResourceScope( - &BaseLimit{Memory: 4096 + 1024}, - []*resourceScope{s3, s1}, "test", nil, nil, - ) - - txn4, err := s4.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn5, err := s5.BeginSpan() - if err != nil { - t.Fatal(err) - } - - txn6, err := s6.BeginSpan() - if err != nil { - t.Fatal(err) - } - - if err := txn4.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 1024}) - - if err := txn5.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 2048}) - - if err := txn6.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 3072}) - - if err := txn4.ReserveMemory(4096, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024 + 4096}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 2048 + 4096}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048 + 4096}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 3072 + 4096}) - - if err := txn4.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - if err := txn5.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - if err := txn6.ReserveMemory(1024, network.ReservationPriorityAlways); err == nil { - t.Fatal("expected ReserveMemory to fail") - } - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{Memory: 1024 + 4096}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 2048 + 4096}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048 + 4096}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 3072 + 4096}) - - txn4.Done() - - checkResources(t, &s6.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 1024}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 2048}) - - if err := txn5.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - if err := txn6.ReserveMemory(1024, network.ReservationPriorityAlways); err != nil { - t.Fatal(err) - } - - checkResources(t, &s6.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s5.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s2.rc, network.ScopeStat{Memory: 2048}) - checkResources(t, &s1.rc, network.ScopeStat{Memory: 4096}) - - txn5.Done() - txn6.Done() - - checkResources(t, &s6.rc, network.ScopeStat{}) - checkResources(t, &s5.rc, network.ScopeStat{}) - checkResources(t, &s4.rc, network.ScopeStat{}) - checkResources(t, &s3.rc, network.ScopeStat{}) - checkResources(t, &s2.rc, network.ScopeStat{}) - checkResources(t, &s1.rc, network.ScopeStat{}) -} diff --git a/sys_not_unix.go b/sys_not_unix.go deleted file mode 100644 index d29b927..0000000 --- a/sys_not_unix.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !linux && !darwin && !windows - -package rcmgr - -import "runtime" - -// TODO: figure out how to get the number of file descriptors on Windows and other systems -func getNumFDs() int { - log.Warnf("cannot determine number of file descriptors on %s", runtime.GOOS) - return 0 -} diff --git a/sys_unix.go b/sys_unix.go deleted file mode 100644 index 75d4f7f..0000000 --- a/sys_unix.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build linux || darwin -// +build linux darwin - -package rcmgr - -import ( - "golang.org/x/sys/unix" -) - -func getNumFDs() int { - var l unix.Rlimit - if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &l); err != nil { - log.Errorw("failed to get fd limit", "error", err) - return 0 - } - return int(l.Cur) -} diff --git a/sys_windows.go b/sys_windows.go deleted file mode 100644 index 7387eb8..0000000 --- a/sys_windows.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build windows - -package rcmgr - -import ( - "math" -) - -func getNumFDs() int { - return math.MaxInt -} diff --git a/trace.go b/trace.go index ae871a0..791d4e3 100644 --- a/trace.go +++ b/trace.go @@ -1,698 +1,39 @@ package rcmgr import ( - "compress/gzip" - "context" - "encoding/json" - "fmt" - "io" - "os" - "strings" - "sync" - "time" - - "github.com/libp2p/go-libp2p-core/network" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" ) -type trace struct { - path string - - ctx context.Context - cancel func() - wg sync.WaitGroup - - mx sync.Mutex - done bool - pendingWrites []interface{} - reporters []TraceReporter -} - -type TraceReporter interface { - // ConsumeEvent consumes a trace event. This is called synchronously, - // implementations should process the event quickly. - ConsumeEvent(TraceEvt) -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.TraceReporter instead +type TraceReporter = rcmgr.TraceReporter +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.WithTrace instead func WithTrace(path string) Option { - return func(r *resourceManager) error { - if r.trace == nil { - r.trace = &trace{path: path} - } else { - r.trace.path = path - } - return nil - } + return rcmgr.WithTrace(path) } +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.WithTraceReporter instead func WithTraceReporter(reporter TraceReporter) Option { - return func(r *resourceManager) error { - if r.trace == nil { - r.trace = &trace{} - } - r.trace.reporters = append(r.trace.reporters, reporter) - return nil - } + return rcmgr.WithTraceReporter(reporter) } -type TraceEvtTyp string +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.TraceEvtTyp instead +type TraceEvtTyp = rcmgr.TraceEvtTyp const ( - TraceStartEvt TraceEvtTyp = "start" - TraceCreateScopeEvt TraceEvtTyp = "create_scope" - TraceDestroyScopeEvt TraceEvtTyp = "destroy_scope" - TraceReserveMemoryEvt TraceEvtTyp = "reserve_memory" - TraceBlockReserveMemoryEvt TraceEvtTyp = "block_reserve_memory" - TraceReleaseMemoryEvt TraceEvtTyp = "release_memory" - TraceAddStreamEvt TraceEvtTyp = "add_stream" - TraceBlockAddStreamEvt TraceEvtTyp = "block_add_stream" - TraceRemoveStreamEvt TraceEvtTyp = "remove_stream" - TraceAddConnEvt TraceEvtTyp = "add_conn" - TraceBlockAddConnEvt TraceEvtTyp = "block_add_conn" - TraceRemoveConnEvt TraceEvtTyp = "remove_conn" + TraceStartEvt = rcmgr.TraceStartEvt + TraceCreateScopeEvt = rcmgr.TraceCreateScopeEvt + TraceDestroyScopeEvt = rcmgr.TraceDestroyScopeEvt + TraceReserveMemoryEvt = rcmgr.TraceReserveMemoryEvt + TraceBlockReserveMemoryEvt = rcmgr.TraceBlockReserveMemoryEvt + TraceReleaseMemoryEvt = rcmgr.TraceReleaseMemoryEvt + TraceAddStreamEvt = rcmgr.TraceAddStreamEvt + TraceBlockAddStreamEvt = rcmgr.TraceBlockAddStreamEvt + TraceRemoveStreamEvt = rcmgr.TraceRemoveStreamEvt + TraceAddConnEvt = rcmgr.TraceAddConnEvt + TraceBlockAddConnEvt = rcmgr.TraceBlockAddConnEvt + TraceRemoveConnEvt = rcmgr.TraceRemoveConnEvt ) -type scopeClass struct { - name string -} - -func (s scopeClass) MarshalJSON() ([]byte, error) { - name := s.name - var span string - if idx := strings.Index(name, "span:"); idx > -1 { - name = name[:idx-1] - span = name[idx+5:] - } - // System and Transient scope - if name == "system" || name == "transient" || name == "allowlistedSystem" || name == "allowlistedTransient" { - return json.Marshal(struct { - Class string - Span string `json:",omitempty"` - }{ - Class: name, - Span: span, - }) - } - // Connection scope - if strings.HasPrefix(name, "conn-") { - return json.Marshal(struct { - Class string - Conn string - Span string `json:",omitempty"` - }{ - Class: "conn", - Conn: name[5:], - Span: span, - }) - } - // Stream scope - if strings.HasPrefix(name, "stream-") { - return json.Marshal(struct { - Class string - Stream string - Span string `json:",omitempty"` - }{ - Class: "stream", - Stream: name[7:], - Span: span, - }) - } - // Peer scope - if strings.HasPrefix(name, "peer:") { - return json.Marshal(struct { - Class string - Peer string - Span string `json:",omitempty"` - }{ - Class: "peer", - Peer: name[5:], - Span: span, - }) - } - - if strings.HasPrefix(name, "service:") { - if idx := strings.Index(name, "peer:"); idx > 0 { // Peer-Service scope - return json.Marshal(struct { - Class string - Service string - Peer string - Span string `json:",omitempty"` - }{ - Class: "service-peer", - Service: name[8 : idx-1], - Peer: name[idx+5:], - Span: span, - }) - } else { // Service scope - return json.Marshal(struct { - Class string - Service string - Span string `json:",omitempty"` - }{ - Class: "service", - Service: name[8:], - Span: span, - }) - } - } - - if strings.HasPrefix(name, "protocol:") { - if idx := strings.Index(name, "peer:"); idx > -1 { // Peer-Protocol scope - return json.Marshal(struct { - Class string - Protocol string - Peer string - Span string `json:",omitempty"` - }{ - Class: "protocol-peer", - Protocol: name[9 : idx-1], - Peer: name[idx+5:], - Span: span, - }) - } else { // Protocol scope - return json.Marshal(struct { - Class string - Protocol string - Span string `json:",omitempty"` - }{ - Class: "protocol", - Protocol: name[9:], - Span: span, - }) - } - } - - return nil, fmt.Errorf("unrecognized scope: %s", name) -} - -type TraceEvt struct { - Time string - Type TraceEvtTyp - - Scope *scopeClass `json:",omitempty"` - Name string `json:",omitempty"` - - Limit interface{} `json:",omitempty"` - - Priority uint8 `json:",omitempty"` - - Delta int64 `json:",omitempty"` - DeltaIn int `json:",omitempty"` - DeltaOut int `json:",omitempty"` - - Memory int64 `json:",omitempty"` - - StreamsIn int `json:",omitempty"` - StreamsOut int `json:",omitempty"` - - ConnsIn int `json:",omitempty"` - ConnsOut int `json:",omitempty"` - - FD int `json:",omitempty"` -} - -func (t *trace) push(evt TraceEvt) { - t.mx.Lock() - defer t.mx.Unlock() - - if t.done { - return - } - evt.Time = time.Now().Format(time.RFC3339Nano) - if evt.Name != "" { - evt.Scope = &scopeClass{name: evt.Name} - } - - for _, reporter := range t.reporters { - reporter.ConsumeEvent(evt) - } - - if t.path != "" { - t.pendingWrites = append(t.pendingWrites, evt) - } -} - -func (t *trace) backgroundWriter(out io.WriteCloser) { - defer t.wg.Done() - defer out.Close() - - gzOut := gzip.NewWriter(out) - defer gzOut.Close() - - jsonOut := json.NewEncoder(gzOut) - - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - var pend []interface{} - - getEvents := func() { - t.mx.Lock() - tmp := t.pendingWrites - t.pendingWrites = pend[:0] - pend = tmp - t.mx.Unlock() - } - - for { - select { - case <-ticker.C: - getEvents() - - if len(pend) == 0 { - continue - } - - if err := t.writeEvents(pend, jsonOut); err != nil { - log.Warnf("error writing rcmgr trace: %s", err) - t.mx.Lock() - t.done = true - t.mx.Unlock() - return - } - - if err := gzOut.Flush(); err != nil { - log.Warnf("error flushing rcmgr trace: %s", err) - t.mx.Lock() - t.done = true - t.mx.Unlock() - return - } - - case <-t.ctx.Done(): - getEvents() - - if len(pend) == 0 { - return - } - - if err := t.writeEvents(pend, jsonOut); err != nil { - log.Warnf("error writing rcmgr trace: %s", err) - return - } - - if err := gzOut.Flush(); err != nil { - log.Warnf("error flushing rcmgr trace: %s", err) - } - - return - } - } -} - -func (t *trace) writeEvents(pend []interface{}, jout *json.Encoder) error { - for _, e := range pend { - if err := jout.Encode(e); err != nil { - return err - } - } - - return nil -} - -func (t *trace) Start(limits Limiter) error { - if t == nil { - return nil - } - - t.ctx, t.cancel = context.WithCancel(context.Background()) - - if t.path != "" { - out, err := os.OpenFile(t.path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) - if err != nil { - return nil - } - - t.wg.Add(1) - go t.backgroundWriter(out) - } - - t.push(TraceEvt{ - Type: TraceStartEvt, - Limit: limits, - }) - - return nil -} - -func (t *trace) Close() error { - if t == nil { - return nil - } - - t.mx.Lock() - - if t.done { - t.mx.Unlock() - return nil - } - - t.cancel() - t.done = true - t.mx.Unlock() - - t.wg.Wait() - return nil -} - -func (t *trace) CreateScope(scope string, limit Limit) { - if t == nil { - return - } - - t.push(TraceEvt{ - Type: TraceCreateScopeEvt, - Name: scope, - Limit: limit, - }) -} - -func (t *trace) DestroyScope(scope string) { - if t == nil { - return - } - - t.push(TraceEvt{ - Type: TraceDestroyScopeEvt, - Name: scope, - }) -} - -func (t *trace) ReserveMemory(scope string, prio uint8, size, mem int64) { - if t == nil { - return - } - - if size == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceReserveMemoryEvt, - Name: scope, - Priority: prio, - Delta: size, - Memory: mem, - }) -} - -func (t *trace) BlockReserveMemory(scope string, prio uint8, size, mem int64) { - if t == nil { - return - } - - if size == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceBlockReserveMemoryEvt, - Name: scope, - Priority: prio, - Delta: size, - Memory: mem, - }) -} - -func (t *trace) ReleaseMemory(scope string, size, mem int64) { - if t == nil { - return - } - - if size == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceReleaseMemoryEvt, - Name: scope, - Delta: -size, - Memory: mem, - }) -} - -func (t *trace) AddStream(scope string, dir network.Direction, nstreamsIn, nstreamsOut int) { - if t == nil { - return - } - - var deltaIn, deltaOut int - if dir == network.DirInbound { - deltaIn = 1 - } else { - deltaOut = 1 - } - - t.push(TraceEvt{ - Type: TraceAddStreamEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - StreamsIn: nstreamsIn, - StreamsOut: nstreamsOut, - }) -} - -func (t *trace) BlockAddStream(scope string, dir network.Direction, nstreamsIn, nstreamsOut int) { - if t == nil { - return - } - - var deltaIn, deltaOut int - if dir == network.DirInbound { - deltaIn = 1 - } else { - deltaOut = 1 - } - - t.push(TraceEvt{ - Type: TraceBlockAddStreamEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - StreamsIn: nstreamsIn, - StreamsOut: nstreamsOut, - }) -} - -func (t *trace) RemoveStream(scope string, dir network.Direction, nstreamsIn, nstreamsOut int) { - if t == nil { - return - } - - var deltaIn, deltaOut int - if dir == network.DirInbound { - deltaIn = -1 - } else { - deltaOut = -1 - } - - t.push(TraceEvt{ - Type: TraceRemoveStreamEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - StreamsIn: nstreamsIn, - StreamsOut: nstreamsOut, - }) -} - -func (t *trace) AddStreams(scope string, deltaIn, deltaOut, nstreamsIn, nstreamsOut int) { - if t == nil { - return - } - - if deltaIn == 0 && deltaOut == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceAddStreamEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - StreamsIn: nstreamsIn, - StreamsOut: nstreamsOut, - }) -} - -func (t *trace) BlockAddStreams(scope string, deltaIn, deltaOut, nstreamsIn, nstreamsOut int) { - if t == nil { - return - } - - if deltaIn == 0 && deltaOut == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceBlockAddStreamEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - StreamsIn: nstreamsIn, - StreamsOut: nstreamsOut, - }) -} - -func (t *trace) RemoveStreams(scope string, deltaIn, deltaOut, nstreamsIn, nstreamsOut int) { - if t == nil { - return - } - - if deltaIn == 0 && deltaOut == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceRemoveStreamEvt, - Name: scope, - DeltaIn: -deltaIn, - DeltaOut: -deltaOut, - StreamsIn: nstreamsIn, - StreamsOut: nstreamsOut, - }) -} - -func (t *trace) AddConn(scope string, dir network.Direction, usefd bool, nconnsIn, nconnsOut, nfd int) { - if t == nil { - return - } - - var deltaIn, deltaOut, deltafd int - if dir == network.DirInbound { - deltaIn = 1 - } else { - deltaOut = 1 - } - if usefd { - deltafd = 1 - } - - t.push(TraceEvt{ - Type: TraceAddConnEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - Delta: int64(deltafd), - ConnsIn: nconnsIn, - ConnsOut: nconnsOut, - FD: nfd, - }) -} - -func (t *trace) BlockAddConn(scope string, dir network.Direction, usefd bool, nconnsIn, nconnsOut, nfd int) { - if t == nil { - return - } - - var deltaIn, deltaOut, deltafd int - if dir == network.DirInbound { - deltaIn = 1 - } else { - deltaOut = 1 - } - if usefd { - deltafd = 1 - } - - t.push(TraceEvt{ - Type: TraceBlockAddConnEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - Delta: int64(deltafd), - ConnsIn: nconnsIn, - ConnsOut: nconnsOut, - FD: nfd, - }) -} - -func (t *trace) RemoveConn(scope string, dir network.Direction, usefd bool, nconnsIn, nconnsOut, nfd int) { - if t == nil { - return - } - - var deltaIn, deltaOut, deltafd int - if dir == network.DirInbound { - deltaIn = -1 - } else { - deltaOut = -1 - } - if usefd { - deltafd = -1 - } - - t.push(TraceEvt{ - Type: TraceRemoveConnEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - Delta: int64(deltafd), - ConnsIn: nconnsIn, - ConnsOut: nconnsOut, - FD: nfd, - }) -} - -func (t *trace) AddConns(scope string, deltaIn, deltaOut, deltafd, nconnsIn, nconnsOut, nfd int) { - if t == nil { - return - } - - if deltaIn == 0 && deltaOut == 0 && deltafd == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceAddConnEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - Delta: int64(deltafd), - ConnsIn: nconnsIn, - ConnsOut: nconnsOut, - FD: nfd, - }) -} - -func (t *trace) BlockAddConns(scope string, deltaIn, deltaOut, deltafd, nconnsIn, nconnsOut, nfd int) { - if t == nil { - return - } - - if deltaIn == 0 && deltaOut == 0 && deltafd == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceBlockAddConnEvt, - Name: scope, - DeltaIn: deltaIn, - DeltaOut: deltaOut, - Delta: int64(deltafd), - ConnsIn: nconnsIn, - ConnsOut: nconnsOut, - FD: nfd, - }) -} - -func (t *trace) RemoveConns(scope string, deltaIn, deltaOut, deltafd, nconnsIn, nconnsOut, nfd int) { - if t == nil { - return - } - - if deltaIn == 0 && deltaOut == 0 && deltafd == 0 { - return - } - - t.push(TraceEvt{ - Type: TraceRemoveConnEvt, - Name: scope, - DeltaIn: -deltaIn, - DeltaOut: -deltaOut, - Delta: -int64(deltafd), - ConnsIn: nconnsIn, - ConnsOut: nconnsOut, - FD: nfd, - }) -} +// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.TraceEvt instead +type TraceEvt = rcmgr.TraceEvt diff --git a/version.json b/version.json index ef97c9c..42c14d1 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "v0.5.3" + "version": "v0.6.0" }