Crate flashdb_rs

Crate flashdb_rs 

Source
Expand description

§flashdb-rs

这是一个为 FlashDB 编写的安全、高性能的 Rust 绑定库。FlashDB 是一款专注于嵌入式产品的超轻量级数据库。

本库旨在为 Rust 开发者提供一个安全且符合人体工程学的接口,以便在 Rust 项目中(包括 no_std 环境)无缝使用 FlashDB 强大的键值(KV)和时序(TSDB)存储功能,而无需直接编写 unsafe 的 C 代码。

§原始库介绍

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

它提供两种数据库模式:

  • 键值数据库 (KVDB):将数据存储为键值对集合,操作简洁,可扩展性强。
  • 时序数据库 (TSDB):将数据按照时间顺序存储,适用于日志记录、传感器数据等场景,具有高性能的插入和查询能力。

§flashdb-rs 的特性

  • 内存安全保证:通过 Rust 的所有权和生命周期管理,将底层的 C 库接口封装在安全的 API 之后。
  • 符合人体工程学的 API:提供 Result 进行错误处理,并为数据访问提供了流式读取器(Reader)和迭代器(Iterator)。
  • 灵活的存储后端:通过 embedded_storage::nor_flash::NorFlash trait 将存储层完全抽象。您可以为任何 Flash 硬件(内部 Flash、QSPI、SPI Nor/NAND 等)实现自己的存储后端。
  • 内置文件系统支持:在 std 环境下,提供开箱即用的文件存储后端(StdStorage),方便在桌面环境进行开发和测试。
  • no_std 兼容:专为嵌入式和裸机环境设计,只需实现 NorFlash trait 即可在不同平台上运行。
  • 特性控制(Feature Gates):您可以根据需要仅启用 kvdbtsdb 功能,最大限度地减少固件体积。

§快速上手

§1. 添加依赖

将以下内容添加到您的 Cargo.toml 中:

[dependencies]
flashdb-rs = { version = "0.2.1", features = ["kvdb", "tsdb", "std", "time64"] }

# 用于桌面测试
anyhow = "1.0"
tempfile = "3.4.0"

§2. KVDB (键值数据库) 示例

use flashdb_rs::KVDB;
use std::ffi::CStr;
use tempfile::tempdir;

fn main() -> anyhow::Result<()> {
    // 1. 创建一个临时目录用于存储数据库文件
    let temp_dir = tempdir()?;
    let db_path = temp_dir.path().to_str().unwrap();

    // 2. 使用 `new_file` 创建数据库实例。
    // 它返回一个 `Box` 以确保其内存地址稳定,防止悬空指针。
    let mut db = KVDB::new_file(
        "kv_db",
        db_path,
        4096,       // sec_size
        128 * 1024, // max_size
        None,       // default_kvs
    )?;

    // 3. 设置键值对
    let key = "boot_count"; // 直接使用 &str,更简洁
    let value = b"10";
    db.set(key, value)?;
    println!("Set '{}' = '{}'", key, std::str::from_utf8(value)?);

    // 4. 获取键值对
    if let Some(retrieved_value) = db.get(key)? {
        let value_str = std::str::from_utf8(&retrieved_value)?;
        println!("Get '{}' = '{}'", key, value_str);
        assert_eq!(value_str.as_bytes(), value);
    }

    // 5. 迭代所有键值对
    println!("\nIterating all KVs:");
    for entry in db.iter() {
        // entry 是一个 KVEntry
        if let Some(name) = entry.name() {
             println!("- Found key: '{}', value_len: {}", name, entry.value_len());
        }
    }

    Ok(())
}

§3. TSDB (时序数据库) 示例

use flashdb_rs::tsdb::TSDB;
use tempfile::tempdir;

