GCC Code Coverage Report


Directory: src/
File: src/index/index_base.h
Date: 2026-09-30 11:11:31
Exec Total Coverage
Lines: 6 10 60.0%
Functions: 2 2 100.0%
Branches: 3 6 50.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 * index_base.h - Common index descriptor for search
6 *
7 * PrismIndexBase contains the fields needed by the shared search
8 * path. Standalone embeds it in PrismIndex; PG populates it from
9 * the meta page and amcache.
10 */
11
12 #ifndef PRISM_INDEX_BASE_H
13 #define PRISM_INDEX_BASE_H
14
15 #include "core/types.h"
16 #include "index/centroid_page.h"
17 #include "index/storage.h"
18 #include "quant/rabitq.h"
19
20 /*
21 * Block 0 holds the metapage, so the centroid region a build reserves
22 * starts here and runs to first_posting.
23 */
24 #define PRISM_FIRST_CENTROID_BLKNO 1
25
26 /*
27 * Posting pages the scan cost estimate prices, and what prism_index_settings
28 * reports as posting_pages.
29 *
30 * Block 0 is the metapage and the centroid region a build reserves starts at
31 * PRISM_FIRST_CENTROID_BLKNO, so on a freshly built index the posting pages
32 * are everything from first_posting onward. That range stops measuring them
33 * once a split overflows a level-0 centroid page: the split extends the
34 * relation and chains the new centroid page past the posting region, so the
35 * page is both counted by ncentroid_pages and, to a range measurement, a
36 * posting page. Taking the maintained count out of the relation's size
37 * instead is layout-independent and leaves it in one term only.
38 *
39 * num_pages is the relation's current size, not pg_class.relpages: both
40 * callers read it straight from the relation, the planner included, so the
41 * count never lags a statistics update.
42 *
43 * An upper bound rather than an exact count: free and new pages from
44 * extension slack are included, the same over-count the estimate already
45 * documents for a bloated index.
46 */
47 static inline double
48 421 prism_index_posting_pages(double num_pages, double ncentroid_pages)
49 {
50 421 double n = num_pages - (double)PRISM_FIRST_CENTROID_BLKNO -
51 ncentroid_pages;
52
53
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 415 times.
421 return n < 1.0 ? 1.0 : n;
54 }
55
56 typedef struct PrismIndexBase
57 {
58 /* RaBitQ (must outlive the search context) */
59 RaBitQParams *params;
60 float *pt_global_mean;
61 uint64_t rabitq_seed;
62
63 /* PG: both point to the same VsPgStorage (one index relation).
64 * Standalone: separate ArrayPageStorage for centroids vs postings. */
65 VsStorage *centroid_storage;
66 VsStorage *posting_storage;
67
68 /* Non-NULL for inline page access (standalone postings) */
69 char *page_base;
70
71 /* Index metadata */
72 Dimension dim;
73 uint8_t nlevels;
74 /* Children per tree node; floors the intermediate beam width so the
75 * top-nprobe leaves stay reachable (0 = unknown, no floor). */
76 uint8_t fan_out;
77 /* Leaf (posting-list) count; when nprobe covers every leaf the
78 * intermediate beam keeps whole levels so no subtree is pruned
79 * (0 = unknown, no full-coverage floor). */
80 uint32_t nlist;
81 /*
82 * Root of the centroid tree, which every descent starts from -- NOT the
83 * first block of the centroid region, despite the name. Where the root
84 * sits inside the region depends on the build: a serial build writes the
85 * centroid pages post-order and the root lands last, a parallel one
86 * places it first. The region itself is always
87 * [PRISM_FIRST_CENTROID_BLKNO, first_posting).
88 */
89 BlockNumber first_centroid;
90 /*
91 * First block of the posting-head region; leaf c's head is
92 * first_posting + c. Fixed for the life of the index, since that formula
93 * is how every head is located, so nothing can be inserted below it.
94 */
95 BlockNumber first_posting;
96 /*
97 * Centroid pages reachable from first_centroid. Maintained rather than
98 * derived, because a split with no room on a level-0 page extends the
99 * relation and chains the new page past first_posting, after which the
100 * reserved block range no longer measures the count.
101 */
102 uint32_t ncentroid_pages;
103 DistanceMetric metric;
104 PrismCentroidFormat centroid_format;
105 int fastscan; /* 0=off, 8=uint8, 16=uint16 hacc */
106 float centroid_error_scale; /* scales centroid pruning error (1=default) */
107 float centroid_beam_scale; /* intermediate beam width / nprobe
108 (0.25=default) */
109 /* Build-only: exact internal-node centroids for the build descent
110 * (see PrismExactInternalCentroids in centroid_search.h). NULL — the
111 * default everywhere the base is zero-initialized — keeps the
112 * estimated scoring; the query and insert paths never set it. */
113 const struct PrismExactInternalCentroids *exact_internal;
114 } PrismIndexBase;
115
116 static inline RaBitQParams *
117 18253 prism_index_ensure_rabitq(PrismIndexBase *idx)
118 {
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18253 times.
18253 if (idx->params == NULL)
120 {
121 ✗ idx->params = vs_rabitq_create(idx->dim, idx->rabitq_seed);
122 ✗ if (idx->pt_global_mean != NULL)
123 ✗ vs_rabitq_rotate(
124 ✗ idx->params, idx->pt_global_mean, idx->pt_global_mean);
125 }
126 18253 return idx->params;
127 }
128
129 #endif /* PRISM_INDEX_BASE_H */
130