autosplit

package
v0.0.0-...-0febee4 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultEvalInterval   = keyviz.DefaultStep
	DefaultSplitCooldown  = 10 * time.Minute
	DefaultSplitTimeout   = 5 * time.Second
	DefaultSamplerBuckets = 16
)

Variables

This section is empty.

Functions

func AggregateColumnRows

func AggregateColumnRows(col keyviz.MatrixColumn) map[RouteKey]RouteLoad

AggregateColumnRows groups all non-aggregate rows by (RouteID, RaftGroupID).

func CooldownUntilFromSplitAtHLC

func CooldownUntilFromSplitAtHLC(splitAtHLC uint64, cooldown time.Duration, now time.Time) time.Time

CooldownUntilFromSplitAtHLC returns a monotonic enforcement deadline derived from SplitAtHLC's physical millis. A zero result means no remaining cooldown.

func HLCPhysicalMillis

func HLCPhysicalMillis(v uint64) int64

HLCPhysicalMillis extracts the physical Unix-ms half of a packed HLC value.

func ObserveSnapshot

func ObserveSnapshot(
	cfg Config,
	state *DetectorState,
	routes []distribution.RouteDescriptor,
	source SnapshotSource,
	readCfg SnapshotReadConfig,
) (Result, SnapshotReadResult)

ObserveSnapshot reads committed keyviz windows and runs the pure detector. Callers may log Result.Decisions in observe-only mode; this helper never mutates the route catalog and never calls SplitRange.

func RemainingCooldownFromSplitAtHLC

func RemainingCooldownFromSplitAtHLC(splitAtHLC uint64, cooldown time.Duration, now time.Time) time.Duration

RemainingCooldownFromSplitAtHLC exposes the arithmetic for regression tests.

func SeedCooldownsFromRoutes

func SeedCooldownsFromRoutes(state *DetectorState, routes []distribution.RouteDescriptor, cooldown time.Duration, now time.Time)

SeedCooldownsFromRoutes rebuilds leader-local cooldown state from durable child-route lineage. It uses only the HLC physical millis component.

Types

type CatalogSnapshotSource

type CatalogSnapshotSource interface {
	Snapshot(ctx context.Context) (distribution.CatalogSnapshot, error)
}

CatalogSnapshotSource supplies the latest route catalog snapshot used for one detector/scheduler cycle.

type ColumnWindow

type ColumnWindow struct {
	Column   keyviz.MatrixColumn
	Duration time.Duration
}

ColumnWindow is a committed keyviz column plus its proven committed duration.

Runtime integration passes only committed windows with a proven duration. keyviz.MatrixColumn.WindowStart is authoritative when present; legacy in-memory rows may be accepted only when the previous contiguous column proves the lower boundary. MatrixColumn carries the exact committed (WindowStart, At] boundary used to align route load and Top-K evidence.

func CommittedWindowsFromColumns

func CommittedWindowsFromColumns(cols []keyviz.MatrixColumn, lastProcessedAt time.Time) ([]ColumnWindow, time.Time, int)

CommittedWindowsFromColumns normalizes raw keyviz columns into detector windows. WindowStart is authoritative when present. For older in-memory columns without WindowStart, the immediately previous column boundary is the only accepted fallback. Columns whose lower boundary is not proven are returned as zero-duration reset sentinels so the detector clears stale confidence instead of carrying it across an unknown interval.

type Config

type Config struct {
	WriteWeight         float64
	ReadWeight          float64
	ThresholdOpsMin     float64
	CandidateWindows    int
	MaxRoutes           int
	MaxSplitsPerCycle   int
	TopKeyShare         float64
	TopKeyAbsoluteFloor float64
}

Config controls the pure detector and scheduler admission checks.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the M3 detector defaults from the design doc.

type Decision

