armink / FlashDB

An ultra-lightweight database that supports key-value and time series data | 一款支持 KV 数据和时序数据的超轻量级数据库
Apache License 2.0
1.83k stars 420 forks source link

fdb_kvdb_init偶现默认参数未写入flash中 #106

Open joechenchen opened 2 years ago

joechenchen commented 2 years ago

hi,朱工: flashdb使用的是1.0.0版本,项目中有个别设备出现flash读取异常,分析原因,工程中创建了两个KV数据库,其中一个数据库正常,另一个数据库异常。 异常原因:fdb_kv_get_blob 返回saved.len <0,数据库占用了4个扇区,通过fal接口读出4个扇区的所有值 第一个扇区sec_hdr + kv_hdr + kv(__ver_num__)信息 00 FF FF FF 00 FF FF FF FF FF FF FF 00 FF FF FF FF FF FF FF FF FF FF FF 46 44 42 30 FF FF FF FF FF FF FF FF 00 FF FF FF 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 4B 56 30 30 38 00 00 00 01 AF 41 E8 0B FF FF FF 04 00 00 00 5F 5F 76 65 72 5F 6E 75 6D 5F 5F FF 01 00 00 00 第2~4个扇区都有sec_hdr 头 00 FF FF FF FF FF FF FF FF FF FF FF 00 FF FF FF FF FF FF FF FF FF FF FF 46 44 42 30

因此可以得出: fdb_kvdb_init时的默认kv数据未写入flash中,导致fdb_kv_get_blob找不到 分析代码是通过_fdb_kv_load写入默认KV参数,该函数执行步骤为: 1)检查扇区头,如果扇区头不符合规则,格式化扇区头,check_failed_count++ 2)所有扇区都不符合规则,写入默认参数

读取的4个扇区都有头,说明都执行过format_sector接口,但是为何fdb_kv_set_default未生效?

joechenchen commented 2 years ago

我自己来回答这个问题,flashdb格式化扇区时间比较久,4个扇区需要300ms左右,假设第一次上电时电源接触不好,很容易触发格式化期间断电,就会造成flashdb 默认值无法写入 比如: fdb_kvdb.c(1610): [FlashDB][kv] fdb_kvdb.c(1610): [env] fdb_kvdb.c(1610): (../../../3th_Utilities/FlashDB-1.0.0/src/fdb_kvdb.c:1610) fdb_kvdb.c(1610): KVDB in partition env_cfg, size is 16384 bytes.

fdb_kvdb.c(1428): [FlashDB][kv] fdb_kvdb.c(1428): [env] fdb_kvdb.c(1428): Sector header info is incorrect. Auto format this sector (0x00000000).

[11:31:51.649]收←◆fdb_kvdb.c(1428): [FlashDB][kv] fdb_kvdb.c(1428): [env] fdb_kvdb.c(1428): Sector header info is incorrect. Auto format this sector (0x00001000).

[11:31:51.726]收←◆fdb_kvdb.c(1428): [FlashDB][kv] fdb_kvdb.c(1428): [env] fdb_kvdb.c(1428): Sector header info is incorrect. Auto format this sector (0x00002000). 再次上电,会继续格式化剩余扇区,但因为检测到其它扇区已格式化,则不会写入默认参数 fdb_kvdb.c(1610): [FlashDB][kv] fdb_kvdb.c(1610): [env] fdb_kvdb.c(1610): (../../../3th_Utilities/FlashDB-1.0.0/src/fdb_kvdb.c:1610) fdb_kvdb.c(1610): KVDB in partition env_cfg, size is 16384 bytes.

fdb_kvdb.c(1428): [FlashDB][kv] fdb_kvdb.c(1428): [env] fdb_kvdb.c(1428): Sector header info is incorrect. Auto format this sector (0x00003000).

解决方案可以在_fdb_kv_load后加入kv校验功能 if (check_failed_count == SECTOR_NUM) { FDB_INFO("All sector header is incorrect. Set it to default.\n"); fdb_kv_set_default(db); } do { for (i = 0; i < db->default_kvs.num; i++) { find_ok = find_kv_no_cache(db, db->default_kvs.kvs[i].key, &kv); if(false == find_ok) { fdb_kv_set_default(db); break; } }
}while(retry--);

armink commented 2 years ago

是不是只有所有扇区都损坏才会恢复出厂设置的,主要是出于保护用户已经存在 Flash 上的数据安全考虑的

你感觉需要一个扇区检查失败就整个数据库都恢复出厂吗

joechenchen commented 2 years ago

朱工: 我的目的是想保证默认参数能够100%写入成功,不能因为电源不稳,比如格式化进行一半,断电再重启,会导致默认参数无法成功写入,于是在_fdb_kv_load接口加了一层校验。 _fdb_kv_load这个函数的作用域是写默认参数,我这边检查的也是默认KV,如果flash中没有默认KV,就擦除所有扇区