Skip to content

Conversation

@EzraZigenbine
Copy link
Contributor

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()

…educe 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
EzraZigenbine added a commit to EzraZigenbine/FlashDB that referenced this pull request Dec 15, 2025
…equential 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 armink#387
@armink armink requested a review from Copilot December 15, 2025 10:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a compile-time optimization for TSDB to reduce flash usage in scenarios where all TSL entries are the same fixed size. When FDB_TSDB_FIXED_BLOB_SIZE is enabled, it removes the log_len and log_addr fields from the log_idx_data structure (saving 8 bytes per entry) and calculates the log address dynamically during reads based on the TSL's position within the sector.

Key changes:

  • Conditionally exclude log_len and log_addr fields from log_idx_data struct when FDB_TSDB_FIXED_BLOB_SIZE is defined
  • Implement dynamic log address calculation in read_tsl() based on TSL index position
  • Add strict size validation in tsl_append() to enforce fixed-size constraint

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
src/fdb_tsdb.c Core implementation: conditional struct fields, dynamic address calculation in read_tsl(), modified write_tsl() to use local log_addr variable, and added size validation in tsl_append()
inc/fdb_cfg_template.h Configuration template: added commented-out FDB_TSDB_FIXED_BLOB_SIZE definition with documentation

Critical Issues Identified:

  1. The change to log_idx_data struct size affects LOG_IDX_DATA_SIZE macro, which is used extensively for sector layout calculations throughout the codebase. This creates an incompatible on-flash format between compilation modes.
  2. The flash write operation at line 335 uses sizeof(struct log_idx_data) which varies based on the compile-time flag, potentially writing incorrect data.
  3. Multiple indentation inconsistencies (tabs vs spaces) throughout the new code.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 131 to 137
#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
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: These lines use tabs while the surrounding code uses spaces. Please use spaces for consistency with the rest of the file.

Copilot uses AI. Check for mistakes.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All code format needs to be checked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed see link

src/fdb_tsdb.c Outdated
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);
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: These lines use tabs while the surrounding code uses spaces. Please use spaces for consistency with the rest of the file.

Copilot uses AI. Check for mistakes.
src/fdb_tsdb.c Outdated
Comment on lines 415 to 418
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;
}
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improved validation message: Consider adding the actual value of FDB_TSDB_FIXED_BLOB_SIZE to the error message for better debugging. Also, there's missing space after "if" which violates standard C style guidelines.

Suggested change
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) does not match required fixed size (%d)\n", blob->size, FDB_TSDB_FIXED_BLOB_SIZE);
return FDB_WRITE_ERR;
}

Copilot uses AI. Check for mistakes.
src/fdb_tsdb.c Outdated
Comment on lines 119 to 122
#ifdef FDB_TSDB_FIXED_BLOB_SIZE
uint32_t tsl_index_in_sector;
uint32_t sector_addr;
#endif
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: These lines use tabs while the surrounding code uses spaces. Please use spaces for consistency with the rest of the file.

Copilot uses AI. Check for mistakes.
src/fdb_tsdb.c Outdated
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);
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: These lines use tabs while the surrounding code uses spaces. Please use spaces for consistency with the rest of the file.

Suggested change
FLASH_WRITE(db, log_addr, blob->buf, blob->size, false);
FLASH_WRITE(db, log_addr, blob->buf, blob->size, false);

Copilot uses AI. Check for mistakes.
src/fdb_tsdb.c Outdated
Comment on lines 414 to 418
#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;
}
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: These lines use tabs while the surrounding code uses spaces. Please use spaces for consistency with the rest of the file.

