基于N32L406+FlashDB(键值数据库 时序数据库)+mdk5 移植教程

news2025/1/12 19:00:44

这里首先感谢作者的开源:

FlashDB: 一款支持 KV 数据和时序数据的超轻量级数据库 (gitee.com)

1.FlashDB简介

在这里插入图片描述

一款超轻量级的嵌入式数据库,专注于提供嵌入式产品的数据存储方案。FlashDB 不仅支持传统的基于文件系统的数据库模式,而且结合了 Flash 的特性,具有较强的性能及可靠性。并在保证极低的资源占用前提下,尽可能延长 Flash 使用寿命

FlashDB 提供两种数据库模式:

  • 键值数据库 :是一种非关系数据库,它将数据存储为键值(Key-Value)对集合,其中键作为唯一标识符。KVDB 操作简洁,可扩展性强。
  • 时序数据库 :时间序列数据库 (Time Series Database , 简称 TSDB),它将数据按照 时间顺序存储 。TSDB 数据具有时间戳,数据存储量大,插入及查询性能高,数据写满后默认状态是滚动写入(也可以设置不覆盖方式)

使用场景

如今,物联网产品种类越来越多,运行时产生的数据种类及总量及也在不断变大。FlashDB 提供了多样化的数据存储方案,不仅资源占用小,并且存储容量大,非常适合用于物联网产品。下面是主要应用场景:

  • 键值数据库
    • 产品参数存储
    • 用户配置信息存储
    • 小文件管理
  • 时序数据库
    • 存储动态产生的结构化数据:如 温湿度传感器采集的环境监测信息,智能手环实时记录的人体健康信息等
    • 记录运行日志:存储产品历史的运行日志,异常告警的记录等

主要特性

  • 资源占用极低,内存占用几乎为 0 ;
  • 支持 多分区,多实例 。数据量大时,可细化分区,降低检索时间;
  • 支持 磨损平衡 ,延长 Flash 寿命;
  • 支持 掉电保护 功能,可靠性高;
  • 支持 字符串及 blob 两种 KV 类型,方便用户操作;
  • 支持 KV 增量升级 ,产品固件升级后, KVDB 内容也支持自动升级;
  • 支持 修改每条 TSDB 记录的状态,方便用户进行管理;

详细的关于FlashDB的文档

在下载目录下查看

在这里插入图片描述

2.基于sfud的FlashDB移植教程

移植准备

下载falshdb库:

http://armink.gitee.io/flashdb/#/zh-cn/

移植平台基于mdk+N32L403MB

外部norflash 使用W25q16,驱动库时sfud

文件目录如下

在这里插入图片描述

复制文件到工程目录

在这里插入图片描述

文件目录结构

在这里插入图片描述

添加头文件

…\middle\flashdb\port\fal\inc

…\middle\flashdb\inc

在这里插入图片描述

修改***port.c文件

我们这里基于sfud的驱动移植,所以打开fal_flash_sfud_port.c即可

接口实现

  1. 初始化接口
  2. 读取函数接口
  3. flash编程(写数据接口)
  4. flash擦除接口

定义各一个FlashDB 对象

对内部个各个参数赋值

static int init(void);
static int read(long offset, uint8_t *buf, size_t size);
static int write(long offset, const uint8_t *buf, size_t size);
static int erase(long offset, size_t size);
/*
    构建一个FlashDB的设备
*/
struct fal_flash_dev nor_flash0 =
    {
        .name = NOR_FLASH_DEV_NAME,        // 设备名-这个名字在分区表会使用
        .addr = 0,                         // 设备开始地址
        .len = 2 * 1024 * 1024,            // 设备大小
        .blk_size = 4096,                  // 扇区大小
        .ops = {init, read, write, erase}, // 几个操作函数
        .write_gran = 1                    // 最小读写颗粒
};

修改fal_cfg.h文件

定义一个设备列表

extern struct fal_flash_dev nor_flash0;

/* 定义一个falsh 设备 flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &nor_flash0,                                                     \
}

定义一个分区表

/* ====================== Partition Configuration ========================== */
#define FAL_PART_HAS_TABLE_CFG

#ifdef FAL_PART_HAS_TABLE_CFG
/* 定义一个分区表partition table */
#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WORD,  "fdb_kvdb1", NOR_FLASH_DEV_NAME,         0, 1024*1024, 0}, \
    {FAL_PART_MAGIC_WORD,  "fdb_tsdb1", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
}

   // {FAL_PART_MAGIC_WORD,        "bl",     "stm32_onchip",         0,   64*1024, 0}, \
   // {FAL_PART_MAGIC_WORD,       "app",     "stm32_onchip",   64*1024,  704*1024, 0}, \

