From 0fb447a4496b448cf00248c10c8dd43478bfa32c Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Mon, 15 Dec 2025 17:19:14 +1000 Subject: [PATCH 01/11] TSDB feature: Added FDB_TSDB_FIXED_BLOB_SIZE compile-time option to reduce Flash usage in fixed-size blob scenarios. When enabled, removes log_len and log_addr fields from log_idx_data structure, saving 8 bytes per TSL entry. The log address is instead calculated at runtime based on the TSL's position within the sector. This optimization is ideal for applications logging fixed-size data (e.g., single temperature as float + timestamp) where the 8-byte overhead per entry becomes significant with large numbers of entries. Changes: - Conditionally exclude log_len/log_addr from log_idx_data struct - Calculate log address dynamically in read_tsl() when enabled - Add strict size validation in tsl_append() - Maintain backward compatibility via conditional compilation --- inc/fdb_cfg_template.h | 5 +++++ src/fdb_tsdb.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/inc/fdb_cfg_template.h b/inc/fdb_cfg_template.h index c2de3c3..b9902da 100644 --- a/inc/fdb_cfg_template.h +++ b/inc/fdb_cfg_template.h @@ -23,6 +23,11 @@ /* using TSDB (Time series database) feature */ #define FDB_USING_TSDB +/* Use fixed-size blobs in TSDB to save flash overhead (8 bytes per entry). + * Define this to the fixed blob size in bytes when all TSL entries are the same size. + * Ideal for logging fixed-size sensor data (e.g., float + timestamp). */ +/* #define FDB_TSDB_FIXED_BLOB_SIZE 4 */ + /* Using FAL storage mode */ #define FDB_USING_FAL_MODE diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 2d66c92..0ef0822 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -94,8 +94,10 @@ typedef struct sector_hdr_data *sector_hdr_data_t; struct log_idx_data { uint8_t status_table[TSL_STATUS_TABLE_SIZE]; /**< node status, @see fdb_tsl_status_t */ fdb_time_t time; /**< node timestamp */ +#ifndef FDB_TSDB_FIXED_BLOB_SIZE uint32_t log_len; /**< node total length (header + name + value), must align by FDB_WRITE_GRAN */ uint32_t log_addr; /**< node address */ +#endif }; typedef struct log_idx_data *log_idx_data_t; @@ -114,6 +116,10 @@ struct check_sec_hdr_cb_args { static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) { struct log_idx_data idx; +#ifdef FDB_TSDB_FIXED_BLOB_SIZE + uint32_t tsl_index_in_sector; + uint32_t sector_addr; +#endif /* read TSL index raw data */ _fdb_flash_read((fdb_db_t)db, tsl->addr.index, (uint32_t *) &idx, sizeof(struct log_idx_data)); tsl->status = (fdb_tsl_status_t) _fdb_get_status(idx.status_table, FDB_TSL_STATUS_NUM); @@ -122,9 +128,17 @@ static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) tsl->addr.log = FDB_DATA_UNUSED; tsl->time = 0; } else { +#ifdef FDB_TSDB_FIXED_BLOB_SIZE + tsl->log_len = FDB_TSDB_FIXED_BLOB_SIZE; + sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); + tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; + tsl->addr.log = sector_addr + db_sec_size(db) - (tsl_index_in_sector + 1) * FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); + tsl->time = idx.time; +#else tsl->log_len = idx.log_len; tsl->addr.log = idx.log_addr; tsl->time = idx.time; +#endif } return FDB_NO_ERR; @@ -306,16 +320,25 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) fdb_err_t result = FDB_NO_ERR; struct log_idx_data idx; uint32_t idx_addr = db->cur_sec.empty_idx; - +#ifdef FDB_TSDB_FIXED_BLOB_SIZE + uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); +#else idx.log_len = blob->size; - idx.time = time; idx.log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(idx.log_len); +#endif + + idx.time = time; + /* write the status will by write granularity */ _FDB_WRITE_STATUS(db, idx_addr, idx.status_table, FDB_TSL_STATUS_NUM, FDB_TSL_PRE_WRITE, false); /* write other index info */ FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false); /* write blob data */ +#ifdef FDB_TSDB_FIXED_BLOB_SIZE + FLASH_WRITE(db, log_addr, blob->buf, blob->size, false); +#else FLASH_WRITE(db, idx.log_addr, blob->buf, blob->size, false); +#endif /* write the status will by write granularity */ _FDB_WRITE_STATUS(db, idx_addr, idx.status_table, FDB_TSL_STATUS_NUM, FDB_TSL_WRITE, true); @@ -388,6 +411,12 @@ static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestam fdb_err_t result = FDB_NO_ERR; fdb_time_t cur_time = timestamp == NULL ? db->get_time() : *timestamp; +#ifdef FDB_TSDB_FIXED_BLOB_SIZE + if(blob->size != FDB_TSDB_FIXED_BLOB_SIZE) { + FDB_INFO("Error: blob size (%zu) must equal FDB_TSDB_FIXED_BLOB_SIZE (%d)\n", blob->size, FDB_TSDB_FIXED_BLOB_SIZE); + return FDB_WRITE_ERR; + } +#else /* check the append length, MUST less than the db->max_len */ if(blob->size > db->max_len) { @@ -395,6 +424,7 @@ static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestam (intmax_t)blob->size, (intmax_t)(db->max_len)); return FDB_WRITE_ERR; } +#endif /* check the current timestamp, MUST more than the last save timestamp */ if (cur_time <= db->last_time) { From dccbad5ad9b749034752b248654bf1ec89460351 Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Mon, 15 Dec 2025 17:34:42 +1000 Subject: [PATCH 02/11] TSDB feature: Added FDB_TSDB_SEQ_MODE compile-time option to enable sequential timestamp mode, reducing flash usage. This mode eliminates per-entry timestamp storage by calculating timestamps on-the-fly, saving sizeof(fdb_time_t) bytes per TSL entry (4 bytes for uint32_t, 8 bytes for uint64_t) per TSL entry. Key changes: - Removes field from structure when FDB_TSDB_SEQ_MODE is defined - Timestamps are calculated as: sector.start_time + TSL_index_in_sector - In tsl_append(), time auto-increments as db->last_time + 1 (no get_time() call needed) - In read_tsl(), timestamp is computed from sector start time and TSL position - Iterators pass sector.start_time via tsl.time before calling read_tsl() - search_start_tsl_addr() receives sector_start_time as additional parameter in SEQ_MODE Trade-offs: - Constraint: Timestamps must be monotonically increasing by 1 Depends on #387 --- inc/fdb_cfg_template.h | 7 ++++ inc/fdb_def.h | 2 ++ src/fdb_tsdb.c | 75 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/inc/fdb_cfg_template.h b/inc/fdb_cfg_template.h index b9902da..3b0d1b0 100644 --- a/inc/fdb_cfg_template.h +++ b/inc/fdb_cfg_template.h @@ -28,6 +28,13 @@ * Ideal for logging fixed-size sensor data (e.g., float + timestamp). */ /* #define FDB_TSDB_FIXED_BLOB_SIZE 4 */ + +/* Use sequentual mode - eliminates per-entry timestamp storage by calculating timestamps + * on-the-fly, saving sizeof(fdb_time_t). In this mode timestamps are monotonically increasing by 1 on each log + * and don't require application to provide a time function. + */ +/* #define FDB_TSDB_USING_SEQ_MODE */ + /* Using FAL storage mode */ #define FDB_USING_FAL_MODE diff --git a/inc/fdb_def.h b/inc/fdb_def.h index 559fd6b..9eec7e4 100644 --- a/inc/fdb_def.h +++ b/inc/fdb_def.h @@ -323,7 +323,9 @@ struct fdb_tsdb { struct fdb_db parent; /**< inherit from fdb_db */ struct tsdb_sec_info cur_sec; /**< current using sector */ fdb_time_t last_time; /**< last TSL timestamp */ +#ifndef FDB_TSDB_USING_SEQ_MODE fdb_get_time get_time; /**< the current timestamp get function */ +#endif size_t max_len; /**< the maximum length of each log */ bool rollover; /**< the oldest data will rollover by newest data, default is true */ diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 0ef0822..6ae38cc 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -36,7 +36,11 @@ #define SECTOR_HDR_DATA_SIZE (FDB_WG_ALIGN(sizeof(struct sector_hdr_data))) #define LOG_IDX_DATA_SIZE (FDB_WG_ALIGN(sizeof(struct log_idx_data))) +#ifdef FDB_TSDB_USING_SEQ_MODE +#define LOG_IDX_TS_OFFSET ((unsigned long)(&((struct log_idx_data *)0)->log_len)) +#else #define LOG_IDX_TS_OFFSET ((unsigned long)(&((struct log_idx_data *)0)->time)) +#endif #define SECTOR_MAGIC_OFFSET ((unsigned long)(&((struct sector_hdr_data *)0)->magic)) #define SECTOR_START_TIME_OFFSET ((unsigned long)(&((struct sector_hdr_data *)0)->start_time)) #define SECTOR_END0_TIME_OFFSET ((unsigned long)(&((struct sector_hdr_data *)0)->end_info[0].time)) @@ -93,7 +97,9 @@ typedef struct sector_hdr_data *sector_hdr_data_t; /* time series log node index data */ struct log_idx_data { uint8_t status_table[TSL_STATUS_TABLE_SIZE]; /**< node status, @see fdb_tsl_status_t */ +#ifndef FDB_TSDB_USING_SEQ_MODE fdb_time_t time; /**< node timestamp */ +#endif #ifndef FDB_TSDB_FIXED_BLOB_SIZE uint32_t log_len; /**< node total length (header + name + value), must align by FDB_WRITE_GRAN */ uint32_t log_addr; /**< node address */ @@ -116,7 +122,7 @@ struct check_sec_hdr_cb_args { static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) { struct log_idx_data idx; -#ifdef FDB_TSDB_FIXED_BLOB_SIZE +#if defined(FDB_TSDB_FIXED_BLOB_SIZE) || defined(FDB_TSDB_USING_SEQ_MODE) uint32_t tsl_index_in_sector; uint32_t sector_addr; #endif @@ -128,16 +134,24 @@ static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) tsl->addr.log = FDB_DATA_UNUSED; tsl->time = 0; } else { +#if defined(FDB_TSDB_FIXED_BLOB_SIZE) || defined(FDB_TSDB_USING_SEQ_MODE) + sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); + tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; +#endif + +#ifdef FDB_TSDB_USING_SEQ_MODE + /* Calculate time based on sector start time + index position */ + tsl->time = tsl->time + tsl_index_in_sector; +#else + tsl->time = idx.time; +#endif + #ifdef FDB_TSDB_FIXED_BLOB_SIZE tsl->log_len = FDB_TSDB_FIXED_BLOB_SIZE; - sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); - tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; tsl->addr.log = sector_addr + db_sec_size(db) - (tsl_index_in_sector + 1) * FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); - tsl->time = idx.time; #else tsl->log_len = idx.log_len; tsl->addr.log = idx.log_addr; - tsl->time = idx.time; #endif } @@ -327,12 +341,23 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) idx.log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(idx.log_len); #endif +#ifdef FDB_TSDB_USING_SEQ_MODE + (void)time; +#else idx.time = time; +#endif /* write the status will by write granularity */ _FDB_WRITE_STATUS(db, idx_addr, idx.status_table, FDB_TSL_STATUS_NUM, FDB_TSL_PRE_WRITE, false); /* write other index info */ +#ifndef FDB_TSDB_USING_SEQ_MODE FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false); +#else +#ifndef FDB_TSDB_FIXED_BLOB_SIZE + FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.log_len, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false); +#endif +// #else no other index info +#endif /* write blob data */ #ifdef FDB_TSDB_FIXED_BLOB_SIZE FLASH_WRITE(db, log_addr, blob->buf, blob->size, false); @@ -409,7 +434,12 @@ static fdb_err_t update_sec_status(fdb_tsdb_t db, tsdb_sec_info_t sector, fdb_bl static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestamp) { fdb_err_t result = FDB_NO_ERR; +#ifdef FDB_TSDB_USING_SEQ_MODE + fdb_time_t cur_time = db->last_time + 1; + (void)timestamp; +#else fdb_time_t cur_time = timestamp == NULL ? db->get_time() : *timestamp; +#endif #ifdef FDB_TSDB_FIXED_BLOB_SIZE if(blob->size != FDB_TSDB_FIXED_BLOB_SIZE) { @@ -542,6 +572,9 @@ void fdb_tsl_iter(fdb_tsdb_t db, fdb_tsl_cb cb, void *arg) tsl.addr.index = sector.addr + SECTOR_HDR_DATA_SIZE; /* search all TSL */ do { +#ifdef FDB_TSDB_USING_SEQ_MODE + tsl.time = sector.start_time; +#endif read_tsl(db, &tsl); /* iterator is interrupted when callback return true */ if (cb(&tsl, arg)) { @@ -592,6 +625,9 @@ void fdb_tsl_iter_reverse(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg) tsl.addr.index = sector.end_idx; /* search all TSL */ do { +#ifdef FDB_TSDB_USING_SEQ_MODE + tsl.time = sector.start_time; +#endif read_tsl(db, &tsl); /* iterator is interrupted when callback return true */ if (cb(&tsl, cb_arg)) { @@ -609,11 +645,18 @@ void fdb_tsl_iter_reverse(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg) /* * Found the matched TSL address. */ -static int search_start_tsl_addr(fdb_tsdb_t db, int start, int end, fdb_time_t from, fdb_time_t to) +static int search_start_tsl_addr(fdb_tsdb_t db, int start, int end, fdb_time_t from, fdb_time_t to +#ifdef FDB_TSDB_USING_SEQ_MODE + ,fdb_time_t start_time +#endif +) { struct fdb_tsl tsl; while (true) { tsl.addr.index = start + FDB_ALIGN((end - start) / 2, LOG_IDX_DATA_SIZE); +#ifdef FDB_TSDB_USING_SEQ_MODE + tsl.time = start_time; +#endif read_tsl(db, &tsl); if (tsl.time < from) { start = tsl.addr.index + LOG_IDX_DATA_SIZE; @@ -626,6 +669,9 @@ static int search_start_tsl_addr(fdb_tsdb_t db, int start, int end, fdb_time_t f if (start > end) { if (from > to) { tsl.addr.index = start; +#ifdef FDB_TSDB_USING_SEQ_MODE + tsl.time = start_time; +#endif read_tsl(db, &tsl); if (tsl.time > from) { start -= LOG_IDX_DATA_SIZE; @@ -700,9 +746,16 @@ void fdb_tsl_iter_by_time(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to, fdb_tsl found_start_tsl = true; /* search the first start TSL address */ - tsl.addr.index = search_start_tsl_addr(db, start, end, from, to); + tsl.addr.index = search_start_tsl_addr(db, start, end, from, to +#ifdef FDB_TSDB_USING_SEQ_MODE + , sector.start_time +#endif + ); /* search all TSL */ do { +#ifdef FDB_TSDB_USING_SEQ_MODE + tsl.time = sector.start_time; +#endif read_tsl(db, &tsl); if (tsl.status != FDB_TSL_UNUSED) { if ((from <= to && tsl.time >= from && tsl.time <= to) @@ -945,7 +998,7 @@ void fdb_tsdb_control(fdb_tsdb_t db, int cmd, void *arg) * @param db database object * @param name database name * @param path FAL mode: partition name, file mode: database saved directory path - * @param get_time get current time function + * @param get_time get current time function, not used if FDB_TSDB_USING_SEQ_MODE defined * @param max_len maximum length of each log * @param user_data user data * @@ -957,7 +1010,11 @@ fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path, fdb_g struct tsdb_sec_info sector; struct check_sec_hdr_cb_args check_sec_arg = { db, false, 0, 0}; +#ifndef FDB_TSDB_USING_SEQ_MODE FDB_ASSERT(get_time); +#else + (void)get_time; +#endif result = _fdb_init_ex((fdb_db_t)db, name, path, FDB_DB_TYPE_TS, user_data); if (result != FDB_NO_ERR) { @@ -967,7 +1024,9 @@ fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path, fdb_g /* lock the TSDB */ db_lock(db); +#ifndef FDB_TSDB_USING_SEQ_MODE db->get_time = get_time; +#endif db->max_len = max_len; /* default rollover flag is true */ db->rollover = true; From a32bcba16ba9df2c6b78bfa7fd439df1cc003764 Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Tue, 16 Dec 2025 20:09:25 +1000 Subject: [PATCH 03/11] Fix inconsistent indentation noted in PR review --- src/fdb_tsdb.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 0ef0822..c485906 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -117,8 +117,8 @@ static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) { struct log_idx_data idx; #ifdef FDB_TSDB_FIXED_BLOB_SIZE - uint32_t tsl_index_in_sector; - uint32_t sector_addr; + uint32_t tsl_index_in_sector; + uint32_t sector_addr; #endif /* read TSL index raw data */ _fdb_flash_read((fdb_db_t)db, tsl->addr.index, (uint32_t *) &idx, sizeof(struct log_idx_data)); @@ -129,11 +129,11 @@ static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) tsl->time = 0; } else { #ifdef FDB_TSDB_FIXED_BLOB_SIZE - tsl->log_len = FDB_TSDB_FIXED_BLOB_SIZE; - sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); - tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; - tsl->addr.log = sector_addr + db_sec_size(db) - (tsl_index_in_sector + 1) * FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); - tsl->time = idx.time; + tsl->log_len = FDB_TSDB_FIXED_BLOB_SIZE; + sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); + tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; + tsl->addr.log = sector_addr + db_sec_size(db) - (tsl_index_in_sector + 1) * FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); + tsl->time = idx.time; #else tsl->log_len = idx.log_len; tsl->addr.log = idx.log_addr; @@ -321,7 +321,7 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) struct log_idx_data idx; uint32_t idx_addr = db->cur_sec.empty_idx; #ifdef FDB_TSDB_FIXED_BLOB_SIZE - uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); + uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); #else idx.log_len = blob->size; idx.log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(idx.log_len); @@ -335,7 +335,7 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false); /* write blob data */ #ifdef FDB_TSDB_FIXED_BLOB_SIZE - FLASH_WRITE(db, log_addr, blob->buf, blob->size, false); + FLASH_WRITE(db, log_addr, blob->buf, blob->size, false); #else FLASH_WRITE(db, idx.log_addr, blob->buf, blob->size, false); #endif @@ -412,10 +412,10 @@ static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestam fdb_time_t cur_time = timestamp == NULL ? db->get_time() : *timestamp; #ifdef FDB_TSDB_FIXED_BLOB_SIZE - if(blob->size != FDB_TSDB_FIXED_BLOB_SIZE) { - FDB_INFO("Error: blob size (%zu) must equal FDB_TSDB_FIXED_BLOB_SIZE (%d)\n", blob->size, FDB_TSDB_FIXED_BLOB_SIZE); - return FDB_WRITE_ERR; - } + if(blob->size != FDB_TSDB_FIXED_BLOB_SIZE) { + FDB_INFO("Error: blob size (%zu) must equal FDB_TSDB_FIXED_BLOB_SIZE (%d)\n", blob->size, FDB_TSDB_FIXED_BLOB_SIZE); + return FDB_WRITE_ERR; + } #else /* check the append length, MUST less than the db->max_len */ if(blob->size > db->max_len) From b2bd249f1864a4add26d9221d9991db282742a52 Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Tue, 16 Dec 2025 20:21:29 +1000 Subject: [PATCH 04/11] Add warning that enabling this macro will cause incompatibility in Flash data format, as requested in PR review --- inc/fdb_cfg_template.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/fdb_cfg_template.h b/inc/fdb_cfg_template.h index b9902da..d54d8ca 100644 --- a/inc/fdb_cfg_template.h +++ b/inc/fdb_cfg_template.h @@ -25,7 +25,8 @@ /* Use fixed-size blobs in TSDB to save flash overhead (8 bytes per entry). * Define this to the fixed blob size in bytes when all TSL entries are the same size. - * Ideal for logging fixed-size sensor data (e.g., float + timestamp). */ + * Ideal for logging fixed-size sensor data (e.g., float + timestamp). + * Warning: If defined will be incompataible with variable blob flash store or if fix blob size is later changed */ /* #define FDB_TSDB_FIXED_BLOB_SIZE 4 */ /* Using FAL storage mode */ From 0d3899a94436047ae31a20322aaa077ae7a6cdd2 Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Tue, 16 Dec 2025 21:02:07 +1000 Subject: [PATCH 05/11] Improve FLASH_WRITE reusability as requested in PR review --- src/fdb_tsdb.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index c485906..45ff6e1 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -320,12 +320,7 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) fdb_err_t result = FDB_NO_ERR; struct log_idx_data idx; uint32_t idx_addr = db->cur_sec.empty_idx; -#ifdef FDB_TSDB_FIXED_BLOB_SIZE - uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE); -#else - idx.log_len = blob->size; - idx.log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(idx.log_len); -#endif + uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(blob->size); idx.time = time; @@ -334,11 +329,7 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) /* write other index info */ FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false); /* write blob data */ -#ifdef FDB_TSDB_FIXED_BLOB_SIZE FLASH_WRITE(db, log_addr, blob->buf, blob->size, false); -#else - FLASH_WRITE(db, idx.log_addr, blob->buf, blob->size, false); -#endif /* write the status will by write granularity */ _FDB_WRITE_STATUS(db, idx_addr, idx.status_table, FDB_TSL_STATUS_NUM, FDB_TSL_WRITE, true); From 6dcd4adaa11456be04bee83f7561032f1730c093 Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Wed, 17 Dec 2025 19:23:29 +1000 Subject: [PATCH 06/11] tsdb: fix missing log address/size for variable blobs This regression was introduced by previous commit 0d3899a. --- src/fdb_tsdb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 45ff6e1..7d83c08 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -322,6 +322,11 @@ static fdb_err_t write_tsl(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t time) uint32_t idx_addr = db->cur_sec.empty_idx; uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(blob->size); +#ifndef FDB_TSDB_FIXED_BLOB_SIZE + // variable-size blobs must store address and size in flash + idx.log_addr = log_addr; + idx.log_len = blob->size; +#endif idx.time = time; /* write the status will by write granularity */ From dc3588448d101f2e6d726419baeeb453b115666c Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Wed, 17 Dec 2025 19:42:32 +1000 Subject: [PATCH 07/11] Move fixed-size variables to reduce #ifdef usage (pre-PR review) --- src/fdb_tsdb.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 7d83c08..97e5dbf 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -116,10 +116,7 @@ struct check_sec_hdr_cb_args { static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) { struct log_idx_data idx; -#ifdef FDB_TSDB_FIXED_BLOB_SIZE - uint32_t tsl_index_in_sector; - uint32_t sector_addr; -#endif + /* read TSL index raw data */ _fdb_flash_read((fdb_db_t)db, tsl->addr.index, (uint32_t *) &idx, sizeof(struct log_idx_data)); tsl->status = (fdb_tsl_status_t) _fdb_get_status(idx.status_table, FDB_TSL_STATUS_NUM); @@ -129,6 +126,8 @@ static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) tsl->time = 0; } else { #ifdef FDB_TSDB_FIXED_BLOB_SIZE + uint32_t tsl_index_in_sector; + uint32_t sector_addr; tsl->log_len = FDB_TSDB_FIXED_BLOB_SIZE; sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; From cf3275c87a30495cdf9be38710e3c3c5b0362eb0 Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Wed, 17 Dec 2025 19:48:18 +1000 Subject: [PATCH 08/11] fix spelling and formatting per PR review --- inc/fdb_cfg_template.h | 2 +- src/fdb_tsdb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/fdb_cfg_template.h b/inc/fdb_cfg_template.h index d54d8ca..f8bde78 100644 --- a/inc/fdb_cfg_template.h +++ b/inc/fdb_cfg_template.h @@ -26,7 +26,7 @@ /* Use fixed-size blobs in TSDB to save flash overhead (8 bytes per entry). * Define this to the fixed blob size in bytes when all TSL entries are the same size. * Ideal for logging fixed-size sensor data (e.g., float + timestamp). - * Warning: If defined will be incompataible with variable blob flash store or if fix blob size is later changed */ + * Warning: If defined will be incompatible with variable blob flash store or if fixed blob size is later changed */ /* #define FDB_TSDB_FIXED_BLOB_SIZE 4 */ /* Using FAL storage mode */ diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 97e5dbf..bc53375 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -407,7 +407,7 @@ static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestam fdb_time_t cur_time = timestamp == NULL ? db->get_time() : *timestamp; #ifdef FDB_TSDB_FIXED_BLOB_SIZE - if(blob->size != FDB_TSDB_FIXED_BLOB_SIZE) { + if (blob->size != FDB_TSDB_FIXED_BLOB_SIZE) { FDB_INFO("Error: blob size (%zu) must equal FDB_TSDB_FIXED_BLOB_SIZE (%d)\n", blob->size, FDB_TSDB_FIXED_BLOB_SIZE); return FDB_WRITE_ERR; } From 5c5c31e839e713e708b1ecfeb3ccda7af1a9e72c Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Thu, 18 Dec 2025 21:40:42 +1000 Subject: [PATCH 09/11] Fixed formatting --- src/fdb_tsdb.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 5463a80..8a0a0a1 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -133,7 +133,7 @@ static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) #if defined(FDB_TSDB_FIXED_BLOB_SIZE) || defined(FDB_TSDB_USING_SEQ_MODE) uint32_t tsl_index_in_sector; uint32_t sector_addr; - sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); + sector_addr = FDB_ALIGN_DOWN(tsl->addr.index, db_sec_size(db)); tsl_index_in_sector = (tsl->addr.index - sector_addr - SECTOR_HDR_DATA_SIZE) / LOG_IDX_DATA_SIZE; #endif @@ -429,8 +429,8 @@ static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestam { fdb_err_t result = FDB_NO_ERR; #ifdef FDB_TSDB_USING_SEQ_MODE - fdb_time_t cur_time = db->last_time + 1; - (void)timestamp; + fdb_time_t cur_time = db->last_time + 1; + (void)timestamp; #else fdb_time_t cur_time = timestamp == NULL ? db->get_time() : *timestamp; #endif @@ -664,7 +664,7 @@ static int search_start_tsl_addr(fdb_tsdb_t db, int start, int end, fdb_time_t f if (from > to) { tsl.addr.index = start; #ifdef FDB_TSDB_USING_SEQ_MODE - tsl.time = start_time; + tsl.time = start_time; #endif read_tsl(db, &tsl); if (tsl.time > from) { @@ -742,13 +742,13 @@ void fdb_tsl_iter_by_time(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to, fdb_tsl /* search the first start TSL address */ tsl.addr.index = search_start_tsl_addr(db, start, end, from, to #ifdef FDB_TSDB_USING_SEQ_MODE - , sector.start_time + , sector.start_time #endif - ); + ); /* search all TSL */ do { #ifdef FDB_TSDB_USING_SEQ_MODE - tsl.time = sector.start_time; + tsl.time = sector.start_time; #endif read_tsl(db, &tsl); if (tsl.status != FDB_TSL_UNUSED) { @@ -1007,7 +1007,7 @@ fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path, fdb_g #ifndef FDB_TSDB_USING_SEQ_MODE FDB_ASSERT(get_time); #else - (void)get_time; + (void)get_time; #endif result = _fdb_init_ex((fdb_db_t)db, name, path, FDB_DB_TYPE_TS, user_data); From a781eb458561cc6536f7ebbe3d1e4736d4015eca Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Thu, 18 Dec 2025 21:49:25 +1000 Subject: [PATCH 10/11] Fixed spelling and added warning comment for sequential mode --- inc/fdb_cfg_template.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/fdb_cfg_template.h b/inc/fdb_cfg_template.h index 3b6e7d6..200121d 100644 --- a/inc/fdb_cfg_template.h +++ b/inc/fdb_cfg_template.h @@ -30,10 +30,10 @@ /* #define FDB_TSDB_FIXED_BLOB_SIZE 4 */ -/* Use sequentual mode - eliminates per-entry timestamp storage by calculating timestamps +/* Use sequential mode - eliminates per-entry timestamp storage by calculating timestamps * on-the-fly, saving sizeof(fdb_time_t). In this mode timestamps are monotonically increasing by 1 on each log * and don't require application to provide a time function. - */ + * Warning: If defined will be incompatible with time flash store */ /* #define FDB_TSDB_USING_SEQ_MODE */ /* Using FAL storage mode */ From c5350179bedd04d5d419752ded916e02905cb06f Mon Sep 17 00:00:00 2001 From: EzraZigenbine Date: Fri, 2 Jan 2026 20:32:56 +1000 Subject: [PATCH 11/11] tsdb: update fdb_get_time signature (breaking change) As per PR review, fdb_get_time now takes fdb_tsdb_t as an argument. This breaking change is required to support FDB_TSDB_USING_SEQ_MODE while keeping the TSDB API consistent across modes. Updated all demos to use the new API. Also updated docs. --- demos/esp32_spi_flash/main/main.c | 16 ++------- .../esp8266_spi_flash/main/hello_world_main.c | 16 ++------- demos/linux/applications/main.c | 8 ++--- demos/stm32f103ve/applications/main.c | 16 ++------- demos/stm32f405rg/applications/main.c | 16 ++------- .../stm32f405rg_spi_flash/applications/main.c | 16 ++------- docs/api.md | 2 +- docs/demo-details.md | 10 +++--- inc/fdb_cfg_template.h | 4 +-- inc/fdb_def.h | 8 ++--- src/fdb_tsdb.c | 34 ++++++++++++------- tests/fdb_tsdb_tc.c | 4 ++- 12 files changed, 49 insertions(+), 101 deletions(-) diff --git a/demos/esp32_spi_flash/main/main.c b/demos/esp32_spi_flash/main/main.c index 069a32a..1a5d5d4 100644 --- a/demos/esp32_spi_flash/main/main.c +++ b/demos/esp32_spi_flash/main/main.c @@ -32,8 +32,6 @@ static struct fdb_default_kv_node default_kv_table[] = { static struct fdb_kvdb kvdb = {0}; /* TSDB object */ struct fdb_tsdb tsdb = {0}; -/* counts for simulated timestamp */ -static int counts = 0; static SemaphoreHandle_t s_lock = NULL; extern void kvdb_basic_sample(fdb_kvdb_t kvdb); @@ -51,14 +49,6 @@ static void unlock(fdb_db_t db) xSemaphoreGive(s_lock); } -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; @@ -114,13 +104,11 @@ int flashdb_demo(void) * "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. + * NULL: Function to get the current timestamp. Define if using RTC; leaving empty (NULL) uses sequential time. * 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); + result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", NULL, 128, NULL); if (result != FDB_NO_ERR) { diff --git a/demos/esp8266_spi_flash/main/hello_world_main.c b/demos/esp8266_spi_flash/main/hello_world_main.c index 89a987a..ff68b1a 100644 --- a/demos/esp8266_spi_flash/main/hello_world_main.c +++ b/demos/esp8266_spi_flash/main/hello_world_main.c @@ -30,8 +30,6 @@ static struct fdb_default_kv_node default_kv_table[] = { static struct fdb_kvdb kvdb = { 0 }; /* TSDB object */ struct fdb_tsdb tsdb = { 0 }; -/* counts for simulated timestamp */ -static int counts = 0; static SemaphoreHandle_t s_lock = NULL; extern void kvdb_basic_sample(fdb_kvdb_t kvdb); @@ -49,14 +47,6 @@ static void unlock(fdb_db_t db) xSemaphoreGive(s_lock); } -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; @@ -110,13 +100,11 @@ int flashdb_demo(void) * "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. + * NULL: Function to get the current timestamp. Define if using RTC; leaving empty (NULL) uses sequential time. * 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); + result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", NULL, 128, NULL); if (result != FDB_NO_ERR) { return -1; diff --git a/demos/linux/applications/main.c b/demos/linux/applications/main.c index 975d124..3bd005d 100644 --- a/demos/linux/applications/main.c +++ b/demos/linux/applications/main.c @@ -27,8 +27,6 @@ static struct fdb_default_kv_node default_kv_table[] = { 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); @@ -45,8 +43,10 @@ static void unlock(fdb_db_t db) pthread_mutex_unlock((pthread_mutex_t *)db->user_data); } -static fdb_time_t get_time(void) +static fdb_time_t get_time(fdb_tsdb_t db) { + /* db not used to get time */ + (void)db; return time(NULL); } @@ -125,8 +125,6 @@ int main(void) * ts_locker: The locker object. */ result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, &ts_locker); - /* 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; diff --git a/demos/stm32f103ve/applications/main.c b/demos/stm32f103ve/applications/main.c index 29971e8..efe1349 100644 --- a/demos/stm32f103ve/applications/main.c +++ b/demos/stm32f103ve/applications/main.c @@ -28,8 +28,6 @@ static struct fdb_default_kv_node default_kv_table[] = { 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); @@ -46,14 +44,6 @@ 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 main(void) { fdb_err_t result; @@ -102,13 +92,11 @@ int main(void) * "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. + * NULL: Function to get the current timestamp. Define if using RTC; leaving empty (NULL) uses sequential time. * 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); + result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", NULL, 128, NULL); if (result != FDB_NO_ERR) { return -1; diff --git a/demos/stm32f405rg/applications/main.c b/demos/stm32f405rg/applications/main.c index 70573c6..05b8c6e 100644 --- a/demos/stm32f405rg/applications/main.c +++ b/demos/stm32f405rg/applications/main.c @@ -28,8 +28,6 @@ static struct fdb_default_kv_node default_kv_table[] = { 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); @@ -46,14 +44,6 @@ 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 main(void) { fdb_err_t result; @@ -102,13 +92,11 @@ int main(void) * "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. + * NULL: Function to get the current timestamp. Define if using RTC; leaving empty (NULL) uses sequential time. * 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); + result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", NULL, 128, NULL); if (result != FDB_NO_ERR) { return -1; diff --git a/demos/stm32f405rg_spi_flash/applications/main.c b/demos/stm32f405rg_spi_flash/applications/main.c index 70573c6..05b8c6e 100644 --- a/demos/stm32f405rg_spi_flash/applications/main.c +++ b/demos/stm32f405rg_spi_flash/applications/main.c @@ -28,8 +28,6 @@ static struct fdb_default_kv_node default_kv_table[] = { 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); @@ -46,14 +44,6 @@ 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 main(void) { fdb_err_t result; @@ -102,13 +92,11 @@ int main(void) * "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. + * NULL: Function to get the current timestamp. Define if using RTC; leaving empty (NULL) uses sequential time. * 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); + result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", NULL, 128, NULL); if (result != FDB_NO_ERR) { return -1; diff --git a/docs/api.md b/docs/api.md index e638732..ff265ff 100644 --- a/docs/api.md +++ b/docs/api.md @@ -250,7 +250,7 @@ Using this iterator API, all KVs in the entire KVDB can be traversed. | db | Database Objects | | name | Database name | | path | FAL mode: the partition name in the partition table, file mode: the path where the database is saved | -| get_time | Function to get the current timestamp | +| get_time | Function to get the current timestamp, NULL to use the default sequential timestamps. | | max_len | Maximum length of each TSL | | user_data | User-defined data, NULL if not available | | Return | Error Code | diff --git a/docs/demo-details.md b/docs/demo-details.md index ba8601e..2210281 100644 --- a/docs/demo-details.md +++ b/docs/demo-details.md @@ -53,13 +53,11 @@ In the demo project, the `main function` in `main.c` is the entry function. This * "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. + * NULL: Function to get the current timestamp. Define if using RTC; leaving empty (NULL) uses sequential time. * 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); + result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", NULL, 128, NULL); if (result != FDB_NO_ERR) { return -1; @@ -86,9 +84,9 @@ For bare metal platforms, the lock and unlock callbacks are usually set to close #### timestamp simulation -For TSDB, the timestamp in the normal project should be obtained through RTC or network clock, but here to enhance the versatility of the demonstration project, use `fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);` to get the last used timestamp of TSDB, Deposit in `counts`. Every time you use `get_time` to get the current time, it will add one to `counts` to simulate the action of moving forward in time and avoid repetition. +In a normal TSDB project, the application should define the get_time function to obtain timestamps from a RTC. In this demonstration project, to keep things simple, passing NULL as the get_time function causes TSDB to use a default timestamp function that increments the last timestamp by one for each record, simulating forward-moving time. -Therefore, the time stamp simulated by this method does not have the meaning of real-time time, just to make the time stamp inserted in each record not repeated. +Tip: If you don’t need RTC timestamps and want to reduce flash usage, you can enable FDB_TSDB_USING_SEQ_MODE in fdb_cfg_template.h #### Example diff --git a/inc/fdb_cfg_template.h b/inc/fdb_cfg_template.h index 200121d..0151837 100644 --- a/inc/fdb_cfg_template.h +++ b/inc/fdb_cfg_template.h @@ -31,8 +31,8 @@ /* Use sequential mode - eliminates per-entry timestamp storage by calculating timestamps - * on-the-fly, saving sizeof(fdb_time_t). In this mode timestamps are monotonically increasing by 1 on each log - * and don't require application to provide a time function. + * on-the-fly, saving sizeof(fdb_time_t). + * In this mode, timestamps increment by 1; providing a non-NULL get_time causes an ASSERT. * Warning: If defined will be incompatible with time flash store */ /* #define FDB_TSDB_USING_SEQ_MODE */ diff --git a/inc/fdb_def.h b/inc/fdb_def.h index 9eec7e4..c410230 100644 --- a/inc/fdb_def.h +++ b/inc/fdb_def.h @@ -109,7 +109,10 @@ if (!(EXPR)) \ typedef int32_t fdb_time_t; #endif /* FDB_USING_TIMESTAMP_64BIT */ -typedef fdb_time_t (*fdb_get_time)(void); +struct fdb_tsdb; +typedef struct fdb_tsdb *fdb_tsdb_t; + +typedef fdb_time_t (*fdb_get_time)(fdb_tsdb_t db); struct fdb_default_kv_node { char *key; @@ -323,15 +326,12 @@ struct fdb_tsdb { struct fdb_db parent; /**< inherit from fdb_db */ struct tsdb_sec_info cur_sec; /**< current using sector */ fdb_time_t last_time; /**< last TSL timestamp */ -#ifndef FDB_TSDB_USING_SEQ_MODE fdb_get_time get_time; /**< the current timestamp get function */ -#endif size_t max_len; /**< the maximum length of each log */ bool rollover; /**< the oldest data will rollover by newest data, default is true */ void *user_data; }; -typedef struct fdb_tsdb *fdb_tsdb_t; /* blob structure */ struct fdb_blob { diff --git a/src/fdb_tsdb.c b/src/fdb_tsdb.c index 6d14761..9d0168b 100644 --- a/src/fdb_tsdb.c +++ b/src/fdb_tsdb.c @@ -119,6 +119,8 @@ struct check_sec_hdr_cb_args { uint32_t empty_addr; }; +static fdb_time_t fdb_default_get_time(fdb_tsdb_t db); + static fdb_err_t read_tsl(fdb_tsdb_t db, fdb_tsl_t tsl) { struct log_idx_data idx; @@ -429,11 +431,10 @@ static fdb_err_t update_sec_status(fdb_tsdb_t db, tsdb_sec_info_t sector, fdb_bl static fdb_err_t tsl_append(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t *timestamp) { fdb_err_t result = FDB_NO_ERR; + fdb_time_t cur_time = timestamp == NULL ? db->get_time(db) : *timestamp; #ifdef FDB_TSDB_USING_SEQ_MODE - fdb_time_t cur_time = db->last_time + 1; - (void)timestamp; -#else - fdb_time_t cur_time = timestamp == NULL ? db->get_time() : *timestamp; + /* should never have a timestamp in sequential mode */ + FDB_ASSERT(!timestamp) #endif #ifdef FDB_TSDB_FIXED_BLOB_SIZE @@ -993,7 +994,7 @@ void fdb_tsdb_control(fdb_tsdb_t db, int cmd, void *arg) * @param db database object * @param name database name * @param path FAL mode: partition name, file mode: database saved directory path - * @param get_time get current time function, not used if FDB_TSDB_USING_SEQ_MODE defined + * @param get_time get current time function * @param max_len maximum length of each log * @param user_data user data * @@ -1005,10 +1006,9 @@ fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path, fdb_g struct tsdb_sec_info sector; struct check_sec_hdr_cb_args check_sec_arg = { db, false, 0, 0}; -#ifndef FDB_TSDB_USING_SEQ_MODE - FDB_ASSERT(get_time); -#else - (void)get_time; +#ifdef FDB_TSDB_USING_SEQ_MODE + /* In sequential mode cannot set get_time function */ + FDB_ASSERT(!get_time); #endif result = _fdb_init_ex((fdb_db_t)db, name, path, FDB_DB_TYPE_TS, user_data); @@ -1019,9 +1019,7 @@ fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path, fdb_g /* lock the TSDB */ db_lock(db); -#ifndef FDB_TSDB_USING_SEQ_MODE - db->get_time = get_time; -#endif + db->get_time = get_time == NULL ? fdb_default_get_time : get_time; db->max_len = max_len; /* default rollover flag is true */ db->rollover = true; @@ -1105,4 +1103,16 @@ fdb_err_t fdb_tsdb_deinit(fdb_tsdb_t db) return FDB_NO_ERR; } +/** + * The time series database default get time. + * default mode is sequential mode - returns last_time + 1 + * @param db database object + * + * @return fdb_time_t + */ +static fdb_time_t fdb_default_get_time(fdb_tsdb_t db) +{ + return db->last_time + 1; +} + #endif /* defined(FDB_USING_TSDB) */ diff --git a/tests/fdb_tsdb_tc.c b/tests/fdb_tsdb_tc.c index 9c4492c..8f04629 100644 --- a/tests/fdb_tsdb_tc.c +++ b/tests/fdb_tsdb_tc.c @@ -45,8 +45,10 @@ static int cur_times = 0; static struct test_tls_sector test_secs_info[10]; static fdb_time_t test_db_start_time = 0x7FFFFFFF, test_db_end_time = 0; -static fdb_time_t get_time(void) +static fdb_time_t get_time(fdb_tsdb_t db) { + /* db not used to get time */ + (void)db; cur_times += TEST_TIME_STEP; return cur_times; }