mirror of
https://github.com/pgvector/pgvector.git
synced 2026-06-06 05:51:21 +08:00
152 lines
3.6 KiB
C
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;
|
|
}
|