Repository navigation
fix: FakeFish pitfalls — mysql callbacks, JIT const, json arrays, pool lease, net send - #20
Merged
Merged
Conversation
…ease, net send
Fixes the 8 issues found by the FakeFish project (fakelua-pitfalls):
- P0-1: mysql callbacks now accept inline closures (VarClosure*) in
addition to global function names; invalid callback types throw a
loud "bad argument" instead of being silently dropped by
CVarToString("").
- P0-2: all early-return paths in Query/StmtPrepare/StmtExecute now
fire the callback with an error. Contract: every conn:query() call
results in exactly one callback.
- P1-3: file-level numeric locals with reassignment points are no
longer emitted as C const (which broke JIT compilation with
"cannot assign to variable with const-qualified type"). Never-
reassigned file constants keep the const optimization.
- P1-4: in-flight query on the same connection is queued instead of
erroring; new pool:with(fn) lease API auto-returns the connection
even when fn throws.
- P1-5: json.encode({}) now produces [] (pure-array heuristic);
new json.encode_array() for strict array-shaped encoding.
- P1-6: sends issued inside dispatch callbacks are queued and pumped
by the tick after dispatch completes; send failures log WARN.
- P2-7: result rows convert values by column type (int/float columns
return numbers instead of strings); result table layout documented.
- P2-8: tick pump order and callback-context rules documented in
native READMEs (zh/en), incl. the allowed/forbidden operation matrix.
exception.const_reassign test updated: it asserted the P1-3 bug
(compile failure); now expects successful compilation per the new
semantics. New regression tests for all the above.
Runtime values sit on the temporary arena, which State::Reset() clears at each top-level Call, so a raw VarClosure* stored for a later tick was dangling. Callbacks are now copied onto the const arena, which lives with the State. Also document the json.encode({}) break, DECIMAL precision loss, and InDispatch, and cover pool:with throw plus numeric column conversion.
Co-authored-by: Cursor <cursoragent@cursor.com>
A file-level numeric literal stays static const, and assigning it from a user function is a compile error with a source location. local x = func() is unchanged: the declaration is lowered to nil and __fakelua_init assigns it once. Co-authored-by: Cursor <cursoragent@cursor.com>
… close-error contract PR20 changed mysql result rows to convert by column type (integer columns return numbers) and changed conn:query on a closed connection to deliver the error via callback instead of throwing. The C++ unit tests and README were updated, but seven legacy Lua integration scripts still asserted the old string values / pcall behavior, failing the Build pipeline (debug, release, cov). - stmt/multi_result/pool/query_error/datatypes/stmt_params: compare integer columns against numbers instead of strings - lifecycle: expect the closed-connection query error through the result callback after runtime.tick(), not a synchronous pcall error
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #20 +/- ##
==========================================
+ Coverage 87.80% 87.93% +0.12%
==========================================
Files 119 122 +3
Lines 24042 24363 +321
==========================================
+ Hits 21110 21423 +313
- Misses 2932 2940 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…alized bound args
Inline closures cannot be held safely across ticks: runtime values live on
the temporary arena that every top-level Call resets, and pinning closure
graphs into the const arena made that arena grow for the whole State
lifetime (no GC).
Async mysql callbacks (connect/query/stmt_prepare/stmt_execute) now accept
only an in-package global function name, optionally followed by pure-data
bound arguments:
conn:query(sql, "on_result", tag, ctx_table)
-> on_result(conn, err, result, tag, ctx_table)
Bound args are encoded at registration into a self-owned byte blob using
the existing serialize wire format (new internal wire_codec module shared
with serialize.encode/decode; the Lua wire format is unchanged), survive
any number of arena Resets, and are decoded in the dispatch frame and
appended after the fixed callback arguments. The blob is released when
the query completes or the connection is destroyed, so memory tracks
in-flight queries instead of growing the const arena.
Non-serializable values (closures, native objects) anywhere in bound args
raise bad argument instead of being silently dropped. pool:with still
takes an inline closure since it invokes fn synchronously in-frame.
- remove arena_pin.{h,cpp} (const-arena closure deep copy)
- extract wire codec from native_serialize into reusable wire_codec
- update contract tests/README; cross-frame test driven on TCC only
(named callbacks dispatch to the TCC artifact, file-level locals are
per-engine statics and not shared across CallAll's engines)
… pinned TCC Named mysql callbacks were always resolved through the TCC artifact, so a callback registered from GCC/interpreter code executed TCC machine code. With CallAll exercising all engines on one State, per-engine file-level statics written by callbacks were not visible to the registering engine. Track the currently executing engine on the State and propagate it through every Lua->C++ invocation boundary: - State holds current_jit_ with a C++ JitContextScope RAII and C-compatible getter/setter (TCC compiles generated code as C, cannot use C++ scopes) - CallByNameImpl (native function dispatch), DispatchCall (Lua function / closure dispatch from C++) and the FlCallClosure case ladder (direct closure calls from JIT C code, incl. the native object method bridge) push/restore the caller engine via FakeluaJitContextPush/Pop - ResultCallback records the engine at registration; InvokeCallback resolves and calls the function in that same engine (fallback to other engines only if its artifact is missing) - pool:with invokes its synchronous fn closure with the current engine This restores the same per-engine closure semantics as inline closures; the cross-frame contract test runs under CallAll again. All 1551 tests pass (excluding local-redis test_redis).
…dead code, and optimize json array check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
FakeFish(fakelua 的真实项目方)在实战中发现 8 个问题,文档见 fakefish 仓库
docs/fakelua-pitfalls.md。本 PR 逐一修复。修复清单
P0-1
conn:query回调与绑定参数跨帧持久化(重大重构)"Module.on_result"),可选携带绑定参数(bound args)。WireEncodeCallbackArgs)封存入堆内存;回调派发时精确反序列化还原,不受顶层 Call 之间 arena 重置影响。current_jit_与JitContextScope),回调派发自动路由回发起调用时的对应引擎(TCC/GCC/解释器),保证文件级状态可见性一致。bad argument,不再静默丢弃。P0-2 查询失败时部分错误路径完全没有回调
Query/StmtPrepare/StmtExecute的所有提前 return 路径统一设置错误并派发回调。Close()时,排队但未执行的 query 统一触发错误回调清空队列(DrainQueryQueue())。P1-3 模块级常量(
const)赋值语义修复与严谨报错const语义:文件级数值常量在编译期严格禁止二次赋值。constant reassignment is not allowed),拒绝静默生成不可预期的 C 代码。P1-4 连接池租约语义与异步查询安全归还
pool:with(fn)租约 API:fn(conn),采用 RAIILeaseGuard管理生命周期。fn内部发起了异步 query,在fn退出时若仍有在途/排队任务,延迟归还并标记__mysql_auto_release__;待本连接所有在途 query 派发完毕后自动归还回池。P1-5
json.encode空 table 产出[]与encode_array优化[];非空仍要求 1..N 连续整数键。json.encode_array()严格通道:非数组形 table 直接报错;重构提取公共校验逻辑,避免双重遍历。spec_bytes,spec_cvars)与无用 arena 函数(HeapAllocator::Contains)。P1-6 回调上下文多重静默限制
IoContext::InDispatch())中的send改为入队、由本轮 tick 派发完后统一泵出(事件驱动改轮询驱动),消除平台相关的静默丢弃;发送失败记录 WARN 日志。P2-7 MySQL 结果值全为字符串、格式未文档化
P2-8 tick 泵序与嵌套回调延迟规范
测试验证
test_mysql.pool_with_lease_apitest_mysql.pool_with_fn_throw_returns_connectiontest_mysql.pool_with_async_query_auto_releasetest_mysql.bad_callback_type_throwstest_mysql.closure_callback_survives_frame_resettest_json.encode_empty_table_as_arraytest_json.encode_array_strictinfer.test_global_const*/exception.const_reassign兼容性说明
json.encode({})行为从"{}"变为"[]";需要空对象的场景请使用带字符串键的表。tonumber(v)原样返回,平滑兼容。