type Decision struct {
	RouteID        uint64
	SplitKey       []byte
	SecondSplitKey []byte
	SplitOrigin    SplitOrigin
	TargetGroupID  uint64
	RouteDelta     int
	RouteStart     []byte
	RouteEnd       []byte
	RouteGroupID   uint64

	ScoreOpsMin          float64
	PerColumnScoreOpsMin float64
	ConsecutiveOver      int
	LeftLoad             float64
	RightLoad            float64
}

Decision is a scheduler-ready automatic split decision.

type DetectorState

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

DetectorState carries leader-local confidence and cooldown state.

func NewDetectorState

func NewDetectorState() *DetectorState

NewDetectorState creates empty detector state.

func (*DetectorState) ApplyRouteState

func (s *DetectorState) ApplyRouteState(routeID uint64, state distribution.RouteState, processedThrough time.Time)

ApplyRouteState applies a catalog state transition to the detector state.

Non-active route states clear confidence and advance the processed watermark through the newest committed column the caller intentionally skipped.

func (*DetectorState) ResetConfidence

func (s *DetectorState) ResetConfidence(routeID uint64)

ResetConfidence clears candidate confidence while preserving cooldown.

func (*DetectorState) RouteStatus

func (s *DetectorState) RouteStatus(routeID uint64) RouteStatus

RouteStatus returns the current detector state for routeID.

func (*DetectorState) SetCooldown

func (s *DetectorState) SetCooldown(routeID uint64, until time.Time)

SetCooldown blocks routeID from promotion until until.

type Event

type Event struct {
	RouteID         uint64
	Reason          SkipReason
	IsolationReason IsolationDeclineReason
	At              time.Time
}

Event records a deterministic skip or reset reason from an evaluation.

type EvidenceFence

type EvidenceFence struct {
	ProcessedThrough     time.Time
	WindowStartNotBefore time.Time
}

EvidenceFence excludes sampler history that was not collected wholly while this node held the relevant default-group and shard-group leadership.

type GroupLeadershipSnapshot

type GroupLeadershipSnapshot func(groupID uint64) (bool, uint64)

GroupLeadershipSnapshot reports local leadership and term for one shard group.

type Input

type Input struct {
	Routes         []distribution.RouteDescriptor
	Windows        []ColumnWindow
	EvidenceFences map[uint64]EvidenceFence
	Now            time.Time
	LiveRouteCount int
}

Input is one pure detector evaluation.

type IsolationDeclineReason

type IsolationDeclineReason string

IsolationDeclineReason explains why aligned Top-K evidence fell through to the sub-range p50 selector.

const (
	IsolationDeclineAbsoluteFloor    IsolationDeclineReason = "absolute_floor"
	IsolationDeclineTopKDegraded     IsolationDeclineReason = "topk_degraded"
	IsolationDeclineTopKInsufficient IsolationDeclineReason = "topk_insufficient"
	IsolationDeclineTopKErrorBound   IsolationDeclineReason = "topk_error_bound"
)

type KillSwitch

type KillSwitch func(ctx context.Context) bool

KillSwitch reports whether the current cycle must observe only and skip new SplitRange calls.

type LeadershipSnapshot

type LeadershipSnapshot func() (bool, uint64)

LeadershipSnapshot reports whether this node owns the catalog key and the current Raft term for that group.

type MatrixSampler

type MatrixSampler interface {
	Snapshot(from, to time.Time) []keyviz.MatrixColumn
	Step() time.Duration
}

MatrixSampler is the keyviz surface the scheduler consumes.

type Observer

type Observer interface {
	ObserveCandidatesPromoted(count int)
	ObserveSplitScheduled()
	ObserveSplitFailed(reason string)
	ObserveSkipped(reason SkipReason)
	ObserveIsolationDeclined(reason IsolationDeclineReason)
	ObserveCompoundPartial()
	ObserveState(enabled bool, trackedRoutes, cooldownActive int, evalDuration time.Duration)
}

Observer receives bounded-cardinality scheduler outcomes. Implementations must not attach route IDs or key bytes as metric labels.

func NewPrometheusObserver

func NewPrometheusObserver(registerer prometheus.Registerer) Observer