#endif /* FAL_PART_HAS_TABLE_CFG */

移植完成

测试

FlashDB提供了很多的测试用例


#include <flashdb.h>
#include <string.h>

#define FDB_LOG_TAG "[main]"

static uint32_t boot_count = 0;
static time_t boot_time[10] = {0, 1, 2, 3};
/* 默认的键值对 default KV nodes */
static struct fdb_default_kv_node default_kv_table[] = {
    {"username", "armink", 0},                       /* string KV */
    {"password", "123456", 0},                       /* string KV */
    {"boot_count", &boot_count, sizeof(boot_count)}, /* int type KV */
    {"boot_time", &boot_time, sizeof(boot_time)},    /* int array type KV */
};
/* 定义一个kv键值对对象 KVDB object */
static struct fdb_kvdb kvdb = {0};
/* TSDB object */
struct fdb_tsdb tsdb = {0};
/* counts for simulated timestamp */
static int counts = 0;

extern void kvdb_basic_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_string_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_blob_sample(fdb_kvdb_t kvdb);
extern void tsdb_sample(fdb_tsdb_t tsdb);

static void lock(fdb_db_t db)
{
    __disable_irq();
}

static void unlock(fdb_db_t db)
{
    __enable_irq();
}

static fdb_time_t get_time(void)
{
    /* Using the counts instead of timestamp.
     * Please change this function to return RTC time.
     */
    return ++counts;
}
int flashdb_demo(void)
{

    fdb_err_t result;

#ifdef FDB_USING_KVDB
    {
        /* 键值对存储 KVDB Sample*/
        struct fdb_default_kv default_kv;

        default_kv.kvs = default_kv_table;
        default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);

        /* 设置一个加锁或解锁函数   set the lock and unlock function if you want */
        fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, (void *)lock);
        fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, (void *)unlock);

        /* Key-Value 键值对数据库初始化 database initialization
         *
         *       &kvdb: database object
         *       "env": database name
         * "fdb_kvdb1": 分区名字,确保分区表内部有这个分区名字 The flash partition name base on FAL. Please make sure it's in FAL partition table.
         *              Please change to YOUR partition name.
         * &default_kv: The default KV nodes. It will auto add to KVDB when first initialize successfully.
         *        NULL: The user data if you need, now is empty.
         */
        result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, NULL);

        if (result != FDB_NO_ERR)
        {
            return -1;
        }

        /* 运行整数值 KV samples */
        kvdb_basic_sample(&kvdb);
        /* 运行键值为字符串的 KV samples */
        kvdb_type_string_sample(&kvdb);
        /* run blob KV samples */
        kvdb_type_blob_sample(&kvdb);
    }
#endif /* FDB_USING_KVDB */

#ifdef FDB_USING_TSDB
    { /* TSDB Sample */
        /* set the lock and unlock function if you want */
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, (void *)lock);
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, (void *)unlock);
        /* Time series database initialization
         *
         *       &tsdb: database object
         *       "log": database name
         * "fdb_tsdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
         *              Please change to YOUR partition name.
         *    get_time: The get current timestamp function.
         *         128: maximum length of each log
         *        NULL: The user data if you need, now is empty.
         */
        result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, NULL);
        /* read last saved time for simulated timestamp */
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);

        if (result != FDB_NO_ERR)
        {
            return -1;
        }

        /* run TSDB sample */
        tsdb_sample(&tsdb);
    }
#endif /* FDB_USING_TSDB */

    return 0;
}

在这里插入图片描述

3.官方的移植指南

FlashDB 底层的 Flash 管理及操作依赖于 RT-Thread 的 FAL (Flash Abstraction Layer) Flash 抽象层开源软件包 ,该开源库也支持运行在 裸机平台 (点击查看介绍)。所以只需要将所用到的 Flash 对接到 FAL ,即可完成整个移植工作。

FAL 底层将不同的 Flash 存储介质进行了统一封装,并提供了分区表机制,暴露给上层用户

FlashDB 的每个数据库就是基于 FAL 提供的分区机制,每个数据库都坐落在某个 FAL 的分区上,相当于一个分区对应一个数据库

FAL 移植

定义 flash 设备

在定义 Flash 设备表前,需要先定义 Flash 设备。可以是片内 flash, 也可以是片外基于 SFUD 的 spi flash:

  • 定义片内 flash 设备可以参考 fal_flash_stm32f2_port.c
  • 定义片外 spi flash 设备可以参考 fal_flash_sfud_port.c

定义具体的 Flash 设备对象,用户需要根据自己的 Flash 情况分别实现 initreadwriteerase 这些操作函数:

  • static int init(void)可选 的初始化操作。
  • static int read(long offset, uint8_t *buf, size_t size):读取操作。
参数描述
offset读取数据的 Flash 偏移地址
buf存放待读取数据的缓冲区
size待读取数据的大小
return返回实际读取的数据大小
  • static int write(long offset, const uint8_t *buf, size_t size) :写入操作。
参数描述
offset写入数据的 Flash 偏移地址
buf存放待写入数据的缓冲区
size待写入数据的大小
return返回实际写入的数据大小
  • static int erase(long offset, size_t size) :擦除操作。
参数描述
offset擦除区域的 Flash 偏移地址
size擦除区域的大小
return返回实际擦除的区域大小

用户需要根据自己的 Flash 情况分别实现这些操作函数。在文件最底部定义了具体的 Flash 设备对象 ,如下示例定义了 stm32f2 片上 flash:stm32f2_onchip_flash

const struct fal_flash_dev stm32f2_onchip_flash =
{
    .name       = "stm32_onchip",//这个名字在分区表内部要使用,否则提示找不到分区
    .addr       = 0x08000000,
    .len        = 1024*1024,
    .blk_size   = 128*1024,
    .ops        = {init, read, write, erase},
    .write_gran = 8
};
  • "stm32_onchip" : Flash 设备的名字。

  • 0x08000000: 对 Flash 操作的起始地址。

  • 1024*1024:Flash 的总大小(1MB)。

  • 128*1024:Flash 块/扇区大小(因为 STM32F2 各块大小不均匀,所以擦除粒度为最大块的大小:128K)。

  • {init, read, write, erase} :Flash 的操作函数。 如果没有 init 初始化过程,第一个操作函数位置可以置空。

  • 8 : 设置写粒度,单位 bit, 0 表示未生效(默认值为 0 ),该成员是 fal 版本大于 0.4.0 的新增成员。各个 flash 写入粒度不尽相同,可通过该成员进行设置,以下列举几种常见 Flash 写粒度:

    • nor flash: 1 bit
    • stm32f2/f4: 8 bit
    • stm32f1: 32 bit
    • stm32l4: 64 bit

定义 flash 设备列表

Flash 设备表定义在 fal_cfg.h 头文件中,定义分区表前需 新建 fal_cfg.h 文件 ,请将该文件统一放在对应 BSP 或工程目录的 port 文件夹下,并将该头文件路径加入到工程。fal_cfg.h 可以参考 示例文件 fal/samples/porting/fal_cfg.h 完成。

设备表示例:

/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32f2_onchip_flash;
extern struct fal_flash_dev nor_flash0;

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &stm32f2_onchip_flash,                                           \
    &nor_flash0,                                                     \
}

Flash 设备表中,有两个 Flash 对象,一个为 STM32F2 的片内 Flash ,一个为片外的 Nor Flash。

定义 flash 分区表

分区表也定义在 fal_cfg.h 头文件中。Flash 分区基于 Flash 设备,每个 Flash 设备又可以有 N 个分区,这些分区的集合就是分区表。在配置分区表前,务必保证已定义好 Flash 设备设备表。fal_cfg.h 可以参考 示例文件 fal/samples/porting/fal_cfg.h 完成。

分区表示例:

#define NOR_FLASH_DEV_NAME             "norflash0"
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WORD,        "bl",     "stm32_onchip",         0,   64*1024, 0}, \
    {FAL_PART_MAGIC_WORD,       "app",     "stm32_onchip",   64*1024,  704*1024, 0}, \
    {FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME,         0, 1024*1024, 0}, \
    {FAL_PART_MAGIC_WORD,  "download", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

上面这个分区表详细描述信息如下:

分区名Flash 设备名偏移地址大小说明
“bl”“stm32_onchip”064KB引导程序
“app”“stm32_onchip”64*1024704KB应用程序
“easyflash”“norflash0”01MBEasyFlash 参数存储
“download”“norflash0”1024*10241MBOTA 下载区

用户需要修改的分区参数包括:分区名称、关联的 Flash 设备名、偏移地址(相对 Flash 设备内部)、大小,需要注意以下几点:

  • 分区名保证 不能重复
  • 关联的 Flash 设备 务必已经在 Flash 设备表中定义好 ,并且 名称一致 ,否则会出现无法找到 Flash 设备的错误;
  • 分区的起始地址和大小 不能超过 Flash 设备的地址范围 ,否则会导致包初始化错误;

注意:每个分区定义时,除了填写上面介绍的参数属性外,需在前面增加 FAL_PART_MAGIC_WORD 属性,末尾增加 0 (目前用于保留功能)

mobaxterm换行符设置

在这里插入图片描述

4.FlashDB基本概念

  • 键值数据库(KVDB):是一种非关系数据库,它将数据存储为键值(Key-Value)对集合,其中键作为唯一标识符。KVDB 操作简洁,可扩展性强。
  • 时序数据(TSDB) :时间序列数据库 (Time Series Database , 简称 TSDB),它将数据按照 时间顺序存储 。TSDB 数据具有时间戳,数据存储量大,插入及查询性能高。
  • 时序记录(TSL) :TSL (Time series log),是 TSDB 中每条记录的简称。
  • Blob :在计算机中,blob 常常是数据库中用来存储二进制文件的字段类型。在 FlashDB 中, KV 和 TSL 都使用 blob 类型来存储,该类型可以兼容任意变量类型。
  • 迭代器(iterator):它可以让用户透过特定的接口巡访容器中的每一个元素,而不用了解底层的实现。 TSDB 和 KVDB 都支持通过迭代器对数据库进行遍历访问。

在这里插入图片描述

功能框图

通过下面的功能框图,可以大致了解 FlashDB 功能模块划分

5.FlashDB API 说明

Blob

构造 blob 对象

构造 blob 对象的过程,其内部是对 blob 结构体初始化赋值的过程,将传入的参数写入 blob 结构体中,并进行返回

fdb_blob_t fdb_blob_make(fdb_blob_t blob, const void *value_buf, size_t buf_len)

参数描述
blobblob 初始对象
value_buf存放数据的缓冲区
buf_len缓冲区的大小
返回创建完成后的 blob 对象

读取 blob 数据

通过 KVDB 和 TSDB 的 API 可以返回 blob 对象,此时返回的 blob 对象里存放了 blob 数据的存储地址。该 API 可以将数据库里存放的 blob 数据读取出来,并存放至 blob->buf

size_t fdb_blob_read(fdb_db_t db, fdb_blob_t blob)

参数描述
db数据库对象
blobblob 对象
返回实际读取到的 blob 数据长度

KVDB

初始化 KVDB

fdb_err_t fdb_kvdb_init(fdb_kvdb_t db, const char *name, const char *path, struct fdb_default_kv *default_kv, void *user_data)

参数描述
db数据库对象
name数据库名称
pathFAL 模式:分区表中的分区名,文件模式:数据库保存的路径
default_kv默认 KV 集合,第一次初始化时,将会把默认 KV 写入数据库中
user_data用户自定义数据,没有时传入 NULL
返回错误码

控制 KVDB

通过命令控制字,用户可以对数据库进行一些控制操作

void fdb_kvdb_control(fdb_kvdb_t db, int cmd, void *arg)

参数描述
db数据库对象
cmd命令控制字
arg控制的参数
返回错误码

支持的命令控制字如下:

#define FDB_KVDB_CTRL_SET_SEC_SIZE     0x00             /**< 设置扇区大小,需要在数据库初始化前配置 */
#define FDB_KVDB_CTRL_GET_SEC_SIZE     0x01             /**< 获取扇区大小 */
#define FDB_KVDB_CTRL_SET_LOCK         0x02             /**< 设置加锁函数 */
#define FDB_KVDB_CTRL_SET_UNLOCK       0x03             /**< 设置解锁函数 */
#define FDB_KVDB_CTRL_SET_FILE_MODE    0x09             /**< 设置文件模式,需要在数据库初始化前配置 */
#define FDB_KVDB_CTRL_SET_MAX_SIZE     0x0A             /**< 在文件模式下,设置数据库最大大小,需要在数据库初始化前配置 */
#define FDB_KVDB_CTRL_SET_NOT_FORMAT   0x0B             /**< 设置初始化时不进行格式化,需要在数据库初始化前配置 */
扇区大小与块大小

FlashDB 内部存储结构由 N 个扇区组成,每次格式化时是以扇区作为最小单位。而一个扇区通常是 Flash 块大小的 N 倍,比如: Nor Flash 的块大小一般为 4096。

默认 KVDB 会使用 1倍 的块大小作为扇区大小,即:4096。此时,该 KVDB 无法存入超过 4096 长度的 KV 。如果想要存入比如:10K 长度的 KV ,可以通过 control 函数,设置扇区大小为 12K,或者更大大小即可。

反初始化 KVDB

fdb_err_t fdb_kvdb_deinit(fdb_kvdb_t db)

参数描述
db数据库对象

设置 KV

使用此方法可以实现对 KV 的增加和修改功能。

  • 增加 :当 KVDB 中不存在该名称的 KV 时,则会执行新增操作;

  • 修改 :入参中的 KV 名称在当前 KVDB 中存在,则把该 KV 值修改为入参中的值;

    在 KVDB 内部实现中,修改 KV 会先删除旧的 KV ,再增加新的 KV,所以修改后数据库剩余容量会变小

通过 KV 的名字来获取其对应的值。支持两种接口

设置 blob 类型KV

fdb_err_t fdb_kv_set_blob(fdb_kvdb_t db, const char *key, fdb_blob_t blob)

参数描述
db数据库对象
keyKV 的名称
blobblob 对象,做为 KV 的 value
返回错误码

示例:

struct fdb_blob blob;
int temp_data = 36;
/* 通过 fdb_blob_make 构造 blob 对象,作为 "temp" KV 的 value */
fdb_kv_set_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
设置 string 类型KV

fdb_err_t fdb_kv_set(fdb_kvdb_t db, const char *key, const char *value)

参数描述
db数据库对象
keyKV 的名称
valueKV 的 value
返回错误码

获取 KV

获取 blob 类型 KV

size_t fdb_kv_get_blob(fdb_kvdb_t db, const char *key, fdb_blob_t blob)

参数描述
db数据库对象
keyKV 的名称
blob通过 blob 对象,返回 KV 的 blob value
返回错误码

示例:

struct fdb_blob blob;
int temp_data = 0;
/* 构造 blob 对象,用于存储 get 回来的 "temp" KV 的 value 数据 */
fdb_kv_get_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
/* 如果有需要,可以检查 blob.saved.len 是否大于 0 ,确保 get 成功 */
if (blob.saved.len > 0) {
    FDB_INFO("get the 'temp' value is: %d\n", temp_data);
}
获取 KV 对象

fdb_kv_get_blob API 不同,该 API 在 get 过程中并不会执行 value 数据的读取动作。返回的 KV 对象中存放了读取回来的 KV 属性,该 API 适用于 value 长度不确定,或 value 长度过长,需要分段读取的场景。

fdb_kv_t fdb_kv_get_obj(fdb_kvdb_t db, const char *key, fdb_kv_t kv)

参数描述
db数据库对象
keyKV 的名称
kv通过 KV 对象,返回 KV 的属性,可以再用 fdb_kv_to_blob 转换为 blob 对象,再进行数据读取
返回错误码
获取字符串类型 KV

注意

  • 该函数不允许连续使用,使用时需使用 strdup 包裹,确保每次返回回来的字符串内存空间独立;
  • 该函数不支持可重入,返回的值位于函数内部缓冲区,出于安全考虑,请加锁保护。

char *fdb_kv_get(fdb_kvdb_t db, const char *key)

参数描述
db数据库对象
keyKV 的名称
返回!=NULL: KV 的 value;NULL: 获取失败

删除 KV

在 KVDB 内部实现中,删除 KV 并不会完全从 KVDB 中移除,而是标记为了删除状态,所以删除后数据库剩余容量不会有变化

fdb_err_t fdb_kv_del(fdb_kvdb_t db, const char *key)

参数描述
db数据库对象
keyKV 的名称
返回错误码

重置 KVDB

将 KVDB 中的 KV 重置为 首次初始时 的默认值

fdb_err_t fdb_kv_set_default(fdb_kvdb_t db)

参数描述
db数据库对象
返回错误码

打印 KVDB 中的 KV 信息

void fdb_kv_print(fdb_kvdb_t db)

参数描述
db数据库对象
返回错误码

KV 对象转换为 blob 对象

fdb_blob_t fdb_kv_to_blob(fdb_kv_t kv, fdb_blob_t blob)

参数描述
kv待转换的 KV 对象
blob转换前的 blob 对象
返回转换后的 blob 对象

初始化 KV 迭代器

fdb_kv_iterator_t fdb_kv_iterator_init(fdb_kvdb_t db, fdb_kv_iterator_t itr)

参数描述
db数据库对象
itr待初始化的迭代器对象
返回初始化后的迭代器对象

迭代 KV

使用该迭代器 API,可以遍历整个 KVDB 中的所有 KV。

注意:使用前请先初始化迭代器

bool fdb_kv_iterate(fdb_kvdb_t db, fdb_kv_iterator_t itr)

点击查看示例

TSDB

初始化 TSDB

fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path, fdb_get_time get_time, size_t max_len, void *user_data)

