stream

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: 15 Imported by: 0

Documentation

Overview

Package stream implements stream-specific vectorized query operators: the pull pipeline that scans elements into columnar batches and merges them in index or timestamp order at egress.

Index

Constants

View Source
const (
	StreamColumnNameTimestamp = "timestamp"
	StreamColumnNameElementID = "elementID"
	StreamColumnNameSeriesID  = "seriesID"
	StreamColumnNameOrderKey  = "orderKey"
)

Metadata column names for the stream vectorized batch schema.

Variables

This section is empty.

Functions

func BuildElementsFromBatch

func BuildElementsFromBatch(batch *vectorized.RecordBatch,
	projectionTags []model.TagProjection,
) ([]*streamv1.Element, error)

BuildElementsFromBatch materializes []*streamv1.Element from a single columnar batch, honoring the batch Selection (post-pipeline batches carry one). The Element shape is byte-identical to the row path's BuildElementsFromStreamResult: hex-encoded elementID, timestamppb timestamp, and tag families/tags in projection order with NullTagValue for a missing projected tag.

This is the single shared columnar→proto egress used by both the data-node standalone path (banyand/stream) and the liaison distributed merge (pkg/query/logical/stream), so the two cannot diverge and neither triggers an import cycle with the other.

func BuildElementsFromBatches

func BuildElementsFromBatches(batches []*vectorized.RecordBatch,
	projectionTags []model.TagProjection,
) ([]*streamv1.Element, error)

BuildElementsFromBatches concatenates BuildElementsFromBatch over a slice of batches, preserving batch order and each batch's Selection.

func BuildStreamBatchSchema

func BuildStreamBatchSchema(tagProjection []model.TagProjection, orderTagFamily, orderTagName string) *vectorized.BatchSchema

BuildStreamBatchSchema builds the columnar batch schema for a stream query. Columns are laid out as Timestamp, ElementID, SeriesID, one passthrough tag column per projected tag (grouped by family), and — when an ordered tag is supplied — a trailing comparable-bytes order-key column.

func BuildStreamMergePipeline

func BuildStreamMergePipeline(
	source vectorized.PullOperator,
	schema *vectorized.BatchSchema,
	desc bool,
	offset, limit uint32,
	batchSize, maxRows int,
) (*vectorized.Pipeline, error)

BuildStreamMergePipeline composes the liaison-side merge → distinct → limit pipeline over a source of stream RecordBatches. SortedMerge is the breaker (global ordering), Distinct and Limit are fusibles applied on the ordered output, in that strict order. There is no pre-merge short-circuit.

maxRows bounds the merge to the in-order top-N (0 = unbounded). This is the per-node scan cap (maxElementSize = limit+offset), applied AFTER the merge sorts — the correct top-N in sort order — matching the row path, which caps after its in-order heap merge (blockHeap.merge / MergeStreamResults). It is distinct from the client offset/limit slice the trailing Limit applies.

func ColumnToElementID

func ColumnToElementID(v int64) uint64

ColumnToElementID reinterprets an int64 ElementID column value back to the original uint64 element id. This is an exact bit reinterpretation.

func ColumnToSeriesID

func ColumnToSeriesID(v int64) uint64

ColumnToSeriesID reinterprets an int64 SeriesID column value back to the original uint64 series id. This is an exact bit reinterpretation.

func ElementIDToColumn

func ElementIDToColumn(id uint64) int64

ElementIDToColumn reinterprets a uint64 element id as the int64 stored in the ElementID column. This is an exact bit reinterpretation, not a value cast.

func IncrQueryCount

func IncrQueryCount()

IncrQueryCount increments the process-wide vectorized stream query counter. Called when the vectorized execution path is taken for a stream query.

func QueryCount

func QueryCount() int64

QueryCount returns the cumulative number of vectorized stream queries executed by this process.

func SeriesIDToColumn

func SeriesIDToColumn(id uint64) int64

SeriesIDToColumn reinterprets a uint64 series id as the int64 stored in the SeriesID column. This is an exact bit reinterpretation, not a value cast.

Types

type Distinct

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

Distinct deduplicates stream rows by ElementID, keeping the first occurrence in the (already merged) input order. It is stateful across batches via a seen set keyed by the raw uint64 element id, mirroring the row path's first-seen dedup (stream_plan_distributed.go seen map keyed by ElementId). It MUST run downstream of SortedMerge so "first occurrence" reflects the global order.

func NewDistinct

func NewDistinct(schema *vectorized.BatchSchema) *Distinct

NewDistinct constructs a stream first-seen dedup fusible.

func (*Distinct) Close

func (d *Distinct) Close() error

Close is idempotent and a no-op.

func (*Distinct) Init

func (d *Distinct) Init(context.Context) error

Init resets the seen set.

func (*Distinct) OutputSchema

func (d *Distinct) OutputSchema() *vectorized.BatchSchema

OutputSchema returns the unchanged input schema.

func (*Distinct) Process

func (d *Distinct) Process(_ context.Context, batch *vectorized.RecordBatch) error

Process rewrites the selection to keep only rows whose ElementID is seen for the first time. Later duplicates are dropped by omission from the selection.

type Limit

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

Limit applies the client-facing global offset+limit slice to the merged, deduplicated stream. It skips the first offset active rows, emits up to limit rows, then signals EOF via ErrLimitExhausted.

These are the CLIENT offset/limit values, applied liaison-side as the final slice (mirrors distributedLimit.Execute in stream_plan_distributed.go). The per-node scan cap of limit+offset is applied UPSTREAM (M6), not here.

func NewLimit

func NewLimit(schema *vectorized.BatchSchema, offset, limit uint32) *Limit

NewLimit constructs a stream global offset+limit fusible.