fn main() -> anyhow::Result<()> {
    // 1. 创建临时目录
    let temp_dir = tempdir()?;
    let db_path = temp_dir.path().to_str().unwrap();

    // 2. 使用 `new_file` 创建 TSDB 实例
    let mut tsdb = TSDB::new_file(
        "ts_db",
        db_path,
        4096,       // sec_size
        128 * 1024, // max_size
        1024,       // 单条日志最大长度
    )?;

    // 3. 追加带时间戳的日志
    let timestamp1 = 1686451200; // Unix aarch
    let data1 = b"log entry 1: system started";
    tsdb.append_with_timestamp(timestamp1, data1)?;
    println!("Appended log at timestamp {}", timestamp1);

    let timestamp2 = 1686451260;
    let data2 = b"log entry 2: sensor reading OK";
    tsdb.append_with_timestamp(timestamp2, data2)?;
    println!("Appended log at timestamp {}", timestamp2);

    // 4. 按时间范围迭代日志 (通过回调)
    println!("\nIterating logs from {} to {}:", timestamp1, timestamp2);
    tsdb.tsdb_iter_by_time(timestamp1, timestamp2, |db, tsl| {
        if let Ok(Some(value)) = db.get_value(tsl) {
            println!(
                "  - Time: {}, Data: '{}'",
                tsl.time(), // 使用 .time() 方法
                std::str::from_utf8(&value).unwrap()
            );
        }
        true // 返回 true 继续迭代
    });

    Ok(())
}

§在嵌入式 (no_std) 环境中使用

  1. 修改 Cargo.toml: 禁用默认的 std 特性,并根据需要启用 kvdbtsdb

    [dependencies]
    flashdb-rs = { version = "0.2.1", default-features = false, features = ["kvdb", "time64"] }
  2. 实现 NorFlash Trait: 您需要为您目标平台的 Flash 存储器(例如 STM32 的内部 Flash 或 ESP32 的 SPI Flash)实现 embedded_storage::nor_flash::NorFlash trait。

    // 伪代码示例
    
    // 您需要为您的硬件实现这些 Trait
  3. 初始化数据库: 在 no_std 环境下,您需要手动创建存储实例,然后创建 KVDBTSDB 实例,最后调用 .init() 方法。

    use flashdb_rs::KVDB;
    use core::ffi::CStr;
    
    
    fn my_embedded_main() {
        let my_flash_storage = MyHardwareFlash; // 1. 创建您的存储实例
    
        // 2. 创建数据库实例
        let mut db = KVDB::new(my_flash_storage);
    
        // 3. 在使用前必须调用 init()
        db.set_name("config").unwrap(); // (可选, 用于日志)
        db.init(None).expect("Failed to initialize db");
        
        // 4. 现在可以正常使用 db
        let key = CStr::from_bytes_with_nul(b"wifi_ssid\0").unwrap();
        db.set(key, b"MyNetwork").unwrap();
    }

§许可证

本项目采用 Apache-2.0 开源协议。

§致谢

  • 感谢 armink 开发了如此出色的 FlashDB C 库。
  • 本项目依赖于原始的 FlashDB 仓库

Re-exports§

pub use storage::StdStorage;
pub use self::fdb_kv_status as fdb_kv_status_t;
pub use self::fdb_tsl_status as fdb_tsl_status_t;
pub use self::fdb_sector_store_status as fdb_sector_store_status_t;
pub use self::fdb_sector_dirty_status as fdb_sector_dirty_status_t;
pub use error::*;
pub use kvdb::*;
pub use tsdb::*;
pub use utils::*;

Modules§

error
kvdb
storage
tsdb
utils

Macros§

define_default_kvs
在编译时定义一组默认的键值对。

Structs§

SyncWrapper
fdb_blob
fdb_blob__bindgen_ty_1
fdb_db
fdb_db__bindgen_ty_1
fdb_default_kv
fdb_default_kv_node
fdb_kv
fdb_kv__bindgen_ty_1
fdb_kv_iterator
fdb_kvdb
fdb_tsdb
fdb_tsl
fdb_tsl__bindgen_ty_1
kv_cache_node
kvdb_sec_info
kvdb_sec_info__bindgen_ty_1
tsdb_sec_info

Constants§