NewPrometheusObserver registers the standalone auto-split metric families.

type Result

type Result struct {
	Decisions []Decision
	Events    []Event
	Promoted  int
}

Result is the complete output of one detector evaluation.

func Evaluate

func Evaluate(cfg Config, state *DetectorState, in Input) Result

Evaluate consumes committed keyviz windows and emits scheduler-ready decisions.

type RouteKey

type RouteKey struct {
	RouteID     uint64
	RaftGroupID uint64
}

RouteKey is the per-column aggregation key for keyviz rows.

type RouteLoad

type RouteLoad struct {
	Reads      uint64
	Writes     uint64
	ReadBytes  uint64
	WriteBytes uint64
}

RouteLoad is the route-level load aggregated from a committed keyviz column.

type RouteReconciler

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

RouteReconciler keeps a sampler's registered route descriptors synchronized with catalog snapshots. It is safe for the catalog watcher and scheduler to share across goroutines.

func NewRouteReconciler

func NewRouteReconciler(registrar RouteRegistrar) *RouteReconciler

NewRouteReconciler creates a catalog-to-sampler membership reconciler.

func (*RouteReconciler) Reconcile

func (r *RouteReconciler) Reconcile(routes []distribution.RouteDescriptor)

Reconcile applies one complete live catalog snapshot to sampler membership.

type RouteRegistrar

type RouteRegistrar interface {
	RegisterRoute(routeID uint64, start, end []byte, groupID uint64) bool
	RemoveRoute(routeID uint64)
}

RouteRegistrar mirrors keyviz.MemSampler's route-membership methods.

type RouteStatus

type RouteStatus struct {
	ConsecutiveOver int
	CooldownUntil   time.Time
	LastProcessedAt time.Time
}

RouteStatus is the observable detector state for one route.

type RuntimeSwitch

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

RuntimeSwitch is the process-local operator switch for automatic splitting. It is independent from the startup Enabled flag: disabling it keeps detector observation active while blocking all new SplitRange calls.

func NewRuntimeSwitch

func NewRuntimeSwitch(enabled bool) *RuntimeSwitch

NewRuntimeSwitch creates a runtime switch with the requested initial state.

func (*RuntimeSwitch) Enabled

func (s *RuntimeSwitch) Enabled() bool

Enabled returns whether new automatic splits are allowed.

func (*RuntimeSwitch) KillSwitch

func (s *RuntimeSwitch) KillSwitch(context.Context) bool

KillSwitch adapts RuntimeSwitch to SchedulerConfig.KillSwitch.

func (*RuntimeSwitch) SetEnabled

func (s *RuntimeSwitch) SetEnabled(enabled bool)

SetEnabled atomically changes whether new automatic splits are allowed.

type Scheduler

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

Scheduler runs the pure detector and commits accepted decisions through SplitRange.

func NewScheduler

func NewScheduler(cfg SchedulerConfig, source CatalogSnapshotSource, splitter Splitter, sampler MatrixSampler, registrar RouteRegistrar) *Scheduler

NewScheduler builds a leader-local scheduler. It is inert when cfg.Enabled is false; callers may still construct it in tests.

func (*Scheduler) Run

func (s *Scheduler) Run(ctx context.Context) error

Run ticks until ctx is canceled. Per-cycle errors are logged and retried; a detector cycle is best-effort and must not tear down the data plane.

func (*Scheduler) Tick

func (s *Scheduler) Tick(ctx context.Context, now time.Time) (SchedulerResult, error)

Tick executes one scheduler cycle. Tests call this directly.

type SchedulerConfig

type SchedulerConfig struct {
	Enabled         bool
	Detector        Config
	EvalInterval    time.Duration
	SplitCooldown   time.Duration
	SplitTimeout    time.Duration
	KillSwitchFile  string
	KillSwitch      KillSwitch
	IsLeader        func() bool
	Leadership      LeadershipSnapshot
	GroupLeadership GroupLeadershipSnapshot
	Logger          *slog.Logger
	Reconciler      *RouteReconciler
	Observer        Observer
	// Now supplies the wall clock a cycle is stamped with. Defaults to
	// time.Now. It exists so tests can prove Run stamps cycles at processing
	// time rather than with the ticker payload.
	Now func() time.Time
}

