所有重要的项目变更都将记录在此文件中。
- 核心功能: 提供动态字段修改能力,支持运行时添加/删除/修改数据字段
- 新增
BasicDataAdapter类,继承自DataAdapter - 支持多种数据类型:string, double, int, int64_t, bool, monostate (nil)
- 提供字段修改 API:
set(key, value): 添加或修改字段(支持多种类型重载)set_null(key): 将字段设置为 nilremove(key): 删除指定字段clear_fields(): 清空所有字段
- 支持字段覆盖:多次调用 set() 会覆盖之前的值
- 自动去重:使用 unordered_map 存储字段,自动处理重复键
- 新增
- 实现细节:
- 使用
std::variant存储多种类型的字段值 push_to_lua(): 创建空 Lua tableexecute_commands(): 将字段设置到 Lua table(由引擎调用)- 空键检查:拒绝空键,防止 Lua 错误
- 使用
- 集成:
JsonAdapter继承BasicDataAdapter,获得字段修改能力- 用户自定义适配器可以继承
BasicDataAdapter获得字段修改功能
- 测试覆盖: 新增 28 个 BasicDataAdapter 测试用例
- Set 方法测试(7个)
- set_null/remove/clear_fields 测试(3个)
- 字段覆盖测试(2个)
- 边界情况测试(4个)
- JsonAdapter 字段修改测试(15个)
- 总测试数量: 从 196 个增加到 224 个 rule_engine_test 测试用例
- 核心功能: 基于 adapter ID 的缓存机制,提升重复匹配性能
- 使用
std::atomic<uint64_t>生成唯一 adapter ID - 使用
std::weak_ptr检测 adapter 生命周期 - 使用
luaL_ref/lua_rawgeti在 Lua registry 中缓存转换后的 table - 支持两种缓存清理策略:Never(永不清理)和 Aggressive(积极清理)
- 使用
- 性能优化:
- 同一 adapter 多次匹配时,直接从缓存获取 table,避免重复转换
- weak_ptr 自动检测 adapter 是否被释放,释放后自动清理缓存
- 大幅提升重复匹配场景的性能(2-10x 提升)
- 实现细节:
match_rule()执行流程:- 检查 adapter ID 是否在缓存中
- 检查 weak_ptr 是否还有效
- 如果有效,直接从 Lua registry 获取缓存的 table
- 如果无效,清理过期缓存,重新转换并缓存
- 调用 execute_commands() 应用字段修改
execute_commands()由BasicDataAdapter实现,应用 set/remove/clear_fields 操作
- 测试覆盖: 新增 5 个缓存生命周期测试
- Adapter 销毁后缓存自动清理
- 多个 adapter 独立缓存
- weak_ptr 过期检测
- Aggressive 清理策略
- API 变更:
match_rule()现在接受std::shared_ptr<DataAdapter>而非引用match_all_rules()现在接受std::shared_ptr<DataAdapter>而非引用- 所有使用 adapter 的地方都需要使用
std::make_shared<JsonAdapter>(data)
- 核心功能: 提供线程安全的规则引擎访问,支持热更新
- 新增
RuleEngineWrapper类,封装多线程访问逻辑 - 使用 Copy-on-Write 模式:shared_ptr + 原子操作
- Thread-Local Storage:每个线程维护独立的引擎副本
- Versioning:通过版本号判断是否需要重新克隆
- Shared Ownership:使用 shared_ptr 确保旧引擎在被使用时不会被销毁
- 新增
- API 设计:
set_template_engine(std::shared_ptr<RuleEngine>): 设置模板引擎(线程安全)get_engine(): 获取线程本地引擎,返回shared_ptr<const RuleEngine>get_version(): 获取当前全局版本号
- Const 正确性:
- 返回
shared_ptr<const RuleEngine>,只能调用 const 方法 - 防止调用配置方法(add_rule, register_function 等)
- 允许调用查询方法(match_rule, has_rule, get_rule_count 等)
- 返回
- 使用场景:
- 多线程服务(如 brpc):每个请求线程安全访问引擎
- 支持热更新:无需重启服务,运行时更新规则配置
- 引擎本身非线程安全,通过包装器实现线程安全
- shared_ptr 安全性:
- 旧引擎的 shared_ptr 在热更新后仍然有效
- 自动管理生命周期,所有引用释放后自动销毁
- 不会出现悬空指针或内存泄漏
- 性能特性:
- 首次调用 get_engine() 需要克隆模板引擎(开销较大)
- 后续调用直接返回 shared_ptr 拷贝(开销极小,< 1 微秒)
- 热更新后,各线程下次调用时自动克隆新版本
- 测试覆盖: 新增 15 个包装器测试用例
- 基础功能测试(4个)
- shared_ptr 安全性测试(2个)
- 热更新测试(2个,包含并发场景)
- 线程本地存储测试(2个)
- 并发压力测试(2个)
- 边界情况测试(2个)
- 性能测试(1个)
- 总测试数量: 从 325 个增加到 340 个测试用例(+15个)
- 文档更新:
- 在 README.md 中添加 "RuleEngineWrapper" 章节
- 包含完整的 API 使用示例和多线程场景说明
- 在 ARCHITECTURE.md 中更新分层架构图
- 在 TESTING.md 中添加包装器测试分类
- 在 CHANGELOG.md 中记录此重要新增功能
- 核心功能: 支持规则引擎克隆,可选择性复制规则、Lua 文件、C++ 函数
- 新增
clone()方法,支持通过CloneOption枚举选择性克隆 CloneOption枚举:NONE, LUA_FILES, CPP_FUNCTIONS, CPP_MEMBER_FUNCTIONS, RULES, ALL- 支持按位或组合多个选项(如
RULES | LUA_FILES) - 便捷方法:
clone_rules(),clone_lua_files(),clone_cpp_functions(),clone_safe()
- 新增
- 克隆独立性:
- 克隆的引擎拥有独立的 Lua 状态
- 修改克隆引擎不影响原引擎
- C++ 成员函数使用相同的实例指针
- 使用场景:
- 多线程环境:每个线程使用独立的克隆引擎
- 批量处理隔离:为每个批次创建独立引擎
- 测试和调试:克隆引擎用于测试,不影响生产环境
- 测试覆盖: 新增 43 个克隆功能测试用例
- 基本克隆测试(6个:NONE, RULES, LUA_FILES, CPP_FUNCTIONS, CPP_MEMBER_FUNCTIONS, ALL)
- 便捷方法测试(4个)
- 组合选项测试(3个)
- 错误处理测试(2个)
- 独立性测试(3个)
- 多次克隆测试(2个)
- 边界情况测试(5个)
- 复杂场景测试(7个)
- 功能验证测试(11个)
- 总测试数量: 从 282 个增加到 325 个测试用例(+43个)
- rule_engine_test: 从 143 个增加到 186 个测试用例
- 文档更新:
- 在 README.md 中添加 "引擎克隆" 章节
- 包含完整的 API 使用示例
- 提供多种使用场景说明
- 在 ARCHITECTURE.md 和 TESTING.md 中更新相关内容
- 异常处理测试: 新增 7 个 C++ 异常处理相关测试用例
- C++ 函数抛出异常的演示测试(使用 pcall 捕获)
- C++ 函数抛出异常测试(不使用 pcall,验证 match_rule 失败)
- C++ 函数安全捕获异常测试(3个场景:正常输入、负数、缺少参数)
- 类成员函数异常处理测试
- 异常处理最佳实践测试
- 直接调用(不使用 pcall)测试
- 多函数异常处理测试
- 重要发现: LuaJIT 可以捕获 C++ 异常,程序不会崩溃!
- 通过实际测试验证:注册的 C++ 函数抛出异常不会导致程序崩溃
- LuaJIT 将 C++ 异常转换为简短的错误信息
"C++ exception" - 使用 pcall 和不使用 pcall 的行为差异已文档化
- 文档更新: 在 README.md 和 ARCHITECTURE.md 中添加详细的异常处理说明
- 说明 LuaJIT 可以安全捕获 C++ 异常
- 提供两种场景(使用/不使用 pcall)的详细对比
- 强调虽然安全,但错误信息会丢失
- 提供正确的异常捕获和转换示例
- 添加异常处理流程对比表
- 包含完整的最佳实践指南
- 总测试数量: 从 266 个增加到 273 个测试用例(+7个)
- rule_engine_test: 从 127 个增加到 134 个测试用例
- 核心功能: 支持加载 Lua 公共函数文件,方便业务逻辑快速迭代
- 新增
RuleEngine::add_lua_file()方法 - 用户可以在 Lua 文件中自由定义全局变量和函数
- 支持自定义命名空间(utils, validators, helpers 等)
- 支持加载多个文件,后加载的文件会覆盖同名变量
- 支持与 C++ 注册函数混合使用
- 新增
- 测试覆盖: 新增 9 个 Lua 公共函数加载测试用例
- utils 命名空间测试(3个场景)
- 多命名空间测试(validators + helpers)
- 全局函数测试
- 与 C++ 函数混合使用测试
- 错误处理测试(文件不存在、语法错误、运行时错误)
- 覆盖已存在函数测试
- 总测试数量: 从 273 个增加到 282 个测试用例(+9个)
- rule_engine_test: 从 134 个增加到 143 个测试用例
- 文档更新:
- 在 README.md 中添加 "Lua 公共函数加载" 章节
- 包含完整的 API 使用示例
- 提供多个命名空间的使用示例
- 说明注意事项和最佳实践
- 在 ARCHITECTURE.md 和 TESTING.md 中更新相关内容
- 问题修复: 修复了
call_match_function中所有错误返回路径未设置result字段的问题- 规则函数表不存在:现在设置
result.matched = false和result.message - 规则函数不存在:现在设置
result.matched = false和result.message - 数据适配器失败:现在设置
result.matched = false和result.message - Lua pcall 失败(包括 C++ 异常):现在设置
result.matched = false和result.message - 返回值类型错误:现在设置
result.matched = false和result.message
- 规则函数表不存在:现在设置
- 错误信息同步: 所有错误路径同时设置
result.message和error_msg参数,保持一致 - 格式统一: lua_pcall 失败的错误信息使用
"Failed to call match: "前缀,与批量匹配版本保持一致 - 改进效果:
- 调用者可以通过
result.message获取详细错误信息,即使match_rule()返回false - 提升了调试体验和错误追踪能力
- 确保
result.matched始终正确反映匹配状态
- 调用者可以通过
- 函数注册机制: 支持将 C++ 函数注册到 Lua 的全局
ljre命名空间- 注册普通 C++ 函数到 Lua
- 注册类成员函数到 Lua(通过静态分发器模式)
- 使用
lua_pushcclosure和lua_pushlightuserdata实现 - 所有注册函数存储在全局
ljre表中,避免命名空间污染
- 函数管理功能:
register_function(): 注册函数(支持普通函数和类成员函数)unregister_function(): 注销指定函数clear_registered_functions(): 清空所有已注册函数has_function(): 检查函数是否已注册get_registered_functions(): 获取所有已注册函数名列表
- 函数在规则中使用:
- Lua 规则可通过
ljre.function_name()调用注册的 C++ 函数 - 支持无返回值、单返回值、多返回值的 C++ 函数
- 支持在规则中调用多个注册函数
- 函数在规则热更新后保持有效(持久化)
- 支持错误处理和栈平衡管理
- Lua 规则可通过
- 测试数量: 新增 30 个函数注册相关测试用例
- 普通 C++ 函数注册测试(2个)
- 类成员函数注册测试(3个)
- 函数管理测试(4个)
- 函数在规则中使用测试(6个)
- 多函数协同测试(3个)
- 错误处理和边界情况测试(6个)
- 无效状态下的函数操作测试(6个)
- 总测试数量: 从 236 个增加到 266 个测试用例(+30个)
- rule_engine_test: 从 103 个增加到 127 个测试用例
- match_all_rules 边界情况测试: 新增 7 个测试用例
- push_to_lua 失败场景测试
- 函数表不存在场景测试
- 函数不存在场景测试
- 第一个返回值不是布尔值场景测试
- 第二个返回值不是字符串场景测试(使用空消息)
- 混合错误场景测试
- 只有错误场景测试
- 总测试数量: 从 228 个增加到 236 个测试用例
- 精确类型检查: 使用
lua_type()代替lua_isstring()- 修复
lua_isstring()对数字返回true的问题(因为 Lua 会自动转换数字为字符串) - 现在只有精确的
LUA_TSTRING类型才会被当作字符串处理 - 数字、nil 等类型不再被误判为字符串
- 修复
- 统一行为:
match_all_rules和match_rule的返回值处理逻辑完全一致- 当第二个返回值不是字符串时,message 字段为空字符串
- 不再使用默认消息 "Matched" 或 "Not matched"
- 更新
MatchAllRules_SecondReturnNotString测试用例- 测试名称改为
MatchAllRules_SecondReturnNotString_UsesEmptyMessage - 验证 message 为空字符串而非包含 "Matched"
- 测试名称改为
- 所有 236 个测试用例全部通过
- 更新 README.md:
- 更新
match函数返回值说明 - 明确第二个返回值必须是精确的 string 类型
- 更新注意事项,说明非字符串类型的处理方式
- 更新
- 更新 ARCHITECTURE.md:
- 更新返回值说明
- 添加类型检查细节
- 更新 CHANGELOG.md:
- 记录类型检查优化
- 记录测试用例增加
- JIT 动态控制: 新增 JIT 编译器的运行时控制功能
enable_jit(): 启用 JIT 编译引擎disable_jit(): 禁用 JIT 编译引擎,切换到解释模式flush_jit(): 刷新 JIT 编译器缓存,清除已编译的代码
- 支持 LuaJIT jit 库的自动加载
- JIT 控制方法支持无效 Lua 状态检测(返回 false)
- 最大嵌套深度控制: 防止深度嵌套 JSON 导致栈溢出和性能问题
- 默认最大深度: 8192 层
- 可通过构造函数参数和
set_max_nesting_depth()方法配置 - 深度限制范围: [1, 8192]
- 超过深度限制时自动截断子元素为 nil
- 深度限制验证:
set_max_nesting_depth()自动限制在有效范围内- 超过最大值时限制为 8192
- 小于最小值时限制为 1
- LuaState 测试: 52 个测试用例
- JIT 控制相关测试(enable/disable/flush)
- 错误处理测试(覆盖栈顶非字符串场景)
- JsonAdapter 测试: 从 35 个增加到 55 个测试用例(+20个)
- 深度嵌套限制测试(9个测试用例)
- 默认深度值测试(MAX_NESTING_DEPTH = 8192)
- 深度设置和边界测试(最小值 1,最大值 8192)
- 深度超限截断测试(对象和数组)
- 浅层嵌套完整转换测试
- 深层数组嵌套截断测试
- 异常处理测试(自定义 ExceptionThrowingDataAdapter)
- 边界条件测试(深度嵌套、大量数据、混合类型)
- 完整覆盖异常捕获和错误传播路径
- 深度嵌套限制测试(9个测试用例)
- RuleEngine 测试: 从 43 个增加到 89 个测试用例(+46个)
- JIT 控制测试(11个测试用例)
- enable_jit/disable_jit/flush_jit 功能测试
- JIT 状态切换测试(多次切换)
- JIT 性能影响测试(验证结果一致性)
- 多规则 JIT 控制测试
- 无效 Lua 状态下的 JIT 控制测试(3个)
- Lua 状态无效场景测试
- 完整覆盖 call_match_function 所有错误路径
- 规则配置文件边界条件测试
- JIT 控制测试(11个测试用例)
- Integration 测试: 从 11 个增加到 15 个测试用例(+4个)
- 深度嵌套限制集成测试(4个)
- 深层对象嵌套截断测试
- 深层数组嵌套截断测试
- 安全访问模式测试(and 短路、pcall、逐层检查)
- 深度限制下的规则执行测试
- 深度嵌套限制集成测试(4个)
- 总测试数量: 从 138 个增加到 228 个测试用例(+65%)
- 移除
Rule和RuleInfo结构体中不必要的loaded成员- 规则在 map 中存在即表示已加载,简化状态管理
- 减少了不必要的复杂度
- 完善了
LuaState::get_error_string()对各种栈顶类型的处理- 正确处理 table、boolean、nil、function、userdata、thread 等非字符串类型
- 栈顶非字符串时返回 "Unknown error" 且不弹出栈元素
- JIT 控制方法在无效 Lua 状态下返回 false,而不是崩溃
- 深度嵌套 JSON 处理性能大幅提升
- 10000 层嵌套:从 10+ 秒优化到微秒级(超限时截断)
- 50000 层嵌套:从崩溃优化到正常处理(超限时截断)
- 默认支持 8192 层完整转换
- 最新性能测试结果(2026-01-12):
- 简单规则:LuaJIT 1.04 μs vs Native 0.36 μs(2.85x 慢)
- 中等规则:LuaJIT 4.54 μs vs Native 7.82 μs(快 1.72x) ✅
- 复杂规则:LuaJIT 20.57 μs vs Native 18.48 μs(1.11x 慢)
- 超复杂规则:LuaJIT 92.63 μs vs Native 26.38 μs(3.51x 慢)
- JIT 启用后性能提升 4.5%(1.20 μs → 1.18 μs)
- 关键发现:中等复杂度规则性能优于 Native 实现,这是 LuaJIT 的最佳应用场景
- 新增
ExceptionThrowingDataAdapter用于测试异常处理路径 - 新增
RuleEngineInternalTest测试子类,支持访问内部 Lua 状态 - 新增
RuleEngineInvalidStateTest测试子类,支持模拟无效 Lua 状态 - 新增
RuleEngineWithInvalidState测试辅助类,用于测试无效状态下的 JIT 控制
- 更新 README.md:
- 反映最新的测试用例数量(228 个)
- 更新特性列表,添加深度嵌套限制和 JIT 控制功能
- 详细列出各测试文件的测试类别,包括新增的深度限制和 JIT 控制测试
- 更新性能测试结果(2026-01-12)
- 中等规则:从"1.01x 慢"更新为"快 1.72x"
- 复杂规则:从"2.88x 慢"更新为"1.11x 慢"
- 超复杂规则:从"11.61x 慢"更新为"3.51x 慢"
- 简单规则:从"4.86x 慢"更新为"2.85x 慢"
- 更新 TESTING.md:
- 更新测试统计表格(228 个测试用例)
- 详细说明各测试模块的覆盖范围
- 添加深度嵌套限制测试分类
- 添加 JIT 控制测试分类
- 更新 ARCHITECTURE.md:
- 更新测试数量(228 个)
- 更新测试覆盖表格
- 更新 CHANGELOG.md:
- 记录所有重要变更
- 添加最新性能测试结果
- ✅ 构造和析构:移动语义、自我赋值
- ✅ 文件加载:成功/失败/语法错误/运行时错误
- ✅ Buffer 加载:各种代码格式和大小
- ✅ 错误处理:栈顶各种类型(string、number、table、boolean、nil、function、userdata、thread)
- ✅ 栈操作:栈平衡检查
- ✅ 安全性:禁用 io 库、状态独立性
- ✅ 边界条件:零大小、超大代码、Unicode 路径
- ✅ JIT 控制:enable/disable/flush 及各种组合场景
- ✅ 基本功能:栈恢复、多次 push/pop
- ✅ 嵌套场景:多层守卫嵌套
- ✅ Release 机制:手动释放、多次调用
- ✅ 空栈处理:栈为空时的行为
- ✅ 函数调用场景:实际使用模式
- ✅ 表迭代场景:遍历表时的栈管理
- ✅ 错误处理:异常情况下的栈恢复
- ✅ 基本类型:null、boolean、integer、float、string
- ✅ 数组转换:空数组、嵌套数组、大数组、混合类型
- ✅ 对象转换:空对象、嵌套对象、大量键、特殊键
- ✅ 特殊字符:含空字符字符串、Unicode 字符、特殊字符键
- ✅ 异常处理:标准异常捕获、错误消息生成、无 error_msg 场景
- ✅ 边界条件:深度嵌套(500+ 层)、1000 个键的大对象
- ✅ 栈平衡:成功和失败时的栈平衡保证
- ✅ 规则管理:添加、移除、重载、清空规则
- ✅ 配置加载:从配置文件加载规则列表
- ✅ 规则匹配:单个规则匹配、所有规则匹配
- ✅ 错误场景:无效状态、规则不存在、规则函数表不存在、match 函数不存在
- ✅ 返回值验证:非布尔返回值、单返回值
- ✅ 数据适配器:push_to_lua 失败场景
- ✅ 边界条件:空配置、重复规则、无效字段
- ✅ 端到端工作流:完整的规则引擎使用流程
- ✅ 用户注册验证:实际业务场景模拟
- ✅ 规则动态管理:运行时添加/删除规则
- ✅ 多引擎独立:多个引擎实例互不干扰
- ✅ 复杂数据结构:嵌套对象和数组
- ✅ 大数据集处理:大量规则和数据
无
无
无
无安全相关问题修复
无
如果你是从之前的版本升级,请注意以下变更:
-
规则结构变更:
RuleInfo结构体不再包含loaded字段- 规则引擎内部也不再跟踪
loaded状态 - 这不影响公共 API,仅影响内部实现
-
JIT 功能:
- LuaState 现在会自动加载 jit 库
- 可以通过
enable_jit()/disable_jit()动态控制 JIT - 默认情况下 JIT 是启用的
-
测试要求:
- 所有新增测试必须通过
- 代码覆盖率要求 ≥85%
本项目遵循语义化版本 (Semantic Versioning) 规范:
- 主版本号: 不兼容的 API 修改
- 次版本号: 向下兼容的功能性新增
- 修订号: 向下兼容的问题修正