mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:57:26 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			880 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			880 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package rcmgr
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	"github.com/libp2p/go-libp2p/core/network"
 | 
						|
	"github.com/libp2p/go-libp2p/core/peer"
 | 
						|
	"github.com/libp2p/go-libp2p/core/protocol"
 | 
						|
 | 
						|
	"github.com/pbnjay/memory"
 | 
						|
)
 | 
						|
 | 
						|
type baseLimitConfig struct {
 | 
						|
	BaseLimit         BaseLimit
 | 
						|
	BaseLimitIncrease BaseLimitIncrease
 | 
						|
}
 | 
						|
 | 
						|
// ScalingLimitConfig is a struct for configuring default limits.
 | 
						|
// {}BaseLimit is the limits that Apply for a minimal node (128 MB of memory for libp2p) and 256 file descriptors.
 | 
						|
// {}LimitIncrease is the additional limit granted for every additional 1 GB of RAM.
 | 
						|
type ScalingLimitConfig struct {
 | 
						|
	SystemBaseLimit     BaseLimit
 | 
						|
	SystemLimitIncrease BaseLimitIncrease
 | 
						|
 | 
						|
	TransientBaseLimit     BaseLimit
 | 
						|
	TransientLimitIncrease BaseLimitIncrease
 | 
						|
 | 
						|
	AllowlistedSystemBaseLimit     BaseLimit
 | 
						|
	AllowlistedSystemLimitIncrease BaseLimitIncrease
 | 
						|
 | 
						|
	AllowlistedTransientBaseLimit     BaseLimit
 | 
						|
	AllowlistedTransientLimitIncrease BaseLimitIncrease
 | 
						|
 | 
						|
	ServiceBaseLimit     BaseLimit
 | 
						|
	ServiceLimitIncrease BaseLimitIncrease
 | 
						|
	ServiceLimits        map[string]baseLimitConfig // use AddServiceLimit to modify
 | 
						|
 | 
						|
	ServicePeerBaseLimit     BaseLimit
 | 
						|
	ServicePeerLimitIncrease BaseLimitIncrease
 | 
						|
	ServicePeerLimits        map[string]baseLimitConfig // use AddServicePeerLimit to modify
 | 
						|
 | 
						|
	ProtocolBaseLimit     BaseLimit
 | 
						|
	ProtocolLimitIncrease BaseLimitIncrease
 | 
						|
	ProtocolLimits        map[protocol.ID]baseLimitConfig // use AddProtocolLimit to modify
 | 
						|
 | 
						|
	ProtocolPeerBaseLimit     BaseLimit
 | 
						|
	ProtocolPeerLimitIncrease BaseLimitIncrease
 | 
						|
	ProtocolPeerLimits        map[protocol.ID]baseLimitConfig // use AddProtocolPeerLimit to modify
 | 
						|
 | 
						|
	PeerBaseLimit     BaseLimit
 | 
						|
	PeerLimitIncrease BaseLimitIncrease
 | 
						|
	PeerLimits        map[peer.ID]baseLimitConfig // use AddPeerLimit to modify
 | 
						|
 | 
						|
	ConnBaseLimit     BaseLimit
 | 
						|
	ConnLimitIncrease BaseLimitIncrease
 | 
						|
 | 
						|
	StreamBaseLimit     BaseLimit
 | 
						|
	StreamLimitIncrease BaseLimitIncrease
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *ScalingLimitConfig) AddServiceLimit(svc string, base BaseLimit, inc BaseLimitIncrease) {
 | 
						|
	if cfg.ServiceLimits == nil {
 | 
						|
		cfg.ServiceLimits = make(map[string]baseLimitConfig)
 | 
						|
	}
 | 
						|
	cfg.ServiceLimits[svc] = baseLimitConfig{
 | 
						|
		BaseLimit:         base,
 | 
						|
		BaseLimitIncrease: inc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *ScalingLimitConfig) AddProtocolLimit(proto protocol.ID, base BaseLimit, inc BaseLimitIncrease) {
 | 
						|
	if cfg.ProtocolLimits == nil {
 | 
						|
		cfg.ProtocolLimits = make(map[protocol.ID]baseLimitConfig)
 | 
						|
	}
 | 
						|
	cfg.ProtocolLimits[proto] = baseLimitConfig{
 | 
						|
		BaseLimit:         base,
 | 
						|
		BaseLimitIncrease: inc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *ScalingLimitConfig) AddPeerLimit(p peer.ID, base BaseLimit, inc BaseLimitIncrease) {
 | 
						|
	if cfg.PeerLimits == nil {
 | 
						|
		cfg.PeerLimits = make(map[peer.ID]baseLimitConfig)
 | 
						|
	}
 | 
						|
	cfg.PeerLimits[p] = baseLimitConfig{
 | 
						|
		BaseLimit:         base,
 | 
						|
		BaseLimitIncrease: inc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *ScalingLimitConfig) AddServicePeerLimit(svc string, base BaseLimit, inc BaseLimitIncrease) {
 | 
						|
	if cfg.ServicePeerLimits == nil {
 | 
						|
		cfg.ServicePeerLimits = make(map[string]baseLimitConfig)
 | 
						|
	}
 | 
						|
	cfg.ServicePeerLimits[svc] = baseLimitConfig{
 | 
						|
		BaseLimit:         base,
 | 
						|
		BaseLimitIncrease: inc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *ScalingLimitConfig) AddProtocolPeerLimit(proto protocol.ID, base BaseLimit, inc BaseLimitIncrease) {
 | 
						|
	if cfg.ProtocolPeerLimits == nil {
 | 
						|
		cfg.ProtocolPeerLimits = make(map[protocol.ID]baseLimitConfig)
 | 
						|
	}
 | 
						|
	cfg.ProtocolPeerLimits[proto] = baseLimitConfig{
 | 
						|
		BaseLimit:         base,
 | 
						|
		BaseLimitIncrease: inc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type LimitVal int
 | 
						|
 | 
						|
const (
 | 
						|
	// DefaultLimit is the default value for resources. The exact value depends on the context, but will get values from `DefaultLimits`.
 | 
						|
	DefaultLimit LimitVal = 0
 | 
						|
	// Unlimited is the value for unlimited resources. An arbitrarily high number will also work.
 | 
						|
	Unlimited LimitVal = -1
 | 
						|
	// BlockAllLimit is the LimitVal for allowing no amount of resources.
 | 
						|
	BlockAllLimit LimitVal = -2
 | 
						|
)
 | 
						|
 | 
						|
func (l LimitVal) MarshalJSON() ([]byte, error) {
 | 
						|
	if l == Unlimited {
 | 
						|
		return json.Marshal("unlimited")
 | 
						|
	} else if l == DefaultLimit {
 | 
						|
		return json.Marshal("default")
 | 
						|
	} else if l == BlockAllLimit {
 | 
						|
		return json.Marshal("blockAll")
 | 
						|
	}
 | 
						|
	return json.Marshal(int(l))
 | 
						|
}
 | 
						|
 | 
						|
func (l *LimitVal) UnmarshalJSON(b []byte) error {
 | 
						|
	if string(b) == `"default"` {
 | 
						|
		*l = DefaultLimit
 | 
						|
		return nil
 | 
						|
	} else if string(b) == `"unlimited"` {
 | 
						|
		*l = Unlimited
 | 
						|
		return nil
 | 
						|
	} else if string(b) == `"blockAll"` {
 | 
						|
		*l = BlockAllLimit
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	var val int
 | 
						|
	if err := json.Unmarshal(b, &val); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if val == 0 {
 | 
						|
		// If there is an explicit 0 in the JSON we should interpret this as block all.
 | 
						|
		*l = BlockAllLimit
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	*l = LimitVal(val)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (l LimitVal) Build(defaultVal int) int {
 | 
						|
	if l == DefaultLimit {
 | 
						|
		return defaultVal
 | 
						|
	}
 | 
						|
	if l == Unlimited {
 | 
						|
		return math.MaxInt
 | 
						|
	}
 | 
						|
	if l == BlockAllLimit {
 | 
						|
		return 0
 | 
						|
	}
 | 
						|
	return int(l)
 | 
						|
}
 | 
						|
 | 
						|
type LimitVal64 int64
 | 
						|
 | 
						|
const (
 | 
						|
	// Default is the default value for resources.
 | 
						|
	DefaultLimit64 LimitVal64 = 0
 | 
						|
	// Unlimited is the value for unlimited resources.
 | 
						|
	Unlimited64 LimitVal64 = -1
 | 
						|
	// BlockAllLimit64 is the LimitVal for allowing no amount of resources.
 | 
						|
	BlockAllLimit64 LimitVal64 = -2
 | 
						|
)
 | 
						|
 | 
						|
func (l LimitVal64) MarshalJSON() ([]byte, error) {
 | 
						|
	if l == Unlimited64 {
 | 
						|
		return json.Marshal("unlimited")
 | 
						|
	} else if l == DefaultLimit64 {
 | 
						|
		return json.Marshal("default")
 | 
						|
	} else if l == BlockAllLimit64 {
 | 
						|
		return json.Marshal("blockAll")
 | 
						|
	}
 | 
						|
 | 
						|
	// Convert this to a string because JSON doesn't support 64-bit integers.
 | 
						|
	return json.Marshal(strconv.FormatInt(int64(l), 10))
 | 
						|
}
 | 
						|
 | 
						|
func (l *LimitVal64) UnmarshalJSON(b []byte) error {
 | 
						|
	if string(b) == `"default"` {
 | 
						|
		*l = DefaultLimit64
 | 
						|
		return nil
 | 
						|
	} else if string(b) == `"unlimited"` {
 | 
						|
		*l = Unlimited64
 | 
						|
		return nil
 | 
						|
	} else if string(b) == `"blockAll"` {
 | 
						|
		*l = BlockAllLimit64
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	var val string
 | 
						|
	if err := json.Unmarshal(b, &val); err != nil {
 | 
						|
		// Is this an integer? Possible because of backwards compatibility.
 | 
						|
		var val int
 | 
						|
		if err := json.Unmarshal(b, &val); err != nil {
 | 
						|
			return fmt.Errorf("failed to unmarshal limit value: %w", err)
 | 
						|
		}
 | 
						|
 | 
						|
		if val == 0 {
 | 
						|
			// If there is an explicit 0 in the JSON we should interpret this as block all.
 | 
						|
			*l = BlockAllLimit64
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
 | 
						|
		*l = LimitVal64(val)
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	i, err := strconv.ParseInt(val, 10, 64)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if i == 0 {
 | 
						|
		// If there is an explicit 0 in the JSON we should interpret this as block all.
 | 
						|
		*l = BlockAllLimit64
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	*l = LimitVal64(i)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (l LimitVal64) Build(defaultVal int64) int64 {
 | 
						|
	if l == DefaultLimit64 {
 | 
						|
		return defaultVal
 | 
						|
	}
 | 
						|
	if l == Unlimited64 {
 | 
						|
		return math.MaxInt64
 | 
						|
	}
 | 
						|
	if l == BlockAllLimit64 {
 | 
						|
		return 0
 | 
						|
	}
 | 
						|
	return int64(l)
 | 
						|
}
 | 
						|
 | 
						|
// ResourceLimits is the type for basic resource limits.
 | 
						|
type ResourceLimits struct {
 | 
						|
	Streams         LimitVal   `json:",omitempty"`
 | 
						|
	StreamsInbound  LimitVal   `json:",omitempty"`
 | 
						|
	StreamsOutbound LimitVal   `json:",omitempty"`
 | 
						|
	Conns           LimitVal   `json:",omitempty"`
 | 
						|
	ConnsInbound    LimitVal   `json:",omitempty"`
 | 
						|
	ConnsOutbound   LimitVal   `json:",omitempty"`
 | 
						|
	FD              LimitVal   `json:",omitempty"`
 | 
						|
	Memory          LimitVal64 `json:",omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
func (l *ResourceLimits) IsDefault() bool {
 | 
						|
	if l == nil {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	if l.Streams == DefaultLimit &&
 | 
						|
		l.StreamsInbound == DefaultLimit &&
 | 
						|
		l.StreamsOutbound == DefaultLimit &&
 | 
						|
		l.Conns == DefaultLimit &&
 | 
						|
		l.ConnsInbound == DefaultLimit &&
 | 
						|
		l.ConnsOutbound == DefaultLimit &&
 | 
						|
		l.FD == DefaultLimit &&
 | 
						|
		l.Memory == DefaultLimit64 {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func (l *ResourceLimits) ToMaybeNilPtr() *ResourceLimits {
 | 
						|
	if l.IsDefault() {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return l
 | 
						|
}
 | 
						|
 | 
						|
// Apply overwrites all default limits with the values of l2
 | 
						|
func (l *ResourceLimits) Apply(l2 ResourceLimits) {
 | 
						|
	if l.Streams == DefaultLimit {
 | 
						|
		l.Streams = l2.Streams
 | 
						|
	}
 | 
						|
	if l.StreamsInbound == DefaultLimit {
 | 
						|
		l.StreamsInbound = l2.StreamsInbound
 | 
						|
	}
 | 
						|
	if l.StreamsOutbound == DefaultLimit {
 | 
						|
		l.StreamsOutbound = l2.StreamsOutbound
 | 
						|
	}
 | 
						|
	if l.Conns == DefaultLimit {
 | 
						|
		l.Conns = l2.Conns
 | 
						|
	}
 | 
						|
	if l.ConnsInbound == DefaultLimit {
 | 
						|
		l.ConnsInbound = l2.ConnsInbound
 | 
						|
	}
 | 
						|
	if l.ConnsOutbound == DefaultLimit {
 | 
						|
		l.ConnsOutbound = l2.ConnsOutbound
 | 
						|
	}
 | 
						|
	if l.FD == DefaultLimit {
 | 
						|
		l.FD = l2.FD
 | 
						|
	}
 | 
						|
	if l.Memory == DefaultLimit64 {
 | 
						|
		l.Memory = l2.Memory
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (l *ResourceLimits) Build(defaults Limit) BaseLimit {
 | 
						|
	if l == nil {
 | 
						|
		return BaseLimit{
 | 
						|
			Streams:         defaults.GetStreamTotalLimit(),
 | 
						|
			StreamsInbound:  defaults.GetStreamLimit(network.DirInbound),
 | 
						|
			StreamsOutbound: defaults.GetStreamLimit(network.DirOutbound),
 | 
						|
			Conns:           defaults.GetConnTotalLimit(),
 | 
						|
			ConnsInbound:    defaults.GetConnLimit(network.DirInbound),
 | 
						|
			ConnsOutbound:   defaults.GetConnLimit(network.DirOutbound),
 | 
						|
			FD:              defaults.GetFDLimit(),
 | 
						|
			Memory:          defaults.GetMemoryLimit(),
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return BaseLimit{
 | 
						|
		Streams:         l.Streams.Build(defaults.GetStreamTotalLimit()),
 | 
						|
		StreamsInbound:  l.StreamsInbound.Build(defaults.GetStreamLimit(network.DirInbound)),
 | 
						|
		StreamsOutbound: l.StreamsOutbound.Build(defaults.GetStreamLimit(network.DirOutbound)),
 | 
						|
		Conns:           l.Conns.Build(defaults.GetConnTotalLimit()),
 | 
						|
		ConnsInbound:    l.ConnsInbound.Build(defaults.GetConnLimit(network.DirInbound)),
 | 
						|
		ConnsOutbound:   l.ConnsOutbound.Build(defaults.GetConnLimit(network.DirOutbound)),
 | 
						|
		FD:              l.FD.Build(defaults.GetFDLimit()),
 | 
						|
		Memory:          l.Memory.Build(defaults.GetMemoryLimit()),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type PartialLimitConfig struct {
 | 
						|
	System    ResourceLimits `json:",omitempty"`
 | 
						|
	Transient ResourceLimits `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    ResourceLimits `json:",omitempty"`
 | 
						|
	AllowlistedTransient ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
	ServiceDefault ResourceLimits            `json:",omitempty"`
 | 
						|
	Service        map[string]ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
	ServicePeerDefault ResourceLimits            `json:",omitempty"`
 | 
						|
	ServicePeer        map[string]ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
	ProtocolDefault ResourceLimits                 `json:",omitempty"`
 | 
						|
	Protocol        map[protocol.ID]ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
	ProtocolPeerDefault ResourceLimits                 `json:",omitempty"`
 | 
						|
	ProtocolPeer        map[protocol.ID]ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
	PeerDefault ResourceLimits             `json:",omitempty"`
 | 
						|
	Peer        map[peer.ID]ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
	Conn   ResourceLimits `json:",omitempty"`
 | 
						|
	Stream ResourceLimits `json:",omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *PartialLimitConfig) MarshalJSON() ([]byte, error) {
 | 
						|
	// we want to marshal the encoded peer id
 | 
						|
	encodedPeerMap := make(map[string]ResourceLimits, len(cfg.Peer))
 | 
						|
	for p, v := range cfg.Peer {
 | 
						|
		encodedPeerMap[p.String()] = v
 | 
						|
	}
 | 
						|
 | 
						|
	type Alias PartialLimitConfig
 | 
						|
	return json.Marshal(&struct {
 | 
						|
		*Alias
 | 
						|
		// String so we can have the properly marshalled peer id
 | 
						|
		Peer map[string]ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		// The rest of the fields as pointers so that we omit empty values in the serialized result
 | 
						|
		System               *ResourceLimits `json:",omitempty"`
 | 
						|
		Transient            *ResourceLimits `json:",omitempty"`
 | 
						|
		AllowlistedSystem    *ResourceLimits `json:",omitempty"`
 | 
						|
		AllowlistedTransient *ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		ServiceDefault *ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		ServicePeerDefault *ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		ProtocolDefault *ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		ProtocolPeerDefault *ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		PeerDefault *ResourceLimits `json:",omitempty"`
 | 
						|
 | 
						|
		Conn   *ResourceLimits `json:",omitempty"`
 | 
						|
		Stream *ResourceLimits `json:",omitempty"`
 | 
						|
	}{
 | 
						|
		Alias: (*Alias)(cfg),
 | 
						|
		Peer:  encodedPeerMap,
 | 
						|
 | 
						|
		System:               cfg.System.ToMaybeNilPtr(),
 | 
						|
		Transient:            cfg.Transient.ToMaybeNilPtr(),
 | 
						|
		AllowlistedSystem:    cfg.AllowlistedSystem.ToMaybeNilPtr(),
 | 
						|
		AllowlistedTransient: cfg.AllowlistedTransient.ToMaybeNilPtr(),
 | 
						|
		ServiceDefault:       cfg.ServiceDefault.ToMaybeNilPtr(),
 | 
						|
		ServicePeerDefault:   cfg.ServicePeerDefault.ToMaybeNilPtr(),
 | 
						|
		ProtocolDefault:      cfg.ProtocolDefault.ToMaybeNilPtr(),
 | 
						|
		ProtocolPeerDefault:  cfg.ProtocolPeerDefault.ToMaybeNilPtr(),
 | 
						|
		PeerDefault:          cfg.PeerDefault.ToMaybeNilPtr(),
 | 
						|
		Conn:                 cfg.Conn.ToMaybeNilPtr(),
 | 
						|
		Stream:               cfg.Stream.ToMaybeNilPtr(),
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func applyResourceLimitsMap[K comparable](this *map[K]ResourceLimits, other map[K]ResourceLimits, fallbackDefault ResourceLimits) {
 | 
						|
	for k, l := range *this {
 | 
						|
		r := fallbackDefault
 | 
						|
		if l2, ok := other[k]; ok {
 | 
						|
			r = l2
 | 
						|
		}
 | 
						|
		l.Apply(r)
 | 
						|
		(*this)[k] = l
 | 
						|
	}
 | 
						|
	if *this == nil && other != nil {
 | 
						|
		*this = make(map[K]ResourceLimits)
 | 
						|
	}
 | 
						|
	for k, l := range other {
 | 
						|
		if _, ok := (*this)[k]; !ok {
 | 
						|
			(*this)[k] = l
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *PartialLimitConfig) Apply(c PartialLimitConfig) {
 | 
						|
	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.ServicePeerDefault.Apply(c.ServicePeerDefault)
 | 
						|
	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)
 | 
						|
 | 
						|
	applyResourceLimitsMap(&cfg.Service, c.Service, cfg.ServiceDefault)
 | 
						|
	applyResourceLimitsMap(&cfg.ServicePeer, c.ServicePeer, cfg.ServicePeerDefault)
 | 
						|
	applyResourceLimitsMap(&cfg.Protocol, c.Protocol, cfg.ProtocolDefault)
 | 
						|
	applyResourceLimitsMap(&cfg.ProtocolPeer, c.ProtocolPeer, cfg.ProtocolPeerDefault)
 | 
						|
	applyResourceLimitsMap(&cfg.Peer, c.Peer, cfg.PeerDefault)
 | 
						|
}
 | 
						|
 | 
						|
func (cfg PartialLimitConfig) Build(defaults ConcreteLimitConfig) ConcreteLimitConfig {
 | 
						|
	out := defaults
 | 
						|
 | 
						|
	out.system = cfg.System.Build(defaults.system)
 | 
						|
	out.transient = cfg.Transient.Build(defaults.transient)
 | 
						|
	out.allowlistedSystem = cfg.AllowlistedSystem.Build(defaults.allowlistedSystem)
 | 
						|
	out.allowlistedTransient = cfg.AllowlistedTransient.Build(defaults.allowlistedTransient)
 | 
						|
	out.serviceDefault = cfg.ServiceDefault.Build(defaults.serviceDefault)
 | 
						|
	out.servicePeerDefault = cfg.ServicePeerDefault.Build(defaults.servicePeerDefault)
 | 
						|
	out.protocolDefault = cfg.ProtocolDefault.Build(defaults.protocolDefault)
 | 
						|
	out.protocolPeerDefault = cfg.ProtocolPeerDefault.Build(defaults.protocolPeerDefault)
 | 
						|
	out.peerDefault = cfg.PeerDefault.Build(defaults.peerDefault)
 | 
						|
	out.conn = cfg.Conn.Build(defaults.conn)
 | 
						|
	out.stream = cfg.Stream.Build(defaults.stream)
 | 
						|
 | 
						|
	out.service = buildMapWithDefault(cfg.Service, defaults.service, out.serviceDefault)
 | 
						|
	out.servicePeer = buildMapWithDefault(cfg.ServicePeer, defaults.servicePeer, out.servicePeerDefault)
 | 
						|
	out.protocol = buildMapWithDefault(cfg.Protocol, defaults.protocol, out.protocolDefault)
 | 
						|
	out.protocolPeer = buildMapWithDefault(cfg.ProtocolPeer, defaults.protocolPeer, out.protocolPeerDefault)
 | 
						|
	out.peer = buildMapWithDefault(cfg.Peer, defaults.peer, out.peerDefault)
 | 
						|
 | 
						|
	return out
 | 
						|
}
 | 
						|
 | 
						|
func buildMapWithDefault[K comparable](definedLimits map[K]ResourceLimits, defaults map[K]BaseLimit, fallbackDefault BaseLimit) map[K]BaseLimit {
 | 
						|
	if definedLimits == nil && defaults == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	out := make(map[K]BaseLimit)
 | 
						|
	for k, l := range defaults {
 | 
						|
		out[k] = l
 | 
						|
	}
 | 
						|
 | 
						|
	for k, l := range definedLimits {
 | 
						|
		if defaultForKey, ok := out[k]; ok {
 | 
						|
			out[k] = l.Build(defaultForKey)
 | 
						|
		} else {
 | 
						|
			out[k] = l.Build(fallbackDefault)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return out
 | 
						|
}
 | 
						|
 | 
						|
// ConcreteLimitConfig is similar to PartialLimitConfig, but all values are defined.
 | 
						|
// There is no unset "default" value. Commonly constructed by calling
 | 
						|
// PartialLimitConfig.Build(rcmgr.DefaultLimits.AutoScale())
 | 
						|
type ConcreteLimitConfig struct {
 | 
						|
	system    BaseLimit
 | 
						|
	transient BaseLimit
 | 
						|
 | 
						|
	// 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
 | 
						|
	allowlistedTransient BaseLimit
 | 
						|
 | 
						|
	serviceDefault BaseLimit
 | 
						|
	service        map[string]BaseLimit
 | 
						|
 | 
						|
	servicePeerDefault BaseLimit
 | 
						|
	servicePeer        map[string]BaseLimit
 | 
						|
 | 
						|
	protocolDefault BaseLimit
 | 
						|
	protocol        map[protocol.ID]BaseLimit
 | 
						|
 | 
						|
	protocolPeerDefault BaseLimit
 | 
						|
	protocolPeer        map[protocol.ID]BaseLimit
 | 
						|
 | 
						|
	peerDefault BaseLimit
 | 
						|
	peer        map[peer.ID]BaseLimit
 | 
						|
 | 
						|
	conn   BaseLimit
 | 
						|
	stream BaseLimit
 | 
						|
}
 | 
						|
 | 
						|
func resourceLimitsMapFromBaseLimitMap[K comparable](baseLimitMap map[K]BaseLimit) map[K]ResourceLimits {
 | 
						|
	if baseLimitMap == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	out := make(map[K]ResourceLimits)
 | 
						|
	for k, l := range baseLimitMap {
 | 
						|
		out[k] = l.ToResourceLimits()
 | 
						|
	}
 | 
						|
 | 
						|
	return out
 | 
						|
}
 | 
						|
 | 
						|
// ToPartialLimitConfig converts a ConcreteLimitConfig to a PartialLimitConfig.
 | 
						|
// The returned PartialLimitConfig will have no default values.
 | 
						|
func (cfg ConcreteLimitConfig) ToPartialLimitConfig() PartialLimitConfig {
 | 
						|
	return PartialLimitConfig{
 | 
						|
		System:               cfg.system.ToResourceLimits(),
 | 
						|
		Transient:            cfg.transient.ToResourceLimits(),
 | 
						|
		AllowlistedSystem:    cfg.allowlistedSystem.ToResourceLimits(),
 | 
						|
		AllowlistedTransient: cfg.allowlistedTransient.ToResourceLimits(),
 | 
						|
		ServiceDefault:       cfg.serviceDefault.ToResourceLimits(),
 | 
						|
		Service:              resourceLimitsMapFromBaseLimitMap(cfg.service),
 | 
						|
		ServicePeerDefault:   cfg.servicePeerDefault.ToResourceLimits(),
 | 
						|
		ServicePeer:          resourceLimitsMapFromBaseLimitMap(cfg.servicePeer),
 | 
						|
		ProtocolDefault:      cfg.protocolDefault.ToResourceLimits(),
 | 
						|
		Protocol:             resourceLimitsMapFromBaseLimitMap(cfg.protocol),
 | 
						|
		ProtocolPeerDefault:  cfg.protocolPeerDefault.ToResourceLimits(),
 | 
						|
		ProtocolPeer:         resourceLimitsMapFromBaseLimitMap(cfg.protocolPeer),
 | 
						|
		PeerDefault:          cfg.peerDefault.ToResourceLimits(),
 | 
						|
		Peer:                 resourceLimitsMapFromBaseLimitMap(cfg.peer),
 | 
						|
		Conn:                 cfg.conn.ToResourceLimits(),
 | 
						|
		Stream:               cfg.stream.ToResourceLimits(),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Scale scales up a limit configuration.
 | 
						|
// memory is the amount of memory that the stack is allowed to consume,
 | 
						|
// for a dedicated node 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) ConcreteLimitConfig {
 | 
						|
	lc := ConcreteLimitConfig{
 | 
						|
		system:               scale(cfg.SystemBaseLimit, cfg.SystemLimitIncrease, memory, numFD),
 | 
						|
		transient:            scale(cfg.TransientBaseLimit, cfg.TransientLimitIncrease, memory, numFD),
 | 
						|
		allowlistedSystem:    scale(cfg.AllowlistedSystemBaseLimit, cfg.AllowlistedSystemLimitIncrease, memory, numFD),
 | 
						|
		allowlistedTransient: scale(cfg.AllowlistedTransientBaseLimit, cfg.AllowlistedTransientLimitIncrease, memory, numFD),
 | 
						|
		serviceDefault:       scale(cfg.ServiceBaseLimit, cfg.ServiceLimitIncrease, memory, numFD),
 | 
						|
		servicePeerDefault:   scale(cfg.ServicePeerBaseLimit, cfg.ServicePeerLimitIncrease, memory, numFD),
 | 
						|
		protocolDefault:      scale(cfg.ProtocolBaseLimit, cfg.ProtocolLimitIncrease, memory, numFD),
 | 
						|
		protocolPeerDefault:  scale(cfg.ProtocolPeerBaseLimit, cfg.ProtocolPeerLimitIncrease, memory, numFD),
 | 
						|
		peerDefault:          scale(cfg.PeerBaseLimit, cfg.PeerLimitIncrease, memory, numFD),
 | 
						|
		conn:                 scale(cfg.ConnBaseLimit, cfg.ConnLimitIncrease, memory, numFD),
 | 
						|
		stream:               scale(cfg.StreamBaseLimit, cfg.ConnLimitIncrease, memory, 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, memory, 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, memory, 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, memory, 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, memory, 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, memory, numFD)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return lc
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *ScalingLimitConfig) AutoScale() ConcreteLimitConfig {
 | 
						|
	return cfg.Scale(
 | 
						|
		int64(memory.TotalMemory())/8,
 | 
						|
		getNumFDs()/2,
 | 
						|
	)
 | 
						|
}
 | 
						|
 | 
						|
func scale(base BaseLimit, inc BaseLimitIncrease, memory int64, numFD int) BaseLimit {
 | 
						|
	// mebibytesAvailable represents how many MiBs we're allowed to use. Used to
 | 
						|
	// scale the limits. If this is below 128MiB we set it to 0 to just use the
 | 
						|
	// base amounts.
 | 
						|
	var mebibytesAvailable int
 | 
						|
	if memory > 128<<20 {
 | 
						|
		mebibytesAvailable = int((memory) >> 20)
 | 
						|
	}
 | 
						|
	l := BaseLimit{
 | 
						|
		StreamsInbound:  base.StreamsInbound + (inc.StreamsInbound*mebibytesAvailable)>>10,
 | 
						|
		StreamsOutbound: base.StreamsOutbound + (inc.StreamsOutbound*mebibytesAvailable)>>10,
 | 
						|
		Streams:         base.Streams + (inc.Streams*mebibytesAvailable)>>10,
 | 
						|
		ConnsInbound:    base.ConnsInbound + (inc.ConnsInbound*mebibytesAvailable)>>10,
 | 
						|
		ConnsOutbound:   base.ConnsOutbound + (inc.ConnsOutbound*mebibytesAvailable)>>10,
 | 
						|
		Conns:           base.Conns + (inc.Conns*mebibytesAvailable)>>10,
 | 
						|
		Memory:          base.Memory + (inc.Memory*int64(mebibytesAvailable))>>10,
 | 
						|
		FD:              base.FD,
 | 
						|
	}
 | 
						|
	if inc.FDFraction > 0 && numFD > 0 {
 | 
						|
		l.FD = int(inc.FDFraction * float64(numFD))
 | 
						|
		if l.FD < base.FD {
 | 
						|
			// Use at least the base amount
 | 
						|
			l.FD = base.FD
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return l
 | 
						|
}
 | 
						|
 | 
						|
// 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{
 | 
						|
		// 8 for now so that it matches the number of concurrent dials we may do
 | 
						|
		// in swarm_dial.go. With future smart dialing work we should bring this
 | 
						|
		// down
 | 
						|
		ConnsInbound:    8,
 | 
						|
		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:        32 << 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,
 | 
						|
}
 | 
						|
 | 
						|
// InfiniteLimits are a limiter configuration that uses unlimited 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 = ConcreteLimitConfig{
 | 
						|
	system:               infiniteBaseLimit,
 | 
						|
	transient:            infiniteBaseLimit,
 | 
						|
	allowlistedSystem:    infiniteBaseLimit,
 | 
						|
	allowlistedTransient: infiniteBaseLimit,
 | 
						|
	serviceDefault:       infiniteBaseLimit,
 | 
						|
	servicePeerDefault:   infiniteBaseLimit,
 | 
						|
	protocolDefault:      infiniteBaseLimit,
 | 
						|
	protocolPeerDefault:  infiniteBaseLimit,
 | 
						|
	peerDefault:          infiniteBaseLimit,
 | 
						|
	conn:                 infiniteBaseLimit,
 | 
						|
	stream:               infiniteBaseLimit,
 | 
						|
}
 |