refactor limit defaults for easy access and user manipulation

This commit is contained in:
vyzo 2022-01-16 19:37:15 +02:00
parent ddb39883f9
commit 575eadee04
6 changed files with 330 additions and 217 deletions

104
limit.go
View File

@ -79,6 +79,13 @@ type BaseLimit struct {
FD int FD int
} }
// MemoryLimit is a mixin type for memory limits
type MemoryLimit struct {
MemoryFraction float64
MinMemory int64
MaxMemory int64
}
func (l *BaseLimit) GetStreamLimit(dir network.Direction) int { func (l *BaseLimit) GetStreamLimit(dir network.Direction) int {
if dir == network.DirInbound { if dir == network.DirInbound {
return l.StreamsInbound return l.StreamsInbound
@ -163,101 +170,12 @@ func (l *BasicLimiter) GetConnLimits() Limit {
return l.ConnLimits return l.ConnLimits
} }
// DefaultSystemBaseLimit returns the default BaseLimit for the System Scope. func (l *MemoryLimit) GetMemory(memoryCap int64) int64 {
func DefaultSystemBaseLimit() BaseLimit { return memoryLimit(memoryCap, l.MemoryFraction, l.MinMemory, l.MaxMemory)
return BaseLimit{
StreamsInbound: 4096,
StreamsOutbound: 16384,
Streams: 16384,
ConnsInbound: 256,
ConnsOutbound: 1024,
Conns: 1024,
FD: 512,
}
} }
// DefaultTransientBaseLimit returns the default BaseLimit for the Transient Scope. func memoryLimit(memoryCap int64, memFraction float64, minMemory, maxMemory int64) int64 {
func DefaultTransientBaseLimit() BaseLimit { memoryCap = int64(float64(memoryCap) * memFraction)
return BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 512,
Streams: 512,
ConnsInbound: 32,
ConnsOutbound: 128,
Conns: 128,
FD: 128,
}
}
// DefaultServiceBaseLimit returns the default BaseLimit for Service Scopes.
func DefaultServiceBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 2048,
StreamsOutbound: 8192,
Streams: 8192,
}
}
// DefaultServicePeerBaseLimit returns the default BaseLimit per peer for Service Scopes.
func DefaultServicePeerBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 256,
StreamsOutbound: 512,
Streams: 512,
}
}
// DefaultProtocolBaseLimit returns the default BaseLimit for Protocol Scopes.
func DefaultProtocolBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 1024,
StreamsOutbound: 4096,
Streams: 4096,
}
}
// DefaultProtocolPeerBaseLimit returns the default BaseLimit per peer for Protocol Scopes.
func DefaultProtocolPeerBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 256,
Streams: 512,
}
}
// DefaultPeerBaseLimit returns the default BaseLimit for Peer Scopes.
func DefaultPeerBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 512,
StreamsOutbound: 1024,
Streams: 1024,
ConnsInbound: 8,
ConnsOutbound: 16,
Conns: 16,
FD: 8,
}
}
// ConnBaseLimit returns the BaseLimit for Connection Scopes.
func ConnBaseLimit() BaseLimit {
return BaseLimit{
ConnsInbound: 1,
ConnsOutbound: 1,
Conns: 1,
FD: 1,
}
}
// StreamBaseLimit returns the BaseLimit for Stream Scopes.
func StreamBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 1,
StreamsOutbound: 1,
Streams: 1,
}
}
func memoryLimit(memoryCap int64, minMemory, maxMemory int64) int64 {
switch { switch {
case memoryCap < minMemory: case memoryCap < minMemory:
return minMemory return minMemory

View File

@ -32,11 +32,11 @@ type limitConfig struct {
FD int FD int
} }
func (cfg *limitConfig) toLimit(base BaseLimit, memFraction float64, minMemory, maxMemory int64) (Limit, error) { func (cfg *limitConfig) toLimit(base BaseLimit, mem MemoryLimit) (Limit, error) {
if cfg == nil { if cfg == nil {
mem := memoryLimit(int64(float64(memory.TotalMemory())*memFraction), minMemory, maxMemory) m := mem.GetMemory(int64(memory.TotalMemory()))
return &StaticLimit{ return &StaticLimit{
Memory: mem, Memory: m,
BaseLimit: base, BaseLimit: base,
}, nil }, nil
} }
@ -75,20 +75,18 @@ func (cfg *limitConfig) toLimit(base BaseLimit, memFraction float64, minMemory,
return nil, fmt.Errorf("negative memory fraction: %f", cfg.MemoryFraction) return nil, fmt.Errorf("negative memory fraction: %f", cfg.MemoryFraction)
} }
if cfg.MemoryFraction > 0 { if cfg.MemoryFraction > 0 {
memFraction = cfg.MemoryFraction mem.MemoryFraction = cfg.MemoryFraction
} }
if cfg.MinMemory > 0 { if cfg.MinMemory > 0 {
minMemory = cfg.MinMemory mem.MinMemory = cfg.MinMemory
} }
if cfg.MaxMemory > 0 { if cfg.MaxMemory > 0 {
maxMemory = cfg.MaxMemory mem.MaxMemory = cfg.MaxMemory
} }
return &DynamicLimit{ return &DynamicLimit{
MinMemory: minMemory, MemoryLimit: mem,
MaxMemory: maxMemory, BaseLimit: base,
MemoryFraction: memFraction,
BaseLimit: base,
}, nil }, nil
default: default:
@ -96,16 +94,67 @@ func (cfg *limitConfig) toLimit(base BaseLimit, memFraction float64, minMemory,
return nil, fmt.Errorf("negative memory fraction: %f", cfg.MemoryFraction) return nil, fmt.Errorf("negative memory fraction: %f", cfg.MemoryFraction)
} }
if cfg.MemoryFraction > 0 { if cfg.MemoryFraction > 0 {
memFraction = cfg.MemoryFraction mem.MemoryFraction = cfg.MemoryFraction
} }
if cfg.MinMemory > 0 { if cfg.MinMemory > 0 {
minMemory = cfg.MinMemory mem.MinMemory = cfg.MinMemory
} }
if cfg.MaxMemory > 0 { if cfg.MaxMemory > 0 {
maxMemory = cfg.MaxMemory mem.MaxMemory = cfg.MaxMemory
} }
mem := memoryLimit(int64(float64(memory.TotalMemory())*memFraction), minMemory, maxMemory) m := mem.GetMemory(int64(memory.TotalMemory()))
return &StaticLimit{
Memory: m,
BaseLimit: base,
}, nil
}
}
func (cfg *limitConfig) toLimitFixed(base BaseLimit, mem int64) (Limit, error) {
if cfg == nil {
return &StaticLimit{
Memory: mem,
BaseLimit: base,
}, nil
}
if cfg.Streams > 0 {
base.Streams = cfg.Streams
}
if cfg.StreamsInbound > 0 {
base.StreamsInbound = cfg.StreamsInbound
}
if cfg.StreamsOutbound > 0 {
base.StreamsOutbound = cfg.StreamsOutbound
}
if cfg.Conns > 0 {
base.Conns = cfg.Conns
}
if cfg.ConnsInbound > 0 {
base.ConnsInbound = cfg.ConnsInbound
}
if cfg.ConnsOutbound > 0 {
base.ConnsOutbound = cfg.ConnsOutbound
}
if cfg.FD > 0 {
base.FD = cfg.FD
}
switch {
case cfg.Memory > 0:
return &StaticLimit{
Memory: cfg.Memory,
BaseLimit: base,
}, nil
case cfg.Dynamic:
return nil, fmt.Errorf("cannot specify dynamic limit for fixed memory limit")
default:
if cfg.MemoryFraction > 0 || cfg.MinMemory > 0 || cfg.MaxMemory > 0 {
return nil, fmt.Errorf("cannot specify dynamic range for fixed memory limit")
}
return &StaticLimit{ return &StaticLimit{
Memory: mem, Memory: mem,
BaseLimit: base, BaseLimit: base,
@ -134,8 +183,14 @@ type limiterConfig struct {
Stream *limitConfig Stream *limitConfig
} }
// NewDefaultLimiterFromJSON creates a new limiter by parsing a json configuration,
// using the default limits for fallback.
func NewDefaultLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
return NewLimiterFromJSON(in, DefaultLimits)
}
// NewLimiterFromJSON creates a new limiter by parsing a json configuration. // NewLimiterFromJSON creates a new limiter by parsing a json configuration.
func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) { func NewLimiterFromJSON(in io.Reader, defaults DefaultLimitConfig) (*BasicLimiter, error) {
jin := json.NewDecoder(in) jin := json.NewDecoder(in)
var cfg limiterConfig var cfg limiterConfig
@ -147,22 +202,22 @@ func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
limiter := new(BasicLimiter) limiter := new(BasicLimiter)
var err error var err error
limiter.SystemLimits, err = cfg.System.toLimit(DefaultSystemBaseLimit(), 0.125, 128<<20, 1<<30) limiter.SystemLimits, err = cfg.System.toLimit(defaults.SystemBaseLimit, defaults.SystemMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid system limit: %w", err) return nil, fmt.Errorf("invalid system limit: %w", err)
} }
limiter.TransientLimits, err = cfg.Transient.toLimit(DefaultTransientBaseLimit(), 0.0078125, 64<<20, 128<<20) limiter.TransientLimits, err = cfg.Transient.toLimit(defaults.TransientBaseLimit, defaults.TransientMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid transient limit: %w", err) return nil, fmt.Errorf("invalid transient limit: %w", err)
} }
limiter.DefaultServiceLimits, err = cfg.ServiceDefault.toLimit(DefaultServiceBaseLimit(), 0.03125, 64<<20, 512<<20) limiter.DefaultServiceLimits, err = cfg.ServiceDefault.toLimit(defaults.ServiceBaseLimit, defaults.ServiceMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invlaid default service limit: %w", err) return nil, fmt.Errorf("invlaid default service limit: %w", err)
} }
limiter.DefaultServicePeerLimits, err = cfg.ServicePeerDefault.toLimit(DefaultServicePeerBaseLimit(), 0.0078125, 16<<20, 64<<20) limiter.DefaultServicePeerLimits, err = cfg.ServicePeerDefault.toLimit(defaults.ServicePeerBaseLimit, defaults.ServicePeerMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invlaid default service peer limit: %w", err) return nil, fmt.Errorf("invlaid default service peer limit: %w", err)
} }
@ -170,7 +225,7 @@ func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
if len(cfg.Service) > 0 { if len(cfg.Service) > 0 {
limiter.ServiceLimits = make(map[string]Limit, len(cfg.Service)) limiter.ServiceLimits = make(map[string]Limit, len(cfg.Service))
for svc, cfgLimit := range cfg.Service { for svc, cfgLimit := range cfg.Service {
limiter.ServiceLimits[svc], err = cfgLimit.toLimit(DefaultServiceBaseLimit(), 0.03125, 64<<20, 512<<20) limiter.ServiceLimits[svc], err = cfgLimit.toLimit(defaults.ServiceBaseLimit, defaults.ServiceMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid service limit for %s: %w", svc, err) return nil, fmt.Errorf("invalid service limit for %s: %w", svc, err)
} }
@ -180,19 +235,19 @@ func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
if len(cfg.ServicePeer) > 0 { if len(cfg.ServicePeer) > 0 {
limiter.ServicePeerLimits = make(map[string]Limit, len(cfg.ServicePeer)) limiter.ServicePeerLimits = make(map[string]Limit, len(cfg.ServicePeer))
for svc, cfgLimit := range cfg.ServicePeer { for svc, cfgLimit := range cfg.ServicePeer {
limiter.ServicePeerLimits[svc], err = cfgLimit.toLimit(DefaultServicePeerBaseLimit(), 0.0078125, 16<<20, 64<<20) limiter.ServicePeerLimits[svc], err = cfgLimit.toLimit(defaults.ServicePeerBaseLimit, defaults.ServicePeerMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid service peer limit for %s: %w", svc, err) return nil, fmt.Errorf("invalid service peer limit for %s: %w", svc, err)
} }
} }
} }
limiter.DefaultProtocolLimits, err = cfg.ProtocolDefault.toLimit(DefaultProtocolBaseLimit(), 0.0078125, 64<<20, 128<<20) limiter.DefaultProtocolLimits, err = cfg.ProtocolDefault.toLimit(defaults.ProtocolBaseLimit, defaults.ProtocolMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invlaid default protocol limit: %w", err) return nil, fmt.Errorf("invlaid default protocol limit: %w", err)
} }
limiter.DefaultProtocolPeerLimits, err = cfg.ProtocolPeerDefault.toLimit(DefaultProtocolPeerBaseLimit(), 0.0078125, 16<<20, 64<<20) limiter.DefaultProtocolPeerLimits, err = cfg.ProtocolPeerDefault.toLimit(defaults.ProtocolPeerBaseLimit, defaults.ProtocolPeerMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invlaid default protocol peer limit: %w", err) return nil, fmt.Errorf("invlaid default protocol peer limit: %w", err)
} }
@ -200,7 +255,7 @@ func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
if len(cfg.Protocol) > 0 { if len(cfg.Protocol) > 0 {
limiter.ProtocolLimits = make(map[protocol.ID]Limit, len(cfg.Protocol)) limiter.ProtocolLimits = make(map[protocol.ID]Limit, len(cfg.Protocol))
for p, cfgLimit := range cfg.Protocol { for p, cfgLimit := range cfg.Protocol {
limiter.ProtocolLimits[protocol.ID(p)], err = cfgLimit.toLimit(DefaultProtocolBaseLimit(), 0.0078125, 64<<20, 128<<20) limiter.ProtocolLimits[protocol.ID(p)], err = cfgLimit.toLimit(defaults.ProtocolBaseLimit, defaults.ProtocolMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid service limit for %s: %w", p, err) return nil, fmt.Errorf("invalid service limit for %s: %w", p, err)
} }
@ -210,14 +265,14 @@ func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
if len(cfg.ProtocolPeer) > 0 { if len(cfg.ProtocolPeer) > 0 {
limiter.ProtocolPeerLimits = make(map[protocol.ID]Limit, len(cfg.ProtocolPeer)) limiter.ProtocolPeerLimits = make(map[protocol.ID]Limit, len(cfg.ProtocolPeer))
for p, cfgLimit := range cfg.ProtocolPeer { for p, cfgLimit := range cfg.ProtocolPeer {
limiter.ProtocolPeerLimits[protocol.ID(p)], err = cfgLimit.toLimit(DefaultProtocolPeerBaseLimit(), 0.0078125, 16<<20, 64<<20) limiter.ProtocolPeerLimits[protocol.ID(p)], err = cfgLimit.toLimit(defaults.ProtocolPeerBaseLimit, defaults.ProtocolPeerMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid service peer limit for %s: %w", p, err) return nil, fmt.Errorf("invalid service peer limit for %s: %w", p, err)
} }
} }
} }
limiter.DefaultPeerLimits, err = cfg.PeerDefault.toLimit(DefaultPeerBaseLimit(), 0.0078125, 64<<20, 1288<<20) limiter.DefaultPeerLimits, err = cfg.PeerDefault.toLimit(defaults.PeerBaseLimit, defaults.PeerMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid peer limit: %w", err) return nil, fmt.Errorf("invalid peer limit: %w", err)
} }
@ -229,19 +284,19 @@ func NewLimiterFromJSON(in io.Reader) (*BasicLimiter, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid peer ID %s: %w", p, err) return nil, fmt.Errorf("invalid peer ID %s: %w", p, err)
} }
limiter.PeerLimits[pid], err = cfgLimit.toLimit(DefaultPeerBaseLimit(), 0.0078125, 64<<20, 1288<<20) limiter.PeerLimits[pid], err = cfgLimit.toLimit(defaults.PeerBaseLimit, defaults.PeerMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid peer limit for %s: %w", p, err) return nil, fmt.Errorf("invalid peer limit for %s: %w", p, err)
} }
} }
} }
limiter.ConnLimits, err = cfg.Conn.toLimit(ConnBaseLimit(), 1, 1<<20, 1<<20) limiter.ConnLimits, err = cfg.Conn.toLimitFixed(defaults.ConnBaseLimit, defaults.ConnMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid conn limit: %w", err) return nil, fmt.Errorf("invalid conn limit: %w", err)
} }
limiter.StreamLimits, err = cfg.Stream.toLimit(StreamBaseLimit(), 1, 16<<20, 16<<20) limiter.StreamLimits, err = cfg.Stream.toLimitFixed(defaults.StreamBaseLimit, defaults.StreamMemory)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid stream limit: %w", err) return nil, fmt.Errorf("invalid stream limit: %w", err)
} }

