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 0 : blbeginscan(Relation r, int nkeys, int norderbys)
27 : {
28 0 : IndexScanDesc scan;
29 0 : BloomScanOpaque so;
30 :
31 0 : scan = RelationGetIndexScan(r, nkeys, norderbys);
32 :
33 0 : so = (BloomScanOpaque) palloc_object(BloomScanOpaqueData);
34 0 : initBloomState(&so->state, scan->indexRelation);
35 0 : so->sign = NULL;
36 :
37 0 : scan->opaque = so;
38 :
39 0 : return scan;
40 0 : }
41 :
42 : /*
43 : * Rescan a bloom index.
44 : */
45 : void
46 0 : blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
47 : ScanKey orderbys, int norderbys)
48 : {
49 0 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
50 :
51 0 : if (so->sign)
52 0 : pfree(so->sign);
53 0 : so->sign = NULL;
54 :
55 0 : if (scankey && scan->numberOfKeys > 0)
56 0 : memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
57 0 : }
58 :
59 : /*
60 : * End scan of bloom index.
61 : */
62 : void
63 0 : blendscan(IndexScanDesc scan)
64 : {
65 0 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
66 :
67 0 : if (so->sign)
68 0 : pfree(so->sign);
69 0 : so->sign = NULL;
70 0 : }
71 :
72 : /*
73 : * Insert all matching tuples into a bitmap.
74 : */
75 : int64
76 0 : blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
77 : {
78 0 : int64 ntids = 0;
79 0 : BlockNumber blkno = BLOOM_HEAD_BLKNO,
80 : npages;
81 0 : int i;
82 0 : BufferAccessStrategy bas;
83 0 : BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
84 :
85 0 : if (so->sign == NULL)
86 : {
87 : /* New search: have to calculate search signature */
88 0 : ScanKey skey = scan->keyData;
89 :
90 0 : so->sign = palloc0_array(BloomSignatureWord, so->state.opts.bloomLength);
91 :
92 0 : 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 0 : 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 0 : signValue(&so->state, so->sign, skey->sk_argument,
107 0 : skey->sk_attno - 1);
108 :
109 0 : skey++;
110 0 : }
111 0 : }
112 :
113 : /*
114 : * We're going to read the whole index. This is why we use appropriate
115 : * buffer access strategy.
116 : */
117 0 : bas = GetAccessStrategy(BAS_BULKREAD);
118 0 : npages = RelationGetNumberOfBlocks(scan->indexRelation);
119 0 : pgstat_count_index_scan(scan->indexRelation);
120 0 : if (scan->instrument)
121 0 : scan->instrument->nsearches++;
122 :
123 0 : for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
124 : {
125 0 : Buffer buffer;
126 0 : Page page;
127 :
128 0 : buffer = ReadBufferExtended(scan->indexRelation, MAIN_FORKNUM,
129 0 : blkno, RBM_NORMAL, bas);
130 :
131 0 : LockBuffer(buffer, BUFFER_LOCK_SHARE);
132 0 : page = BufferGetPage(buffer);
133 :
134 0 : if (!PageIsNew(page) && !BloomPageIsDeleted(page))
135 : {
136 0 : OffsetNumber offset,
137 0 : maxOffset = BloomPageGetMaxOffset(page);
138 :
139 0 : for (offset = 1; offset <= maxOffset; offset++)
140 : {
141 0 : BloomTuple *itup = BloomPageGetTuple(&so->state, page, offset);
142 0 : bool res = true;
143 :
144 : /* Check index signature with scan signature */
145 0 : for (i = 0; i < so->state.opts.bloomLength; i++)
146 : {
147 0 : if ((itup->sign[i] & so->sign[i]) != so->sign[i])
148 : {
149 0 : res = false;
150 0 : break;
151 : }
152 0 : }
153 :
154 : /* Add matching tuples to bitmap */
155 0 : if (res)
156 : {
157 0 : tbm_add_tuples(tbm, &itup->heapPtr, 1, true);
158 0 : ntids++;
159 0 : }
160 0 : }
161 0 : }
162 :
163 0 : UnlockReleaseBuffer(buffer);
164 0 : CHECK_FOR_INTERRUPTS();
165 0 : }
166 0 : FreeAccessStrategy(bas);
167 :
168 0 : return ntids;
169 0 : }
|