LCOV - code coverage report
Current view: top level - contrib/bloom - blscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 57 61 93.4 %
Date: 2026-01-14 11:16:57 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.16