FDB_FILE_CACHE_TABLE_SIZE
FDB_KVDB_CTRL_GET_SEC_SIZE
FDB_KVDB_CTRL_SET_FILE_MODE
FDB_KVDB_CTRL_SET_LOCK
FDB_KVDB_CTRL_SET_MAX_SIZE
FDB_KVDB_CTRL_SET_NOT_FORMAT
FDB_KVDB_CTRL_SET_SEC_SIZE
FDB_KVDB_CTRL_SET_UNLOCK
FDB_KV_CACHE_TABLE_SIZE
FDB_KV_NAME_MAX
FDB_KV_STATUS_NUM
FDB_SECTOR_CACHE_TABLE_SIZE
FDB_SECTOR_DIRTY_STATUS_NUM
FDB_SECTOR_STORE_STATUS_NUM
FDB_SW_VERSION
FDB_SW_VERSION_NUM
FDB_TSDB_CTRL_GET_LAST_TIME
FDB_TSDB_CTRL_GET_ROLLOVER
FDB_TSDB_CTRL_GET_SEC_SIZE
FDB_TSDB_CTRL_SET_FILE_MODE
FDB_TSDB_CTRL_SET_LOCK
FDB_TSDB_CTRL_SET_MAX_SIZE
FDB_TSDB_CTRL_SET_NOT_FORMAT
FDB_TSDB_CTRL_SET_ROLLOVER
FDB_TSDB_CTRL_SET_SEC_SIZE
FDB_TSDB_CTRL_SET_UNLOCK
FDB_TSL_STATUS_NUM
FDB_WRITE_GRAN
fdb_db_type_FDB_DB_TYPE_KV
fdb_db_type_FDB_DB_TYPE_TS
fdb_err_t_FDB_ERASE_ERR
fdb_err_t_FDB_INIT_FAILED
fdb_err_t_FDB_KV_NAME_ERR
fdb_err_t_FDB_KV_NAME_EXIST
fdb_err_t_FDB_NO_ERR
fdb_err_t_FDB_PART_NOT_FOUND
fdb_err_t_FDB_READ_ERR
fdb_err_t_FDB_SAVED_FULL
fdb_err_t_FDB_WRITE_ERR
fdb_kv_status_FDB_KV_DELETED
fdb_kv_status_FDB_KV_ERR_HDR
fdb_kv_status_FDB_KV_PRE_DELETE
fdb_kv_status_FDB_KV_PRE_WRITE
fdb_kv_status_FDB_KV_UNUSED
fdb_kv_status_FDB_KV_WRITE
fdb_sector_dirty_status_FDB_SECTOR_DIRTY_FALSE
fdb_sector_dirty_status_FDB_SECTOR_DIRTY_GC
fdb_sector_dirty_status_FDB_SECTOR_DIRTY_TRUE
fdb_sector_dirty_status_FDB_SECTOR_DIRTY_UNUSED
fdb_sector_store_status_FDB_SECTOR_STORE_EMPTY
fdb_sector_store_status_FDB_SECTOR_STORE_FULL
fdb_sector_store_status_FDB_SECTOR_STORE_UNUSED
fdb_sector_store_status_FDB_SECTOR_STORE_USING
fdb_storage_type_FDB_STORAGE_CUSTOM
fdb_storage_type_FDB_STORAGE_FAL
fdb_storage_type_FDB_STORAGE_FILE
fdb_tsl_status_FDB_TSL_DELETED
fdb_tsl_status_FDB_TSL_PRE_WRITE
fdb_tsl_status_FDB_TSL_UNUSED
fdb_tsl_status_FDB_TSL_USER_STATUS1
fdb_tsl_status_FDB_TSL_USER_STATUS2
fdb_tsl_status_FDB_TSL_WRITE

Traits§

RawHandle

Functions§

fdb_blob_make
fdb_blob_read
fdb_calc_crc32
fdb_custom_erase
fdb_custom_read
fdb_custom_write
fdb_kv_del
fdb_kv_get
fdb_kv_get_blob
fdb_kv_get_obj
fdb_kv_iterate
fdb_kv_iterator_init
fdb_kv_print
fdb_kv_set
fdb_kv_set_blob
fdb_kv_set_default
fdb_kv_to_blob
fdb_kvdb_check
fdb_kvdb_control
fdb_kvdb_deinit
fdb_kvdb_init
fdb_tsdb_control
fdb_tsdb_deinit
fdb_tsdb_init
fdb_tsl_append
fdb_tsl_append_with_ts
fdb_tsl_clean
fdb_tsl_iter
fdb_tsl_iter_by_time
fdb_tsl_iter_reverse
fdb_tsl_query_count
fdb_tsl_set_status
fdb_tsl_to_blob
rust_log

Type Aliases§

fdb_blob_t
fdb_db_t
fdb_db_type
fdb_err_t
fdb_get_time
fdb_kv_iterator_t
fdb_kv_status
fdb_kv_t
fdb_kvdb_t
fdb_sector_dirty_status
fdb_sector_store_status
fdb_storage_type
fdb_time_t
fdb_tsdb_t
fdb_tsl_cb
fdb_tsl_status
fdb_tsl_t