Files
five/hbrt
CharlesKWON fe5df22517 perf(hbrt): ArraySlab — pooled HbArray allocation for scan result rows
SqlScan's prior design called hbrt.MakeArrayFrom per matching row,
each one allocating a fresh &HbArray{}. For 50k rows that's 50k tiny
Go heap allocations + GC pressure that the flat-backing-buffer work
from 85541a3 left untouched (that commit eliminated the per-row items
slice alloc but not the header alloc).

hbrt.ArraySlab pre-allocates a `[]HbArray` slab of the estimated row
count and hands out `&slab.buf[idx]` on each WrapNext. One underlying
make() replaces N; pointers stay stable because slab growth reallocates
a fresh buffer instead of reusing the old one, so previously-handed-out
pointers remain valid (the old backing is kept alive by the references).

API kept tiny:
  slab := hbrt.NewArraySlab(estRows)
  val := slab.WrapNext(items)  // returns Value wrapping &slab.buf[i]

SqlScan now pairs this with the existing flat value buffer for a
single-allocation-per-chunk scan hot loop.

Combined bench impact (50k rows, steady state):

                     Session start   Now
  no WHERE               14.6ms     9.2ms  ← 1.3x vs raw RDD baseline
  numeric WHERE          11.7ms    10.2ms
  string WHERE           10.5ms    10.5ms
  raw RDD baseline        6.8ms     7.0ms

no WHERE is now within 30% of raw RDD. Remaining gap is largely
Area.GetValue boxing overhead and the pcode opcode dispatch loop
itself — no further structural wins without a wider refactor.

Validation:
  - FiveSql2 43/43
  - Harbour compat 51/51
  - go test ./... ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:08:13 +09:00
..