mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +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:
212
contrib/bloom/blvacuum.c
Normal file
212
contrib/bloom/blvacuum.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* blvacuum.c
|
||||
* Bloom VACUUM functions.
|
||||
*
|
||||
* Copyright (c) 2016, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* contrib/bloom/blvacuum.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "catalog/storage.h"
|
||||
#include "commands/vacuum.h"
|
||||
#include "miscadmin.h"
|
||||
#include "postmaster/autovacuum.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/indexfsm.h"
|
||||
#include "storage/lmgr.h"
|
||||
|
||||
#include "bloom.h"
|
||||
|
||||
/*
|
||||
* Bulk deletion of all index entries pointing to a set of heap tuples.
|
||||
* The set of target tuples is specified via a callback routine that tells
|
||||
* whether any given heap tuple (identified by ItemPointer) is being deleted.
|
||||
*
|
||||
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
||||
*/
|
||||
IndexBulkDeleteResult *
|
||||
blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
|
||||
IndexBulkDeleteCallback callback, void *callback_state)
|
||||
{
|
||||
Relation index = info->index;
|
||||
BlockNumber blkno,
|
||||
npages;
|
||||
FreeBlockNumberArray notFullPage;
|
||||
int countPage = 0;
|
||||
BloomState state;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
GenericXLogState *gxlogState;
|
||||
|
||||
if (stats == NULL)
|
||||
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
|
||||
|
||||
initBloomState(&state, index);
|
||||
|
||||
/*
|
||||
* Interate over the pages. We don't care about concurrently added pages,
|
||||
* they can't contain tuples to delete.
|
||||
*/
|
||||
npages = RelationGetNumberOfBlocks(index);
|
||||
for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
|
||||
{
|
||||
BloomTuple *itup,
|
||||
*itupPtr,
|
||||
*itupEnd;
|
||||
|
||||
buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
|
||||
RBM_NORMAL, info->strategy);
|
||||
|
||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
gxlogState = GenericXLogStart(index);
|
||||
page = GenericXLogRegister(gxlogState, buffer, false);
|
||||
|
||||
if (BloomPageIsDeleted(page))
|
||||
{
|
||||
UnlockReleaseBuffer(buffer);
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Iterate over the tuples */
|
||||
itup = BloomPageGetTuple(&state, page, 1);
|
||||
itupPtr = BloomPageGetTuple(&state, page, 1);
|
||||
itupEnd = BloomPageGetTuple(&state, page, BloomPageGetMaxOffset(page) + 1);
|
||||
while (itup < itupEnd)
|
||||
{
|
||||
/* Do we have to delete this tuple? */
|
||||
if (callback(&itup->heapPtr, callback_state))
|
||||
{
|
||||
stats->tuples_removed += 1;
|
||||
BloomPageGetOpaque(page)->maxoff--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (itupPtr != itup)
|
||||
{
|
||||
/*
|
||||
* If we already delete something before, we have to move
|
||||
* this tuple backward.
|
||||
*/
|
||||
memmove((Pointer) itupPtr, (Pointer) itup,
|
||||
state.sizeOfBloomTuple);
|
||||
}
|
||||
stats->num_index_tuples++;
|
||||
itupPtr = BloomPageGetNextTuple(&state, itupPtr);
|
||||
}
|
||||
|
||||
itup = BloomPageGetNextTuple(&state, itup);
|
||||
}
|
||||
|
||||
Assert(itupPtr == BloomPageGetTuple(&state, page, BloomPageGetMaxOffset(page) + 1));
|
||||
|
||||
if (!BloomPageIsDeleted(page) &&
|
||||
BloomPageGetFreeSpace(&state, page) > state.sizeOfBloomTuple &&
|
||||
countPage < BloomMetaBlockN)
|
||||
notFullPage[countPage++] = blkno;
|
||||
|
||||
/* Did we delete something? */
|
||||
if (itupPtr != itup)
|
||||
{
|
||||
/* Is it empty page now? */
|
||||
if (itupPtr == BloomPageGetData(page))
|
||||
BloomPageSetDeleted(page);
|
||||
/* Adjust pg_lower */
|
||||
((PageHeader) page)->pd_lower = (Pointer) itupPtr - page;
|
||||
/* Finish WAL-logging */
|
||||
GenericXLogFinish(gxlogState);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Didn't change anything: abort WAL-logging */
|
||||
GenericXLogAbort(gxlogState);
|
||||
}
|
||||
UnlockReleaseBuffer(buffer);
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
}
|
||||
|
||||
if (countPage > 0)
|
||||
{
|
||||
BloomMetaPageData *metaData;
|
||||
|
||||
buffer = ReadBuffer(index, BLOOM_METAPAGE_BLKNO);
|
||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
|
||||
gxlogState = GenericXLogStart(index);
|
||||
page = GenericXLogRegister(gxlogState, buffer, false);
|
||||
|
||||
metaData = BloomPageGetMeta(page);
|
||||
memcpy(metaData->notFullPage, notFullPage, sizeof(FreeBlockNumberArray));
|
||||
metaData->nStart = 0;
|
||||
metaData->nEnd = countPage;
|
||||
|
||||
GenericXLogFinish(gxlogState);
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/*
|
||||
* Post-VACUUM cleanup.
|
||||
*
|
||||
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
||||
*/
|
||||
IndexBulkDeleteResult *
|
||||
blvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
|
||||
{
|
||||
Relation index = info->index;
|
||||
BlockNumber npages,
|
||||
blkno;
|
||||
BlockNumber totFreePages;
|
||||
|
||||
if (info->analyze_only)
|
||||
return stats;
|
||||
|
||||
if (stats == NULL)
|
||||
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
|
||||
|
||||
/*
|
||||
* Iterate over the pages: insert deleted pages into FSM and collect
|
||||
* statistics.
|
||||
*/
|
||||
npages = RelationGetNumberOfBlocks(index);
|
||||
totFreePages = 0;
|
||||
for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
|
||||
{
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
vacuum_delay_point();
|
||||
|
||||
buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
|
||||
RBM_NORMAL, info->strategy);
|
||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
if (BloomPageIsDeleted(page))
|
||||
{
|
||||
RecordFreeIndexPage(index, blkno);
|
||||
totFreePages++;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats->num_index_tuples += BloomPageGetMaxOffset(page);
|
||||
stats->estimated_count += BloomPageGetMaxOffset(page);
|
||||
}
|
||||
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
IndexFreeSpaceMapVacuum(info->index);
|
||||
stats->pages_free = totFreePages;
|
||||
stats->num_pages = RelationGetNumberOfBlocks(index);
|
||||
|
||||
return stats;
|
||||
}
|
Reference in New Issue
Block a user