AYEYA
(Ayeya)
1
问题描述
CSR对象通过CreateXXX手动上树,采用远程 下电持久化,如何去在on_add_object时获取持久化数据?
Model.json:
“Port”: {
“path”: “/bmc/kepler/Switch/:id/Ports/:ID”,
“tableName”: “t_port_attr”,
“tableType”: “PoweroffPer”,
“privilege”: [“ConfigureSelf”],
“interfaces”: {
“bmc.kepler.Switch.Port”: {
“properties”: {
“LogicPortId”: {
“baseType”: “U32”,
“usage”: [ “CSR” ],
“primaryKey”: true
},
“PortName”: {
“baseType”: “String”,
“usage”: [ “CSR” ],
“primaryKey”: true
},
“Enable”: {
“baseType”: “String”,
“usage”: [ “CSR” ]
}
}
}
}
回调处理:
function port_attr_mgmt:add_port_object(obj, position)
local ret, port_obj = constants.RET.RET_OK, nil
base_service:CreatePort(1, obj.LogicPortId, function(object)
object.LogicPortId = obj.LogicPortId
object.PortName = obj.PortName
object.Enable = obj.Enable
end)
table.insert(self.ports_obj, obj)
end
答案内容由AI生成,仅供参考:
六、总结
| 要点 |
说明 |
必须设置主键 |
否则无法匹配数据库中的记录 |
使用预处理回调 |
在 on_add_object 前完成主键赋值 |
不要在预处理中覆盖属性值 |
否则会阻止数据库恢复 |
usage: CSR 属性需被修改才会持久化 |
初始化设置不等于持久化 |
手动上树对象不会自动恢复数据 |
必须依赖 ORM 主键机制自动恢复 |
最终结论:
要使手动上树的 CSR 对象实现远程掉电持久化并在 on_add_object 时获取持久化数据:
- 确保
LogicPortId 和 PortName 在 预处理回调 中正确赋值;
- 不要提前给
Enable 等属性赋值;
- 框架会自动根据主键从
t_port_attr 表恢复数据;
- 首次修改属性后会自动触发持久化写入远程数据库。
这样即可实现“手动创建 + 自动恢复 + 掉电不丢”的完整持久化闭环。
点击此处查看详细分析解答
CSR对象手动上树时的持久化机制与 on_add_object 中获取持久化数据的方法
当通过 CreateXXX 方法手动上树CSR对象,并采用**远程掉电持久化(PoweroffPer)**时,若需在 on_add_object 回调中正确加载已持久化的数据,必须确保系统能够根据对象的主键(Primary Key)从远程数据库中恢复其属性值。以下是基于您提供的配置和代码的详细分析与解决方案。
一、问题核心
“CSR对象手动上树后,如何在 on_add_object 时获取已持久化的属性数据?”
尽管已配置 PoweroffPer 持久化类型、tableName 和主键(primaryKey: true),但由于对象是手动创建(非自发现),系统不会自动执行“从数据库恢复数据”的过程,除非显式触发。
二、关键机制说明
1. usage: CSR 属性的特殊含义
在MDS模型中:
"usage": [ "CSR" ]
表示该属性的初始值来源于CSR文件(配置文件),且 只有在该属性被修改后才会触发持久化写入。
同时,对于 usage: CSR 的表,在系统重启后:
- 仅会加载 CSR 文件中存在的对象的数据到内存数据库(按主键匹配);
- 如果 CSR 中没有配置该对象,则即使数据库中有数据,也不会被加载 → 导致读不到持久化值。
结论:手动创建的对象若不在CSR中配置,则无法通过常规机制加载持久化数据。
2. 手动上树 vs 自发现上树的区别
| 特性 |
自发现上树 |
手动上树(CreateXXX) |
| 对象来源 |
来自CSR或硬件探测 |
代码中显式调用 |
| 属性初始化 |
从CSR解析赋值 |
需手动设置 |
| 持久化恢复 |
自动从数据库按主键恢复 |
不自动恢复 |
| 信号触发 |
触发 on_add_object |
触发 on_add_object |
| 数据恢复时机 |
第7步“从持久化恢复数据到对象” |
无此流程 |
因此,手动上树的对象不会自动执行“从持久化数据库恢复属性”的步骤,需要开发者主动处理。
三、解决方案:在 on_add_object 中主动加载持久化数据
正确做法:使用 ORM 预处理回调 + 主键匹配从数据库加载
修改您的回调函数,利用框架提供的 预处理回调(pre-process callback),在此阶段完成从数据库恢复数据的操作。
修改后的代码建议:
function port_attr_mgmt:add_port_object(obj, position)
local ret, port_obj = constants.RET.RET_OK, nil
-- 使用 CreatePort 并添加预处理回调以恢复持久化数据
base_service:CreatePort(1, obj.LogicPortId,
function(object)
-- ✅ 预处理回调:用于主键赋值(必需!)
object.LogicPortId = obj.LogicPortId
object.PortName = obj.PortName
-- 注意:此处不设置 Enable,让它从数据库恢复
end,
function(object)
-- ✅ 对象添加回调:此时可安全访问已恢复的属性
if object.Enable == nil or object.Enable == "" then
object.Enable = obj.Enable -- 使用默认值回填
end
-- 可在此处进行其他初始化逻辑
self:register_port_signals(object)
end
)
table.insert(self.ports_obj, obj)
end
关键点解释:
1. 预处理回调中必须设置主键属性
object.LogicPortId = obj.LogicPortId
object.PortName = obj.PortName
- 因为这两个字段是
primaryKey: true,框架将用它们作为查询条件去远程数据库查找匹配的记录。
- 若未设置主键 → 无法找到对应数据 → 无法恢复。
2. 属性 Enable 不应在预处理中强制赋值
- 应让其留空,以便 ORM 框架根据主键去数据库查询并自动恢复其值。
- 若数据库中无对应记录,则返回 nil,此时再在
on_add_object 回调中设置默认值。
3. 持久化生效前提是属性曾被修改过
根据文档:
- 对于
usage: CSR 的属性,只有业务代码显式修改过该属性值后,才会写入持久化数据库。
- 初始值来自 CSR 或手动设置,不自动持久化。
建议:在首次设置 Enable 时,使用 object.Enable = "enabled" 并确保后续有保存操作(如重启、触发 on_need_save)。
四、确保远程持久化正确工作
1. 配置检查清单
| 检查项 |
是否满足 |
tableName 已定义 |
 |
tableType: PoweroffPer |
 |
两个主键字段都标注 primaryKey: true |
 |
主键字段在 on_add_object 前已赋值 |
(预处理回调中) |
| 属性修改后触发了持久化机制 |
(通过 ORM 自动跟踪变更) |
2. 数据库写入触发机制
当对象属性发生变更时:
属性修改 → 触发 on_need_save 信号 → ORM 通知 persistence 服务 → 通过 RPC 写入远程数据库
- 无需手动调用 save。
- 但需保证对象所属组件正常运行且网络通信正常。
3. 排查持久化失败常见原因
| 问题 |
排查方法 |
| 重启后数据丢失 |
检查是否执行了 datafs_reset(查 kernel log) |
| 数据库未写入 |
检查是否修改过属性值(只读不改不持久化) |
| 主键冲突 |
多个对象使用相同主键组合 → 数据相互覆盖 |
| CSR 配置缺失 |
usage: CSR 对象若不在 CSR 中 → 不加载数据库数据 |
五、验证方法
1. 查看资源树是否存在对象
busctl --user tree bmc.kepler.Switch
2. 检查数据库中是否有数据
sqlite3 /data/persistence/per_poweroff.db "select * from t_port_attr;"
3. 注入代码查看内存数据
inject hardware /path/to/debug.lua
在脚本中打印 object:get_properties() 查看是否恢复成功。
六、总结
| 要点 |
说明 |
必须设置主键 |
否则无法匹配数据库中的记录 |
使用预处理回调 |
在 on_add_object 前完成主键赋值 |
不要在预处理中覆盖属性值 |
否则会阻止数据库恢复 |
usage: CSR 属性需被修改才会持久化 |
初始化设置不等于持久化 |
手动上树对象不会自动恢复数据 |
必须依赖 ORM 主键机制自动恢复 |
最终结论:
要使手动上树的 CSR 对象实现远程掉电持久化并在 on_add_object 时获取持久化数据:
- 确保
LogicPortId 和 PortName 在 预处理回调 中正确赋值;
- 不要提前给
Enable 等属性赋值;
- 框架会自动根据主键从
t_port_attr 表恢复数据;
- 首次修改属性后会自动触发持久化写入远程数据库。
这样即可实现“手动创建 + 自动恢复 + 掉电不丢”的完整持久化闭环。
如果你是指添加对象时使用持久化数据的话,当前应用框架的能力会在添加对象时候自动去获取持久化数据的
AYEYA
(Ayeya)
5
手动上树的对象,如果通过busctl将属性值更改,会自动触发持久化吗?
而且你这既然是自发现对象,你再调CreateXXX方法会造成你实际上有两个对象
AYEYA
(Ayeya)
9
我目前是通过’mc.mdb.object_manage’去注册添加对象的回调, 在object_manage.on_add_object(self.bus, function(class_name, object, position)
self.lsw.lsw_cfg_mgmt:on_add_object(class_name, object, position)
end,
function(object)
return false
end)
第三个参数返回false,会取消CSR自动上树,
我们采用手动上树主要是因为"path": "/bmc/kepler/Switch/:id/Ports/:ID"我们的资源树路径这里的动态参数,CSR自动上树的话会填充成比如:/bmc/kepler/Switch/Port_1_01010B/Ports/Port_1_01010B
但我们其实是期望资源树路径为:/bmc/kepler/Switch/1/Ports/1,后面的ID自定义为端口的id
那你可以直接修改on_add_object获取的object的path,你这样手动创建的对象connector置为不在位之后应该是不会卸载的吧