mirror of https://github.com/postgres/postgres
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;
|
|
}
|