Branch data 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 : : #include "storage/read_stream.h"
22 : :
23 : : /*
24 : : * Begin scan of bloom index.
25 : : */
26 : : IndexScanDesc
27 : 387 : blbeginscan(Relation r, int nkeys, int norderbys)
28 : : {
29 : : IndexScanDesc scan;
30 : : BloomScanOpaque so;
31 : :
32 : 387 : scan = RelationGetIndexScan(r, nkeys, norderbys);
33 : :
34 : 387 : so = (BloomScanOpaque) palloc_object(BloomScanOpaqueData);
35 : 387 : initBloomState(&so->state, scan->indexRelation);
36 : 387 : so->sign = NULL;
37 : :
38 : 387 : scan->opaque = so;
39 : :
40 : 387 : return scan;
41 : : }
42 : :
43 : : /*
44 : : * Rescan a bloom index.
45 : : */
46 : : void
47 : 387 : blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
48 : : ScanKey orderbys, int norderbys)
49 : : {
50 : 387 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
51 : :
52 [ - + ]: 387 : if (so->sign)
53 : 0 : pfree(so->sign);
54 : 387 : so->sign = NULL;
55 : :
56 [ + - + - ]: 387 : if (scankey && scan->numberOfKeys > 0)
57 : 387 : memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
58 : 387 : }
59 : :
60 : : /*
61 : : * End scan of bloom index.
62 : : */
63 : : void
64 : 387 : blendscan(IndexScanDesc scan)
65 : : {
66 : 387 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
67 : :
68 [ + - ]: 387 : if (so->sign)
69 : 387 : pfree(so->sign);
70 : 387 : so->sign = NULL;
71 : 387 : }
72 : :
73 : : /*
74 : : * Insert all matching tuples into a bitmap.
75 : : */
76 : : int64
77 : 387 : blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
78 : : {
79 : 387 : int64 ntids = 0;
80 : : BlockNumber blkno,
81 : : npages;
82 : : int i;
83 : : BufferAccessStrategy bas;
84 : 387 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
85 : : BlockRangeReadStreamPrivate p;
86 : : ReadStream *stream;
87 : :
88 [ + - ]: 387 : if (so->sign == NULL)
89 : : {
90 : : /* New search: have to calculate search signature */
91 : 387 : ScanKey skey = scan->keyData;
92 : :
93 : 387 : so->sign = palloc0_array(BloomSignatureWord, so->state.opts.bloomLength);
94 : :
95 [ + + ]: 903 : for (i = 0; i < scan->numberOfKeys; i++)
96 : : {
97 : : /*
98 : : * Assume bloom-indexable operators to be strict, so nothing could
99 : : * be found for NULL key.
100 : : */
101 [ - + ]: 516 : if (skey->sk_flags & SK_ISNULL)
102 : : {
103 : 0 : pfree(so->sign);
104 : 0 : so->sign = NULL;
105 : 0 : return 0;
106 : : }
107 : :
108 : : /* Add next value to the signature */
109 : 516 : signValue(&so->state, so->sign, skey->sk_argument,
110 : 516 : skey->sk_attno - 1);
111 : :
112 : 516 : skey++;
113 : : }
114 : : }
115 : :
116 : : /*
117 : : * We're going to read the whole index. This is why we use appropriate
118 : : * buffer access strategy.
119 : : */
120 : 387 : bas = GetAccessStrategy(BAS_BULKREAD);
121 : 387 : npages = RelationGetNumberOfBlocks(scan->indexRelation);
122 [ - + - - : 387 : pgstat_count_index_scan(scan->indexRelation);
+ - ]
123 [ - + ]: 387 : if (scan->instrument)
124 : 0 : scan->instrument->nsearches++;
125 : :
126 : : /* Scan all blocks except the metapage using streaming reads */
127 : 387 : p.current_blocknum = BLOOM_HEAD_BLKNO;
128 : 387 : p.last_exclusive = npages;
129 : :
130 : : /*
131 : : * It is safe to use batchmode as block_range_read_stream_cb takes no
132 : : * locks.
133 : : */
134 : 387 : stream = read_stream_begin_relation(READ_STREAM_FULL |
135 : : READ_STREAM_USE_BATCHING,
136 : : bas,
137 : : scan->indexRelation,
138 : : MAIN_FORKNUM,
139 : : block_range_read_stream_cb,
140 : : &p,
141 : : 0);
142 : :
143 [ + + ]: 29334 : for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
144 : : {
145 : : Buffer buffer;
146 : : Page page;
147 : :
148 : 28947 : buffer = read_stream_next_buffer(stream, NULL);
149 : 28947 : LockBuffer(buffer, BUFFER_LOCK_SHARE);
150 : 28947 : page = BufferGetPage(buffer);
151 : :
152 [ + - + + ]: 28947 : if (!PageIsNew(page) && !BloomPageIsDeleted(page))
153 : : {
154 : : OffsetNumber offset,
155 : 28926 : maxOffset = BloomPageGetMaxOffset(page);
156 : :
157 [ + + ]: 14161176 : for (offset = 1; offset <= maxOffset; offset++)
158 : : {
159 : 14132250 : BloomTuple *itup = BloomPageGetTuple(&so->state, page, offset);
160 : 14132250 : bool res = true;
161 : :
162 : : /* Check index signature with scan signature */
163 [ + + ]: 35371848 : for (i = 0; i < so->state.opts.bloomLength; i++)
164 : : {
165 [ + + ]: 34486186 : if ((itup->sign[i] & so->sign[i]) != so->sign[i])
166 : : {
167 : 13246588 : res = false;
168 : 13246588 : break;
169 : : }
170 : : }
171 : :
172 : : /* Add matching tuples to bitmap */
173 [ + + ]: 14132250 : if (res)
174 : : {
175 : 885662 : tbm_add_tuples(tbm, &itup->heapPtr, 1, true);
176 : 885662 : ntids++;
177 : : }
178 : : }
179 : : }
180 : :
181 : 28947 : UnlockReleaseBuffer(buffer);
182 [ - + ]: 28947 : CHECK_FOR_INTERRUPTS();
183 : : }
184 : :
185 : : Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer);
186 : 387 : read_stream_end(stream);
187 : 387 : FreeAccessStrategy(bas);
188 : :
189 : 387 : return ntids;
190 : : }
|