参数描述
db数据库对象
name数据库名称
pathFAL 模式:分区表中的分区名,文件模式:数据库保存的路径
get_time获取当前时间戳的函数
max_len每条 TSL 的最大长度
user_data用户自定义数据,没有时传入 NULL
返回错误码

控制 TSDB

通过命令控制字,用户可以对数据库进行一些控制操作

void fdb_tsdb_control(fdb_tsdb_t db, int cmd, void *arg)

参数描述
db数据库对象
cmd命令控制字
arg控制的参数
返回错误码

支持的命令控制字如下:

#define FDB_TSDB_CTRL_SET_SEC_SIZE     0x00             /**< 设置扇区大小,需要在数据库初始化前配置 */
#define FDB_TSDB_CTRL_GET_SEC_SIZE     0x01             /**< 获取扇区大小 */
#define FDB_TSDB_CTRL_SET_LOCK         0x02             /**< 设置加锁函数 */
#define FDB_TSDB_CTRL_SET_UNLOCK       0x03             /**< 设置解锁函数 */
#define FDB_TSDB_CTRL_SET_ROLLOVER     0x04             /**< 设置是否滚动写入,默认滚动。设置非滚动时,如果数据库写满,无法再追加写入。需要在数据库初始化后配置 */
#define FDB_TSDB_CTRL_GET_ROLLOVER     0x05             /**< 获取是否滚动写入 */
#define FDB_TSDB_CTRL_GET_LAST_TIME    0x06             /**< 获取上次追加 TSL 时的时间戳  */
#define FDB_TSDB_CTRL_SET_FILE_MODE    0x09             /**< 设置文件模式,需要在数据库初始化前配置,需要在数据库初始化前配置 */
#define FDB_TSDB_CTRL_SET_MAX_SIZE     0x0A             /**< 在文件模式下,设置数据库最大大小,需要在数据库初始化前配置 */
#define FDB_TSDB_CTRL_SET_NOT_FORMAT   0x0B             /**< 设置初始化时不进行格式化,需要在数据库初始化前配置 */

