| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2026 Tiger Data, Inc. | ||
| 3 | * Licensed under the PostgreSQL License. See LICENSE for details. | ||
| 4 | * | ||
| 5 | * centroid_page.c - Centroid tree page operations | ||
| 6 | * | ||
| 7 | * Implements page initialization and entry insertion for centroid pages | ||
| 8 | * using bidirectional growth: metadata forward, vector data backward. | ||
| 9 | * The data format (RaBitQ, float32, float16) is stored in the page | ||
| 10 | * opaque flags and determines per-entry data size. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "index/centroid_page.h" | ||
| 14 | |||
| 15 | void | ||
| 16 | 2209 | prism_centroid_page_init_fmt(Page page, uint8_t level, PrismCentroidFormat fmt) | |
| 17 | { | ||
| 18 | 2209 | PageInit(page, BLCKSZ, sizeof(PrismCentroidPageOpaque)); | |
| 19 | |||
| 20 | /* Initialize the opaque area */ | ||
| 21 | 2209 | PrismCentroidPageOpaque *opaque = PRISM_CENTROID_OPAQUE(page); | |
| 22 | 2209 | opaque->next_blkno = InvalidBlockNumber; | |
| 23 | 2209 | opaque->entry_count = 0; | |
| 24 | 2209 | opaque->level = level; | |
| 25 | 2209 | opaque->flags = fmt & PRISM_CENTROID_FMT_MASK; | |
| 26 | 2209 | opaque->page_id = PRISM_CENTROID_PAGE_ID; | |
| 27 | 2209 | } | |
| 28 | |||
| 29 | void * | ||
| 30 | 6623 | prism_centroid_page_add_entry_begin( | |
| 31 | Page page, | ||
| 32 | Dimension dim, | ||
| 33 | BlockNumber child_blkno, | ||
| 34 | uint16_t child_count, | ||
| 35 | uint16_t flags) | ||
| 36 | { | ||
| 37 |
2/2✓ Branch 1 taken 1599 times.
✓ Branch 2 taken 5024 times.
|
6623 | if (!prism_centroid_page_has_room(page, dim, false)) |
| 38 | 8 | return NULL; | |
| 39 | |||
| 40 | 6611 | PageHeader header = (PageHeader)page; | |
| 41 | 6611 | PrismCentroidPageOpaque *opaque = PRISM_CENTROID_OPAQUE(page); | |
| 42 | 6611 | PrismCentroidFormat fmt = prism_centroid_page_format(page); | |
| 43 | 6611 | uint16_t index = opaque->entry_count; | |
| 44 | |||
| 45 | /* Write metadata (forward region) */ | ||
| 46 | 6611 | PrismCentroidEntryMeta *meta = prism_centroid_meta_mut(page, index); | |
| 47 | 6611 | meta->child_blkno = child_blkno; | |
| 48 | 6611 | meta->child_count = child_count; | |
| 49 | 6611 | meta->flags = flags; | |
| 50 | |||
| 51 | /* Reserve data space (backward region) */ | ||
| 52 | 6611 | uint32_t data_size = prism_centroid_data_size(dim, fmt); | |
| 53 | 6611 | header->pd_upper -= data_size; | |
| 54 | |||
| 55 | 6611 | opaque->entry_count = index + 1; | |
| 56 | |||
| 57 | /* | ||
| 58 | * Recompute rather than advance: a page committed outside index build | ||
| 59 | * comes back with pd_lower covering the hole (see | ||
| 60 | * prism_centroid_meta_end), so incrementing it would leave the page | ||
| 61 | * looking permanently full. | ||
| 62 | */ | ||
| 63 | 8202 | header->pd_lower = (LocationIndex) | |
| 64 | 6611 | prism_centroid_meta_end(page, opaque->entry_count); | |
| 65 | |||
| 66 | 6611 | return page + header->pd_upper; | |
| 67 | } | ||
| 68 | |||
| 69 | bool | ||
| 70 | 2266 | prism_centroid_page_add_entry( | |
| 71 | Page page, | ||
| 72 | Dimension dim, | ||
| 73 | BlockNumber child_blkno, | ||
| 74 | uint16_t child_count, | ||
| 75 | uint16_t flags, | ||
| 76 | const void *data) | ||
| 77 | { | ||
| 78 | 2266 | PrismCentroidFormat fmt = prism_centroid_page_format(page); | |
| 79 | 2266 | uint32_t data_size = prism_centroid_data_size(dim, fmt); | |
| 80 | |||
| 81 | 2266 | void *dest = prism_centroid_page_add_entry_begin( | |
| 82 | page, dim, child_blkno, child_count, flags); | ||
| 83 |
2/2✓ Branch 0 taken 378 times.
✓ Branch 1 taken 1888 times.
|
2266 | if (dest == NULL) |
| 84 | 8 | return false; | |
| 85 | |||
| 86 | 2254 | memcpy(dest, data, data_size); | |
| 87 | 2254 | return true; | |
| 88 | } | ||
| 89 | |||
| 90 | void | ||
| 91 | 138 | prism_centroid_page_overwrite_entry( | |
| 92 | Page page, | ||
| 93 | Dimension dim, | ||
| 94 | uint32_t index, | ||
| 95 | BlockNumber child_blkno, | ||
| 96 | const void *data) | ||
| 97 | { | ||
| 98 | 138 | PrismCentroidFormat fmt = prism_centroid_page_format(page); | |
| 99 | 138 | uint32_t data_size = prism_centroid_data_size(dim, fmt); | |
| 100 | |||
| 101 | /* | ||
| 102 | * In-place replacement of an existing entry: rewrite the fixed-size | ||
| 103 | * metadata slot (forward region) and the fixed-size data slot (backward | ||
| 104 | * region) without touching pd_lower/pd_upper or entry_count, so the page | ||
| 105 | * layout is unchanged and no relayout is needed. child_count/flags are | ||
| 106 | * preserved (a leaf entry stays a leaf). Used by the incremental split to | ||
| 107 | * repoint a leaf at its first child list and update its routing centroid. | ||
| 108 | */ | ||
| 109 | 138 | PrismCentroidEntryMeta *meta = prism_centroid_meta_mut(page, index); | |
| 110 | 138 | meta->child_blkno = child_blkno; | |
| 111 | |||
| 112 | 138 | void *dest = (char *)PageGetSpecialPointer(page) - | |
| 113 | 138 | (size_t)(index + 1) * data_size; | |
| 114 | 138 | memcpy(dest, data, data_size); | |
| 115 | 138 | } | |
| 116 |