func (*Limit) Close

func (l *Limit) Close() error

Close is idempotent and a no-op.

func (*Limit) Init

func (l *Limit) Init(context.Context) error

Init is a no-op.

func (*Limit) OutputSchema

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

OutputSchema returns the unchanged input schema.

func (*Limit) Process

func (l *Limit) Process(_ context.Context, batch *vectorized.RecordBatch) error

Process rewrites the selection to the client offset+limit window. A zero limit emits nothing and signals EOF immediately.

type SortedMerge

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

SortedMerge is a globally-ordering breaker over stream RecordBatches.

It Consumes every input batch (buffering row references), Finalize sorts them stably by the schema order key, and NextBatch emits key-ordered output batches sized to batchSize. Time-order keys on the Timestamp int64 column (stream timestamps are non-negative UnixNano, so a direct int64 compare matches the row path's convert.Uint64ToBytes big-endian byte order); index-order keys on the OrderKey comparable-bytes column (byte-lexicographic, matching the row path's MarshalTagValue bytes). asc/desc is honored; ties preserve input arrival order so downstream first-seen dedup stays deterministic.

func NewSortedMerge

func NewSortedMerge(schema *vectorized.BatchSchema, desc bool, batchSize int) *SortedMerge

NewSortedMerge constructs a stream global-merge breaker over the given schema.

func NewSortedMergeWithCap

func NewSortedMergeWithCap(schema *vectorized.BatchSchema, desc bool, batchSize, maxRows int) *SortedMerge

NewSortedMergeWithCap constructs a stream global-merge breaker that keeps only the first maxRows rows in sort order after the stable sort — the correct in-order top-N. A maxRows of 0 means unbounded (equivalent to NewSortedMerge). The cap is applied AFTER the merge sorts, so it matches the row path's cap-after-in-order-merge semantics (blockHeap.merge / MergeStreamResults).

func (*SortedMerge) Close

func (s *SortedMerge) Close() error

Close is idempotent and releases buffered references.

func (*SortedMerge) Consume

func (s *SortedMerge) Consume(_ context.Context, batch *vectorized.RecordBatch) error

Consume buffers references to every active row in the batch. The batch is retained (not copied); callers must not recycle a consumed batch until this operator is closed.

func (*SortedMerge) Finalize

func (s *SortedMerge) Finalize(context.Context) error

Finalize stably sorts the buffered rows by the schema order key, then applies the in-order top-N cap.

The cap keeps the first maxRows rows counted by UNIQUE ElementID, in sort order. This matches the row path's oracle exactly: MergeStreamResults / blockHeap.merge dedup by ElementID DURING their in-order merge and stop once the DEDUPED count reaches the limit (mergedResult.Len() < topN). Capping on the raw pre-dedup row count would drop unique rows the oracle keeps whenever a duplicate ElementID falls inside the retained window (an ElementID can span parts). Rows are truncated at the sort position where the maxRows-th distinct ElementID first appears, so the retained prefix carries every row (including still-undeduped duplicates) up to that boundary; the downstream Distinct then removes the duplicates from that already-correct top-N prefix.

func (*SortedMerge) Init

func (s *SortedMerge) Init(context.Context) error

Init sizes the batch size and prepares the output pool.

func (*SortedMerge) NextBatch

func (s *SortedMerge) NextBatch(ctx context.Context) (*vectorized.RecordBatch, error)

NextBatch emits the next key-ordered output batch. Empty input returns EOF immediately.

func (*SortedMerge) OutputSchema

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

OutputSchema returns the shared input/output schema.

type VectorizedConfig

type VectorizedConfig struct {
	BatchSize int
	// QueryMemoryMiB is a soft element-loading threshold: it caps the cumulative
	// uncompressed element bytes fetched from disk per query. Tags, record-batch
	// overhead, and other per-query allocations are not counted. The first block
	// always loads regardless of the budget (first-block exception), so a single
	// oversized block may exceed this value.
	QueryMemoryMiB int
	Enabled        bool
}

VectorizedConfig controls the v1 vectorized Stream query path.

func DefaultConfig

func DefaultConfig() VectorizedConfig

DefaultConfig returns the default stream vectorized configuration — enabled, with the shared default batch size and a 256 MiB per-query memory budget.

The query layer dedups by element_id and holds the seen-set for the whole query, because an element_id identifies an element GLOBALLY: two rows carrying one element_id are one element, whatever their timestamps or which parts they were read from. test/cases/stream's "deduplication test" pins that — 50 records over 27 distinct ids at 50 different timestamps must come back as 27 rows.

The row path uses the same key but allocates its seen-set per merge round (blockCursorHeap.merge / model.MergeStreamResults, one per runTabScanner call), so it only collapses duplicates that land in the same round. That is a weaker guarantee than this path gives, not a different semantic; a fixture that reuses an element_id across two writes is malformed either way.

Enabled also selects the liaison<->data wire format: a flag-on distributed data node emits the native columnar frame instead of protobuf. A liaison decodes both (it dispatches on the frame magic byte per message), but an older liaison has no frame decoder at all, so a cluster must upgrade liaison nodes BEFORE data nodes. See docs/operation/upgrade.md.

To roll back the vec path entirely, pass --stream-vectorized-enabled=false on the standalone or data-node command line and restart; the row path resumes immediately.

func (VectorizedConfig) Validate

func (c VectorizedConfig) Validate() error

Validate rejects invalid stream vectorized configurations.

Directories

Path Synopsis
Package frame binds the shared vec columnar frame codec (pkg/query/vectorized/frame) to the stream engine.
Package frame binds the shared vec columnar frame codec (pkg/query/vectorized/frame) to the stream engine.

Jump to

Keyboard shortcuts

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