Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * blscan.c
4 : * Bloom index scan functions.
5 : *
6 : * Copyright (c) 2016-2026, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * contrib/bloom/blscan.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 : #include "postgres.h"
14 :
15 : #include "access/relscan.h"
16 : #include "bloom.h"
17 : #include "executor/instrument_node.h"
18 : #include "miscadmin.h"
19 : #include "pgstat.h"
20 : #include "storage/bufmgr.h"
21 :
22 : /*
23 : * Begin scan of bloom index.
24 : */
25 : IndexScanDesc
26 387 : blbeginscan(Relation r, int nkeys, int norderbys)
27 : {
28 : IndexScanDesc scan;
29 : BloomScanOpaque so;
30 :
31 387 : scan = RelationGetIndexScan(r, nkeys, norderbys);
32 :
33 387 : so = (BloomScanOpaque) palloc_object(BloomScanOpaqueData);
34 387 : initBloomState(&so->state, scan->indexRelation);
35 387 : so->sign = NULL;
36 :
37 387 : scan->opaque = so;
38 :
39 387 : return scan;
40 : }
41 :
42 : /*
43 : * Rescan a bloom index.
44 : */
45 : void
46 387 : blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
47 : ScanKey orderbys, int norderbys)
48 : {
49 387 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
50 :
51 387 : if (so->sign)
52 0 : pfree(so->sign);
53 387 : so->sign = NULL;
54 :
55 387 : if (scankey && scan->numberOfKeys > 0)
56 387 : memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
57 387 : }
58 :
59 : /*
60 : * End scan of bloom index.
61 : */
62 : void
63 387 : blendscan(IndexScanDesc scan)
64 : {
65 387 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
66 :
67 387 : if (so->sign)
68 387 : pfree(so->sign);
69 387 : so->sign = NULL;
70 387 : }
71 :
72 : /*
73 : * Insert all matching tuples into a bitmap.
74 : */
75 : int64
76 387 : blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
77 : {
78 387 : int64 ntids = 0;
79 387 : BlockNumber blkno = BLOOM_HEAD_BLKNO,
80 : npages;
81 : int i;
82 : BufferAccessStrategy bas;
83 387 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
84 :
85 387 : if (so->sign == NULL)
86 : {
87 : /* New search: have to calculate search signature */
88 387 : ScanKey skey = scan->keyData;
89 :
90 387 : so->sign = palloc0_array(BloomSignatureWord, so->state.opts.bloomLength);
91 :
92 903 : for (i = 0; i < scan->numberOfKeys; i++)
93 : {
94 : /*
95 : * Assume bloom-indexable operators to be strict, so nothing could
96 : * be found for NULL key.
97 : */
98 516 : if (skey->sk_flags & SK_ISNULL)
99 : {
100 0 : pfree(so->sign);
101 0 : so->sign = NULL;
102 0 : return 0;
103 : }
104 :
105 : /* Add next value to the signature */
106 516 : signValue(&so->state, so->sign, skey->sk_argument,
107 516 : skey->sk_attno - 1);
108 :
109 516 : skey++;
110 : }
111 : }
112 :
113 : /*
114 : * We're going to read the whole index. This is why we use appropriate
115 : * buffer access strategy.
116 : */
117 387 : bas = GetAccessStrategy(BAS_BULKREAD);
118 387 : npages = RelationGetNumberOfBlocks(scan->indexRelation);
119 387 : pgstat_count_index_scan(scan->indexRelation);
120 387 : if (scan->instrument)
121 387 : scan->instrument->nsearches++;
122 :
123 29334 : for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
124 : {
125 : Buffer buffer;
126 : Page page;
127 :
128 28947 : buffer = ReadBufferExtended(scan->indexRelation, MAIN_FORKNUM,
129 : blkno, RBM_NORMAL, bas);
130 :
131 28947 : LockBuffer(buffer, BUFFER_LOCK_SHARE);
132 28947 : page = BufferGetPage(buffer);
133 :
134 28947 : if (!PageIsNew(page) && !BloomPageIsDeleted(page))
135 : {
136 : OffsetNumber offset,
137 28926 : maxOffset = BloomPageGetMaxOffset(page);
138 :
139 14161176 : for (offset = 1; offset <= maxOffset; offset++)
140 : {
141 14132250 : BloomTuple *itup = BloomPageGetTuple(&so->state, page, offset);
142 14132250 : bool res = true;
143 :
144 : /* Check index signature with scan signature */
145 35371848 : for (i = 0; i < so->state.opts.bloomLength; i++)
146 : {
147 34486186 : if ((itup->sign[i] & so->sign[i]) != so->sign[i])
148 : {
149 13246588 : res = false;
150 13246588 : break;
151 : }
152 : }
153 :
154 : /* Add matching tuples to bitmap */
155 14132250 : if (res)
156 : {
157 885662 : tbm_add_tuples(tbm, &itup->heapPtr, 1, true);
158 885662 : ntids++;
159 : }
160 : }
161 : }
162 :
163 28947 : UnlockReleaseBuffer(buffer);
164 28947 : CHECK_FOR_INTERRUPTS();
165 : }
166 387 : FreeAccessStrategy(bas);
167 :
168 387 : return ntids;
169 : }
|