Skip to content

Commit f877027

Browse files
committed
Preserve typed vector write performance
marcboeker#276 made SetChunkValue generic to avoid allocating when table UDFs write values. Routing every write through the any-valued callback restored correctness locality but boxed each generic value. Install optional exact-type callbacks for each vector canonical Go type, with setFn as the fallback for all other values, and keep numeric conversion setters generic. The numeric optimization defaults to the vector-installed setFn, so types it does not recognize retain the single correctness dispatch in vector initialization. Add benchmarks for both public table UDF write paths and a matrix covering cross-numeric and representative canonical writes. These paths now match or improve on main allocation counts.
1 parent 406940d commit f877027

5 files changed

Lines changed: 203 additions & 30 deletions

File tree

data_chunk.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func SetChunkValue[T any](chunk DataChunk, colIdx, rowIdx int, val T) error {
9696
return getError(errAPI, err)
9797
}
9898

99-
return chunk.columns[colIdx].SetValue(rowIdx, val)
99+
return setVectorVal(&chunk.columns[colIdx], mapping.IdxT(rowIdx), val)
100100
}
101101

102102
func inBounds[T any](s []T, idx int) bool {

vector.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ type vector struct {
2323
getFn fnGetVectorValue
2424
// A callback function to write to this vector.
2525
setFn fnSetVectorValue
26+
// An optional exact-type setter that avoids boxing generic writes.
27+
setTypedFn any
2628
// The child vectors of nested data types.
2729
childVectors []vector
2830
// structTemplate is a pre-allocated map[string]any with all struct keys
@@ -168,6 +170,7 @@ func initBool(vec *vector) {
168170
}
169171
return setBool(vec, rowIdx, val)
170172
}
173+
vec.setTypedFn = fnSetVectorValueTyped[bool](setBool[bool])
171174
vec.Type = TYPE_BOOLEAN
172175
}
173176

@@ -185,6 +188,7 @@ func initNumeric[T numericType](vec *vector, t Type) {
185188
}
186189
return setNumeric[any, T](vec, rowIdx, val)
187190
}
191+
vec.setTypedFn = fnSetVectorValueTyped[T](setNumeric[T, T])
188192
vec.Type = t
189193
}
190194

@@ -202,6 +206,7 @@ func (vec *vector) initTS(t Type) {
202206
}
203207
return setTS(vec, rowIdx, val)
204208
}
209+
vec.setTypedFn = fnSetVectorValueTyped[time.Time](setTS[time.Time])
205210
vec.Type = t
206211
}
207212

@@ -219,6 +224,7 @@ func (vec *vector) initDate() {
219224
}
220225
return setDate(vec, rowIdx, val)
221226
}
227+
vec.setTypedFn = fnSetVectorValueTyped[time.Time](setDate[time.Time])
222228
vec.Type = TYPE_DATE
223229
}
224230

@@ -236,6 +242,7 @@ func (vec *vector) initTime(t Type) {
236242
}
237243
return setTime(vec, rowIdx, val)
238244
}
245+
vec.setTypedFn = fnSetVectorValueTyped[time.Time](setTime[time.Time])
239246
vec.Type = t
240247
}
241248

@@ -253,6 +260,7 @@ func (vec *vector) initInterval() {
253260
}
254261
return setInterval(vec, rowIdx, val)
255262
}
263+
vec.setTypedFn = fnSetVectorValueTyped[Interval](setInterval[Interval])
256264
vec.Type = TYPE_INTERVAL
257265
}
258266

@@ -321,6 +329,11 @@ func (vec *vector) initBytes(t Type) {
321329
}
322330
return setBytes(vec, rowIdx, val)
323331
}
332+
if t == TYPE_VARCHAR {
333+
vec.setTypedFn = fnSetVectorValueTyped[string](setBytes[string])
334+
} else {
335+
vec.setTypedFn = fnSetVectorValueTyped[[]byte](setBytes[[]byte])
336+
}
324337
vec.Type = t
325338
}
326339

@@ -338,6 +351,7 @@ func (vec *vector) initBit() {
338351
}
339352
return setBit(vec, rowIdx, val)
340353
}
354+
vec.setTypedFn = fnSetVectorValueTyped[Bit](setBit[Bit])
341355
vec.Type = TYPE_BIT
342356
}
343357

@@ -355,6 +369,7 @@ func (vec *vector) initJSON() {
355369
}
356370
return setJSON(vec, rowIdx, val)
357371
}
372+
vec.setTypedFn = fnSetVectorValueTyped[string](setJSON[string])
358373
vec.Type = TYPE_VARCHAR
359374
}
360375

@@ -423,6 +438,7 @@ func (vec *vector) initEnum(logicalType mapping.LogicalType, colIdx int) error {
423438

424439
vec.Type = TYPE_ENUM
425440
vec.internalType = t
441+
vec.setTypedFn = fnSetVectorValueTyped[string](setEnum[string])
426442
return nil
427443
}
428444

@@ -451,6 +467,7 @@ func (vec *vector) initList(logicalType mapping.LogicalType, colIdx int) error {
451467
}
452468
return setList(vec, rowIdx, val)
453469
}
470+
vec.setTypedFn = fnSetVectorValueTyped[[]any](setList[[]any])
454471
vec.Type = TYPE_LIST
455472
return nil
456473
}
@@ -502,6 +519,7 @@ func (vec *vector) initStruct(logicalType mapping.LogicalType, colIdx int) error
502519
}
503520
return setStruct(vec, rowIdx, val)
504521
}
522+
vec.setTypedFn = fnSetVectorValueTyped[map[string]any](setStruct[map[string]any])
505523
vec.Type = TYPE_STRUCT
506524
return nil
507525
}
@@ -544,6 +562,7 @@ func (vec *vector) initMap(logicalType mapping.LogicalType, colIdx int) error {
544562
}
545563
return setMap(vec, rowIdx, val)
546564
}
565+
vec.setTypedFn = fnSetVectorValueTyped[OrderedMap](setMap[OrderedMap])
547566
vec.Type = TYPE_MAP
548567
return nil
549568
}
@@ -575,6 +594,7 @@ func (vec *vector) initArray(logicalType mapping.LogicalType, colIdx int) error
575594
}
576595
return setArray(vec, rowIdx, val)
577596
}
597+
vec.setTypedFn = fnSetVectorValueTyped[[]any](setArray[[]any])
578598
vec.Type = TYPE_ARRAY
579599
return nil
580600
}
@@ -621,6 +641,7 @@ func (vec *vector) initUnion(logicalType mapping.LogicalType, colIdx int) error
621641
}
622642
return setUnion(vec, rowIdx, val)
623643
}
644+
vec.setTypedFn = fnSetVectorValueTyped[Union](setUnion[Union])
624645
vec.Type = TYPE_UNION
625646
return nil
626647
}
@@ -640,6 +661,7 @@ func (vec *vector) initUUID() {
640661
}
641662
return setUUID(vec, rowIdx, val)
642663
}
664+
vec.setTypedFn = fnSetVectorValueTyped[UUID](setUUID[UUID])
643665
vec.Type = TYPE_UUID
644666
}
645667

0 commit comments

Comments
 (0)