Write a completed interior page to disk and record it as a parent. Returns updated parent_count, or -1 on allocation failure.
| 597 | // Write a completed interior page to disk and record it as a parent. |
| 598 | // Returns updated parent_count, or -1 on allocation failure. |
| 599 | static int write_interior_page(PageBuilder *pb, uint8_t *page, int cell_count, int content_offset, |
| 600 | uint32_t right_child_page, const PageRef *children, |
| 601 | int right_child_idx, bool is_index, PageRef **parents, |
| 602 | int parent_count, int *parent_cap) { |
| 603 | pb->next_page = cbm_skip_pending_byte(pb->next_page); |
| 604 | uint32_t pnum = pb->next_page++; |
| 605 | page[0] = is_index ? INTERIOR_INDEX_FLAG : INTERIOR_TABLE_FLAG; |
| 606 | put_u16(page + HDR_FREEBLOCK_OFF, 0); |
| 607 | put_u16(page + HDR_CELLCOUNT_OFF, (uint16_t)cell_count); |
| 608 | put_u16(page + HDR_CONTENT_OFF, (uint16_t)content_offset); |
| 609 | page[HDR_FRAGBYTES_OFF] = 0; |
| 610 | put_u32(page + HDR_RIGHTCHILD_OFF, right_child_page); |
| 611 | |
| 612 | (void)fseek(pb->fp, (long)(pnum - SKIP_ONE) * CBM_PAGE_SIZE, SEEK_SET); |
| 613 | (void)fwrite(page, SKIP_ONE, CBM_PAGE_SIZE, pb->fp); |
| 614 | |
| 615 | if (parent_count >= *parent_cap) { |
| 616 | int old_pcap = *parent_cap; |
| 617 | *parent_cap = old_pcap == 0 ? INITIAL_PARENT_CAP : old_pcap * GROWTH_FACTOR; |
| 618 | PageRef *tmp = (PageRef *)realloc(*parents, *parent_cap * sizeof(PageRef)); |
| 619 | if (!tmp) { |
| 620 | free(*parents); |
| 621 | *parents = NULL; |
| 622 | return CBM_NOT_FOUND; |
| 623 | } |
| 624 | *parents = tmp; |
| 625 | memset(&(*parents)[old_pcap], 0, |
| 626 | ((size_t)*parent_cap - (size_t)old_pcap) * sizeof(PageRef)); |
| 627 | } |
| 628 | (*parents)[parent_count].page_num = pnum; |
| 629 | (*parents)[parent_count].max_key = children[right_child_idx].max_key; |
| 630 | if (is_index && children[right_child_idx].sep_cell) { |
| 631 | int slen = children[right_child_idx].sep_cell_len; |
| 632 | (*parents)[parent_count].sep_cell = (uint8_t *)malloc(slen); |
| 633 | memcpy((*parents)[parent_count].sep_cell, children[right_child_idx].sep_cell, slen); |
| 634 | (*parents)[parent_count].sep_cell_len = slen; |
| 635 | } else { |
| 636 | (*parents)[parent_count].sep_cell = NULL; |
| 637 | (*parents)[parent_count].sep_cell_len = 0; |
| 638 | } |
| 639 | return parent_count + SKIP_ONE; |
| 640 | } |
| 641 | |
| 642 | // Free a PageRef array (sep_cell allocations), unless it's the original leaves. |
| 643 | static void free_children(PageRef *children, int child_count, const PageRef *leaves) { |
no test coverage detected