FlashDB
FlashDB copied to clipboard
现有迭代器函数很难覆盖更多应用,一些新迭代器函数的实现探讨
目前的TSDB提供了一些迭代器函数如fdb_tsl_iter/reverse(),通过它们虽然可以实现遍历,读取等很多功能。但是在回调中处理tsl,很难满足很多应用的使用,比如这个例子:
tsdb中有100个数据,需要通过网络进行上送到服务器
- 用户在回调函数读取最老的tsl,进行联网上送,上送成功后,标记此tsl
- 用户在回调函数读取下一个tsl,进行联网上送,上送成功后,标记此tsl
- 循环上面的步骤
上述例子中,用户必须在回调函数中一气呵成,否则:
- 每次读取时都要遍历数据库,这样效率会变的很差
- 回调函数是在互斥锁中的,太多的应用代码逻辑会影响异步append
- 回调函数会打断用户的正常使用流程,没有kv那样直接读取方便
总之,如果在数据库中的某个中间点上进行顺序的向下读取,使用上述函数就会变的很困难且低效。
因此,我们是否可以增加一些更便利的迭代器函数,使其实现如下功能:
- tsl = fdb_tsl_next_find(db, cur_tsl):根据当前的tsl来读取下一个tsl
- tsl = fdb_tsl_prev_find(db, cur_tsl):根据当前的tsl来读取下一个tsl 这样就可以完美的解决如下功能。
但因为追加可能是异步的,上面的函数可能会有面临如下一些问题:
- 在使用当前cur_tsl后, 异步append()造成cur_tsl所在扇区被重写,此时调用fdb_tsl_next_find()会出现错误情况
- 如何检测cur_tsl所在扇区被重写? 检测到后如何处理?
如何检测cur_tsl所在扇区被重写,我的思路如下:
- fdb_tsl_next_find()内部,先读取cur_tsl所在地址的信息,如果发现id不一致,则表明此扇区被重写了
检测到后如何处理,我的思路如下:
- 检测到被重写后,直接返回下一个最老的tsl,或者直接告诉用户被覆盖了?
当然,我认为,用户应该在使用时尽量避免这种情况
对于上面的问题,你有更好的解决思路吗?下面是我的一些简单实现思路,代码进行了简单测试,目前看起来可以实现上述问题
/* 代码实现 */
struct fdb_tsl fdb_tsl_next_find(fdb_tsdb_t db, fdb_tsl_t prestl)
{
bool index_flag = false;
struct tsdb_sec_info sector;
uint32_t sec_addr, traversed_len = 0;
struct fdb_tsl tsl;
tsl.status = FDB_TSL_UNUSED;
if (!prestl) return tsl;
if (!db_init_ok(db)) {
FDB_INFO("Error: TSL (%s) isn't initialize OK.\n", db_name(db));
}
db_lock(db);
tsl.addr.index = prestl->addr.index;
read_tsl(db, &tsl);
if (tsl.status != FDB_TSL_UNUSED && tsl.time == prestl->time) {
sec_addr = FDB_ALIGN_DOWN(tsl.addr.index, db_sec_size(db));
index_flag = true;
} else {
sec_addr = db_oldest_addr(db);
}
do {
traversed_len += db_sec_size(db);
if (read_sector_info(db, sec_addr, §or, false) != FDB_NO_ERR) {
index_flag = false;
continue;
}
if (sector.status == FDB_SECTOR_STORE_USING || sector.status == FDB_SECTOR_STORE_FULL) {
if (sector.status == FDB_SECTOR_STORE_USING) {
/* copy the current using sector status */
sector = db->cur_sec;
}
if (index_flag) {
index_flag = false;
tsl.addr.index = get_next_tsl_addr(§or, &tsl);
} else {
tsl.addr.index = sector.addr + SECTOR_HDR_DATA_SIZE;
}
if (tsl.addr.index != FAILED_ADDR) {
read_tsl(db, &tsl);
db_unlock(db);
return tsl;
}
}
if (sec_addr == db->cur_sec.addr) {
break;
}
} while ((sec_addr = get_next_sector_addr(db, §or, traversed_len)) != FAILED_ADDR);
db_unlock(db);
tsl.status = FDB_TSL_UNUSED;
return tsl;
}
想法非常赞的,考虑的也很完善
检测到被重写后,直接返回下一个最老的tsl,或者直接告诉用户被覆盖了
我觉得可能要看当前 TSDB 模式,我觉得可以增加一个入参,比如回滚模式。为真时,可以直接返回最老的 TSL ,否则是不是直接 返回空