FlashDB嵌入式数据库之TSDB数据存储解析

article/2025/9/2 20:48:23

一、驱动层:SFUD(Serial Flash Universal Driver) 是一款开源的串行 SPI Flash 通用驱动库
二、中间层:FAL(FLASH ABSTRACTION LAYER))FLASH 抽象层
三、应用层:FlashDB(FlashDB 是一款超轻量级的嵌入式数据库)
后记1:FlashDB嵌入式数据库之TSDB数据存储解析


FlashDB之TSDB解析

  • 一、初始化过程记录
  • 二、Flash中的存储格式
  • 三、实际使用率计算
  • 四、查询流程
  • 五、补充:性能测试

写在前面,好久才来写这边文章,读源码还是比较累的,先记录下来后期会议的时候方便一点。

一、初始化过程记录

先看一下帧头结构体

struct sector_hdr_data {uint8_t status[FDB_STORE_STATUS_TABLE_SIZE]; /**< sector store status @see fdb_sector_store_status_t */uint32_t magic;                              /**< magic word(`T`, `S`, `L`, `0`) */fdb_time_t start_time;                       /**< the first start node's timestamp */struct {fdb_time_t time;                         /**< the last end node's timestamp */uint32_t index;                          /**< the last end node's index */uint8_t status[TSL_STATUS_TABLE_SIZE];   /**< end node status, @see fdb_tsl_status_t */} end_info[2];uint32_t reserved;
};

根据计算sizeof(struct sector_hdr_data)= 40bytes
根据注释可以看出来,帧头中存储了扇区的状态、关键字、开始时间、结束时间、和预留了一个32位的数这样就可以实现对单个扇区的快速检索
只需要读取头部的40个字节,就可以快速判断扇区是否已存满,扇区中的数据的开始时间和结束时间,如果需要检索数据本扇区中的数据是否符合条件,当然前提是时间戳是连续的,这个是默认条件。

二、Flash中的存储格式

源代码调用的层次很多,我们直接讲结果,有兴趣的自己看源码,都是开源的。
先看下实际的存储格式
可以看到帧头后面紧跟着的是数据头信息,每条数据头信息由16个字节组成

  • 数据头信息 = 数据状态 + 数据时间戳 + 数据长度 + 数据内容起始地址
  • 这样的好处是数据头信息是固定长度和固定位置的,可以方便我们快速根据时间戳检索,数据的内容是可以不定长的。
  • log内容用指针指向特定的地址,长度就不需要固定的
  • 每个扇区单独成块,就是一个最小的数据库单元
扇区头log1_hdrlog2_hdr剩余空间剩余空间log2_datalog1_data

可以看到log1的数据头指向的数据内容在扇区的最后面,log2指向的内容再次后面,二边向中间挤压

三、实际使用率计算

每条记录固定占用空间为16字节

如果你的数据内容是16字节
实际使用率 = 16/(16+16) = 50%

一个扇区可以储存数量 = (4096 - 40) / 16 + 16 = 126(条)

1M FLASH有扇区数量 = 1M / 4096 = 256 (个)
1M FLASH可以存储数据 = 126*256 = 32256(条)
如果你的flash是8M的自己算一下。

四、查询流程

原生的api接口只有一个按时间查询的命令

/*** The TSDB iterator for each TSL by timestamp.** @param db database object* @param from starting timestap* @param to ending timestap* @param cb callback* @param arg callback argument*/
void fdb_tsl_iter_by_time(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to, fdb_tsl_cb cb, void *cb_arg)
{struct tsdb_sec_info sector;uint32_t sec_addr, oldest_addr = db->oldest_addr, traversed_len = 0;struct fdb_tsl tsl;bool found_start_tsl = false;if (!db_init_ok(db)) {FDB_INFO("Error: TSL (%s) isn't initialize OK.\n", db_name(db));}//    FDB_INFO("from %s", ctime((const time_t * )&from));
//    FDB_INFO("to %s", ctime((const time_t * )&to));if (cb == NULL) {return;}sec_addr = oldest_addr;/* search all sectors */do {if (read_sector_info(db, sec_addr, §or, false) != FDB_NO_ERR) {continue;}/* sector has TSL */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 ((!found_start_tsl && ((from >= sector.start_time && from <= sector.end_time)|| (sec_addr == oldest_addr && from <= sector.start_time))) || (found_start_tsl)) {uint32_t start = sector.addr + SECTOR_HDR_DATA_SIZE, end = sector.end_idx;found_start_tsl = true;/* search start TSL address, using binary search algorithm */while (start <= end) {tsl.addr.index = start + ((end - start) / 2 + 1) / LOG_IDX_DATA_SIZE * LOG_IDX_DATA_SIZE;read_tsl(db, &tsl);if (tsl.time < from) {start = tsl.addr.index + LOG_IDX_DATA_SIZE;} else {end = tsl.addr.index - LOG_IDX_DATA_SIZE;}}tsl.addr.index = start;/* search all TSL */do {read_tsl(db, &tsl);if (tsl.time >= from && tsl.time <= to) {/* iterator is interrupted when callback return true */if (cb(&tsl, cb_arg)) {return;}} else {return;}} while ((tsl.addr.index = get_next_tsl_addr(§or, &tsl)) != FAILED_ADDR);}} else if (sector.status == FDB_SECTOR_STORE_EMPTY) {return;}traversed_len += db_sec_size(db);} while ((sec_addr = get_next_sector_addr(db, §or, traversed_len)) != FAILED_ADDR);
}