反初始化 TSDB

fdb_err_t fdb_tsdb_deinit(fdb_tsdb_t db)

参数描述
db数据库对象

追加 TSL

对于 TSDB ,新增 TSL 的过程,就是往 TSDB 末尾追加新 TSL 的过程

fdb_err_t fdb_tsl_append(fdb_tsdb_t db, fdb_blob_t blob)

参数描述
db数据库对象
blobblob 对象,做为 TSL 的数据
返回错误码

迭代 TSL

遍历整个 TSDB 并执行迭代回调

void fdb_tsl_iter(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg)

参数描述
db数据库对象
cb回调函数,每次遍历到 TSL 时会执行该回调
cb_arg回调函数的参数
返回错误码

逆序迭代 TSL

逆序遍历整个 TSDB 并执行迭代回调

void fdb_tsl_iter_reverse(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg)

参数描述
db数据库对象
cb回调函数,每次遍历到 TSL 时会执行该回调
cb_arg回调函数的参数
返回错误码

按时间段迭代 TSL

按时间段范围,遍历整个 TSDB 并执行迭代回调

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)

参数描述
db数据库对象
from开始时间戳。如果结束时间戳比开始时间戳要小,此时将会执行逆序迭代。
to结束时间戳
cb回调函数,每次遍历到 TSL 时会执行该回调
cb_arg回调函数的参数
返回错误码

查询 TSL 的数量

按照传入的时间段,查询符合状态的 TSL 数量
size_t fdb_tsl_query_count(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to, fdb_tsl_status_t status)

参数描述
db数据库对象
from开始时间戳
to结束时间戳
statusTSL 的状态条件
返回数量

设置 TSL 状态

TSL 状态详见 enum fdb_tsl_status ,必须按照顺序设置 TSL 状态, 点击查看示例

fdb_err_t fdb_tsl_set_status(fdb_tsdb_t db, fdb_tsl_t tsl, fdb_tsl_status_t status)

