Files
pgvector/ivfvacuum.c
Andrew Kane 6df7fa05b2 First commit
2021-04-20 14:04:28 -07:00

152 lines
3.6 KiB
C

#include "postgres.h"
#include "commands/vacuum.h"
#include "ivfflat.h"
#include "storage/bufmgr.h"
/*
* Bulk delete tuples from the index
*/
IndexBulkDeleteResult *
ivfflatbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback, void *callback_state)
{
Relation index = info->index;
Buffer cbuf;
Page cpage;
Buffer buf;
Page page;
IvfflatList list;
IndexTuple itup;
ItemPointer htup;
OffsetNumber deletable[MaxOffsetNumber];
int ndeletable;
OffsetNumber startPages[MaxOffsetNumber];
BlockNumber nextblkno = IVFFLAT_HEAD_BLKNO;
BlockNumber searchPage;
BlockNumber insertPage;
GenericXLogState *state;
OffsetNumber coffno;
OffsetNumber cmaxoffno;
OffsetNumber offno;
OffsetNumber maxoffno;
ListInfo listInfo;
BufferAccessStrategy bas = GetAccessStrategy(BAS_BULKREAD);
if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
/* Iterate over list pages */
while (BlockNumberIsValid(nextblkno))
{
cbuf = ReadBuffer(index, nextblkno);
LockBuffer(cbuf, BUFFER_LOCK_SHARE);
cpage = BufferGetPage(cbuf);
cmaxoffno = PageGetMaxOffsetNumber(cpage);
/* Iterate over lists */
for (coffno = FirstOffsetNumber; coffno <= cmaxoffno; coffno = OffsetNumberNext(coffno))
{
list = (IvfflatList) PageGetItem(cpage, PageGetItemId(cpage, coffno));
startPages[coffno - FirstOffsetNumber] = list->startPage;
}
listInfo.blkno = nextblkno;
nextblkno = IvfflatPageGetOpaque(cpage)->nextblkno;
UnlockReleaseBuffer(cbuf);
for (coffno = FirstOffsetNumber; coffno <= cmaxoffno; coffno = OffsetNumberNext(coffno))
{
searchPage = startPages[coffno - FirstOffsetNumber];
insertPage = InvalidBlockNumber;
/* Iterate over entry pages */
while (BlockNumberIsValid(searchPage))
{
vacuum_delay_point();
buf = ReadBufferExtended(index, MAIN_FORKNUM, searchPage, RBM_NORMAL, bas);
/*
* ambulkdelete cannot delete entries from pages that are
* pinned by other backends
*
* https://www.postgresql.org/docs/current/index-locking.html
*/
LockBufferForCleanup(buf);
state = GenericXLogStart(index);
page = GenericXLogRegisterBuffer(state, buf, 0);
maxoffno = PageGetMaxOffsetNumber(page);
ndeletable = 0;
/* Find deleted tuples */
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
{
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offno));
htup = &(itup->t_tid);
if (callback(htup, callback_state))
{
deletable[ndeletable++] = offno;
stats->tuples_removed++;
}
else
stats->num_index_tuples++;
}
searchPage = IvfflatPageGetOpaque(page)->nextblkno;
if (ndeletable > 0)
{
/* Delete tuples */
PageIndexMultiDelete(page, deletable, ndeletable);
MarkBufferDirty(buf);
GenericXLogFinish(state);
/* Set to first free page */
if (!BlockNumberIsValid(insertPage))
insertPage = searchPage;
}
else
GenericXLogAbort(state);
UnlockReleaseBuffer(buf);
}
/*
* Update after all tuples deleted.
*
* We don't add or delete items from lists pages, so offset won't
* change.
*/
if (!BlockNumberIsValid(insertPage))
{
listInfo.offno = coffno;
IvfflatUpdateList(index, state, listInfo, insertPage, InvalidBlockNumber, MAIN_FORKNUM);
}
}
}
return stats;
}
/*
* Clean up after a VACUUM operation
*/
IndexBulkDeleteResult *
ivfflatvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
Relation rel = info->index;
if (stats == NULL)
return NULL;
stats->num_pages = RelationGetNumberOfBlocks(rel);
return stats;
}