Flush current leaf page to file
| 477 | |
| 478 | // Flush current leaf page to file |
| 479 | static void pb_flush_leaf(PageBuilder *pb) { |
| 480 | if (pb->cell_count == 0) { |
| 481 | return; |
| 482 | } |
| 483 | |
| 484 | int hdr = pb->page1_offset; |
| 485 | // Write leaf page header |
| 486 | pb->page[hdr + 0] = pb->is_index ? BTREE_LEAF_INDEX : BTREE_LEAF_TABLE; // leaf flag |
| 487 | put_u16(pb->page + hdr + HDR_FREEBLOCK_OFF, 0); // first freeblock |
| 488 | put_u16(pb->page + hdr + HDR_CELLCOUNT_OFF, (uint16_t)pb->cell_count); |
| 489 | put_u16(pb->page + hdr + HDR_CONTENT_OFF, (uint16_t)pb->content_offset); |
| 490 | pb->page[hdr + HDR_FRAGBYTES_OFF] = 0; // fragmented free bytes |
| 491 | |
| 492 | // Write page to file. Skip the pending byte page (SQLite reserved). |
| 493 | pb->next_page = cbm_skip_pending_byte(pb->next_page); |
| 494 | uint32_t page_num = pb->next_page; |
| 495 | long offset = (long)(page_num - SKIP_ONE) * CBM_PAGE_SIZE; |
| 496 | (void)fseek(pb->fp, offset, SEEK_SET); |
| 497 | (void)fwrite(pb->page, SKIP_ONE, CBM_PAGE_SIZE, pb->fp); |
| 498 | |
| 499 | // Record this leaf for interior page building |
| 500 | if (pb->leaf_count >= pb->leaf_cap) { |
| 501 | int old_cap = pb->leaf_cap; |
| 502 | pb->leaf_cap = old_cap == 0 ? INITIAL_LEAF_CAP : old_cap * GROWTH_FACTOR; |
| 503 | void *tmp = realloc(pb->leaves, (size_t)pb->leaf_cap * sizeof(PageRef)); |
| 504 | if (!tmp) { |
| 505 | free(pb->leaves); |
| 506 | pb->leaves = NULL; |
| 507 | return; |
| 508 | } |
| 509 | pb->leaves = (PageRef *)tmp; |
| 510 | /* Zero-init new slots */ |
| 511 | memset(&pb->leaves[old_cap], 0, ((size_t)pb->leaf_cap - (size_t)old_cap) * sizeof(PageRef)); |
| 512 | } |
| 513 | pb->leaves[pb->leaf_count].page_num = page_num; |
| 514 | // max_key is set by caller before flush |
| 515 | pb->leaf_count++; |
| 516 | |
| 517 | // Reset for next page |
| 518 | pb->next_page++; |
| 519 | pb->cell_count = 0; |
| 520 | pb->content_offset = CBM_PAGE_SIZE; |
| 521 | pb->page1_offset = 0; // only page 1 has the 100-byte header |
| 522 | pb->ptr_offset = BTREE_HEADER_SIZE; // standard B-tree header size for non-page-1 |
| 523 | memset(pb->page, 0, CBM_PAGE_SIZE); |
| 524 | } |
| 525 | |
| 526 | // Check if a cell of given size fits in the current page |
| 527 | static bool pb_cell_fits(PageBuilder *pb, int cell_len) { |
no test coverage detected