package rcmgr import ( "runtime" "github.com/pbnjay/memory" ) // DynamicLimit is a limit with dynamic memory values, based on available (free) memory type DynamicLimit struct { BaseLimit MemoryLimit } var _ Limit = (*DynamicLimit)(nil) func (l *DynamicLimit) GetMemoryLimit() int64 { freemem := memory.FreeMemory() // account for memory retained by the runtime that is actually free // HeapInuse - HeapAlloc is the memory available in allocator spans // HeapIdle - HeapReleased is memory held by the runtime that could be returned to the OS var memstat runtime.MemStats runtime.ReadMemStats(&memstat) freemem += (memstat.HeapInuse - memstat.HeapAlloc) + (memstat.HeapIdle - memstat.HeapReleased) return l.MemoryLimit.GetMemory(int64(freemem)) } func (l *DynamicLimit) WithMemoryLimit(memFraction float64, minMemory, maxMemory int64) Limit { r := new(DynamicLimit) *r = *l r.MemoryLimit.MemoryFraction *= memFraction r.MemoryLimit.MinMemory = minMemory r.MemoryLimit.MaxMemory = maxMemory return r } func (l *DynamicLimit) WithStreamLimit(numStreamsIn, numStreamsOut, numStreams int) Limit { r := new(DynamicLimit) *r = *l r.BaseLimit.StreamsInbound = numStreamsIn r.BaseLimit.StreamsOutbound = numStreamsOut r.BaseLimit.Streams = numStreams return r } func (l *DynamicLimit) WithConnLimit(numConnsIn, numConnsOut, numConns int) Limit { r := new(DynamicLimit) *r = *l r.BaseLimit.ConnsInbound = numConnsIn r.BaseLimit.ConnsOutbound = numConnsOut r.BaseLimit.Conns = numConns return r } func (l *DynamicLimit) WithFDLimit(numFD int) Limit { r := new(DynamicLimit) *r = *l r.BaseLimit.FD = numFD return r } // NewDefaultDynamicLimiter creates a limiter with default limits and a memory cap // dynamically computed based on available memory. func NewDefaultDynamicLimiter(memFraction float64, minMemory, maxMemory int64) *BasicLimiter { return NewDynamicLimiter(DefaultLimits.WithSystemMemory(memFraction, minMemory, maxMemory)) } // NewDynamicLimiter crates a dynamic limiter with the specified defaults func NewDynamicLimiter(cfg DefaultLimitConfig) *BasicLimiter { system := &DynamicLimit{ MemoryLimit: cfg.SystemMemory, BaseLimit: cfg.SystemBaseLimit, } transient := &DynamicLimit{ MemoryLimit: cfg.TransientMemory, BaseLimit: cfg.TransientBaseLimit, } svc := &DynamicLimit{ MemoryLimit: cfg.ServiceMemory, BaseLimit: cfg.ServiceBaseLimit, } svcPeer := &DynamicLimit{ MemoryLimit: cfg.ServicePeerMemory, BaseLimit: cfg.ServicePeerBaseLimit, } proto := &DynamicLimit{ MemoryLimit: cfg.ProtocolMemory, BaseLimit: cfg.ProtocolBaseLimit, } protoPeer := &DynamicLimit{ MemoryLimit: cfg.ProtocolPeerMemory, BaseLimit: cfg.ProtocolPeerBaseLimit, } peer := &DynamicLimit{ MemoryLimit: cfg.PeerMemory, BaseLimit: cfg.PeerBaseLimit, } conn := &StaticLimit{ Memory: cfg.ConnMemory, BaseLimit: cfg.ConnBaseLimit, } stream := &StaticLimit{ Memory: cfg.StreamMemory, BaseLimit: cfg.StreamBaseLimit, } return &BasicLimiter{ SystemLimits: system, TransientLimits: transient, DefaultServiceLimits: svc, DefaultServicePeerLimits: svcPeer, DefaultProtocolLimits: proto, DefaultProtocolPeerLimits: protoPeer, DefaultPeerLimits: peer, ConnLimits: conn, StreamLimits: stream, } }