capacity

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package capacity implements admission control for sandbox creation.

Admission is purely resource-math — there is no fixed "max sandboxes" number. The admitter combines two signals before letting a sandbox in:

  1. Sum-of-reservations against host CPU cores and total memory, scaled by configurable ratios. This is predictable: the operator knows that accepted requests will not collectively exceed the ratio of host capacity, regardless of whether the sandboxes are actually using it. A 64-core box can run 200 tiny sandboxes or 8 huge ones — whatever the math allows.
  2. A live free-memory floor read from /proc/meminfo. This catches the case where reservations look fine but the host is genuinely tight right now (e.g. another process is eating RAM).

Reservations are tracked in-process. They must be replayed at startup from persistent state so a daemon restart doesn't reset accounting to zero.

Index

Constants

This section is empty.

Variables

View Source
var ErrCapacityExceeded = errors.New("host capacity exceeded")

ErrCapacityExceeded is returned by Admit when the host cannot accept a new sandbox. The wrapped error carries human-readable reasons; callers can use errors.Is to map this to a 503 response.

Functions

This section is empty.

Types

type Admitter

type Admitter struct {
	// contains filtered or unexported fields
}

Admitter is the thread-safe admission controller. Construct with New and keep a single instance per daemon.

func New

func New(host HostInfo, limits Limits, probe MemProbe) *Admitter

New builds an admitter. host should reflect the machine's total capacity; callers that don't care about per-host detection can use DetectHost.

func (*Admitter) Admit

func (a *Admitter) Admit(sandboxID string, req Request) error

Admit decides whether a new sandbox with the given resource request can be accepted right now. On success it reserves the request under sandboxID and returns nil. On failure it returns an error wrapping ErrCapacityExceeded with reasons attached; no reservation is made.

Callers that fail downstream (e.g. docker create errors) must call Release to free the reservation. Reserve is idempotent per sandboxID — re-admitting the same ID overwrites the prior reservation.

func (*Admitter) Release

func (a *Admitter) Release(sandboxID string)

Release frees the reservation for sandboxID. Safe to call for unknown IDs.

func (*Admitter) Reserve

func (a *Admitter) Reserve(sandboxID string, req Request)

Reserve records a reservation without running admission checks. Use this on startup to replay existing sandboxes from persistent state. Subsequent Admit calls see the replayed reservations as already-counted.

func (*Admitter) Snapshot

func (a *Admitter) Snapshot() Snapshot

Snapshot returns a point-in-time view. Includes a CanAdmit answer for a hypothetical zero-resource sandbox so operators can see "is this host accepting at all" without having to make a real request.

type HostInfo

type HostInfo struct {
	CPUCores      int
	MemoryTotalMB int
}

HostInfo describes the static host capacity.

func DetectHost

func DetectHost() (HostInfo, error)

DetectHost returns CPU core count from runtime and memory total from /proc/meminfo via the default probe. Callers may override either field.

type Limits

type Limits struct {
	// CPUReservationRatio is the maximum fraction of host CPU cores that may
	// be reserved across all sandboxes. 0 = unlimited.
	CPUReservationRatio float64
	// MemoryReservationRatio is the maximum fraction of host memory that may
	// be reserved across all sandboxes. 0 = unlimited.
	MemoryReservationRatio float64
	// MemoryFloorRatio is the minimum live MemAvailable the host must retain
	// after admitting the request, expressed as a fraction of total host
	// memory (e.g. 0.05 = keep at least 5% of RAM free). Expressing this as a
	// ratio means a 16 GB laptop and a 256 GB box scale their headroom
	// proportionally — a fixed MB floor would be either pointless on big
	// hosts or starve small ones. 0 = no floor.
	MemoryFloorRatio float64
}

Limits configures the admitter. Zero values disable the corresponding check.

type MemProbe

type MemProbe interface {
	FreeMB() (int, error)
}

MemProbe reports live free memory in MB. The default implementation reads /proc/meminfo MemAvailable. Tests can substitute a fake.

func NewProcMeminfoProbe

func NewProcMeminfoProbe() MemProbe

NewProcMeminfoProbe returns a MemProbe backed by /proc/meminfo with a 500ms cache. The cache window is small enough that decisions remain responsive to actual host memory pressure but large enough to absorb a burst of concurrent CreateSandbox calls without 50 file reads.

type Request

type Request struct {
	CPU      float64
	MemoryMB int
}

Request is the per-sandbox resource ask, in normalized units. CPU is fractional cores (e.g. 0.5 = half a core); memory is whole MB.

type Snapshot

type Snapshot struct {
	HostCPUCores           int      `json:"host_cpu_cores"`
	HostMemoryTotalMB      int      `json:"host_memory_total_mb"`
	ReservedCPU            float64  `json:"reserved_cpu"`
	ReservedMemoryMB       int      `json:"reserved_memory_mb"`
	LiveMemoryFreeMB       int      `json:"live_memory_free_mb"`
	SandboxesActive        int      `json:"sandboxes_active"`
	CanAdmit               bool     `json:"can_admit"`
	Reasons                []string `json:"reasons,omitempty"`
	CPUReservationRatio    float64  `json:"cpu_reservation_ratio"`
	MemoryReservationRatio float64  `json:"memory_reservation_ratio"`
	MemoryFloorRatio       float64  `json:"memory_floor_ratio"`
	// MemoryFloorMB is the absolute floor derived from MemoryFloorRatio and
	// host memory, exposed for operators reading /capacity.
	MemoryFloorMB int `json:"memory_floor_mb"`
}

Snapshot is a read-only view of admitter state, suitable for an HTTP /capacity response.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL