dockerpool

package
v0.7.21 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package dockerpool is the in-memory warm-container pool for Docker sandboxes.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoSlot = errors.New("docker pool: no slot")

ErrNoSlot is returned when no warm slot is available for the key.

View Source
var ErrStaleImage = errors.New("docker pool: stale image")

ErrStaleImage is returned when a parked slot's image ID no longer matches.

Functions

func NewSlotID

func NewSlotID() (string, error)

NewSlotID mints a unique pool slot identifier.

func ParkReservationID

func ParkReservationID(slotID string) string

ParkReservationID is the capacity admitter key for a parked slot.

func RunRefill

func RunRefill(ctx context.Context, pool *Pool, cfg RefillConfig, spawner Spawner, gate RefillGate, logger *slog.Logger)

RunRefill is a convenience wrapper matching daemon wiring style.

Types

type Key

type Key struct {
	Image                 string
	ImageDigest           string
	ImageRegistryRef      string
	ImageDistributionMode string
	Runtime               string
}

Key identifies a warm-pool target by resolved image identity + runtime.

func KeyFromRequest

func KeyFromRequest(req models.CreateSandboxRequest, runtime string) Key

KeyFromRequest builds a pool key from a create request and resolved runtime.

func (Key) KeyString

func (k Key) KeyString() string

KeyString returns a stable map key for the pool. It canonicalizes through the same defaulting rule the service's image-distribution normalization applies (empty mode → external_registry, empty ref → image), because keys reach the pool from two sides that MUST collide: boot-time pins are built bare (Key{Image, Runtime}), while create-path keys are computed after NormalizeCreateImageDistribution filled the metadata. Without this, pinned slots sit under a keystring no create ever computes — permanently unreachable and, being pinned, never idle-reaped.

type Metrics

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

Metrics exposes pool counters for tests and expvar export.

func (*Metrics) RecordAdoptMS

func (m *Metrics) RecordAdoptMS(ms float64)

RecordAdoptMS publishes the latest successful adopt handshake duration. Exported because the adopt happens in pkg/docker, not in this package.

func (*Metrics) RecordSpawnFail

func (m *Metrics) RecordSpawnFail()

func (*Metrics) Stats

func (m *Metrics) Stats() Snapshot

Stats returns current counter values.

type ParkShape

type ParkShape struct {
	CPU       float64
	MemoryMB  int
	DiskGB    int
	GPUs      int
	GPUVendor string
	Runtime   string
}

ParkShape is the resource reservation shape for one parked slot.

type ParkedSlot

type ParkedSlot struct {
	ID             string
	ContainerID    string
	ContainerIP    string
	ImageID        string
	Key            Key
	BootstrapToken string
	Handle         SpawnerHandle
}

ParkedSlot is the in-memory handle for one warm container.

type Pool

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

Pool keeps pre-started Docker containers keyed by image identity + runtime.

func New

func New(logger *slog.Logger) *Pool

New constructs a warm pool.

func (*Pool) Acquire

func (p *Pool) Acquire(ctx context.Context, key Key, currentImageID string) (*ParkedSlot, error)

Acquire removes one warm slot for key. imageID is re-validated at hand-out. Dead and stale-image slots found along the way are pruned and destroyed — container, netrules, AND park reservation — otherwise their DROP rules and admitter reservations outlive the container object. All queue surgery happens under one continuous lock hold; releasing p.mu mid-scan let a concurrent RecordLoaded slot be clobbered by a stale slice write-back.

func (*Pool) ClearSpawnFailures

func (p *Pool) ClearSpawnFailures(ks string)

ClearSpawnFailures resets the consecutive-failure count after a successful park, so the eviction threshold only ever measures an unbroken run.

func (*Pool) Close

func (p *Pool) Close() int

Close drains all warm slots.

func (*Pool) HasReady

func (p *Pool) HasReady(key Key) bool

HasReady reports whether any slot is queued for key. It exists so the create path can skip the image-inspect engine call on a guaranteed miss — keeping the miss path free of added boot-path work.

func (*Pool) ListTargets

func (p *Pool) ListTargets() []Key

ListTargets returns keys eligible for refill.

func (*Pool) MarkSpawning

func (p *Pool) MarkSpawning(ks string)

MarkSpawning increments in-flight spawn counter for key string.

func (*Pool) Metrics

func (p *Pool) Metrics() *Metrics