SchedulerConfig controls background auto-split execution.

type SchedulerResult

type SchedulerResult struct {
	CatalogVersion uint64
	Detector       Result
	Scheduled      int
	Failed         int
	KillSwitch     bool
	Leader         bool
}

SchedulerResult describes one scheduler tick.

type SkipReason

type SkipReason string

SkipReason explains why a route did not produce a split decision.

const (
	SkipReasonNoSplitKey         SkipReason = "no_split_key"
	SkipReasonRouteCap           SkipReason = "route_cap"
	SkipReasonBudgetExhausted    SkipReason = "budget_exhausted"
	SkipReasonNonActiveState     SkipReason = "non_active_state"
	SkipReasonAggregateRow       SkipReason = "aggregate_row"
	SkipReasonCooldown           SkipReason = "cooldown"
	SkipReasonInvalidWindow      SkipReason = "invalid_window"
	SkipReasonLeadershipFence    SkipReason = "leadership_fence"
	SkipReasonUnsplittableHotKey SkipReason = "unsplittable_hot_key"
)

type SnapshotReadConfig

type SnapshotReadConfig struct {
	Step             time.Duration
	CandidateWindows int
	LastProcessedAt  time.Time
	Now              time.Time
}

SnapshotReadConfig controls one off-path autosplit sampler read.

type SnapshotReadResult

type SnapshotReadResult struct {
	Windows           []ColumnWindow
	NewestCommittedAt time.Time
	SnapshotFrom      time.Time
	SnapshotTo        time.Time
	SkippedInvalid    int
}

SnapshotReadResult is the committed keyviz material consumed by the detector.

func ReadCommittedWindows

func ReadCommittedWindows(source SnapshotSource, cfg SnapshotReadConfig) SnapshotReadResult

ReadCommittedWindows converts a time-range keyviz snapshot into detector windows, excluding columns that have already been processed and columns whose committed lower boundary is not proven.

type SnapshotSource

type SnapshotSource interface {
	Snapshot(from, to time.Time) []keyviz.MatrixColumn
}

SnapshotSource is the narrow keyviz snapshot surface the observe-only autosplit reader needs.

type SplitOrigin

type SplitOrigin string

SplitOrigin describes how an automatic split key was selected.

const (
	SplitOriginP50Mid                   SplitOrigin = "p50_mid"
	SplitOriginP50LastBucketLo          SplitOrigin = "p50_last_bucket_lo"
	SplitOriginP50FirstBucketHi         SplitOrigin = "p50_first_bucket_hi"
	SplitOriginIsolationCompound        SplitOrigin = "isolation_compound"
	SplitOriginIsolationSingleLowerEdge SplitOrigin = "isolation_single_lower_edge"
	SplitOriginIsolationSingleUpperEdge SplitOrigin = "isolation_single_upper_edge"
)

type SplitRequest

type SplitRequest struct {
	ExpectedCatalogVersion uint64
	RouteID                uint64
	SplitKey               []byte
	TargetGroupID          uint64
	ParentStart            []byte
	ParentEnd              []byte
	ParentGroupID          uint64
}

SplitRequest is the scheduler's stable request surface. TargetGroupID is carried for the post-M2 hook; M3 standalone always sends zero.

type SplitResult

type SplitResult struct {
	CatalogVersion uint64
	Left           distribution.RouteDescriptor
	Right          distribution.RouteDescriptor
}

SplitResult contains the committed catalog version and children when SplitRange succeeds.

type Splitter

type Splitter interface {
	SplitRange(ctx context.Context, req SplitRequest) (SplitResult, error)
}

Splitter executes catalog mutations. Production wiring calls proto.Distribution.SplitRange through the local DistributionServer.

Jump to

Keyboard shortcuts

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