GCC Code Coverage Report


Directory: src/
File: src/index/posting_page.c
Date: 2026-09-30 11:11:31
Exec Total Coverage
Lines: 81 86 94.2%
Functions: 7 7 100.0%
Branches: 14 20 70.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2026 Tiger Data, Inc.
3 * Licensed under the PostgreSQL License. See LICENSE for details.
4 *
5 * posting_page.c - Posting list page operations
6 */
7
8 #include "vs_config.h"
9
10 #include "core/log.h"
11 #include "index/posting_page.h"
12
13 #ifndef VS_STANDALONE
14 #include <miscadmin.h> /* CHECK_FOR_INTERRUPTS */
15 #endif
16
17 void
18 3041 prism_posting_check_count(
19 BlockNumber blkno, const PrismPostingPageOpaque *op, Dimension dim)
20 {
21 3041 uint32_t cap = prism_posting_page_cap(op, dim);
22
23
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3041 times.
3041 if (op->entry_count > cap)
24 ✗ vs_error(
25 VS_EXTENSION_NAME
26 ": posting page %u has an invalid entry count (%u > %u); "
27 "the index may be corrupted -- REINDEX it",
28 blkno,
29 (unsigned)op->entry_count,
30 cap);
31 3041 }
32
33 /* ----------------------------------------------------------------
34 * Paged mode (BLCKSZ pages with PG header + opaque)
35 * ---------------------------------------------------------------- */
36
37 void
38 32668 prism_posting_page_init(
39 Page page, uint32_t cluster_id, Dimension dim, uint16_t flags)
40 {
41 32668 PageInit(page, BLCKSZ, sizeof(PrismPostingPageOpaque));
42
43 /* First pages have reduced capacity due to pt_centroid */
44 65336 uint32_t max = (flags & PRISM_POSTING_PAGE_FIRST)
45 11964 ? prism_posting_max_entries_first(dim)
46
2/2
✓ Branch 0 taken 11964 times.
✓ Branch 1 taken 20704 times.
32668 : prism_posting_max_entries(dim);
47 32668 PrismPostingPageOpaque *opaque = prism_posting_opaque(page);
48 32668 opaque->next_blkno = InvalidBlockNumber;
49 32668 opaque->cluster_id = cluster_id;
50 32668 opaque->entry_count = 0;
51 32668 opaque->flags = flags;
52 32668 opaque->page_id = PRISM_POSTING_PAGE_ID;
53 32668 opaque->max_entries = (uint16_t)max;
54 /* Head metadata starts "not computed"; the first insert fills it (the
55 * fields are only consulted on the FIRST page). */
56 32668 opaque->live_count = 0;
57 32668 opaque->tail_blkno = InvalidBlockNumber;
58 32668 }
59
60 bool
61 256832 prism_posting_page_add(
62 Page page,
63 Dimension dim,
64 ItemPointerData tid,
65 float f_add,
66 float f_rescale,
67 float f_error,
68 const uint8_t *bits,
69 uint8_t entry_flags)
70 {
71
2/2
✓ Branch 1 taken 60812 times.
✓ Branch 2 taken 196020 times.
256832 if (!prism_posting_page_has_room(page))
72 2 return false;
73
74 256830 PrismPostingPageOpaque *opaque = prism_posting_opaque(page);
75 256830 uint32_t i = opaque->entry_count;
76 256830 char *content = prism_posting_page_content(page, dim);
77
78 /* Write the entry header (meta + factors) + bits in one contiguous
79 * block at content + i * entry_size. */
80 256830 PrismPostingEntryHeader *hdr = prism_posting_entry_at(content, i, dim);
81 256830 hdr->meta.tid = tid;
82 256830 hdr->meta.flags = entry_flags;
83 256830 hdr->meta.reserved = 0;
84 256830 hdr->f_add = f_add;
85 256830 hdr->f_rescale = f_rescale;
86 256830 hdr->f_error = f_error;
87 256830 memcpy(hdr->bits, bits, VS_RABITQ_BYTES(dim));
88
89 256830 opaque->entry_count = i + 1;
90 256830 return true;
91 }
92
93 /* ----------------------------------------------------------------
94 * Chain walks
95 * ---------------------------------------------------------------- */
96
97 void
98 3688 prism_posting_chain_walk(
99 VsStorage *storage,
100 BlockNumber head,
101 PrismPostingChainCb cb,
102 void *state)
103 {
104 3688 PrismPostingChainPos pos = {.storage = storage, .first = true};
105 3688 BlockNumber blk = head;
106
107
2/2
✓ Branch 0 taken 4392 times.
✓ Branch 1 taken 3688 times.
8080 while (blk != InvalidBlockNumber)
108 {
109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3608 times.
3608 CHECK_FOR_INTERRUPTS();
110
111 4392 pos.blkno = blk;
112 4392 pos.page = vs_storage_read_page(storage, blk);
113
114 /*
115 * Reading next_blkno means casting the special area, so establish
116 * that it is a posting page first -- the same guard every other
117 * page read applies. A chain that leaves posting pages is a
118 * corrupt chain, and ends the walk rather than being followed.
119 */
120
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4392 times.
4392 if (!prism_page_is_posting(pos.page))
121 {
122 ✗ prism_posting_chain_release(&pos);
123 ✗ return;
124 }
125
126 4392 pos.next = prism_posting_opaque(pos.page)->next_blkno;
127
128 4392 bool keep_going = cb(&pos, state);
129
130 /* No-op when the callback released it already. */
131 4392 prism_posting_chain_release(&pos);
132
133
2/2
✓ Branch 0 taken 3608 times.
✓ Branch 1 taken 784 times.
4392 if (!keep_going)
134 ✗ return;
135
136 4392 pos.first = false;
137 4392 blk = pos.next;
138 }
139 }
140
141 void
142 164 prism_posting_chain_mutate(
143 VsStorage *storage,
144 BlockNumber head,
145 PrismPostingChainMutateCb cb,
146 void *state)
147 {
148 164 BlockNumber blk = head;
149
150
2/2
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 164 times.
581 while (blk != InvalidBlockNumber)
151 {
152 417 Page page = vs_storage_write_page(storage, blk);
153 417 PrismPostingPageOpaque *op = prism_posting_opaque(page);
154 417 BlockNumber next = op->next_blkno;
155
156 417 cb(op, state);
157
158 417 vs_storage_commit_page(storage, blk);
159 206 blk = next;
160 }
161 164 }
162
163 /* ----------------------------------------------------------------
164 * Flat mode (one buffer per cluster, custom header)
165 * ---------------------------------------------------------------- */
166
167 void
168 150 prism_posting_flat_init(char *buf, uint32_t max_entries, uint32_t cluster_id)
169 {
170 150 PrismFlatPostingHeader *hdr = prism_flat_posting_header(buf);
171 150 hdr->max_entries = max_entries;
172 150 hdr->entry_count = 0;
173 150 hdr->cluster_id = cluster_id;
174 150 hdr->_pad = 0;
175 150 }
176
177 bool
178 10000 prism_posting_flat_add(
179 char *buf,
180 Dimension dim,
181 ItemPointerData tid,
182 float f_add,
183 float f_rescale,
184 float f_error,
185 const uint8_t *bits,
186 uint8_t entry_flags)
187 {
188 10000 PrismFlatPostingHeader *flat_hdr = prism_flat_posting_header(buf);
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10000 times.
10000 if (flat_hdr->entry_count >= flat_hdr->max_entries)
190 ✗ return false;
191
192 10000 uint32_t i = flat_hdr->entry_count;
193 10000 char *content = prism_flat_posting_content(buf);
194
195 10000 PrismPostingEntryHeader *hdr = prism_posting_entry_at(content, i, dim);
196 10000 hdr->meta.tid = tid;
197 10000 hdr->meta.flags = entry_flags;
198 10000 hdr->meta.reserved = 0;
199 10000 hdr->f_add = f_add;
200 10000 hdr->f_rescale = f_rescale;
201 10000 hdr->f_error = f_error;
202 10000 memcpy(hdr->bits, bits, VS_RABITQ_BYTES(dim));
203
204 10000 flat_hdr->entry_count = i + 1;
205 10000 return true;
206 }
207