mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
Bloom index contrib module
Module provides new access method. It is actually a simple Bloom filter implemented as pgsql's index. It could give some benefits on search with large number of columns. Module is a single way to test generic WAL interface committed earlier. Author: Teodor Sigaev, Alexander Korotkov Reviewers: Aleksander Alekseev, Michael Paquier, Jim Nasby
This commit is contained in:
175
contrib/bloom/blscan.c
Normal file
175
contrib/bloom/blscan.c
Normal file
@ -0,0 +1,175 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* blscan.c
|
||||
* Bloom index scan functions.
|
||||
*
|
||||
* Copyright (c) 2016, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* contrib/bloom/blscan.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/relscan.h"
|
||||
#include "pgstat.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
#include "bloom.h"
|
||||
|
||||
/*
|
||||
* Begin scan of bloom index.
|
||||
*/
|
||||
IndexScanDesc
|
||||
blbeginscan(Relation r, int nkeys, int norderbys)
|
||||
{
|
||||
IndexScanDesc scan;
|
||||
|
||||
scan = RelationGetIndexScan(r, nkeys, norderbys);
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rescan a bloom index.
|
||||
*/
|
||||
void
|
||||
blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
|
||||
ScanKey orderbys, int norderbys)
|
||||
{
|
||||
BloomScanOpaque so;
|
||||
|
||||
so = (BloomScanOpaque) scan->opaque;
|
||||
|
||||
if (so == NULL)
|
||||
{
|
||||
/* if called from blbeginscan */
|
||||
so = (BloomScanOpaque) palloc(sizeof(BloomScanOpaqueData));
|
||||
initBloomState(&so->state, scan->indexRelation);
|
||||
scan->opaque = so;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
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 to 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 && scan->numberOfKeys > 0)
|
||||
{
|
||||
/* New search: have to calculate search signature */
|
||||
ScanKey skey = scan->keyData;
|
||||
|
||||
so->sign = palloc0(sizeof(SignType) * 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);
|
||||
|
||||
if (!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; res && i < so->state.opts->bloomLength; i++)
|
||||
{
|
||||
if ((itup->sign[i] & so->sign[i]) != so->sign[i])
|
||||
res = false;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
Reference in New Issue
Block a user