mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			173 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * blscan.c
 | 
						|
 *		Bloom index scan functions.
 | 
						|
 *
 | 
						|
 * Copyright (c) 2016-2023, PostgreSQL Global Development Group
 | 
						|
 *
 | 
						|
 * IDENTIFICATION
 | 
						|
 *	  contrib/bloom/blscan.c
 | 
						|
 *
 | 
						|
 *-------------------------------------------------------------------------
 | 
						|
 */
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include "access/relscan.h"
 | 
						|
#include "bloom.h"
 | 
						|
#include "miscadmin.h"
 | 
						|
#include "pgstat.h"
 | 
						|
#include "storage/bufmgr.h"
 | 
						|
#include "storage/lmgr.h"
 | 
						|
#include "utils/memutils.h"
 | 
						|
#include "utils/rel.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Begin scan of bloom index.
 | 
						|
 */
 | 
						|
IndexScanDesc
 | 
						|
blbeginscan(Relation r, int nkeys, int norderbys)
 | 
						|
{
 | 
						|
	IndexScanDesc scan;
 | 
						|
	BloomScanOpaque so;
 | 
						|
 | 
						|
	scan = RelationGetIndexScan(r, nkeys, norderbys);
 | 
						|
 | 
						|
	so = (BloomScanOpaque) palloc(sizeof(BloomScanOpaqueData));
 | 
						|
	initBloomState(&so->state, scan->indexRelation);
 | 
						|
	so->sign = NULL;
 | 
						|
 | 
						|
	scan->opaque = so;
 | 
						|
 | 
						|
	return scan;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Rescan a bloom index.
 | 
						|
 */
 | 
						|
void
 | 
						|
blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
 | 
						|
		 ScanKey orderbys, int norderbys)
 | 
						|
{
 | 
						|
	BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
 | 
						|
 | 
						|
	if (so->sign)
 | 
						|
		pfree(so->sign);
 | 
						|
	so->sign = NULL;
 | 
						|
 | 
						|
	if (scankey && scan->numberOfKeys > 0)
 | 
						|
	{
 | 
						|
		memmove(scan->keyData, scankey,
 | 
						|
				scan->numberOfKeys * sizeof(ScanKeyData));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * End scan of bloom index.
 | 
						|
 */
 | 
						|
void
 | 
						|
blendscan(IndexScanDesc scan)
 | 
						|
{
 | 
						|
	BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
 | 
						|
 | 
						|
	if (so->sign)
 | 
						|
		pfree(so->sign);
 | 
						|
	so->sign = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Insert all matching tuples into a bitmap.
 | 
						|
 */
 | 
						|
int64
 | 
						|
blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
 | 
						|
{
 | 
						|
	int64		ntids = 0;
 | 
						|
	BlockNumber blkno = BLOOM_HEAD_BLKNO,
 | 
						|
				npages;
 | 
						|
	int			i;
 | 
						|
	BufferAccessStrategy bas;
 | 
						|
	BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
 | 
						|
 | 
						|
	if (so->sign == NULL)
 | 
						|
	{
 | 
						|
		/* New search: have to calculate search signature */
 | 
						|
		ScanKey		skey = scan->keyData;
 | 
						|
 | 
						|
		so->sign = palloc0(sizeof(BloomSignatureWord) * so->state.opts.bloomLength);
 | 
						|
 | 
						|
		for (i = 0; i < scan->numberOfKeys; i++)
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 * Assume bloom-indexable operators to be strict, so nothing could
 | 
						|
			 * be found for NULL key.
 | 
						|
			 */
 | 
						|
			if (skey->sk_flags & SK_ISNULL)
 | 
						|
			{
 | 
						|
				pfree(so->sign);
 | 
						|
				so->sign = NULL;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
 | 
						|
			/* Add next value to the signature */
 | 
						|
			signValue(&so->state, so->sign, skey->sk_argument,
 | 
						|
					  skey->sk_attno - 1);
 | 
						|
 | 
						|
			skey++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * We're going to read the whole index. This is why we use appropriate
 | 
						|
	 * buffer access strategy.
 | 
						|
	 */
 | 
						|
	bas = GetAccessStrategy(BAS_BULKREAD);
 | 
						|
	npages = RelationGetNumberOfBlocks(scan->indexRelation);
 | 
						|
 | 
						|
	for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
 | 
						|
	{
 | 
						|
		Buffer		buffer;
 | 
						|
		Page		page;
 | 
						|
 | 
						|
		buffer = ReadBufferExtended(scan->indexRelation, MAIN_FORKNUM,
 | 
						|
									blkno, RBM_NORMAL, bas);
 | 
						|
 | 
						|
		LockBuffer(buffer, BUFFER_LOCK_SHARE);
 | 
						|
		page = BufferGetPage(buffer);
 | 
						|
		TestForOldSnapshot(scan->xs_snapshot, scan->indexRelation, page);
 | 
						|
 | 
						|
		if (!PageIsNew(page) && !BloomPageIsDeleted(page))
 | 
						|
		{
 | 
						|
			OffsetNumber offset,
 | 
						|
						maxOffset = BloomPageGetMaxOffset(page);
 | 
						|
 | 
						|
			for (offset = 1; offset <= maxOffset; offset++)
 | 
						|
			{
 | 
						|
				BloomTuple *itup = BloomPageGetTuple(&so->state, page, offset);
 | 
						|
				bool		res = true;
 | 
						|
 | 
						|
				/* Check index signature with scan signature */
 | 
						|
				for (i = 0; i < so->state.opts.bloomLength; i++)
 | 
						|
				{
 | 
						|
					if ((itup->sign[i] & so->sign[i]) != so->sign[i])
 | 
						|
					{
 | 
						|
						res = false;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				/* Add matching tuples to bitmap */
 | 
						|
				if (res)
 | 
						|
				{
 | 
						|
					tbm_add_tuples(tbm, &itup->heapPtr, 1, true);
 | 
						|
					ntids++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		UnlockReleaseBuffer(buffer);
 | 
						|
		CHECK_FOR_INTERRUPTS();
 | 
						|
	}
 | 
						|
	FreeAccessStrategy(bas);
 | 
						|
 | 
						|
	return ntids;
 | 
						|
}
 |