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