参数描述
db数据库对象
tslTSL 对象
statusTSL 的新状态
返回错误码

清空 TSDB

void fdb_tsl_clean(fdb_tsdb_t db)

参数描述
db数据库对象
返回错误码

TSL 对象转换为 blob 对象

fdb_blob_t fdb_tsl_to_blob(fdb_tsl_t tsl, fdb_blob_t blob)

参数描述
tsl待转换的 TSL 对象
blob转换前的 blob 对象
返回转换后的 blob 对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【YOLOv8】一文全解+亮点介绍+训练教程+独家魔改优化技巧

前言 Hello&#xff0c;大家好&#xff0c;我是cv君&#xff0c;最近开始在空闲之余&#xff0c;经常更新文章啦&#xff01;除目标检测、分类、分隔、姿态估计等任务外&#xff0c;还会涵盖图像增强领域&#xff0c;如超分辨率、画质增强、降噪、夜视增强、去雾去雨、ISP、海…

o(∩_∩)o设置代理访问博客(五)o(∩_∩)o --使用BeeWare打包应用

背景&#xff1a; 最近了解了一个新的打包框架BeeWare&#xff0c;据说他支持的平台要比nuitka更多。利用之前访问博客的脚本&#xff0c;来尝试一下打包windows应用程序。 BeeWare 从零开始 环境&#xff1a;python -m pip install briefcase 使用pycharm新建了一个名为bee…

【HTML入门】第二十一课 - 【实战】做一个简单的数据表格

这一小节&#xff0c;我们继续练习纯HTML&#xff0c;开发一个简单的数据表格吧。就像这样&#xff1a; 目录 1 设计需求分析 2 用到的标签 3 实战代码 1 设计需求分析 做之前&#xff0c;我们仍然是分析一下这张图&#xff0c;以便更好的更快的开发出来。 分2个大部分第一个…

掌控板(为Python编程学习而生)文章目录+入门教程 简介

前言 文章目录 掌控入门系列教程目录 【Mind】掌控板入门教程01 “秀”出我创意 【Mind】掌控板入门教程02 趣味相框 【Mind】掌控板入门教程03 节日的祝福【Mind】掌控板入门教程04 迷你动画片【Mind】掌控板入门教程05 心情灯【Mind】掌控板入门教程06 多彩呼吸灯【Mind】掌…

word预览方式---iframe,Microsoft Office Online、xDoc、Google Docs

提示&#xff1a;word预览方式—iframe 文章目录 [TOC](文章目录) 前言一、Microsoft Office Online二、xDoc三、Google Docs四、预览组件总结 前言 使用vue/cli脚手架vue create创建 一、Microsoft Office Online https://view.officeapps.live.com/op/view.aspx?src二、xDo…

java的命令执行漏洞揭秘

0x01 前言 在Java中可用于执行系统命令常见的方式有两种&#xff0c;API为&#xff1a;java.lang.Runtime、java.lang.ProcessBuilder 0x02 java.lang.Runtime GetMapping("/runtime/exec")public String CommandExec(String cmd) {Runtime run Runtime.getRunti…

关于#define的使用方法总结

文章目录 #define 预处理指令一、#define宏定义二、查看预处理文件三、#define 的使用方法四、C语言宏中“#”和“##”的用法五、常见的宏定义总结六、常考题目 #define 预处理指令 #define 是 C 和 C 编程语言中的预处理指令&#xff0c;用于定义宏&#xff08;macro&#xf…

JVM系列 | 对象的消亡——HotSpot的设计细节

HotSpot 的细节实现 文章目录 HotSpot 的细节实现OopMap 与 根节点枚举根节点类型及说明HotSpot中的实现 OopMap 与 安全点安全点介绍如何保证程序在安全点上&#xff1f; 安全区域记忆集与卡表记忆集卡表 写屏障并发的可达性分析&#xff08;与用户线程&#xff09;并发可达性…

计算机底层知识点(一)晶体管与CPU执行指令之间的联系

该文主要通过详细介绍晶体管在CPU执行指令时的作用。本文所讲解例子为NPN型二极管。这里简单介绍一下&#xff0c;NPN是共阳极&#xff0c;即两个NP结的P结相连为基极&#xff0c;另两个N结分别做集电极和发射极&#xff0c;发射极电流 集电极电流 基极电流。 图5 LED两脚分别…

【Vue3】具名插槽

【Vue3】具名插槽 背景简介开发环境开发步骤及源码 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子。本文内…