就是从起始时间查询到结束时间,提供了一个回调接口,在这个接口中把数据显示在LCD屏上。

五、补充:性能测试

单纯的速度测试我没有做,原文给出了大概的速度,而且也没有实际的使用价值。
原文给的速度

msh />tsl bench
Append 13421 TSL in 5 seconds, average: 2684.20 tsl/S, 0.37 ms/per
Query total spent 1475 (ms) for 13422 TSL, min 0, max 1, average: 0.11 ms/per

我的环境是 STM32F4+TSDB+FATFS+U盘(USB_Host)
导出了10W条速度用时1分35秒(实际工程中测试)

导出至USB ≈ 1052per/s,差距还是挺大的。


http://chatgpt.dhexx.cn/article/M8AVbUb1.shtml

相关文章

时间序列数据库 (TSDB)

参考文档&#xff1a;时间序列数据库 TSDB_时间序列数据库 TSDB-阿里云帮助中心 什么是时序数据库 时序数据是随时间不断产生的一系列数据&#xff0c;简单来说&#xff0c;就是带时间戳的数据。数据可能来自服务器和应用程序的指标、物联网传感器的读数、网站或应用程序上的…

TSDB在高速公路大数据平台的应用

好久没有跟大家聊TSDB的应用场景了&#xff0c;Jesse也在国庆期间进行了补课&#xff0c;今天就跟大家聊聊TSDB在高速公路大数据平台的应用。本文借鉴了郝建明、袁逸涛发表在《上海船舶运输科学研究生学报》的《基于时序数据库的高速公路数据集成平台》一文&#xff0c;感谢二位…

时序数据库(TSDB)

时序数据库&#xff08;TSDB&#xff09;是一种特定类型的数据库&#xff0c;主要用来存储时序数据。随着5G技术的不断成熟&#xff0c;物联网技术将会使得万物互联。物联网时代之前只有手机、电脑可以联网&#xff0c;以后所有设备都会联网&#xff0c;这些设备每时每刻都会吐…

TSDB数据库

目录 为什么需要时序数据库&#xff1a; 时间序列数据库的特点&#xff1a; 常见的时间序列数据库&#xff1a; 时间序列数据库存储&#xff1a; 时间序列数据库问题&#xff1a; 参考资料&#xff1a; 内容是在我球的docs上直接复制过来的&#xff0c;懒得写两份&#x…

关于时许数据库的相关名词解释

1 时序数据库TSDB 英文全称为 Time Series Database&#xff0c;提供高效存取时序数据和统计分析功能的数据管理系统。 2 时序数据&#xff08;Time Series Data&#xff09; 基于稳定频率持续产生的一系列指标监测数据。例如&#xff0c;监测某城市的空气质量时&#xff0c…

物联网平台搭建的全过程介绍(六)——物联网TSDB之基本知识及读写代码介绍

目录 一、TSDB基本知识 二、物联网平台数据流通架构 三、TSDB数据结构 1、TSDB数据包的组成 2、TSDB的另外两个相关概念 四、阿里云物联网平台实例内TSDB功能介绍 1、数据写入 &#xff08;1&#xff09;需要添加的依赖 &#xff08;2&#xff09;写入数据代码 2、数据…

ES6—简介

目录 一、概述 二、扩展&#xff1a;Babel转码器 三、拓展&#xff1a;编译打包 一、概述 概念 ES6全称ECMAScript 6.0&#xff0c;是Javascript语言的下一代标准&#xff0c;2015年6月正式发布。 注意&#xff0c;ES6既是一个历史名词&#xff0c;也是一个泛指&#xff0c;…

深入浅出ES6(一):ES6是什么

深入浅出ES6&#xff08;一&#xff09;&#xff1a;ES6是什么 作者 Jason Orendorff &#xff0c;译者 刘振涛 发布于 2015年6月5日 | http://www.infoq.com/cn/articles/es6-in-depth-an-introduction 我的阅读清单 编者按&#xff1a;ECMAScript 6离我们越来越近了&#…

