cloudflared-mirror/session/limiter.go

78 lines
1.7 KiB
Go

package session
import (
"errors"
"sync"
)
const (
unlimitedActiveSessions = 0
)
var (
ErrTooManyActiveSessions = errors.New("too many active sessions")
)
type Limiter interface {
// Acquire tries to acquire a free slot for a session, if the value of sessions is already above
// the maximum it returns ErrTooManyActiveSessions.
Acquire(sessionType string) error
// Release releases a slot for a session.
Release()
// SetLimit allows to hot swap the limit value of the limiter.
SetLimit(uint64)
}
type sessionLimiter struct {
limiterLock sync.Mutex
activeSessionsCounter uint64
maxActiveSessions uint64
unlimited bool
}
func NewLimiter(maxActiveSessions uint64) Limiter {
sessionLimiter := &sessionLimiter{
maxActiveSessions: maxActiveSessions,
unlimited: isUnlimited(maxActiveSessions),
}
return sessionLimiter
}
func (s *sessionLimiter) Acquire(sessionType string) error {
s.limiterLock.Lock()
defer s.limiterLock.Unlock()
if !s.unlimited && s.activeSessionsCounter >= s.maxActiveSessions {
sessionRegistrationsDropped.WithLabelValues(sessionType).Inc()
return ErrTooManyActiveSessions
}
s.activeSessionsCounter++
return nil
}
func (s *sessionLimiter) Release() {
s.limiterLock.Lock()
defer s.limiterLock.Unlock()
if s.activeSessionsCounter <= 0 {
return
}
s.activeSessionsCounter--
}
func (s *sessionLimiter) SetLimit(newMaxActiveSessions uint64) {
s.limiterLock.Lock()
defer s.limiterLock.Unlock()
s.maxActiveSessions = newMaxActiveSessions
s.unlimited = isUnlimited(newMaxActiveSessions)
}
// isUnlimited checks if the value received matches the configuration for the unlimited session limiter.
func isUnlimited(value uint64) bool {
return value == unlimitedActiveSessions
}