blob: 0ac57fb13c93f209004424d76976b4c889160a8f [file]
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package vectorized
// ColumnRole identifies the semantic role of a column within a RecordBatch.
type ColumnRole int
// Column roles. Each batch schema may include at most one column per metadata role.
const (
RoleTimestamp ColumnRole = iota
RoleVersion
RoleSeriesID
RoleShardID
RoleTag
RoleField
)
// ColumnDef describes one column in a BatchSchema.
type ColumnDef struct {
Name string
TagFamily string
Role ColumnRole
Type ColumnType
}
// tagKey is the composite key used to index tag columns by (family, name).
// Using a struct key eliminates two issues with a string-concatenated key:
// - it cannot collide when family or name contains the separator character;
// - the lookup avoids allocating a fresh string on every hot-path call.
type tagKey struct {
family string
name string
}
// TagFamilyGroup pre-computes the (family, [column indices]) layout used by
// the row-by-row serializer. Storing it on the schema lets the hot path
// stamp out one TagFamily per family per row without re-grouping or
// allocating a `map[string]*modelv1.TagFamily` on every row.
type TagFamilyGroup struct {
Family string
Columns []int
}
// BatchSchema is the immutable column layout shared by every RecordBatch in a pipeline.
type BatchSchema struct {
tagByPath map[tagKey]int
fieldByName map[string]int
Columns []ColumnDef
TagFamilyGroups []TagFamilyGroup // ordered tag-column groups by family
FieldColumns []int // ordered field column indices
timestampIdx int
versionIdx int
seriesIDIdx int
shardIDIdx int
}
// NewBatchSchema builds a BatchSchema and precomputes lookup indices.
func NewBatchSchema(cols []ColumnDef) *BatchSchema {
s := &BatchSchema{
Columns: cols,
timestampIdx: -1,
versionIdx: -1,
seriesIDIdx: -1,
shardIDIdx: -1,
tagByPath: make(map[tagKey]int),
fieldByName: make(map[string]int),
}
familyIdx := make(map[string]int)
for i, c := range cols {
switch c.Role {
case RoleTimestamp:
s.timestampIdx = i
case RoleVersion:
s.versionIdx = i
case RoleSeriesID:
s.seriesIDIdx = i
case RoleShardID:
s.shardIDIdx = i
case RoleTag:
s.tagByPath[tagKey{family: c.TagFamily, name: c.Name}] = i
groupIdx, ok := familyIdx[c.TagFamily]
if !ok {
groupIdx = len(s.TagFamilyGroups)
familyIdx[c.TagFamily] = groupIdx
s.TagFamilyGroups = append(s.TagFamilyGroups, TagFamilyGroup{Family: c.TagFamily})
}
s.TagFamilyGroups[groupIdx].Columns = append(s.TagFamilyGroups[groupIdx].Columns, i)
case RoleField:
s.fieldByName[c.Name] = i
s.FieldColumns = append(s.FieldColumns, i)
}
}
return s
}
// TimestampIndex returns the timestamp column index, or -1 if absent.
func (s *BatchSchema) TimestampIndex() int { return s.timestampIdx }
// VersionIndex returns the version column index, or -1 if absent.
func (s *BatchSchema) VersionIndex() int { return s.versionIdx }
// SeriesIDIndex returns the series-id column index, or -1 if absent.
func (s *BatchSchema) SeriesIDIndex() int { return s.seriesIDIdx }
// ShardIDIndex returns the shard-id column index, or -1 if absent.
func (s *BatchSchema) ShardIDIndex() int { return s.shardIDIdx }
// TagIndex returns the column index for a (family, name) tag.
// Lookup uses a struct key, so it does not allocate.
func (s *BatchSchema) TagIndex(family, name string) (int, bool) {
i, ok := s.tagByPath[tagKey{family: family, name: name}]
return i, ok
}
// FieldIndex returns the column index for a field name.
func (s *BatchSchema) FieldIndex(name string) (int, bool) {
i, ok := s.fieldByName[name]
return i, ok
}