measure

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package measure implements measure-specific vectorized operators (scan, cursor, extract, limit, group-by, aggregation, top, output serialization).

Index

Constants

View Source
const DefaultBroadcastTimeout = 15 * time.Second

DefaultBroadcastTimeout is the per-broadcast wait the vec distributed liaison uses when the caller (banyand/dquery) does not override it. The value matches the historical hard-coded constant so behavior is unchanged when the operator does not set --dst-broadcast-timeout.

Variables

View Source
var ErrAggModeNotImplemented = errors.New("vectorized.measure: BatchAggregation mode not implemented")

ErrAggModeNotImplemented is returned by Consume / Finalize / NextBatch when AggMode falls outside the implemented modes. AggModeAll and AggModeMap have been implemented since G9f.2; AggModeReduce ships in G9f.3. The error remains for any future mode addition that lands without operator support, so an out-of-range mode fails loud rather than silently degrading.

Functions

func AppendColumnRange

func AppendColumnRange(dst, src vectorized.Column, srcPos, n int) error

AppendColumnRange delegates to the shared vectorized helper.

func ApplyTopToReduce

func ApplyTopToReduce(reduced []*vectorized.RecordBatch, spec ReduceTopSpec, batchSize int) ([]*vectorized.RecordBatch, error)

ApplyTopToReduce composes the Reduce output through a BatchTop operator, returning the top-N rows by FieldName. This is the liaison-side completion of the distributed Top-over-Agg pattern: data nodes emit AggModeMap partials (optionally pre-topped via the per-node BatchTop), the liaison Reduces them, then a second BatchTop selects the global top-N. Mirrors the row path's two-pass Top approach — sorting by partial value on each node, then re-sorting the merged reductions on the coordinator.

fieldName MUST match a RoleField column in the reduced output schema (typically the AggReduceSpec.OutputName). N <= 0 returns reduced input unchanged.

func BuildBatchSchema

func BuildBatchSchema(measureSchema *databasev1.Measure, opts model.MeasureQueryOptions) (*vectorized.BatchSchema, error)

BuildBatchSchema derives a BatchSchema from a Measure schema and a query's projection list. The output column order is fixed:

timestamp, version, sid, shardID, then projected tags (in TagProjection
order, family-by-family, name-by-name), then projected fields (in
FieldProjection order).

Tag families and tag names that are not present in the Measure schema are dropped — the row path silently skips unknown tags as well, so this matches existing semantics. Fields not present in the schema yield a Null-typed column so projection still produces a slot in the output.

Column types — passthrough vs native (G8d.2):

Tag and field projections default to passthrough columns: the column cell type is *modelv1.TagValue / *modelv1.FieldValue, holding the original protobuf pointer from the scan source unchanged. The egress serializer returns those pointers directly, matching the row path's zero-alloc per-cell behavior. With the gRPC wire format frozen (`*measurev1.InternalDataPoint` is row-shaped), passthrough wins for plain scans because native columns would force egress to reconstruct the protobuf wrapper (3 allocs/cell), regressing the G5a bench gates.

When opts.GroupBy or opts.Agg name a projected tag or field, that specific column is emitted as a NATIVE typed column instead. The downstream BatchAggregation operator reads typed primitives directly from those columns (computeKey / fold) and produces aggregated rows whose count is bounded by group cardinality, amortizing the eventual wrapper reconstruction at egress. Columns not referenced by GroupBy / Agg remain passthrough.

func BuildMeasureBatchFromResult

func BuildMeasureBatchFromResult(r *model.MeasureResult, schema *vectorized.BatchSchema) (*model.MeasureBatch, error)

BuildMeasureBatchFromResult converts a *model.MeasureResult produced by a row-shaped MeasureQueryResult.Pull() call into a *model.MeasureBatch whose columns match the supplied BatchSchema.

This is the G5b "dual-emit" wrapper helper: the storage layer can implement MeasureBatchResult.PullBatch by calling its existing Pull() and passing the result through this converter. It preserves the existing row-path decode pipeline; the architectural decode-elimination is left to G5c/G5d (block_cursor native column emit).

Schema-declared tag/field columns missing from the result are null-filled using pbv1.Null{Tag,Field}Value singletons — matching the multi-group projection behavior in fillTags / fillFields when one group's schema lacks a tag the other has.

Returns (nil, nil) when r is nil. Returns (nil, err) when a length invariant is violated (a value slice is shorter than the timestamp count).

func BuildOperators

func BuildOperators(
	opts model.MeasureQueryOptions, schema *vectorized.BatchSchema,
	tracker *vectorized.MemoryTracker, batchSize int, mode AggMode,
) ([]vectorized.BreakerOperator, error)

BuildOperators translates the GroupBy + Agg slice of MeasureQueryOptions into a list of BreakerOperators that, chained after the scan source, form the vectorized aggregation pipeline.