View File

@ -12,14 +12,16 @@ func TestLimitConfigParser(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer in.Close() defer in.Close()
limiter, err := NewLimiterFromJSON(in) limiter, err := NewDefaultLimiterFromJSON(in)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
&DynamicLimit{ &DynamicLimit{
MinMemory: 16384, MemoryLimit: MemoryLimit{
MaxMemory: 65536, MinMemory: 16384,
MemoryFraction: 0.125, MaxMemory: 65536,
MemoryFraction: 0.125,
},
BaseLimit: BaseLimit{ BaseLimit: BaseLimit{
Streams: 64, Streams: 64,
StreamsInbound: 32, StreamsInbound: 32,
@ -35,21 +37,21 @@ func TestLimitConfigParser(t *testing.T) {
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 4096, Memory: 4096,
BaseLimit: DefaultTransientBaseLimit(), BaseLimit: DefaultLimits.TransientBaseLimit,
}, },
limiter.TransientLimits) limiter.TransientLimits)
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 8192, Memory: 8192,
BaseLimit: DefaultServiceBaseLimit(), BaseLimit: DefaultLimits.ServiceBaseLimit,
}, },
limiter.DefaultServiceLimits) limiter.DefaultServiceLimits)
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 2048, Memory: 2048,
BaseLimit: DefaultServicePeerBaseLimit(), BaseLimit: DefaultLimits.ServicePeerBaseLimit,
}, },
limiter.DefaultServicePeerLimits) limiter.DefaultServicePeerLimits)
@ -57,7 +59,7 @@ func TestLimitConfigParser(t *testing.T) {
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 8192, Memory: 8192,
BaseLimit: DefaultServiceBaseLimit(), BaseLimit: DefaultLimits.ServiceBaseLimit,
}, },
limiter.ServiceLimits["A"]) limiter.ServiceLimits["A"])
@ -65,20 +67,20 @@ func TestLimitConfigParser(t *testing.T) {
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 4096, Memory: 4096,
BaseLimit: DefaultServicePeerBaseLimit(), BaseLimit: DefaultLimits.ServicePeerBaseLimit,
}, },
limiter.ServicePeerLimits["A"]) limiter.ServicePeerLimits["A"])
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 2048, Memory: 2048,
BaseLimit: DefaultProtocolBaseLimit(), BaseLimit: DefaultLimits.ProtocolBaseLimit,
}, },
limiter.DefaultProtocolLimits) limiter.DefaultProtocolLimits)
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 1024, Memory: 1024,
BaseLimit: DefaultProtocolPeerBaseLimit(), BaseLimit: DefaultLimits.ProtocolPeerBaseLimit,
}, },
limiter.DefaultProtocolPeerLimits) limiter.DefaultProtocolPeerLimits)
@ -86,7 +88,7 @@ func TestLimitConfigParser(t *testing.T) {
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 8192, Memory: 8192,
BaseLimit: DefaultProtocolBaseLimit(), BaseLimit: DefaultLimits.ProtocolBaseLimit,
}, },
limiter.ProtocolLimits["/A"]) limiter.ProtocolLimits["/A"])
@ -94,28 +96,28 @@ func TestLimitConfigParser(t *testing.T) {
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 4096, Memory: 4096,
BaseLimit: DefaultProtocolPeerBaseLimit(), BaseLimit: DefaultLimits.ProtocolPeerBaseLimit,
}, },
limiter.ProtocolPeerLimits["/A"]) limiter.ProtocolPeerLimits["/A"])
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 4096, Memory: 4096,
BaseLimit: DefaultPeerBaseLimit(), BaseLimit: DefaultLimits.PeerBaseLimit,
}, },
limiter.DefaultPeerLimits) limiter.DefaultPeerLimits)
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 1 << 20, Memory: 1 << 20,
BaseLimit: ConnBaseLimit(), BaseLimit: DefaultLimits.ConnBaseLimit,
}, },
limiter.ConnLimits) limiter.ConnLimits)
require.Equal(t, require.Equal(t,
&StaticLimit{ &StaticLimit{
Memory: 16 << 20, Memory: 16 << 20,
BaseLimit: StreamBaseLimit(), BaseLimit: DefaultLimits.StreamBaseLimit,
}, },
limiter.StreamLimits) limiter.StreamLimits)

147
limit_defaults.go Normal file
View File

@ -0,0 +1,147 @@
package rcmgr
// DefaultLimitConfig is a struct for configuring default limits.
type DefaultLimitConfig struct {
SystemBaseLimit BaseLimit
SystemMemory MemoryLimit
TransientBaseLimit BaseLimit
TransientMemory MemoryLimit
ServiceBaseLimit BaseLimit
ServiceMemory MemoryLimit
ServicePeerBaseLimit BaseLimit
ServicePeerMemory MemoryLimit
ProtocolBaseLimit BaseLimit
ProtocolMemory MemoryLimit
ProtocolPeerBaseLimit BaseLimit
ProtocolPeerMemory MemoryLimit
PeerBaseLimit BaseLimit
PeerMemory MemoryLimit
ConnBaseLimit BaseLimit
ConnMemory int64
StreamBaseLimit BaseLimit
StreamMemory int64
}
// DefaultLimits are the limits used by the default limiter constructors.
var DefaultLimits = DefaultLimitConfig{
SystemBaseLimit: BaseLimit{
StreamsInbound: 4096,
StreamsOutbound: 16384,
Streams: 16384,
ConnsInbound: 256,
ConnsOutbound: 1024,
Conns: 1024,
FD: 512,
},
SystemMemory: MemoryLimit{
MemoryFraction: 0.125,
MinMemory: 128 << 20,
MaxMemory: 1 << 30,
},
TransientBaseLimit: BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 512,
Streams: 512,
ConnsInbound: 32,
ConnsOutbound: 128,
Conns: 128,
FD: 128,
},
TransientMemory: MemoryLimit{
MemoryFraction: 1,
MinMemory: 64 << 20,
MaxMemory: 64 << 20,
},
ServiceBaseLimit: BaseLimit{
StreamsInbound: 2048,
StreamsOutbound: 8192,
Streams: 8192,
},
ServiceMemory: MemoryLimit{
MemoryFraction: 0.125 / 4,
MinMemory: 64 << 20,
MaxMemory: 256 << 20,
},
ServicePeerBaseLimit: BaseLimit{
StreamsInbound: 256,
StreamsOutbound: 512,
Streams: 512,
},
ServicePeerMemory: MemoryLimit{
MemoryFraction: 0.125 / 16,
MinMemory: 16 << 20,
MaxMemory: 64 << 20,
},
ProtocolBaseLimit: BaseLimit{
StreamsInbound: 1024,
StreamsOutbound: 4096,
Streams: 4096,
},
ProtocolMemory: MemoryLimit{
MemoryFraction: 0.125 / 8,
MinMemory: 64 << 20,
MaxMemory: 128 << 20,
},
ProtocolPeerBaseLimit: BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 256,
Streams: 512,
},
ProtocolPeerMemory: MemoryLimit{
MemoryFraction: 0.125 / 16,
MinMemory: 16 << 20,
MaxMemory: 64 << 20,
},
PeerBaseLimit: BaseLimit{
StreamsInbound: 512,
StreamsOutbound: 1024,
Streams: 1024,
ConnsInbound: 8,
ConnsOutbound: 16,
Conns: 16,
FD: 8,
},
PeerMemory: MemoryLimit{
MemoryFraction: 0.125 / 16,
MinMemory: 64 << 20,
MaxMemory: 128 << 20,
},
ConnBaseLimit: BaseLimit{
ConnsInbound: 1,
ConnsOutbound: 1,
Conns: 1,
FD: 1,
},
ConnMemory: 1 << 20,
StreamBaseLimit: BaseLimit{
StreamsInbound: 1,
StreamsOutbound: 1,
Streams: 1,
},
StreamMemory: 16 << 20,
}

View File

@ -9,14 +9,7 @@ import (
// DynamicLimit is a limit with dynamic memory values, based on available (free) memory // DynamicLimit is a limit with dynamic memory values, based on available (free) memory
type DynamicLimit struct { type DynamicLimit struct {
BaseLimit BaseLimit
MemoryLimit
// MinMemory is the minimum memory for this limit
MinMemory int64
// MaxMemory is the maximum memory for this limit
MaxMemory int64
// MemoryFraction is the fraction of available memory allowed for this limit,
// bounded by [MinMemory, MaxMemory]
MemoryFraction float64
} }
var _ Limit = (*DynamicLimit)(nil) var _ Limit = (*DynamicLimit)(nil)
@ -31,18 +24,16 @@ func (l *DynamicLimit) GetMemoryLimit() int64 {
runtime.ReadMemStats(&memstat) runtime.ReadMemStats(&memstat)
freemem += (memstat.HeapInuse - memstat.HeapAlloc) + (memstat.HeapIdle - memstat.HeapReleased) freemem += (memstat.HeapInuse - memstat.HeapAlloc) + (memstat.HeapIdle - memstat.HeapReleased)
return l.MemoryLimit.GetMemory(int64(freemem))
limit := int64(float64(freemem) * l.MemoryFraction)
return memoryLimit(limit, l.MinMemory, l.MaxMemory)
} }
func (l *DynamicLimit) WithMemoryLimit(memFraction float64, minMemory, maxMemory int64) Limit { func (l *DynamicLimit) WithMemoryLimit(memFraction float64, minMemory, maxMemory int64) Limit {
r := new(DynamicLimit) r := new(DynamicLimit)
*r = *l *r = *l
r.MemoryFraction *= memFraction r.MemoryLimit.MemoryFraction *= memFraction
r.MinMemory = minMemory r.MemoryLimit.MinMemory = minMemory
r.MaxMemory = maxMemory r.MemoryLimit.MaxMemory = maxMemory
return r return r
} }
@ -78,61 +69,49 @@ func (l *DynamicLimit) WithFDLimit(numFD int) Limit {
return r return r
} }
// NewDynamicLimiter creates a limiter with default limits and a memory cap dynamically computed // NewDefaultDynamicLimiter creates a limiter with default limits and a memory cap
// based on available memory. minMemory and maxMemory specify the system memory bounds, // dynamically computed based on available memory.
// while memFraction specifies the fraction of available memory available for the system, within func NewDefaultDynamicLimiter() *BasicLimiter {
// the specified bounds. return NewDynamicLimiter(DefaultLimits)
func NewDynamicLimiter(memFraction float64, minMemory, maxMemory int64) *BasicLimiter { }
// NewDynamicLimiter crates a dynamic limiter with the specified defaults
func NewDynamicLimiter(cfg DefaultLimitConfig) *BasicLimiter {
system := &DynamicLimit{ system := &DynamicLimit{
MinMemory: minMemory, MemoryLimit: cfg.SystemMemory,
MaxMemory: maxMemory, BaseLimit: cfg.SystemBaseLimit,
MemoryFraction: memFraction,
BaseLimit: DefaultSystemBaseLimit(),
} }
transient := &DynamicLimit{ transient := &DynamicLimit{
MinMemory: 64 << 20, MemoryLimit: cfg.TransientMemory,
MaxMemory: 128 << 20, BaseLimit: cfg.TransientBaseLimit,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultTransientBaseLimit(),
} }
svc := &DynamicLimit{ svc := &DynamicLimit{
MinMemory: 64 << 20, MemoryLimit: cfg.ServiceMemory,
MaxMemory: 512 << 20, BaseLimit: cfg.ServiceBaseLimit,
MemoryFraction: memFraction / 4,
BaseLimit: DefaultServiceBaseLimit(),
} }
svcPeer := &DynamicLimit{ svcPeer := &DynamicLimit{
MinMemory: 16 << 20, MemoryLimit: cfg.ServicePeerMemory,
MaxMemory: 64 << 20, BaseLimit: cfg.ServicePeerBaseLimit,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultServicePeerBaseLimit(),
} }
proto := &DynamicLimit{ proto := &DynamicLimit{
MinMemory: 64 << 20, MemoryLimit: cfg.ProtocolMemory,
MaxMemory: 128 << 20, BaseLimit: cfg.ProtocolBaseLimit,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultProtocolBaseLimit(),
} }
protoPeer := &DynamicLimit{ protoPeer := &DynamicLimit{
MinMemory: 16 << 20, MemoryLimit: cfg.ProtocolPeerMemory,
MaxMemory: 64 << 20, BaseLimit: cfg.ProtocolPeerBaseLimit,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultProtocolPeerBaseLimit(),
} }
peer := &DynamicLimit{ peer := &DynamicLimit{
MinMemory: 64 << 20, MemoryLimit: cfg.PeerMemory,
MaxMemory: 128 << 20, BaseLimit: cfg.PeerBaseLimit,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultPeerBaseLimit(),
} }
conn := &StaticLimit{ conn := &StaticLimit{
Memory: 1 << 20, Memory: cfg.ConnMemory,
BaseLimit: ConnBaseLimit(), BaseLimit: cfg.ConnBaseLimit,
} }
stream := &StaticLimit{ stream := &StaticLimit{
Memory: 16 << 20, Memory: cfg.StreamMemory,
BaseLimit: StreamBaseLimit(), BaseLimit: cfg.StreamBaseLimit,
} }
return &BasicLimiter{ return &BasicLimiter{

View File

@ -61,55 +61,67 @@ func (l *StaticLimit) WithFDLimit(numFD int) Limit {
return r return r
} }
// NewStaticLimiter creates a limiter with default base limits and a system memory cap specified as // NewDefaultStaticLimiter creates a static limiter with default base limits and a system memory cap
// a fraction of total system memory. The assigned memory will not be less than minMemory or more // specified as a fraction of total system memory. The assigned memory will not be less than
// than maxMemory. // minMemory or more than maxMemory.
func NewStaticLimiter(memFraction float64, minMemory, maxMemory int64) *BasicLimiter { func NewDefaultStaticLimiter(memFraction float64, minMemory, maxMemory int64) *BasicLimiter {
memoryCap := memoryLimit(int64(float64(memory.TotalMemory())*memFraction), minMemory, maxMemory) memoryCap := memoryLimit(int64(memory.TotalMemory()), memFraction, minMemory, maxMemory)
return newDefaultStaticLimiter(memoryCap) return NewStaticLimiter(memoryCap, DefaultLimits)
} }
// NewFixedLimiter creates a limiter with default base limits and a specified system memory cap. // NewDefaultFixedLimiter creates a static limiter with default base limits and a specified system
func NewFixedLimiter(memoryCap int64) *BasicLimiter { // memory cap.
return newDefaultStaticLimiter(memoryCap) func NewDefaultFixedLimiter(memoryCap int64) *BasicLimiter {
return NewStaticLimiter(memoryCap, DefaultLimits)
} }
func newDefaultStaticLimiter(memoryCap int64) *BasicLimiter { // NewDefaultLimiter creates a static limiter with the default limits
func NewDefaultLimiter() *BasicLimiter {
return NewDefaultStaticLimiter(
DefaultLimits.SystemMemory.MemoryFraction,
DefaultLimits.SystemMemory.MinMemory,
DefaultLimits.SystemMemory.MaxMemory,
)
}
// NewStaticLimiter creates a static limiter using the specified system memory cap and default
// limit config.
func NewStaticLimiter(memoryCap int64, cfg DefaultLimitConfig) *BasicLimiter {
system := &StaticLimit{ system := &StaticLimit{
Memory: memoryCap, Memory: memoryCap,
BaseLimit: DefaultSystemBaseLimit(), BaseLimit: cfg.SystemBaseLimit,
} }
transient := &StaticLimit{ transient := &StaticLimit{
Memory: memoryLimit(memoryCap/16, 64<<20, 128<<20), Memory: cfg.SystemMemory.GetMemory(memoryCap),
BaseLimit: DefaultTransientBaseLimit(), BaseLimit: cfg.TransientBaseLimit,
} }
svc := &StaticLimit{ svc := &StaticLimit{
Memory: memoryLimit(memoryCap/4, 64<<20, 512<<20), Memory: cfg.ServiceMemory.GetMemory(memoryCap),
BaseLimit: DefaultServiceBaseLimit(), BaseLimit: cfg.ServiceBaseLimit,
} }
svcPeer := &StaticLimit{ svcPeer := &StaticLimit{
Memory: memoryLimit(memoryCap/16, 16<<20, 64<<20), Memory: cfg.ServicePeerMemory.GetMemory(memoryCap),
BaseLimit: DefaultServicePeerBaseLimit(), BaseLimit: cfg.ServicePeerBaseLimit,
} }
proto := &StaticLimit{ proto := &StaticLimit{
Memory: memoryLimit(memoryCap/16, 64<<20, 128<<20), Memory: cfg.ProtocolMemory.GetMemory(memoryCap),
BaseLimit: DefaultProtocolBaseLimit(), BaseLimit: cfg.ProtocolBaseLimit,
} }
protoPeer := &StaticLimit{ protoPeer := &StaticLimit{
Memory: memoryLimit(memoryCap/16, 16<<20, 64<<20), Memory: cfg.ProtocolPeerMemory.GetMemory(memoryCap),
BaseLimit: DefaultProtocolPeerBaseLimit(), BaseLimit: cfg.ProtocolPeerBaseLimit,
} }
peer := &StaticLimit{ peer := &StaticLimit{
Memory: memoryLimit(memoryCap/16, 64<<20, 128<<20), Memory: cfg.PeerMemory.GetMemory(memoryCap),
BaseLimit: DefaultPeerBaseLimit(), BaseLimit: cfg.PeerBaseLimit,
} }
conn := &StaticLimit{ conn := &StaticLimit{
Memory: 1 << 20, Memory: cfg.ConnMemory,
BaseLimit: ConnBaseLimit(), BaseLimit: cfg.ConnBaseLimit,
} }
stream := &StaticLimit{ stream := &StaticLimit{
Memory: 16 << 20, Memory: cfg.StreamMemory,
BaseLimit: StreamBaseLimit(), BaseLimit: cfg.StreamBaseLimit,
} }
return &BasicLimiter{ return &BasicLimiter{