279a16a88c
refactor: pure Go — recursion→iteration, COW records, zero alloc
...
CDX Seek iterative (cdx.go):
- Converted recursive seekPage → iterative loop
- Single buf reused across all B-tree levels (was: make per level)
- Internal node: binary search (was: linear O(n))
- Eliminates 3 heap allocations per CDX SEEK
DBF Copy-on-Write records (dbf.go):
- GoTo: recBuf = mmap slice reference (zero-copy read)
- PutValue/Delete/Recall: promote to ownBuf before write
- Eliminates memcpy per GoTo for read-only SCAN operations
- recOwned flag tracks COW state
NTX build.go:
- setKeyEntry: write directly to page (no temp make([]byte))
- padCopy: copy+fill (no pre-fill entire buffer)
CDX DecodeLeafKeys slab (cdx.go):
- Single slab allocation for all keys per page
82/82 stress PASS. All unit tests PASS.
50K SEEK random: 63ms (Harbour 67ms — FASTER!)
50K DELSCAN: 2ms (Harbour 12ms — 6x FASTER!)
CDX SCOPE: 2ms (Harbour 4ms — 2x FASTER!)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 22:56:20 +09:00
0102c3c94e
perf: CGo review — slab alloc, compareKeys simplify, zero-alloc padCopy
...
From CGo expert review (verdict: stay pure Go, CGo would be slower):
CDX DecodeLeafKeys slab allocation (cdx.go):
- Single make() for all keys + prevKey (was 30+ allocs per page)
- Keys are slices into pre-allocated slab (zero copy)
NTX compareKeys simplified (ntx.go):
- bytes.Compare already returns normalized -1/0/+1
- Removed redundant normalization branches
NTX build.go zero-alloc:
- padCopy: copy+fill instead of make+fill+copy
- setKeyEntry: write directly to page data (no temp buffer)
82/82 stress PASS. 14 packages ALL PASS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 22:44:56 +09:00
b72623f79c
perf: CDX binary search + leaf cache hit + DBF/NTX zero-copy
...
CDX Seek (cdx.go — ported from rddfive/cdx_engine.c):
- Linear search → binary search on decoded leaf keys (O(N) → O(log N))
- Leftmost match: continues searching left after match (duplicate key correctness)
- Leaf cache hit: skip decode if same page (SEEK loop optimization)
NTX zero-copy Page (ntx.go — BoltDB pattern):
- Page.data: []byte slice into mmap (was [1024]byte copy)
- cachedLoadPage: p.data = mmap[offset:offset+1024] (no memcpy!)
- pagePool: 8-slot ring for Page struct reuse
DBF mmap (dbf.go):
- GoTo: copy from mmap instead of file.ReadAt syscall
- Unmap before Append/Close/Flush (file growth), re-mmap after
Results (50K, ext4, Harbour comparison):
┌──────────────┬──────────┬──────────┬──────────────┐
│ │ Harbour │ Five │ │
├──────────────┼──────────┼──────────┼──────────────┤
│ CDX SEEK │ 27ms │ 49ms │ 1.8x (was 6.5x!)│
│ CDX SEEK ID │ 17ms │ 24ms │ 1.4x (was 8.4x!)│
│ CDX SCAN │ 5ms │ 4ms │ ✅ FASTER │
│ CDX SCOPE │ 4ms │ 3ms │ ✅ FASTER │
│ NTX SCAN │ 4ms │ 3ms │ ✅ FASTER │
│ NTX DELSCAN │ 12ms │ 3ms │ ✅ 4x FASTER │
│ NTX SEEK rnd │ 67ms │ 69ms │ ≈ equal │
└──────────────┴──────────┴──────────┴──────────────┘
82/82 stress PASS. CDX 18/18 cross-read PASS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 20:18:54 +09:00
96d72a456c
perf: CDX zero-alloc internal node seek — SEEK 45% faster
...
Internal node traversal: read directly from mmap/buf slice
- No DecodeIntKeys allocation (was nKeys+1 IntKeyEntry structs)
- No key byte slice copy (compare directly against buf)
- Big-endian child/recNo read inline
CDX 50K benchmark:
SEEK NAME: 362ms → 199ms (45% faster)
SEEK ID: 320ms → 184ms (42% faster)
SCAN: 14ms (unchanged — leaf cache handles this)
SCOPE: 20ms → 14ms
Harbour comparison:
SEEK: 27ms (Harbour) vs 199ms (Five) = 7.4x
SCAN: 6ms (Harbour) vs 14ms (Five) = 2.3x
CDX cross-read: 18/18 PASS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 14:05:20 +09:00
40935b6103
perf: CDX byte-level decode + leaf cache — SCAN 20x faster
...
Ported from rddfive/cdx_engine.c cdx_leaf_decode_all():
- Replaced bit-by-bit extractBits loop with byte-level shift/mask
- Read reqByte as little-endian integer, extract recNo/dup/trl via masks
- 10x+ faster than per-bit extraction
Leaf page decode cache:
- Tag.cachedLeafOff/cachedLeafKeys: avoid re-decoding same leaf page
- SkipNext/SkipPrev use getLeafKeys() with cache
- GoTop/Seek populate cache on first decode
CDX 50K benchmark (ext4):
┌──────────────┬──────────┬──────────┬──────────┐
│ CDX 50K │ Harbour │ Before │ After │
├──────────────┼──────────┼──────────┼──────────┤
│ SCAN 50K │ 6ms │ 276ms │ 14ms │ ← 20x faster
│ SCOPE 35K │ 4ms │ 238ms │ 20ms │ ← 12x faster
│ SEEK NAME │ 27ms │ 362ms │ 239ms │
│ SEEK ID │ 18ms │ 320ms │ 195ms │
└──────────────┴──────────┴──────────┴──────────┘
CDX cross-read: 18/18 PASS. All unit tests PASS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 13:37:57 +09:00
1b41384675
fix: CDX mmap + internal node format (BE key-first) — 50K works
...
CDX internal node format fix:
- Was: [child LE][recNo LE][key] (NTX-style)
- Now: [key][recNo BE][child BE] (correct CDX format)
- Fixes GoTop/Seek/Scan for large CDX files (50K+ records)
CDX mmap:
- syscall.Mmap on OpenIndex for zero-copy reads
- idx.readAt() helper: mmap slice or file fallback
- All ReadAt calls in Tag navigation replaced
- Close: munmap
CDX 50K benchmark (all counts correct):
SEEK NAME 50K: 362ms (f=50000)
SCAN 50K: 276ms (c=50000)
SCOPE 35K: 238ms (c=35000)
SEEK ID 50K: 320ms (f=50000)
CDX is slower than NTX due to bit-packed leaf decompression per page.
Cross-read test: 18/18 still PASS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 13:32:06 +09:00
7e2a159b88
feat: CDX support + ORDSCOPE + cross-read Harbour compatibility
...
CDX Integration:
- IndexEngine interface: common for NTX Index and CDX Tag
- OrderListAdd: auto-detects .cdx/.ntx extension, opens CDX tags
- decodeCompoundLeaf: proper bit-packed tag directory decoding
(was stub falling through to scanCompoundLeaves with wrong names)
- CDX Tag: added KeyLen(), KeyExpr(), ForExpr(), IsDescending(), Close()
- CDX compound recNo = direct byte offset (not page number)
ORDSCOPE:
- SetScope/ClearScope/SetScopeTop/SetScopeBottom on DBFArea
- GoTopIndexed: seeks to scopeTop, validates within scopeBottom
- GoBottomIndexed: seeks to scopeBottom boundary
- SkipIndexed: stops at scope boundaries (top and bottom)
- OrdScope RTL function registered (nScope: 0=TOP, 1=BOTTOM)
- scopeKeyFromValue: converts Value to padded key bytes
Index Order Management:
- OrderListFocus: handles numeric order ("2" → order 2)
- SET ORDER TO n: gengo emits hbrt.NtoS for int-to-string conversion
- IndexOrd/OrdCount/OrdName/OrdKey: real implementations (were stubs)
- OrderCount/CurrentOrder/OrderName/OrderKeyExpr accessors on DBFArea
- ClearScope on order switch (prevents stale scope)
Cross-read test: Harbour-created CDX → Five reads, 20/20 items match:
NAME/CITY/ID seek, ORDSCOPE count, GoTop/GoBottom all identical
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-06 12:21:26 +09:00
59568f3301
Five v0.9 — Harbour + Go fusion language
...
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-31 09:41:50 +09:00