func (*Pool) NoteMiss

func (p *Pool) NoteMiss(key Key)

NoteMiss registers a miss without scanning the queue: the target is noted for self-warming, the miss is counted, and refill is kicked — the same side effects an empty-queue Acquire would have had.

func (*Pool) NoteSpawnFailure

func (p *Pool) NoteSpawnFailure(ks string) bool

NoteSpawnFailure counts a failed park for key and evicts the target once the consecutive-failure threshold is crossed. Returns true when the target was evicted. Slot destruction happens outside the lock (same rationale as Acquire/NoteTarget).

func (*Pool) NoteTarget

func (p *Pool) NoteTarget(key Key)

NoteTarget registers a miss-driven refill target with LRU bounds.

func (*Pool) PinTarget

func (p *Pool) PinTarget(key Key)

PinTarget registers a key warmed from daemon start (never idle-expires).

func (*Pool) ReapIdle

func (p *Pool) ReapIdle(now time.Time) int

ReapIdle drops non-pinned targets with no recent use past idleTTL. Map surgery happens under one lock hold; slot destruction after unlock (same rationale as Acquire/NoteTarget).

func (*Pool) RecordLoaded

func (p *Pool) RecordLoaded(slot *ParkedSlot)

RecordLoaded pushes a freshly parked slot into the ready queue.

func (*Pool) ReleasePark

func (p *Pool) ReleasePark(slotID string)

ReleasePark frees the capacity reservation of a slot that already left the pool via Acquire but was discarded by the caller (e.g. adopt failure). Every parked slot holds a park:<slot-id> admitter reservation; any path that destroys the container without releasing it leaks capacity until the node stops admitting creates.

func (*Pool) ReturnSlot

func (p *Pool) ReturnSlot(slot *ParkedSlot)

ReturnSlot puts an acquired-but-untouched slot back into the ready queue (duplicate-create rename conflict: the parked container was never adopted). Unlike RecordLoaded it does not decrement the in-flight spawn counter — no spawn completed here, and skewing that counter makes SpawnBudget park past depth, each excess slot pinning a park reservation.

func (*Pool) Run

func (p *Pool) Run(ctx context.Context, cfg RefillConfig, spawner Spawner, gate RefillGate)

Run starts the refill loop until ctx is cancelled.

func (*Pool) SetDefaultDepth

func (p *Pool) SetDefaultDepth(n int)

func (*Pool) SetIdleTTL

func (p *Pool) SetIdleTTL(d time.Duration)

func (*Pool) SetMaxImages

func (p *Pool) SetMaxImages(n int)

func (*Pool) SetParkReleaser

func (p *Pool) SetParkReleaser(fn func(slotID string))

func (*Pool) SetSpawner

func (p *Pool) SetSpawner(s Spawner)

func (*Pool) SpawnBudget

func (p *Pool) SpawnBudget(ks string) int

SpawnBudget returns how many slots refill should create for key on this tick.

func (*Pool) UnmarkSpawning

func (p *Pool) UnmarkSpawning(ks string)

UnmarkSpawning decrements in-flight spawn counter after failed warm.

type RefillConfig

type RefillConfig struct {
	RefillInterval time.Duration
	SpawnTimeout   time.Duration
	IdleTTL        time.Duration
	ParkShape      ParkShape
}

RefillConfig holds timing knobs for the background refill loop.

type RefillGate

type RefillGate interface {
	CanPark(shape ParkShape) bool
	ParkReservation(slotID string, shape ParkShape) error
	ReleasePark(slotID string)
}

RefillGate decides whether a new park is allowed and tracks reservations.

type Snapshot

type Snapshot struct {
	Hits         int64
	Misses       int64
	Refilled     int64
	Orphans      int64
	StaleImages  int64
	SpawnFail    int64
	TargetEvicts int64
}

Snapshot is a point-in-time view of pool counters.

type Spawner

type Spawner interface {
	Park(ctx context.Context, slotID string, key Key) (*ParkedSlot, error)
	DestroyParked(ctx context.Context, slot *ParkedSlot) error
}

Spawner parks containers ahead of demand.

type SpawnerHandle

type SpawnerHandle interface {
	Alive() bool
	Adopt(ctx context.Context, sandboxID, token, adoptNonce string) error
	Close() error
}

SpawnerHandle is the host-side parked connection and listener state.

Jump to

Keyboard shortcuts

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