[ 前端开发 ] 为什么要学习ES6?

ECMAScript 6 概念 ECMAScript 6 简称 ES6 为什么要学习ES6? ES6 是 JavaScript 的下一个版本标准&#xff0c;诞生于2015年6月份。ES6 的主要目的是为了解决 ES5 的先天不足。ES6 的终极目标是为了使 JavaScript 语言可以用来编写复杂的大型应用程序&#xff0c;成为企业…

前端基础之ES6

ES6 ES6简介 ES6实际上是一个泛指&#xff0c;泛指ES2015及后续版本 为什么使用ES6&#xff1f; 每一次标准的诞生都意味着语言的完善&#xff0c;功能的加强。JavaScript语言本身也有一些令人不满意的地方。 变量提升特性增加了程序运行时的不可预测性语法过于松散&#x…

第一节:ES是什么?ES6是什么?

系列文章目录 第一节&#xff1a;ES是什么&#xff1f;ES6是什么&#xff1f; 文章目录 系列文章目录前言一、ES是什么&#xff1f;二、ES6是什么&#xff1f; 前言 学习一下ES&#xff0c;都是自己学习的总结和理解&#xff0c;大家有什么问题都可以提出&#xff0c;一起讨论…

1.什么是ES6,为什么使用它

1.什么是ES6&#xff1f; ECMAScript 6&#xff08;以下简称ES6&#xff09;是JavaScript语言的下一代标准&#xff0c;已经在2015年6月正式发布了。Mozilla公司将在这个标准的基础上&#xff0c;推出JavaScript 2.0。ES6主要是为了解决ES5的先天不足&#xff0c;比如JavaScri…

ES6是什么

ES6是什么 ECMAScript 6.0&#xff08;以下简称 ES6&#xff09;是 JavaScript 语言的下一代标准&#xff0c;已经在 2015 年 6 月正式发布了。 它的目标&#xff0c;是使得 JavaScript 语言可以用来编写复杂的大型应用程序&#xff0c;成为企业级开发语言。 现在大部分的编…

ES6是什么?通俗理解

1.了解一门语言&#xff0c;首先要搞明白它到底是什么&#xff1f; ECMA (Eurupean Compuler Manuluclurers Assuxiation)中文名为欧洲计算机制造商协会&#xff0c;这个组织的日常是评估、开发和认可电信和计算机标准。19919 年后该组织改名为ECMA国际。 ES6是门脚本语言&…

list集合转换成string字符串

集合转换成字符串 闲来无事&#xff0c;总结了几种list转换成string的方法 第一种 <jdk8新特性&#xff0c;string集合、integer集合均可随意转换成string> 个人觉得这个方法应该属于jdk8的新特性 ArrayList<String> arrayList new ArrayList<String>(){{…

python set转为list_python 怎么把set转成list

今天小就为大家分享一篇python-list,set间的转换实例&#xff0c;具有很好的参考价值&#xff0c;推荐手册&#xff1a;Python 基础入门教程 其实python中&#xff0c;set转list的非常的简单&#xff0c;直接将set的值放入list()的括号中即可&#xff0c;相反&#xff0c;list转…

Java list转set;JDK8 下list 集合转Set 集合

List 集合转Set 集合 1. List 集合和Set 集合的区别 在说如何List集合转Set 集合之前我们先回顾一下 List 集合和Set 集合的区别, 细致上说List 集合和Set 集合的区别还是有蛮多的有兴趣的同学可以去看一下源码&#xff0c;粗糙地讲List 集合和Set 集合的区别主要有那么几点 …

Java中的List与Set转换

一、List列表与Set列表的区别 List列表是有序、可以重复、线程不安全的列表,Set是无序、不能重复、线程不安全的列表。但List和Set可以通过方法来转换为线程安全的&#xff0c;加互斥锁。 Set<Long> setnew HashSet<>();// 转换为线程安全的集合Collections.sy…

BigDecimal中divide方法与setScale方法详解

BigDecimal中divide方法详解 1、首先说一下用法&#xff0c;BigDecimal中的divide主要就是用来做除法的运算。其中有这么一个方法. public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode)第一个参数是除数&#xff0c;第二个参数代表保留几位小数&#x…

BigDecimal加减乘除及setScale的用法小结

Bigdecimal初始化&#xff1a; BigDecimal num new BigDecimal(2.225667);//这种写法不允许&#xff0c;会造成精度损失。 BigDecimal num new BigDecimal("2.225667");//一般都会这样写最好。 两种方式在下面会有实例比较。 一、setScale 1. ROUND_DOWN BigDecima…