纯技术手段实现内网穿透,免注册免收费

纯技术手段实现内网穿透&#xff0c;免注册免收费 一、内网穿透二、方法分类2.1 基于隧道协议的内网穿透2.2 基于反向代理的内网穿透2.3 基于SSH的内网穿透具体工具的分类如下&#xff1a;基于隧道协议基于反向代理基于SSH 三、本文方法四、具体操作4.1 安装服务端4.2 安装客户…

【Linux 网络】链路层

文章目录 链路层1 以太网1.1 以太网帧格式1.2 MAC地址1.3 MTU 2. ARP协议2.1 ARP协议的作用2.2 ARP数据报格式2.3 ARP的流程 其他协议3. DNS协议3.1 域名3.2 输入URL后的事情 4. ICMP协议4.1 ICMP 功能都有啥&#xff1f;4.2 基于ICMP的命令ping命令 5. NAT协议5.1 NAT技术背景…

android13关机按钮 去掉长按事件 去掉启动到安全模式 删除关机长按

总纲 android13 rom 开发总纲说明 目录 1.前言 2.界面效果 3.问题分析 4.代码修改 5.编译替换运行 6.彩蛋 1.前言 在Android操作系统中,关机按钮通常具有多种功能,包括短按关机、长按启动语音助手或重启设备等。在某些情况下,用户或设备管理员可能希望自定义关机按…

爬虫中常见的加密算法Base64伪加密,MD5加密【DES/AES/RSA/SHA/HMAC】及其代码实现(一)

目录 基础常识 Base64伪加密 python代码实现 摘要算法 1. MD5 1.1 JavaScript 实现 1.2 Python 实现 2. SHA 2.1 JavaScript 实现 2.2 Python 实现 2.3 sha系列特征 3. HMAC 3.1 JavaScript 实现 3.2 Python 实现 对称加密 一. 常见算法归纳 1. 工作模式归纳 …

码农职场:一本专为IT行业求职者量身定制的指南

目录 写在前面 推荐图书 推荐理由 写在后面 写在前面 本期博主给大家推荐一本专为IT行业求职者量身定制的指南&#xff1a;《码农职场》。 推荐图书 https://item.jd.com/14716160.html 内容简介 这是一本专为广大IT 行业求职者量身定制的指南&#xff0c;提供了从职前…

使用Python实现栅格划分(渔网)

在QGIS中&#xff0c;“渔网”&#xff08;Fishnet&#xff09;是指一种创建规则网格&#xff08;通常是矩形或正方形&#xff09;的工具&#xff0c;这些网格可以用于空间数据的采样、分区或作为其他地理空间分析的基础。渔网工具可以生成一个由多边形组成的图层&#xff0c;每…

文件解析漏洞—IIS解析漏洞—IIS7.X

在IIS7.0和IIS7.5版本下也存在解析漏洞&#xff0c;在默认Fast-CGI开启状况下&#xff0c;在一个文件路径/xx.jpg后面加上/xx.php会将 “/xx.jpg/xx.php” 解析为 php 文件 利用条件 php.ini里的cgi.fix_pathinfo1 开启IIS7在Fast-CGI运行模式下 在 phpstudy2018 根目录创建…

4、postgresql拓展表空间

base是数据保存目录&#xff0c; OID&#xff1a;对象标识符&#xff0c;无符号4字节整数&#xff0c; 数据库的oid在pg_database中&#xff0c;表&#xff0c;索引&#xff0c;序列等OID存储在pg_class中 表空间&#xff1a;pg最大的逻辑存储单元&#xff0c;表索引数据库都…

Linux安装Zabbix7.0并且使用外置Mysql数据库

MySQL 数据库服务版本。必须至少为 8.00.30 # rpm -Uvh https://repo.zabbix.com/zabbix/7.0/alma/9/x86_64/zabbix-release-7.0-5.el9.noarch.rpm # dnf clean all #安装zabbix # dnf install zabbix-server-mysql zabbix-web-mysql zabbix-nginx-conf zabbix-sql-scripts za…

【一图学技术】6.反向代理 vs API网关 vs 负载均衡的原理和使用场景

反向代理 vs API网关 vs 负载均衡 一、概念 ​ &#x1f30f;反向代理&#xff08;Reverse Proxy&#xff09;是一种位于服务器和客户端之间的代理服务器。 ​ 它接收来自客户端的请求&#xff0c;并将其转发给后端服务器&#xff0c;然后将后端服务器的响应返回给客户端。客…