LCOV - code coverage report
Current view: top level - contrib/bloom - blscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 92.2 % 64 59
Test Date: 2026-03-24 02:15:55 Functions: 100.0 % 4 4
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              : #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              : }
        

Generated by: LCOV version 2.0-1