Copilot uses AI. Check for mistakes.
/* 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);
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical bug: When FDB_TSDB_FIXED_BLOB_SIZE is defined, the log_idx_data structure no longer contains log_len and log_addr fields. This write operation attempts to write "sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET" bytes from &idx.time, which would only write the time field. However, in the non-fixed-size case, this writes time, log_len, and log_addr. The size calculation needs to be conditional on FDB_TSDB_FIXED_BLOB_SIZE to ensure the correct number of bytes are written.

Suggested change
FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false);
#ifdef FDB_TSDB_FIXED_BLOB_SIZE
FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(idx.time), false);
#else
FLASH_WRITE(db, idx_addr + LOG_IDX_TS_OFFSET, &idx.time, sizeof(struct log_idx_data) - LOG_IDX_TS_OFFSET, false);
#endif

Copilot uses AI. Check for mistakes.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This AI comments can be ignored

Comment on lines +97 to +100
#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
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical design issue: LOG_IDX_DATA_SIZE is defined as FDB_WG_ALIGN(sizeof(struct log_idx_data)) and is used throughout the codebase for sector layout calculations, address computations, and space accounting. When FDB_TSDB_FIXED_BLOB_SIZE is enabled, the struct size changes (removing 8 bytes), which changes LOG_IDX_DATA_SIZE. This creates an incompatible on-flash format - databases created with this feature enabled cannot be read by code compiled without it, and vice versa. This breaks the entire storage layout and makes the feature fundamentally incompatible with existing data. Consider using a separate macro or ensuring the struct size remains constant to maintain format compatibility.

Suggested change
#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
uint32_t log_len; /**< node total length (header + name + value), must align by FDB_WRITE_GRAN */
uint32_t log_addr; /**< node address */

Copilot uses AI. Check for mistakes.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignoring the AI's comment for now, enabling this macro will indeed cause incompatibility in the data format stored in Flash. Just specify this when configuring the macro.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated see link

src/fdb_tsdb.c Outdated
Comment on lines 134 to 135
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);
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential calculation error: The calculation of tsl_index_in_sector divides by LOG_IDX_DATA_SIZE, but LOG_IDX_DATA_SIZE itself changes when FDB_TSDB_FIXED_BLOB_SIZE is enabled (smaller struct). This means the index calculation will be correct for the current compilation mode, but the data layout on flash will be incompatible with code compiled in a different mode. Additionally, verify that the log address calculation correctly accounts for alignment - it assumes entries are packed from the end of the sector backwards with FDB_WG_ALIGN(FDB_TSDB_FIXED_BLOB_SIZE) spacing, which should match how write_tsl() allocates them.

Copilot uses AI. Check for mistakes.
idx.log_len = blob->size;
idx.time = time;
idx.log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(idx.log_len);
#endif
Copy link
Owner

@armink armink Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#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_len = FDB_TSDB_FIXED_BLOB_SIZE;
#else
uint32_t log_addr = db->cur_sec.empty_data - FDB_WG_ALIGN(idx.log_len);
uint32_t log_len = blob->size;
#endif

With this code modification, the following code should have higher reusability.

Copy link
Contributor Author

@EzraZigenbine EzraZigenbine Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.
As I understand the request, this update improves reusability of the flash write calls later in the function by removing #ifdef.
Instead of the suggested approach, used blob->size, which is already fixed or variable depending on the macro.

tsl->addr.log = FDB_DATA_UNUSED;
tsl->time = 0;
} else {
#ifdef FDB_TSDB_FIXED_BLOB_SIZE
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code can move to here

   uint32_t tsl_index_in_sector;
    uint32_t sector_addr;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/* 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 */
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "incompataible" should be "incompatible".

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

src/fdb_tsdb.c Outdated
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) {
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after 'if' keyword. C style conventions typically require a space between 'if' and the opening parenthesis for better readability.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

/* 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 */
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "fix" should be "fixed" (as in "fixed blob size").

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 405 to 418
#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)
{
FDB_INFO("Warning: append length (%" PRIdMAX ") is more than the db->max_len (%" PRIdMAX "). This tsl will be dropped.\n",
(intmax_t)blob->size, (intmax_t)(db->max_len));
return FDB_WRITE_ERR;
}
#endif
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new FDB_TSDB_FIXED_BLOB_SIZE feature lacks test coverage. Consider adding tests to verify the fixed-size blob validation logic, the runtime address calculation, and the interaction with existing TSDB operations.

Copilot uses AI. Check for mistakes.
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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Is there a way to simplify the logic here?

@armink armink merged commit 8856961 into armink:master Dec 17, 2025
2 checks passed
@armink
Copy link
Owner

armink commented Dec 17, 2025

Thx @EzraZigenbine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants