mirror of
https://github.com/libp2p/go-libp2p-resource-manager.git
synced 2025-01-25 11:51:11 +08:00
deprecate this repo
This commit is contained in:
parent
9bb1bbdc78
commit
06199e0142
@ -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
|
||||
|
209
allowlist.go
209
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)
|
||||
}
|
||||
|
@ -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)])
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
81
error.go
81
error.go
@ -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)
|
||||
}
|
147
extapi.go
147
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)
|
||||
}
|
||||
// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ResourceScopeLimiter instead
|
||||
type ResourceScopeLimiter = rcmgr.ResourceScopeLimiter
|
||||
|
||||
var _ ResourceScopeLimiter = (*resourceScope)(nil)
|
||||
// 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
|
||||
|
||||
// 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()
|
||||
|
||||
// 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()
|
||||
|
||||
return result
|
||||
}
|
||||
// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ResourceManagerStat instead
|
||||
type ResourceManagerStat = rcmgr.ResourceManagerStat
|
||||
|
50
go.mod
50
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
|
||||
)
|
||||
|
730
go.sum
730
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=
|
||||
|
244
limit.go
244
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
|
||||
return rcmgr.NewLimiterFromJSON(in, defaults)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
// Deprecated: use github.com/libp2p/go-libp2p/p2p/host/resource-manager.ScalingLimitConfig instead
|
||||
type ScalingLimitConfig = rcmgr.ScalingLimitConfig
|
||||
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
|
||||
})
|
||||
}
|
159
metrics.go
159
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)
|
||||
}
|
||||
|
@ -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.
|
File diff suppressed because it is too large
Load Diff
363
obs/stats.go
363
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"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs"
|
||||
)
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
861
rcmgr.go
861
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)
|
||||
}
|
||||
|
1052
rcmgr_test.go
1052
rcmgr_test.go
File diff suppressed because it is too large
Load Diff
766
scope.go
766
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)
|
||||
}
|
||||
|
1200
scope_test.go
1200
scope_test.go
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
17
sys_unix.go
17
sys_unix.go
@ -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)
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package rcmgr
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
func getNumFDs() int {
|
||||
return math.MaxInt
|
||||
}
|
705
trace.go
705
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
|
||||
|
Loading…
Reference in New Issue
Block a user