CSR对象手动上树,如何持久化?

问题描述

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生成,仅供参考:

六、总结

要点 说明
:white_check_mark: 必须设置主键 否则无法匹配数据库中的记录
:white_check_mark: 使用预处理回调 on_add_object 前完成主键赋值
:warning: 不要在预处理中覆盖属性值 否则会阻止数据库恢复
:warning: usage: CSR 属性需被修改才会持久化 初始化设置不等于持久化
:light_bulb: 手动上树对象不会自动恢复数据 必须依赖 ORM 主键机制自动恢复

:white_check_mark: 最终结论:

要使手动上树的 CSR 对象实现远程掉电持久化并在 on_add_object 时获取持久化数据:

  1. 确保 LogicPortIdPortName预处理回调 中正确赋值;
  2. 不要提前给 Enable 等属性赋值;
  3. 框架会自动根据主键从 t_port_attr 表恢复数据;
  4. 首次修改属性后会自动触发持久化写入远程数据库。

这样即可实现“手动创建 + 自动恢复 + 掉电不丢”的完整持久化闭环。

点击此处查看详细分析解答

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 中没有配置该对象,则即使数据库中有数据,也不会被加载 → 导致读不到持久化值

:white_check_mark: 结论:手动创建的对象若不在CSR中配置,则无法通过常规机制加载持久化数据。


2. 手动上树 vs 自发现上树的区别

特性 自发现上树 手动上树(CreateXXX)
对象来源 来自CSR或硬件探测 代码中显式调用
属性初始化 从CSR解析赋值 需手动设置
持久化恢复 自动从数据库按主键恢复 :cross_mark: 不自动恢复
信号触发 触发 on_add_object 触发 on_add_object
数据恢复时机 第7步“从持久化恢复数据到对象” :cross_mark: 无此流程

因此,手动上树的对象不会自动执行“从持久化数据库恢复属性”的步骤,需要开发者主动处理。


三、解决方案:在 on_add_object 中主动加载持久化数据

:white_check_mark: 正确做法:使用 ORM 预处理回调 + 主键匹配从数据库加载

修改您的回调函数,利用框架提供的 预处理回调(pre-process callback),在此阶段完成从数据库恢复数据的操作。

:check_mark: 修改后的代码建议:

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

:magnifying_glass_tilted_left: 关键点解释:

1. 预处理回调中必须设置主键属性

object.LogicPortId = obj.LogicPortId
object.PortName = obj.PortName
  • 因为这两个字段是 primaryKey: true,框架将用它们作为查询条件去远程数据库查找匹配的记录。
  • 若未设置主键 → 无法找到对应数据 → 无法恢复。

2. 属性 Enable 不应在预处理中强制赋值

  • 应让其留空,以便 ORM 框架根据主键去数据库查询并自动恢复其值。
  • 若数据库中无对应记录,则返回 nil,此时再在 on_add_object 回调中设置默认值。

3. 持久化生效前提是属性曾被修改过

根据文档:

  • 对于 usage: CSR 的属性,只有业务代码显式修改过该属性值后,才会写入持久化数据库
  • 初始值来自 CSR 或手动设置,不自动持久化。

:white_check_mark: 建议:在首次设置 Enable 时,使用 object.Enable = "enabled" 并确保后续有保存操作(如重启、触发 on_need_save)。


四、确保远程持久化正确工作

1. 配置检查清单

检查项 是否满足
tableName 已定义 :white_check_mark:
tableType: PoweroffPer :white_check_mark:
两个主键字段都标注 primaryKey: true :white_check_mark:
主键字段在 on_add_object 前已赋值 :white_check_mark:(预处理回调中)
属性修改后触发了持久化机制 :white_check_mark:(通过 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() 查看是否恢复成功。


六、总结

要点 说明
:white_check_mark: 必须设置主键 否则无法匹配数据库中的记录
:white_check_mark: 使用预处理回调 on_add_object 前完成主键赋值
:warning: 不要在预处理中覆盖属性值 否则会阻止数据库恢复
:warning: usage: CSR 属性需被修改才会持久化 初始化设置不等于持久化
:light_bulb: 手动上树对象不会自动恢复数据 必须依赖 ORM 主键机制自动恢复

:white_check_mark: 最终结论:

要使手动上树的 CSR 对象实现远程掉电持久化并在 on_add_object 时获取持久化数据:

  1. 确保 LogicPortIdPortName预处理回调 中正确赋值;
  2. 不要提前给 Enable 等属性赋值;
  3. 框架会自动根据主键从 t_port_attr 表恢复数据;
  4. 首次修改属性后会自动触发持久化写入远程数据库。

这样即可实现“手动创建 + 自动恢复 + 掉电不丢”的完整持久化闭环。

如果你是指添加对象时使用持久化数据的话,当前应用框架的能力会在添加对象时候自动去获取持久化数据的

手动上树的对象,如果通过busctl将属性值更改,会自动触发持久化吗?

而且你这既然是自发现对象,你再调CreateXXX方法会造成你实际上有两个对象

我目前是通过’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置为不在位之后应该是不会卸载的吧