键值存储(KV DB)

更新时间:2023-12-19 08:36:58下载pdf

键值存储(KV DB)是一个小型键值(key-value,KV)存储数据库模块,提供小型数据的存储、检索等功能。

功能描述

  • 支持添加、删除和查询
  • 支持模糊匹配模式查询和读取
  • 默认加密存储
  • 支持内部 Cache 加速
  • 支持损耗平衡
  • 支持掉电保护
  • 支持 KV 核心数据保护

工作原理

存储器划分出一块连续的存储空间(32KB 或者 64KB),并在该空间按照 4KB 划分出 block,最后在每个 block 中按照 128B 划分出一个一个 page。
page 按照用途可以分为:

  • 管理页:每个 block 的第一个 page 是作为管理页,您维护该 block 中每个 page 的使用情况。

  • 索引页:用于包括 key 以及 key 对应的 value 的开始、结束 page 地址,每一个 key 独占一个 page。

  • 数据页:用于存储 value,可以跨多个 page 存储。

    键值存储(KV DB)

适用场景

适用于按照 key-value 的形式,将数据存储新到 KV DB 中,并支持读取、删除和编辑等操作。

API 说明

KV DB 初始化

KV DB 初始化是在设备产测的时候完成的,一般不需要您关注。如果您不使用涂鸦的产测工具,您需要对 KV DB 进行初始化/格式化。

/**
* @brief tuya key-value database initialization in mf
*
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*
* @note user don't need to care about this function, it will be called during tuya IoTOS initialization.
*
*/
OPERATE_RET ws_db_init_mf(VOID);

KV DB 写入

向 KV DB 写入一组 key-value 数据,需要提供 key、value 以及 value 的长度。

/**
* @brief tuya key-value database write entry
*
* @param[in] key key of the entry you want to write
* @param[in] value value buffer you want to write
* @param[in] len the numbers of byte you want to write
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*/
OPERATE_RET wd_common_write(IN CONST CHAR_T *key, IN CONST BYTE_T *value, IN CONST UINT_T len);

KV DB 读取

从 KV DB 中读取一组 key-value 数据,需要提供 key,并提供一个用于存储 value 的缓冲区和缓冲区的长度。读取成功之后,获得 value 以及 value 的长度。

/**
* @brief tuya key-value database read entry
*
* @param[in] key key of the entry you want to read
* @param[out] value buffer of the value
* @param[out] p_len length of the buffer
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*
* @note must free the value buffer with wd_common_free_data when you no longer need the buffer
*/
OPERATE_RET wd_common_read(IN CONST CHAR_T *key, OUT BYTE_T **value, OUT UINT_T *p_len);

KV DB 删除数据

从 KV DB 中删除一组 key-value 数据,需要提供 key。

/**
* @brief delete the entry from key-value database
*
* @param[in] key key of the entry you want to delete
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*/
OPERATE_RET wd_common_delete(IN CONST CHAR_T *key);

KV DB 模糊读取

使用模糊匹配的方式,从 KV DB 中读取一组符合包含 key 的 key-value 数据,需要提供 fuzzy key(key 的子段),并提供一个用于存储 value 的缓冲区和缓冲区的长度。读取成功之后,获得 value 以及 value 的长度,wd_common_fuzzy_read 会按照查找的 index 逐个返回查找命中的 key-value 数据。

/**
* @brief tuya key-value database fuzzy read entry
*
* @param[in] fuzzy_name key of the entry you want to read
* @param[in] index index of the value sequnence
* @param[out] data buffer of the value
* @param[out] p_len length of the buffer
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*
* @note if we have three entries "x1","x2","x3" in database, and read use "x" as the key will got all these 3 entries
* and will choose the return entry by index
*
* @note must free the value buffer with wd_common_free_data when you no longer need the buffer
*/
OPERATE_RET wd_common_fuzzy_read(IN CONST CHAR_T *fuzzy_name, INOUT UINT_T *index, OUT BYTE_T **data, OUT UINT_T *len);

KV DB 模糊删除数据