Routing rules:

  • GroupBy + Agg both set → emit a single BatchAggregation. The operator's own keyIndex map produces per-group buckets and folds the agg slot; a separate BatchGroupBy would double the row materialization.
  • Agg set without GroupBy → scalar reduce: a BatchAggregation with no key columns. Every row maps to one group, so a single output row is emitted carrying the first-seen projected tags plus the agg result, matching the row path's aggAllIterator.
  • GroupBy set without Agg → raw GroupBy: a first-seen-row-per-group BatchGroupBy. The output preserves the input schema; one row per group is emitted in group-insertion order, matching the row path's groupIterator + processor.go's current[0] read.
  • Neither set → empty operator list; caller emits raw rows.

tracker is the per-pipeline MemoryTracker (G7a); it must be non-nil when any operator is emitted so per-group reservations route to the shared budget. batchSize controls the operator's output pagination.

mode selects the BatchAggregation strategy when an agg operator is built (Agg set): AggModeAll for single-node final reduce; AggModeMap for the distributed Map phase (G9f.2) that emits typed-column partials. mode is ignored for the raw-GroupBy branch (BatchGroupBy doesn't carry partial state — first-seen-row per group is already the final shape). AggModeReduce is rejected here loudly; its operator is built by the liaison-side reduce plan (G9f.3), not via BuildOperators.

func DecodeFramesPerSource

func DecodeFramesPerSource(frames [][]byte) ([][]*measurev1.InternalDataPoint, error)

DecodeFramesPerSource decodes a sequence of vec raw frame bodies and returns one []*measurev1.InternalDataPoint slice per non-empty frame — preserving the per-data-node grouping the row path's sortedMIterator + sort.NewItemIter merger needs to dedup replicas. Each data node's scan output is internally sort-field ordered; sort.NewItemIter merges the per-source streams and loadOneGroup's hashDataPoint map removes (sid, timestamp) duplicates within each equal-sortField group. Concatenating into a single slice (as DecodeFramesToInternalDataPoints does) defeats the dedup because duplicate rows from different sources end up in different sortField groups across the flat sequence.

nil / empty frame bodies produce no slice in the output — the codec carve-out for empty bodies is honored here too.

func DecodeFramesToInternalDataPoints

func DecodeFramesToInternalDataPoints(frames [][]byte) ([]*measurev1.InternalDataPoint, error)

DecodeFramesToInternalDataPoints decodes a sequence of vec raw frame bodies and concatenates their active rows into a single []*measurev1.InternalDataPoint, ready to feed the row-side pushedDownAggregatedIterator (agg path's flatten step).

For the NON-agg distributed merge path use DecodeFramesPerSource instead — concatenation here destroys the per-source ordering the sortedMIterator's cross-iterator merge + (sid, timestamp) dedup depends on, which is what caused replica duplicates to slip past the dedup map under flag-on.

nil/empty bodies are skipped — the codec layer's RawFrameCodec carve-out returns nil for an empty distributed result and the decoder is below that carve-out.

func DrainPipelineToFrame

func DrainPipelineToFrame(ctx context.Context, p *vectorized.Pipeline, schema *vectorized.BatchSchema) ([]byte, error)

DrainPipelineToFrame consumes a vec Pipeline end-to-end, concatenates every emitted batch into a single RecordBatch, and frame.Encode-s the result. It is the data-node side of the G9f throughout-vec wire: under flag-on, TopicInternalMeasureQuery responses are exactly this single raw frame body (one row per group for AggModeMap, one row per source row for non-agg queries).

schema is the propagated terminal-operator output schema (typically the same as the egress pool's). It MUST match each emitted batch — a mismatch is a planner bug, not a data error, so this function will fail loud on a per-batch shape check instead of silently coercing.

Multi-batch coalesce: pipeline.Next is called until it returns nil; every non-nil batch's active rows are appended to a single output batch via copyOneValue. This is intentionally NOT a streaming-write of multiple frames — the codec contract carries one body per response (api/data/codec.go), and frame.Encode expects one batch. For typical distributed agg responses (one row per group, group count ≤ batchSize) the pipeline emits a single batch and coalesce is a no-op fast path.

Returns the encoded frame body and the close error from pipeline.Close joined into a single error (mirrors vectorizedMIterator.Close).

func FormatReduceOutput

func FormatReduceOutput(b *vectorized.RecordBatch) string

FormatReduceOutput is a debug helper for the topology matrix harness: it renders the reduced batch as "key1=v1,key2=v2|<aggname>=<val>" lines for stable, sorted comparison against the AggModeAll oracle.

func ReduceFramesToInternalDataPoints

func ReduceFramesToInternalDataPoints(
	frames [][]byte,
	keyTagNames []string,
	aggSpecs []AggReduceSpec,
	topSpec *ReduceTopSpec,
	batchSize int,
	tracker *vectorized.MemoryTracker,
) ([]*measurev1.InternalDataPoint, error)

ReduceFramesToInternalDataPoints is the liaison-side composition for distributed agg queries under flag-on: it decodes the per-data-node partial frames, runs the (shard, group)-deduped Reduce, optionally applies a final Top-N (when topSpec.N > 0), and serializes the resulting batches back to []*measurev1.InternalDataPoint so the row-side pushedDownAggregatedIterator + downstream MIterator surface stay unchanged.

The conversion back to proto is the price of bridging vec output into the row-path liaison's existing iterator. Once the row-path distributedPlan is replaced by a fully vec-distributed plan (out of scope for G9f.5), this round trip drops out.

Empty input (no non-empty frames) returns an empty slice with no error — matches the row path's behavior when every data node returned an empty distributed result.

func SerializeDataPointsToFrame

func SerializeDataPointsToFrame(idps []*measurev1.InternalDataPoint) ([]byte, error)

SerializeDataPointsToFrame is the fallback wire-emit path for iterator wrappers (hiddenTagsMIterator, sortedMIterator) whose internal sort / strip / cross-group merge logic operates on []*InternalDataPoint rather than on a vec Pipeline. The wrapper drains itself via the row-side Next / Current API (so its existing strip / merge / dedup logic still runs); the resulting rows are reverse-serialized into a passthrough RecordBatch, convertPassthroughForFrame decodes the passthrough columns to typed wire columns, and frame.Encode produces the body.

This path is less efficient than the vec native pipeline drain — it allocates a *modelv1.TagValue / *FieldValue per cell during reverse- serialize — but it keeps the wrapper's egress semantics intact end- to-end on the wire (hidden tags stripped, cross-group order honored, version dedup applied) without re-implementing each one in columnar form.

idps in the empty/zero case yields a nil body, matching the codec layer's RawFrameCodec carve-out for empty distributed results.

Types

type AggFunc

type AggFunc int

AggFunc selects the reduction function applied to a column.

const (
	AggSum AggFunc = iota
	AggCount
	AggMin
	AggMax
	AggMean
)

AggFunc values.

type AggMode

type AggMode int

AggMode selects the per-node aggregation strategy.

  • AggModeAll — single-node full reduce. emits one final value per (group, agg).
  • AggModeMap — distributed Map phase (G9f.2). Emits a typed-column partial batch (one row per group) carrying the Partial state from aggregation.Map: Value for SUM/COUNT/MIN/MAX, plus a sidecar Count column (named "<output>__agg_count") for MEAN. The batch is prefixed with a RoleShardID column populated from the input batch's shard-id column at the first row that creates each group (matching the row path's incidental "first-idp" rule, measure_plan_aggregation.go:285); scalar reduce (len(keyIndices)==0) emits shard_id=0 (matching the row path's aggAllIterator.Current() at :364). The partial batch is then serialized by pkg/query/vectorized/measure/frame.Encode for cluster transport.
  • AggModeReduce — coordinator's Reduce phase (G9f.3). Consumes the typed-column partial batches emitted by AggModeMap (one row per (shard, group)), dedupes them on (shard_id, group_key) — replica duplicates of the same shard collapse to one contribution, mirroring the row path's deduplicateAggregatedDataPointsWithShard — and combines them through aggregation.Reduce[N] into a final batch shaped like AggModeAll (tags + final value column, no shard column, no count sidecar). The aggregation.Reduce[N].Val() handles MEAN finalization (sum÷count) so the emit path stays type-symmetric with AggModeAll.
const (
	AggModeAll AggMode = iota
	AggModeMap
	AggModeReduce
)

AggMode values.

type AggReduceSpec

type AggReduceSpec struct {
	OutputName string
	Func       AggFunc
}

AggReduceSpec configures one aggregation output for the liaison-side Reduce. OutputName MUST match the column name produced by the data-node AggModeMap for the same aggregation (i.e. the AggSpec.Output that drove buildAggOutputLayout). Func selects the reducer (must agree with the Map-side function — SUM-Map paired with SUM-Reduce, MEAN with MEAN, etc).

type AggSpec

type AggSpec struct {
	Output   string
	Func     AggFunc
	InputCol int // index into the input schema; must be int64 or float64
}

AggSpec configures one aggregation output column.

type AggValuePath

type AggValuePath string

AggValuePath records which column-type path bindAggReduceSpecs used to resolve the aggregation value column.

const (
	// AggValuePathTyped means all agg specs resolved via a native int64 or
	// float64 column — the normal AggModeMap partial path.
	AggValuePathTyped AggValuePath = "typed"
	// AggValuePathFieldValueFallback means at least one agg spec fell back
	// to a ColumnTypeFieldValue passthrough column because no native typed
	// column was found — the DataPoint-egress passthrough path.
	AggValuePathFieldValueFallback AggValuePath = "fieldvalue-fallback"
	// AggValuePathUnresolved means bindAggReduceSpecs could not find any
	// matching column for at least one agg spec and returned an error.
	AggValuePathUnresolved AggValuePath = "unresolved"
)

AggValuePath constants match the trace tag values required by US-VT-1.

func ReducePartialBatches

func ReducePartialBatches(
	partials []*vectorized.RecordBatch,
	keyTagNames []string,
	aggSpecs []AggReduceSpec,
	batchSize int,
	tracker *vectorized.MemoryTracker,
) ([]*vectorized.RecordBatch, AggValuePath, error)

ReducePartialBatches is the in-memory counterpart of ReduceRawFrames — useful for tests and for callers that have already decoded their partials. Empty batches (nil or Len==0) are skipped; the first non-empty batch defines the schema and structural compatibility is checked against subsequent ones.

Returns the reduced batches and the AggValuePath that describes how the value column was resolved (typed, fieldvalue-fallback, or unresolved).

func ReduceRawFrames

func ReduceRawFrames(
	frames [][]byte,
	keyTagNames []string,
	aggSpecs []AggReduceSpec,
	batchSize int,
	tracker *vectorized.MemoryTracker,
) ([]*vectorized.RecordBatch, AggValuePath, error)

ReduceRawFrames runs the liaison-side Reduce phase on a sequence of vec partial frame bodies. Each frame is decoded into a RecordBatch and fed to a single AggModeReduce BatchAggregation that dedupes (shard_id, group_key) replica duplicates and combines partials across shards via aggregation.Reduce[N].

Empty/nil frame bodies are skipped — a data node emitting an empty distributed result sends a body-less SendResponse and the codec layer passes nil bytes through (see api/data/codec.go's RawFrameCodec carve-out for nil/empty). Treating those as zero-row partials matches the row path, which simply has no contributing rows to combine.

The first non-empty frame defines the partial schema (column count, roles, types, and names). Subsequent frames MUST share that schema — any structural mismatch is a producer bug, not a recoverable data error, and is reported loudly.

keyTagNames selects which tags form the group key — the same names the request's GroupBy used. Tags present in the partial schema but NOT listed here are still carried forward in the output as the first-seen value per group (mirrors the data-node operator's first-seen non-key tag rule).

Returns the final reduced batches in group-insertion order (paginated by batchSize) and the AggValuePath that describes how the value column was resolved. Callers walk the batches sequentially; one row per group.

type BatchAggregation

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

BatchAggregation is a BreakerOperator that groups input rows by the configured key columns and reduces value columns via the configured AggSpec list.

Per-function arithmetic delegates to pkg/query/aggregation, the same package the row-based path uses. This keeps numeric semantics in lockstep across the two paths so a fix in one path is shared by the other.

Output schema = all projected tag columns (in input schema order — keys AND non-key tags) followed by one column per AggSpec. Non-key tags are carried forward as the first-seen value per group, matching the row path's aggregator (pkg/query/logical/measure/measure_plan_aggregation.go), which preserves any tag the request projected even when it is not a GroupBy key.

Output rows are emitted one per group, in group-insertion order, paginated by batchSize.

func NewBatchAggregation

func NewBatchAggregation(
	input *vectorized.BatchSchema, keyIndices []int,
	aggs []AggSpec, mode AggMode, batchSize int,
	tracker *vectorized.MemoryTracker, entrySize int64,
) *BatchAggregation

NewBatchAggregation constructs a BatchAggregation. It builds the output schema internally (keys + agg outputs) and owns its output BatchPool.

tracker carries the per-pipeline memory budget; entrySize is the bytes reserved per new group bucket (key columns + slots + map entry overhead). Pass entrySize=0 to disable per-group bookkeeping. tracker must not be nil — use a large NewMemoryTracker for unit tests that don't care about budget.

func (*BatchAggregation) Close

func (a *BatchAggregation) Close() error

Close releases the group map and refunds the outstanding memory reservation. Idempotent.

func (*BatchAggregation) Consume

Consume folds every active row into its group's accumulator. Null values are excluded from aggregation (count not incremented; sum/min/max unchanged).

Each new group reserves entrySize bytes from the shared MemoryTracker. If the budget is exhausted, Consume returns the wrapped tracker error and the row's group is not added — partial-batch state is consistent.

AggModeAll and AggModeMap share the per-row fold path; they diverge only at emit time (NextBatch). AggModeReduce uses a parallel combinePartial path: each input row is one (shard, group) partial; replica duplicates (same shard + same group_key) are dropped via dedupSeen, then the Partial is Combine'd into the group's Reduce accumulator. Cross-shard rows that share a group_key are KEPT and combined, matching the row path's deduplicateAggregatedDataPointsWithShard semantics.

func (*BatchAggregation) Finalize

func (a *BatchAggregation) Finalize(_ context.Context) error

Finalize is a no-op for AggModeAll, AggModeMap, and AggModeReduce — Consume eagerly maintains every group's accumulator state (Map or Reduce), so there is no batched flush step.

func (*BatchAggregation) Init

func (a *BatchAggregation) Init(ctx context.Context) error

Init prepares the group map. It does NOT validate the mode — mode rejection happens at the per-method level (Consume/Finalize/NextBatch) so the dispatcher matches the spec's distributed forward-compat language. For AggModeReduce, Init also resets the (shard, group_key) replica-dedup map so the operator can be reused across distributed reduce runs without a fresh allocation per call.

func (*BatchAggregation) NextBatch

NextBatch emits one row per group in group-insertion order, paginated by batchSize. AggModeAll emits final values; AggModeMap emits typed-column partial state plus a leading shard-id column (see AggMode docs). AggModeReduce emits the same shape as AggModeAll — tags + final reduced value — but draws the value from aggregation.Reduce[N].Val() so MEAN finalization (sum÷count) happens inside the reducer.

func (*BatchAggregation) OutputSchema

func (a *BatchAggregation) OutputSchema() *vectorized.BatchSchema

OutputSchema returns the schema of emitted batches: key columns followed by agg output columns.

type BatchGroupBy

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

BatchGroupBy is a BreakerOperator that partitions input rows by the values of one or more key columns. Output preserves the input schema; rows are emitted in group-insertion order, with all rows of the first group flushed before the next group begins.

When firstOnly is set the operator keeps only the first-seen row of each group and drops subsequent rows. This reproduces the row path's raw GroupBy egress: the row aggregator wraps every group in a single InternalDataPoint slice and banyand/query/processor.go reads only current[0] per Next, so a raw GroupBy surfaces exactly one row (the first-seen) per group in group-insertion order.

Memory accounting follows a pessimistic-reserve, refund-unused pattern:

  • entrySize is the per-new-group bucket overhead.
  • rowSize is the per-row data cost (independent of group identity).
  • On Consume, reserve worst-case = activeRows * (entrySize + rowSize).
  • After actual consumption, refund (worstCaseNewGroups - actualNewGroups) * entrySize.

Close releases every outstanding reservation, even mid-Consume cancellations.

func NewBatchGroupBy

func NewBatchGroupBy(
	schema *vectorized.BatchSchema, keyIndices []int,
	pool *vectorized.BatchPool, batchSize int,
	tracker *vectorized.MemoryTracker, entrySize, rowSize int64,
) *BatchGroupBy

NewBatchGroupBy constructs a BatchGroupBy.

  • entrySize: per-new-group bucket overhead.
  • rowSize: per-row data cost.

Pass rowSize=0 to charge only per-new-group; pass entrySize=0 to charge only per-row.

func NewBatchGroupByFirst

func NewBatchGroupByFirst(
	schema *vectorized.BatchSchema, keyIndices []int,
	pool *vectorized.BatchPool, batchSize int,
	tracker *vectorized.MemoryTracker, entrySize int64,
) *BatchGroupBy

NewBatchGroupByFirst constructs a BatchGroupBy that emits only the first-seen row of each group (raw GroupBy without aggregation). It matches the row path: groupBy.Execute produces a groupIterator whose Current() returns the whole group, and processor.go keeps only current[0], so each group surfaces a single row in group-insertion order with the input schema unchanged.

func (*BatchGroupBy) Close

func (g *BatchGroupBy) Close() error

Close releases every outstanding memory reservation. Idempotent.

func (*BatchGroupBy) Consume

Consume reserves the worst-case bytes for new groups + per-row cost, accumulates rows into per-group buckets, then refunds the unused reservation.

func (*BatchGroupBy) Finalize

func (g *BatchGroupBy) Finalize(_ context.Context) error

Finalize is a no-op for v1 — groups are already materialized.

func (*BatchGroupBy) Init

func (g *BatchGroupBy) Init(ctx context.Context) error

Init prepares the group map.

func (*BatchGroupBy) NextBatch

NextBatch emits accumulated rows in group-insertion order, paginated by batchSize. Returns (nil, nil) when all groups are drained.

func (*BatchGroupBy) OutputSchema

func (g *BatchGroupBy) OutputSchema() *vectorized.BatchSchema

OutputSchema returns the unchanged input schema.

type BatchLimit

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

BatchLimit applies offset+limit windowing as a fusible in-place selection rewrite. State across batches is carried via a cumulative-seen counter.

When the window closes (seen >= offset+limit), the current batch's selection is sliced to whatever portion of the window it contributed and Process returns vectorized.ErrLimitExhausted. The fused stage translates that sentinel into "emit current batch, then EOF on next pull".

func NewBatchLimit

func NewBatchLimit(schema *vectorized.BatchSchema, offset, limit uint32) *BatchLimit

NewBatchLimit constructs a fusible limit operator.

func (*BatchLimit) Close

func (l *BatchLimit) Close() error

Close is idempotent and a no-op.

func (*BatchLimit) Init

func (l *BatchLimit) Init(ctx context.Context) error

Init is a no-op. Limit has no per-pipeline setup.

func (*BatchLimit) OutputSchema

func (l *BatchLimit) OutputSchema() *vectorized.BatchSchema

OutputSchema returns the unchanged input schema.

func (*BatchLimit) Process

Process rewrites b.Selection to keep only rows in [offset, offset+limit) of the cumulative active stream.

type BatchScan

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

BatchScan is the v1 PullOperator that wraps a MeasureQueryResult and produces RecordBatches. It uses a SeriesCursor to manage cross-series boundaries and bulk-extracts metadata, tags, and fields per series fill.

func NewBatchScan

func NewBatchScan(qr model.MeasureQueryResult, schema *vectorized.BatchSchema,
	pool *vectorized.BatchPool, batchSize int,
) *BatchScan

NewBatchScan returns a BatchScan; call Init before NextBatch.

func (*BatchScan) Close

func (s *BatchScan) Close() error

Close releases the underlying cursor exactly once.

func (*BatchScan) Init

func (s *BatchScan) Init(ctx context.Context) error

Init prepares the cursor and pulls the first non-empty MeasureResult.

func (*BatchScan) NextBatch

func (s *BatchScan) NextBatch(_ context.Context) (*vectorized.RecordBatch, error)

NextBatch fills a fresh batch up to batchSize rows. Returns:

  • (batch, nil) for a valid batch with Len > 0;
  • (nil, nil) for clean EOF;
  • (nil, err) for storage error (the partial batch is dropped to GC).

func (*BatchScan) OutputSchema

func (s *BatchScan) OutputSchema() *vectorized.BatchSchema

OutputSchema returns the schema declared at construction.

type BatchSourceFromBatchResult

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

BatchSourceFromBatchResult is a PullOperator that drives a model.MeasureBatchResult through PullBatch and accumulates rows into *vectorized.RecordBatch instances of the configured batchSize.

G5c (US-007 partial) — provides the wiring path that lets NewMIterator consume PullBatch output directly. Storage's queryResult / indexSortResult both implement MeasureBatchResult; the columns inside the *MeasureBatch are typed (passthrough today; native after US-005). BatchSourceFromBatchResult column-copies into a RecordBatch whose schema matches the source. extract.go is bypassed entirely on this path — the source columns are already typed.

Schema contract: the supplied schema must match every *MeasureBatch produced by br.PullBatch. Enforced loosely — the column-copy helper returns an error on TypedColumn[T] mismatches, which surfaces as a pipeline error.

func NewBatchSourceFromBatchResult

func NewBatchSourceFromBatchResult(br model.MeasureBatchResult, schema *vectorized.BatchSchema,
	pool *vectorized.BatchPool, batchSize int,
) *BatchSourceFromBatchResult

NewBatchSourceFromBatchResult constructs the source. Init is required before NextBatch (no-op today, kept to satisfy PullOperator).

func (*BatchSourceFromBatchResult) Close

func (s *BatchSourceFromBatchResult) Close() error

Close releases any in-flight pending MeasureBatch back to the column pool and then the underlying MeasureBatchResult exactly once. Idempotent.

func (*BatchSourceFromBatchResult) Init

Init satisfies PullOperator.

func (*BatchSourceFromBatchResult) NextBatch

NextBatch pulls *MeasureBatch instances from the underlying MeasureBatchResult and copies their rows into a fresh RecordBatch from the pool, up to batchSize rows or source EOF, whichever comes first.

EOF is sticky: once observed, subsequent calls return (nil, nil) without re-entering the source. Errors are sticky too.

func (*BatchSourceFromBatchResult) OutputSchema

OutputSchema returns the schema declared at construction.

type BatchTop

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

BatchTop is a BreakerOperator that retains the top-N rows by a designated field column. asc=true keeps the lowest N; asc=false keeps the highest N.

Tie-break is stable on insertion order — earlier rows win. Nulls in the key column are treated as the lowest value (kept first in asc, evicted first in desc).

func NewBatchTop

func NewBatchTop(schema *vectorized.BatchSchema, fieldCol, n int, asc bool, batchSize int) *BatchTop

NewBatchTop constructs a BatchTop. fieldCol is the index of the int64 or float64 column to sort by; n is the bound; asc selects ascending or descending order.

func (*BatchTop) Close

func (t *BatchTop) Close() error

Close releases the heap and sorted buffer. Idempotent.

func (*BatchTop) Consume

func (t *BatchTop) Consume(_ context.Context, b *vectorized.RecordBatch) error

Consume considers each active row for inclusion in the top-N heap.

n <= 0 is a no-op (matches the row-path's top-N convention) — without this guard the bounded-heap logic would dereference an empty heap on the first row.

func (*BatchTop) Finalize

func (t *BatchTop) Finalize(_ context.Context) error

Finalize drains the heap into a sorted slice in user-facing order.

func (*BatchTop) Init

func (t *BatchTop) Init(ctx context.Context) error

Init initializes the heap.

func (*BatchTop) NextBatch

func (t *BatchTop) NextBatch(_ context.Context) (*vectorized.RecordBatch, error)

NextBatch emits the sorted rows in batches of batchSize.

func (*BatchTop) OutputSchema

func (t *BatchTop) OutputSchema() *vectorized.BatchSchema

OutputSchema returns the unchanged input schema.

type FrameEmitter

type FrameEmitter interface {
	EmitFrame(ctx context.Context) ([]byte, error)
}

FrameEmitter is the data-node wire-emit contract under flag-on: any MIterator that participates in a TopicInternalMeasureQuery response must encapsulate its own drain + encode strategy via this method, so the processor.go Rev can dispatch uniformly without case-by-case knowledge of each wrapper.

Implementations:

  • VectorizedMIterator: drains the underlying vec Pipeline directly via DrainPipelineToFrame — the throughput-optimal path that never materializes proto datapoints.
  • emptyMIterator: returns a nil body (matches the codec layer's RawFrameCodec carve-out for empty distributed results).
  • hiddenTagsMIterator: drains via Next / Current (which already strips hidden criteria tags from the egress datapoints), then reverse-serializes the surviving rows into a passthrough RecordBatch through SerializeDataPointsToFrame.
  • sortedMIterator: drains via Next / Current (which already applies cross-group merge + version dedup), then reverse- serializes through SerializeDataPointsToFrame.

The reverse-serialize path is less efficient than draining a vec Pipeline (one allocation per cell during passthrough rebuild) but keeps the wrapper's row-side semantics — hidden-tag strip, sort, dedup — as the single source of truth on the wire.

type RawFrameSource

type RawFrameSource interface {
	// Pipeline returns the vec pipeline the iterator wraps. Drain it via
	// vectorized.Pipeline.Next until nil; the iterator's own Close still
	// owns the pipeline lifecycle.
	Pipeline() *vectorized.Pipeline
	// Schema returns the terminal-operator output schema — the same
	// schema every emitted batch carries.
	Schema() *vectorized.BatchSchema
}

RawFrameSource is the capability a vec MIterator exposes when the caller wants to short-circuit per-row proto serialization and instead drain the underlying Pipeline into a single columnar raw frame body (G9f.5.b). The data-node processor type-asserts to this interface when data.MeasureWireModeRaw() is true on TopicInternalMeasureQuery, calls DrainPipelineToFrame(ctx, src.Pipeline(), src.Schema()), then Close()s the wrapping iterator to release pooled batches + the pipeline. The row-path iterators do NOT implement this interface, so the type assertion failing is the correct fall-through signal.

IMPORTANT: a caller that drains the Pipeline directly MUST NOT also drive Next() on the MIterator afterwards — the pipeline is now empty and the iterator's internal cursor is stale. The data-node processor honors this by branching on RawFrameSource BEFORE the iterator's proto-collection loop.

type ReduceTopSpec

type ReduceTopSpec struct {
	FieldName string
	N         int
	Asc       bool
}

ReduceTopSpec configures an optional post-Reduce Top-N step. FieldName names the agg output column to sort by; N is the number of rows to retain; Asc=true keeps the lowest N, Asc=false keeps the highest N (mirrors the row path's distributed Top-over-Agg pattern — see pkg/query/logical/measure/measure_plan_distributed.go's DistributedAnalyze, where Top is applied AFTER the distributedPlan on the liaison).

type SeriesCursor

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

SeriesCursor walks across MeasureResult instances yielded by a MeasureQueryResult, presenting either single-row access (NextRow) or bulk-copy access (Current+Advance) to BatchScan.

Sticky-error contract: once Pull yields a result with Error != nil, the cursor stores the error and every subsequent NextRow returns it. Init is the only way to reset.

func (*SeriesCursor) Advance

func (c *SeriesCursor) Advance(n int)

Advance moves the cursor n rows forward. Crosses to the next series if the new position reaches the end of the current MeasureResult.

func (*SeriesCursor) Close

func (c *SeriesCursor) Close()

Close releases the underlying MeasureQueryResult exactly once. Idempotent and safe after EOF.

func (*SeriesCursor) Current

func (c *SeriesCursor) Current() (*model.MeasureResult, int)

Current returns the underlying MeasureResult and the cursor's position within it. Used by BatchScan's bulk-copy path to read parallel arrays directly.

func (*SeriesCursor) Err

func (c *SeriesCursor) Err() error

Err returns the sticky storage error, or nil. Once non-nil it remains so until Init is called again.

func (*SeriesCursor) Exhausted

func (c *SeriesCursor) Exhausted() bool

Exhausted reports whether the cursor has run out of input (clean EOF or after an error).

func (*SeriesCursor) Init

Init resets the cursor and advances to the first non-empty series (or EOF/err).

func (*SeriesCursor) RemainingInSeries

func (c *SeriesCursor) RemainingInSeries() int

RemainingInSeries returns how many rows are left in the current MeasureResult. 0 when at EOF, on error, or between series.

type VectorizedConfig

type VectorizedConfig struct {
	BroadcastTimeout time.Duration
	BatchSize        int
	QueryMemoryMiB   int
	Enabled          bool
}

VectorizedConfig controls the v1 vectorized Measure query path.

func DefaultConfig

func DefaultConfig() VectorizedConfig

DefaultConfig returns the v1 default — enabled, 1024-row batches, 256 MiB per-query memory budget, 15 s broadcast timeout. To roll back the vec path entirely, pass --measure-vectorized-enabled=false on the standalone or data-node command line and restart.

func (VectorizedConfig) Validate

func (c VectorizedConfig) Validate() error

Validate rejects nonsense configurations.

type VectorizedMIterator

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

VectorizedMIterator is the public adapter exposed to other packages. It is a thin facade over the unexported vectorizedMIterator so the executor interface is satisfied without leaking the package-private type.

func NewIteratorFromPipeline

func NewIteratorFromPipeline(ctx context.Context, pipeline *vectorized.Pipeline, schema *vectorized.BatchSchema, pool *vectorized.BatchPool) *VectorizedMIterator

NewIteratorFromPipeline wraps an already-built *vectorized.Pipeline (with its source/operators already attached and Pipeline.Init called) as a VectorizedMIterator. Used by the G8 vec executor at pkg/query/vectorized/measure/plan to compose plan trees into the public MIterator contract without going through NewMIterator's leaf-substitution path. pool is the egress BatchPool the adapter recycles consumed batches into; schema is the terminal-operator output schema — same shape every batch will carry — used by the RawFrameSource capability path (G9f.5.b) to drain the pipeline into a single columnar raw frame body.

func NewMIterator

NewMIterator builds a vectorized adapter that drives a Pipeline over qr and satisfies executor.MIterator. The returned VectorizedMIterator owns the qr lifetime through the pipeline: Close → pipeline.Close → BatchScan.Close → SeriesCursor.Close → qr.Release. Callers must NOT release qr themselves on the success path.

On error, ownership of qr stays with the caller; the caller is responsible for releasing it. Construction is split so qr.Release-on-failure is decided at the call site (where build inputs other than qr are also tracked).

func (*VectorizedMIterator) Close

func (v *VectorizedMIterator) Close() error

Close releases the pipeline (and through it the BatchScan, cursor, and underlying MeasureQueryResult). Returns the join of the sticky iteration error and the pipeline-close error, matching resultMIterator.Close.

func (*VectorizedMIterator) Current

Current returns the current row as a single-element slice (matches row-path contract).

func (*VectorizedMIterator) EmitFrame

func (v *VectorizedMIterator) EmitFrame(ctx context.Context) ([]byte, error)

EmitFrame implements FrameEmitter on the public adapter — delegates to the inner iterator's vec-native DrainPipelineToFrame path so the data-node Rev under flag-on emits a columnar raw frame body directly without proto materialization. The exported facade must implement the method too because that is the type processor.go sees from the vec dispatch return.

func (*VectorizedMIterator) Err

func (v *VectorizedMIterator) Err() error

Err returns any sticky storage error that terminated iteration.

func (*VectorizedMIterator) Next

func (v *VectorizedMIterator) Next() bool

Next advances one DataPoint.

func (*VectorizedMIterator) Pipeline

func (v *VectorizedMIterator) Pipeline() *vectorized.Pipeline

Pipeline implements RawFrameSource on the public adapter — delegates to the inner iterator so callers (e.g. the data-node Rev under flag-on) can drain the pipeline directly.

func (*VectorizedMIterator) Schema

Schema implements RawFrameSource on the public adapter.

Directories

Path Synopsis
Package frame binds the shared vec columnar frame codec (pkg/query/vectorized/frame) to the measure engine.
Package frame binds the shared vec columnar frame codec (pkg/query/vectorized/frame) to the measure engine.
Package plan is the vectorized measure-query plan tree (G8).
Package plan is the vectorized measure-query plan tree (G8).

Jump to

Keyboard shortcuts

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