I added the following code to FDS:
static void dump_headers(void) {
for (uint16_t page = 0; page < FDS_DATA_PAGES; page++) {
uint32_t const *p_page_end = (m_pages[page].p_addr + FDS_PAGE_SIZE);
fds_header_t const *p_header = (fds_header_t *) (m_pages[page].p_addr + FDS_PAGE_TAG_SIZE);
bool page_valid = true;
while (page_valid && header_has_next(p_header, p_page_end)) {
switch (header_check(p_header, p_page_end)) {
case FDS_HEADER_VALID:
NRF_LOG_INFO("Valid header on page %d, offset %d, file %d, record key %d, length %d words, record id %d", page, ((uint32_t)p_header) - ((uint32_t)m_pages[page].p_addr), p_header->file_id, p_header->record_key, p_header->length_words, p_header->record_id);
p_header = header_jump(p_header);
break;
case FDS_HEADER_DIRTY:
NRF_LOG_INFO("Dirty header on page %d, offset %d, file %d, record key %d, length %d words, record id %d", page, ((uint32_t)p_header) - ((uint32_t)m_pages[page].p_addr), p_header->file_id, p_header->record_key, p_header->length_words, p_header->record_id);
p_header = header_jump(p_header);
break;
case FDS_HEADER_CORRUPT:
// We can't reliably jump over this record.
// There is nothing more we can do on this page.
NRF_LOG_INFO("Corrupt header on page %d, offset %d, file %d, record key %d, length %d words, record id %d", page, ((uint32_t)p_header) - ((uint32_t)m_pages[page].p_addr), p_header->file_id, p_header->record_key, p_header->length_words, p_header->record_id);
page_valid = false;
break;
}
}
}
}
static void queue_process(ret_code_t result)
{
// snip
switch (m_p_cur_op->op_code)
{
// snip
case FDS_OP_GC:
result = gc_execute(result);
if(result == FDS_OP_COMPLETED) {
NRF_LOG_INFO("GC complete. Dumping storage headers:");
dump_headers();
}
break;
}
}
It seems sometimes this works fine, and after GC is complete all record headers are valid. However, sometimes it doesn't, and dirty records remain after GC:
<info> app: GC complete. Dumping storage headers: <info> app: Valid header on page 0, offset 8, file 3, record key 1, length 3 words, record id 1 <info> app: Valid header on page 0, offset 32, file 4, record key 1, length 4 words, record id 2 <info> app: Valid header on page 0, offset 60, file 1, record key 1, length 1 words, record id 3 <info> app: Valid header on page 0, offset 76, file 2, record key 1, length 4 words, record id 4 <info> app: Valid header on page 0, offset 104, file 1, record key 4, length 8 words, record id 5 <info> app: Valid header on page 0, offset 148, file 2, record key 4, length 4 words, record id 6 <info> app: Dirty header on page 0, offset 176, file 1, record key 0, length 1 words, record id 7 <info> app: Dirty header on page 0, offset 192, file 2, record key 0, length 4 words, record id 8 <info> app: Valid header on page 0, offset 220, file 1, record key 2, length 3 words, record id 9 <info> app: Valid header on page 0, offset 244, file 2, record key 2, length 4 words, record id 10 <info> app: Dirty header on page 0, offset 272, file 1, record key 0, length 1 words, record id 11 <info> app: Dirty header on page 0, offset 288, file 2, record key 0, length 4 words, record id 12 <info> app: Valid header on page 0, offset 316, file 1, record key 7, length 1 words, record id 13 <info> app: Valid header on page 0, offset 332, file 2, record key 7, length 4 words, record id 14 <info> app: Valid header on page 0, offset 360, file 1, record key 6, length 30 words, record id 15 <info> app: Valid header on page 0, offset 492, file 2, record key 6, length 4 words, record id 16 <info> app: Valid header on page 0, offset 520, file 1, record key 5, length 26 words, record id 17 <info> app: Valid header on page 0, offset 636, file 2, record key 5, length 4 words, record id 18 <info> app: Dirty header on page 0, offset 664, file 1, record key 0, length 236 words, record id 19 <info> app: Dirty header on page 0, offset 1620, file 2, record key 0, length 4 words, record id 20 <info> app: Dirty header on page 0, offset 1648, file 1, record key 0, length 1 words, record id 21 <info> app: Dirty header on page 0, offset 1664, file 2, record key 0, length 4 words, record id 22 <info> app: Valid header on page 0, offset 1692, file 1, record key 3, length 1 words, record id 23 <info> app: Valid header on page 0, offset 1708, file 2, record key 3, length 4 words, record id 24 <info> app: Dirty header on page 0, offset 1736, file 1, record key 0, length 234 words, record id 25 <info> app: Dirty header on page 0, offset 2684, file 2, record key 0, length 4 words, record id 26 <info> app: Dirty header on page 0, offset 2712, file 1, record key 0, length 1 words, record id 27 <info> app: Dirty header on page 0, offset 2728, file 2, record key 0, length 4 words, record id 28 <info> app: Dirty header on page 0, offset 2756, file 1, record key 0, length 233 words, record id 29 <info> app: Dirty header on page 0, offset 3700, file 2, record key 0, length 4 words, record id 30 <info> app: Dirty header on page 0, offset 3728, file 1, record key 0, length 1 words, record id 31 <info> app: Dirty header on page 0, offset 3744, file 2, record key 0, length 4 words, record id 32 <info> app: Dirty header on page 0, offset 3772, file 2, record key 0, length 4 words, record id 34 <info> app: Dirty header on page 0, offset 3800, file 1, record key 0, length 1 words, record id 35 <info> app: Dirty header on page 0, offset 3816, file 2, record key 0, length 4 words, record id 36 <info> app: Dirty header on page 0, offset 3844, file 2, record key 0, length 4 words, record id 38 <info> app: Dirty header on page 0, offset 3872, file 1, record key 0, length 1 words, record id 39 <info> app: Dirty header on page 0, offset 3888, file 2, record key 0, length 4 words, record id 40 <info> app: Dirty header on page 0, offset 3916, file 2, record key 0, length 4 words, record id 42 <info> app: Dirty header on page 0, offset 3944, file 1, record key 0, length 1 words, record id 43 <info> app: Dirty header on page 0, offset 3960, file 2, record key 0, length 4 words, record id 44 <info> app: Dirty header on page 0, offset 3988, file 2, record key 0, length 4 words, record id 46 <info> app: Dirty header on page 0, offset 4016, file 1, record key 0, length 1 words, record id 47 <info> app: Dirty header on page 0, offset 4032, file 2, record key 0, length 4 words, record id 48 <info> app: Dirty header on page 0, offset 4060, file 2, record key 0, length 4 words, record id 50 <info> app: Dirty header on page 1, offset 8, file 1, record key 0, length 233 words, record id 33 <info> app: Dirty header on page 1, offset 952, file 1, record key 0, length 233 words, record id 37 <info> app: Dirty header on page 1, offset 1896, file 1, record key 0, length 233 words, record id 41 <info> app: Dirty header on page 1, offset 2840, file 1, record key 0, length 50 words, record id 45 <info> app: Dirty header on page 1, offset 3052, file 1, record key 0, length 234 words, record id 49 <info> app: Valid header on page 1, offset 4000, file 1, record key 9, length 1 words, record id 51 <info> app: Valid header on page 1, offset 4016, file 2, record key 9, length 4 words, record id 52
This causes FDS_ERR_NO_SPACE_IN_FLASH on next write, and repeating GC doesn't fix it. Why would GC succeed when it doesn't clean up dirty records? And why is garbage collection not cleaning up records?