adaptive

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package adaptive implements a dual-engine controller that dynamically switches between io_uring and epoll based on runtime telemetry.

The adaptive Engine starts both sub-engines on the same port (via SO_REUSEPORT) and periodically evaluates their performance scores. If the standby engine's historical score exceeds the active engine's score by more than a threshold, the controller triggers a switch. Oscillation detection locks switching for five minutes after three rapid switches.

Users select the adaptive engine via celeris.Config{Engine: celeris.Adaptive}. It is the default engine on Linux.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Engine

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

Engine is an adaptive meta-engine that switches between io_uring and epoll.

func New

func New(cfg resource.Config, handler stream.Handler) (*Engine, error)

New creates a new adaptive engine with epoll as primary and io_uring as secondary. Epoll starts first because it has lower H2 latency on current kernels (single-pass read→process→write vs io_uring's two-iteration CQE model). The controller may switch to io_uring if telemetry indicates it would perform better for the workload. Both sub-engines get the full resource config. This is safe because standby workers are fully suspended (zero CPU, zero connections, listen sockets closed).

func (*Engine) ActiveEngine

func (e *Engine) ActiveEngine() engine.Engine

ActiveEngine returns the currently active engine.

func (*Engine) Addr

func (e *Engine) Addr() net.Addr

Addr returns the bound listener address.

func (*Engine) DriverFDCount added in v1.4.0

func (e *Engine) DriverFDCount() int

DriverFDCount reports the number of driver FDs currently registered on either sub-engine. Exposed for tests and observability.

func (*Engine) ForceSwitch added in v0.3.5

func (e *Engine) ForceSwitch()

ForceSwitch triggers an immediate engine switch (for testing).

func (*Engine) FreezeSwitching

func (e *Engine) FreezeSwitching()

FreezeSwitching prevents the controller from switching engines.

FreezeSwitching is reference-counted: every call must be matched by a corresponding UnfreezeSwitching. The engine remains frozen until every external freeze has been released AND every driver-registered FD has been unregistered. This makes it safe for benchmarks and drivers to hold independent freezes without clobbering each other.

func (*Engine) Listen

func (e *Engine) Listen(ctx context.Context) error

Listen starts both sub-engines and the evaluation loop.

func (*Engine) Metrics

func (e *Engine) Metrics() engine.EngineMetrics

Metrics aggregates metrics from both sub-engines.

func (*Engine) NumWorkers added in v1.4.0

func (e *Engine) NumWorkers() int

NumWorkers delegates to the currently active sub-engine's EventLoopProvider. Returns 0 if the active engine does not implement EventLoopProvider.

func (*Engine) SetFreezeCooldown added in v1.1.0

func (e *Engine) SetFreezeCooldown(d time.Duration)

SetFreezeCooldown sets the duration to suppress further switches after a switch. Zero disables the cooldown (default). This prevents oscillation under unstable load.

func (*Engine) Shutdown

func (e *Engine) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down both sub-engines.

func (*Engine) SwitchRejectedCount added in v1.4.0

func (e *Engine) SwitchRejectedCount() uint64

SwitchRejectedCount reports how many engine-switch attempts were blocked by outstanding driver FDs since the engine started. Monotonic; useful for tests asserting that a switch actually happened (or did not).

func (*Engine) Type

func (e *Engine) Type() engine.EngineType

Type returns the engine type.

func (*Engine) UnfreezeSwitching

func (e *Engine) UnfreezeSwitching()

UnfreezeSwitching releases one external freeze. The engine only becomes thawed when the external freeze count and the driver-FD count both reach zero. Calling UnfreezeSwitching more times than FreezeSwitching is a no-op (and does NOT unfreeze the engine if drivers still hold FDs).

func (*Engine) WorkerLoop added in v1.4.0

func (e *Engine) WorkerLoop(n int) engine.WorkerLoop

WorkerLoop returns a driver-safe wrapper around the currently active sub-engine's worker N. The wrapper:

  1. Re-fetches the active sub-engine on every RegisterConn, so the FD lands on whichever sub-engine is active at that instant — this matters only during the tiny window between one register/unregister cycle and the next (the refcount pins frozen while any FD lives).
  2. Pins the specific inner engine.WorkerLoop each FD was registered on so Write/Unregister always go to the right sub-engine.
  3. Increments the engine's driver-FD refcount on RegisterConn and decrements on UnregisterConn, which keeps [Engine.performSwitch] from swapping sub-engines while any FD is live.

Callers never need to call Engine.FreezeSwitching manually.

type ScoreWeights

type ScoreWeights struct {
	// Throughput is the weight applied to requests-per-second in the score.
	Throughput float64
	// ErrorRate is the penalty weight applied to the error fraction.
	ErrorRate float64
}

ScoreWeights defines the weighting for each telemetry signal in score computation. Higher throughput weight favors faster engines; higher error weight penalizes unreliable ones.

func DefaultWeights

func DefaultWeights() ScoreWeights

DefaultWeights returns the default score weights.

type TelemetrySampler

type TelemetrySampler interface {
	Sample(e engine.Engine) TelemetrySnapshot
}

TelemetrySampler produces telemetry snapshots from an engine.

type TelemetrySnapshot

type TelemetrySnapshot struct {
	// Timestamp is when this snapshot was taken.
	Timestamp time.Time
	// ThroughputRPS is the recent requests-per-second rate.
	ThroughputRPS float64
	// ErrorRate is the fraction of requests that resulted in errors (0.0-1.0).
	ErrorRate float64
	// ActiveConnections is the current number of open connections.
	ActiveConnections int64
	// CPUUtilization is the estimated CPU usage fraction (0.0-1.0). Currently unused.
	CPUUtilization float64
}

TelemetrySnapshot captures a point-in-time view of engine performance, used by the controller to decide whether to switch engines.

Jump to

Keyboard shortcuts

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