使用模糊匹配的方式,从 KV DB 中删除一组符合包含 key 的 key-value 数据,需要提供 fuzzy key(key 的子段)。

/**
* @brief fuzzy delete the entry from key-value database
*
* @param[in] key key of the entry you want to delete
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*
* @note delete all entries if the key matches the prefix of entry key
*/
OPERATE_RET wd_common_fuzzy_delete(IN CONST CHAR_T *key);

KV DB 写入用户自定义数据

专门用于 key user_param_key 写入的接口,user_param_key 是一个专用于您自定义数据存储的 key。因此,不需要输入 key。

/**
* @brief write the user parameter to the Tuya key-value database
*
* @param[in] data buffer of the data
* @param[in] len length of the data
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*
* @note the key of user parameter entry is "user_param_key"
*/
OPERATE_RET wd_user_param_write(IN CONST BYTE_T *data, IN CONST UINT_T len);

KV DB 读取自定义数据

专门用于 key user_param_key 读取的接口,user_param_key 是一个专用于您自定义数据存储的 key。因此,不需要输入 key。

/**
* @brief read the user parameter from tuya key-value database
*
* @param[out] buf buffer of the data
* @param[out] len length of the data
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*
* @note the key of user parameter entry is "user_param_key",must free the value buffer with
* wd_common_free_data when you nolonger need the buffer
*/
OPERATE_RET wd_user_param_read(OUT BYTE_T **buf, OUT UINT_T *len);

KV DB 数据释放

释放 wd_common_readwd_common_fuzzy_readwd_user_param_read 时申请的资源。注意,在使用 wd_common_readwd_common_fuzzy_read 成功之后,必须调用 wd_common_free_data 接口,否则会造成内存泄露。

/**
* @brief free the buffer which is allocated by wd_common_read or wd_common_fuzzy_read
*
* @param[in] data the buffer got from wd_common_read or wd_common_fuzzy_read
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*/
OPERATE_RET wd_common_free_data(IN BYTE_T *data);

使用示例

sample_kv_demo()
{
    int rt = OPRT_OK;
    // 写一个数据"ddi-xxx":"hello-world-x"
    rt = wd_common_write("ddi-xxx", "hello-world-x", 13);
    EXPECT_EQ(rt, OPRT_OK);

    // 读取数据"ddi-xxx",需要 wd_common_free_data
    BYTE_T *value = NULL;
    UINT_T len = 0;
    rt = wd_common_read("ddi-xxx", &value, &len);
    EXPECT_EQ(rt, OPRT_OK);
    EXPECT_EQ(memcmp(value, "hello-world-x", 13), 0);
    wd_common_free_data(value);
    value = NULL;
    len = 0;

    // 写一个数据"ddi-xxx":"hello-world-y"
    rt = wd_common_write("ddi-yyy", "hello-world-y", 13);
    EXPECT_EQ(rt, OPRT_OK);

    // 修改数据"ddi-xxx":"hello-world-z"
    rt = wd_common_write("ddi-xxx", "hello-world-z", 13);
    EXPECT_EQ(rt, OPRT_OK);
    // 读取所有包含"ddi-"的数据,会自动迭代读取全部数据
    UINT index = 0;
    while(rt == OPRT_OK) {
        rt = wd_common_fuzzy_read("ddi-", &index, &value, &len);
        if(value) {
            wd_common_free_data(value);
            value = NULL;
        }
    }

    // 删除数据"ddi-xxx"
    rt = wd_common_delete("ddi-xxx");
    EXPECT_EQ(rt, OPRT_OK);

    // 删除所有包含"ddi-"的数据
    rt = wd_common_fuzzy_delete("ddi-");
    EXPECT_EQ(rt, OPRT_OK);
    return OPRT_OK;
}

常见问题

能否使用 KV DB 保存自定义数据

可以的,但需要注意 KV DB 的存储空间是有限的,一般是 32KB。另外,读写 KV DB 不要过于频繁,特别是在设备启动过程中尽量避免读写 KV DB。一方面比较耗时,影响设备启动时间。另一方面,设备启动过程中电压不稳,容易造成 Flash 失效。