Files
five/hbrtl
CharlesKWON 5e4a1c5d72 refactor(FiveSql2): cross-session globals → Go atomic + RWMutex
Completes the per-STATIC migration started in 5bba0c2. The
remaining three TSqlExecutor module STATICs (s_nSchemaVer,
s_nRCJSeq, s_hAutoInc) genuinely needed cross-connection
visibility — a CREATE TABLE on connection A MUST invalidate B's
plan cache, an RCJ alias MUST be unique across all live queries,
and an IDENTITY column MUST hand out monotonic values across all
writers. Moving them to TSqlSession (per-instance) would have
broken those semantics.

Solution: back them with Go-side primitives exposed via HB_FUNCs:

  s_nSchemaVer  →  atomic.Uint64 (SqlSchemaVer / SqlBumpSchemaVer)
  s_nRCJSeq     →  atomic.Uint64 (SqlNextRCJSeq, returns mod-100000)
  s_hAutoInc    →  sync.RWMutex + map[string][]string
                    (SqlSetAutoInc / SqlGetAutoIncFields)

Lives in `hbrtl/sqlglobals.go`. The PRG-side `FUNCTION
SqlSchemaVer() / SqlBumpSchemaVer() / SqlSetAutoInc() /
SqlGetAutoIncFields()` definitions in TSqlExecutor.prg are
deleted; the HB_FUNC dispatch takes their place. The single PRG
caller of `s_nRCJSeq` (in the RCJ helper around line 5600)
becomes `SqlNextRCJSeq()` and reads cleaner — the old
`s_nRCJSeq := (s_nRCJSeq + 1) % 100000` was both racy and a
non-atomic two-write update under multi-conn load.

The other module STATIC, `s_hAutoInc`, used to lazy-init on
first use (`IF s_hAutoInc == NIL ... := { => }`); two concurrent
first-CREATE TABLE calls hit "concurrent map writes" on that
branch. The Go RWMutex eliminates the race; reads still scale
(RLock) so the IDENTITY-lookup at INSERT time isn't a contention
hot-spot.

All six release gates green:
  go test ./...               ✓
  FiveSql2 SQL:1999 43/43     ✓
  Harbour compat 56/56        ✓
  std.ch 17/17                ✓
  FRB 7/7                     ✓
  pgserver integration 6/6    ✓

Concurrency stress (3-worker × 20):
  pre-Layer-1:    ~60% pass + occasional Go panic
  +Layer 1+2:     80% pass, no panics
  +3a:            80% pass
  +per-session 3 STATIC move:  90% pass
  +this commit:   ~75% pass (variability — Go map atomic + mutex
                  serialise the writers but the underlying
                  hbrdd multi-area mmap path still has its own
                  race, deferred to follow-up)

The next bottleneck is at the hbrdd workarea layer (multi-Area
instances per file each holding their own mmap snapshot), not at
the FiveSql2 STATIC level. That fix is its own commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:58:52 +09:00
..