- PureBasic 100%
Die *Bytes-Map-API (MapGetBytes/MapSetBytes/MapDeleteBytes) hat den Key
IMMER per _HashAndLowerUtf8 case-gefaltet (ASCII 'A'..'Z' -> 'a'..'z',
RFC-7230-Header-Namen). Fuer BINAERE Keys (z.B. 8-Byte QUIC-Stream-IDs)
ist das falsch: Keys die sich nur im Case-Bit unterscheiden kollidieren —
0x44 ('D', Stream 68) faltet auf 0x64 ('d', Stream 100) und liefert beim
Lookup einen Falsch-Treffer auf den fremden (ggf. schon reclaimten) Eintrag.
Fix: neuer Parameter fold.b = #True (Default = bisheriges Verhalten,
quell-/ABI-kompatibel, kein Header-Pfad-Caller muss angefasst werden).
fold=#False nutzt _HashBytesRaw (reiner FNV-1a, KEIN In-Place-Lowercase)
fuer Hash UND Vergleich → binaer-exakte Keys.
Wurzel des H3-Stalls (NETLIB-122 Bug #2): H3_Stream nutzt die Bytes-API mit
8-Byte-Stream-ID-Keys → Stall sobald eine Uppercase-Letter-Stream-ID und ihr
Lowercase-Pendant beide auftreten (~Req 25-32/Conn).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| DATA | ||
| GC_MEM | ||
| GUI | ||
| SYS | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
lhs_lib
Includes entwickelt und erweitert aus bestehenden Sourcen um PureBasic-Funktionalitäten zu erweitern.
Module
SYS/
| Modul | Beschreibung | C-Backend |
|---|---|---|
lhs_log.pbi / lhs_log_ext.pbi |
Logging-Modul (single- bzw. multi-threaded Logger) | nein |
lhs_sys_debug_wrapper.pbi |
Debug-Wrapper für PB-Default-Debug, lhs_log, lhs_log_ext | nein |
lhs_uuid.pbi |
UUID-Generator (v1, v3, v4, v5) | nein |
lhs_arena.pbi |
Arena-Allocator mit case-insensitive HashMap und FlatList — Hot-Path-Performance für Result-Sets, HTTP-Header-Maps, Per-Request-Pools | ja |
lhs_atomic.pbi |
Lock-free Atomics über GCC builtins (CAS, AtomicLoad/Store, Increment/Decrement, Add, Memory-Barriers) | ja |
lhs_lockfree_queue.pbi |
MPMC-bounded Queue (Dmitry-Vyukov-Algorithmus), benötigt lhs_atomic |
ja |
GUI/
| Modul | Beschreibung |
|---|---|
lhs_dialog.pbi |
Erweiterte Dialog-Bausteine |
Tests / Benchmarks
Liegen im separaten Wrapper-Repo lhs_lib_full (lhs_lib selbst eingebunden als Git-Submodule). Enthält:
lhs_arena_bench.pb— Performance-Benchmark gegen PB-Native Map/List mit Realworld-Szenarien (HTTP Lifecycle, Mixed Workload, Concurrent, PPQL Result-Sets, Search-Index, Cookie-Parser, Header-Match)lhs_arena_memprof.pb— Memory-Footprint-Profiler (Peak-RSS, Page-Faults)build_csv.sh— Vergleichstabellen-Generator- Bench-Outputs für verschiedene Hardware (Ryzen, Xeon X5650, …)
Build-Hinweise
Module mit C-Backend-Pflicht (lhs_arena, lhs_atomic, lhs_lockfree_queue) müssen mit dem PureBasic-C-Backend gebaut werden:
pbcompilerc dein_programm.pb --thread --optimizer --executable dein_programm
Das C-Backend ist auf Linux, macOS, Windows und ARM verfügbar. Der ASM-Backend wird für diese Module nicht unterstützt (GCC-builtin-Atomics und Inline-C-Hotpaths sind C-spezifisch).
Programming recommendations in this collection
Debugging
Es empfiehlt sich, SYS/lhs_sys_debug_wrapper.pbi zu verwenden statt direkt Debug:
Initial:
Global LoggerUUID.s = ""
Global Log_Level_Info = 0
Global Log_Level_Debug = 0
Global Log_Level_Error = 2
Im Code:
ldl::Logging("Something on Info Log", LoggerUUID, Log_Level_Info)
Arena (HTTP/PPQL Hot-Path)
Pro Request/Query eine Arena, am Ende Reset (Speicher bleibt für nächsten Cycle wiederverwendbar) oder Destroy:
XIncludeFile "lhs_lib/SYS/lhs_arena.pbi"
Define *arena.lhs_arena::Arena = lhs_arena::Create(65536)
; HashMap mit case-insensitive Key-Vergleich (ideal für HTTP-Header)
Define *headers.lhs_arena::HashMap = lhs_arena::MapCreate(*arena, 32)
lhs_arena::MapSet(*headers, "Content-Type", "text/html")
v.s = lhs_arena::MapGet(*headers, "content-type") ; → "text/html"
; Zero-UTF-Boundary für Bytes direkt aus Socket-Buffer (HTTP-Parser-Pfad)
lhs_arena::MapSetBytes(*headers, *key_ptr, key_len, *val_ptr, val_len)
*vp = lhs_arena::MapGetBytes(*headers, *key_ptr, key_len, @vlen)
lhs_arena::Reset(*arena) ; Alles zurück, Chunks behalten
lhs_arena::Destroy(*arena) ; Alles freigeben
Benchmark-Auszug (Ryzen AI 9 HX 370, 24 Cores) gegen PB-Native bei 100 000 Map-Einträgen:
| Test | PB-Native | Arena | Speedup |
|---|---|---|---|
| Map-Lifecycle (Insert + Lookup + Cleanup) | 269 ms | 27.6 ms | 9.7× |
| Concurrent (1000 Threads × 5k ops, 90% read) | 4.62 s | 102 ms | 45× |
| PPQL Result-Set 50k Rows × 10 Cols | 9.89 s | 69 ms | 143× |
| HTTP Header-Match (500 known, Bytes-API) | 1.4 µs/op | 43 ns/op | 32× |
Details, X5650-Vergleich und Memory-Footprint: siehe tests/.
Lock-Free Queue (MPMC)
XIncludeFile "lhs_lib/SYS/lhs_atomic.pbi"
XIncludeFile "lhs_lib/SYS/lhs_lockfree_queue.pbi"
Define *q = lhs_lockfree_queue::Create(1024) ; Power-of-2 capacity
; Producer (mehrere Threads ok)
lhs_lockfree_queue::Push(*q, *work_item)
; Consumer (mehrere Threads ok)
*item = lhs_lockfree_queue::Pop(*q)
If *item
; arbeiten ...
EndIf
lhs_lockfree_queue::Free(*q)
Autoren
René Linder [Ground0]
Lizenz
Sofern in den Sourcen nicht anders erwähnt gilt:
- LGPL v2.1: https://www.gnu.org/licenses/old-licenses/lgpl-2.1
- Commercial: Für proprietary/closed-source Projekte. Kontakt: info@lihaso.ch
SPDX-License-Identifier: LGPL-2.1-or-later OR Commercial