blob: e234eb1fe0ab74c2f3843526281e224e3ed741f8 [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
import (
modelv1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
"github.com/apache/skywalking-banyandb/pkg/pool"
)
// One pool per supported column element type. Pools hold *TypedColumn[T]
// instances that have been Reset; on Get the caller may need to grow the
// backing slice if the prior capacity is smaller than the new request.
var (
int64ColumnPool = pool.Register[*TypedColumn[int64]]("vectorized.column.int64")
float64ColumnPool = pool.Register[*TypedColumn[float64]]("vectorized.column.float64")
stringColumnPool = pool.Register[*TypedColumn[string]]("vectorized.column.string")
bytesColumnPool = pool.Register[*TypedColumn[[]byte]]("vectorized.column.bytes")
int64ArrayColumnPool = pool.Register[*TypedColumn[[]int64]]("vectorized.column.int64array")
strArrayColumnPool = pool.Register[*TypedColumn[[]string]]("vectorized.column.strarray")
tagValueColumnPool = pool.Register[*TypedColumn[*modelv1.TagValue]]("vectorized.column.tagvalue")
fieldValueColumnPool = pool.Register[*TypedColumn[*modelv1.FieldValue]]("vectorized.column.fieldvalue")
)
// AcquireColumn returns a recycled Column of the requested type. The
// returned column is Reset (length 0, validity cleared) and has a backing
// capacity of at least the requested size. Callers must pair every
// AcquireColumn with a matching ReleaseColumn once they are done with the
// column.
//
// Capacity behavior: pooled columns retain whichever capacity they had at
// the last Release. If a pooled column is too small for the new request the
// backing slice is reallocated; otherwise the existing backing slice is
// reused. Over time the pool converges to the largest capacity seen.
func AcquireColumn(t ColumnType, capacity int) Column {
switch t {
case ColumnTypeInt64:
c := int64ColumnPool.Get()
if c == nil {
return NewInt64Column(capacity)
}
if cap(c.data) < capacity {
c.data = make([]int64, 0, capacity)
}
return c
case ColumnTypeFloat64:
c := float64ColumnPool.Get()
if c == nil {
return NewFloat64Column(capacity)
}
if cap(c.data) < capacity {
c.data = make([]float64, 0, capacity)
}
return c
case ColumnTypeString:
c := stringColumnPool.Get()
if c == nil {
return NewStringColumn(capacity)
}
if cap(c.data) < capacity {
c.data = make([]string, 0, capacity)
}
return c
case ColumnTypeBytes:
c := bytesColumnPool.Get()
if c == nil {
return NewBytesColumn(capacity)
}
if cap(c.data) < capacity {
c.data = make([][]byte, 0, capacity)
}
return c
case ColumnTypeInt64Array:
c := int64ArrayColumnPool.Get()
if c == nil {
return NewInt64ArrayColumn(capacity)
}
if cap(c.data) < capacity {
c.data = make([][]int64, 0, capacity)
}
return c
case ColumnTypeStrArray:
c := strArrayColumnPool.Get()
if c == nil {
return NewStrArrayColumn(capacity)
}
if cap(c.data) < capacity {
c.data = make([][]string, 0, capacity)
}
return c
case ColumnTypeTagValue:
c := tagValueColumnPool.Get()
if c == nil {
return NewTagValueColumn(capacity)
}
if cap(c.data) < capacity {
c.data = make([]*modelv1.TagValue, 0, capacity)
}
return c
case ColumnTypeFieldValue:
c := fieldValueColumnPool.Get()
if c == nil {
return NewFieldValueColumn(capacity)
}
if cap(c.data) < capacity {
c.data = make([]*modelv1.FieldValue, 0, capacity)
}
return c
}
panic("vectorized: unknown ColumnType " + t.String())
}
// ReleaseColumn returns a column to its per-type pool. The column is Reset
// (length cleared, validity cleared) before being put back. A nil column is
// a no-op so callers can release defensively. Unknown column types are also
// no-ops — the column is simply dropped on the floor for the GC.
func ReleaseColumn(c Column) {
if c == nil {
return
}
switch col := c.(type) {
case *TypedColumn[int64]:
col.Reset()
int64ColumnPool.Put(col)
case *TypedColumn[float64]:
col.Reset()
float64ColumnPool.Put(col)
case *TypedColumn[string]:
col.Reset()
stringColumnPool.Put(col)
case *TypedColumn[[]byte]:
col.Reset()
bytesColumnPool.Put(col)
case *TypedColumn[[]int64]:
col.Reset()
int64ArrayColumnPool.Put(col)
case *TypedColumn[[]string]:
col.Reset()
strArrayColumnPool.Put(col)
case *TypedColumn[*modelv1.TagValue]:
col.Reset()
tagValueColumnPool.Put(col)
case *TypedColumn[*modelv1.FieldValue]:
col.Reset()
fieldValueColumnPool.Put(col)
}
}