mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-11 23:26:55 +08:00
Improved logic for updating HNSW insert page
This commit is contained in:
@@ -34,7 +34,7 @@ GetInsertPage(Relation index)
|
|||||||
* Check for a free offset
|
* Check for a free offset
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
HnswFreeOffset(Relation index, Buffer buf, Page page, HnswElement element, Size ntupSize, Buffer *nbuf, Page *npage, OffsetNumber *freeOffno, OffsetNumber *freeNeighborOffno, BlockNumber *firstFreePage)
|
HnswFreeOffset(Relation index, Buffer buf, Page page, HnswElement element, Size ntupSize, Buffer *nbuf, Page *npage, OffsetNumber *freeOffno, OffsetNumber *freeNeighborOffno, BlockNumber *newInsertPage)
|
||||||
{
|
{
|
||||||
OffsetNumber offno;
|
OffsetNumber offno;
|
||||||
OffsetNumber maxoffno = PageGetMaxOffsetNumber(page);
|
OffsetNumber maxoffno = PageGetMaxOffsetNumber(page);
|
||||||
@@ -49,14 +49,15 @@ HnswFreeOffset(Relation index, Buffer buf, Page page, HnswElement element, Size
|
|||||||
|
|
||||||
if (etup->deleted)
|
if (etup->deleted)
|
||||||
{
|
{
|
||||||
|
BlockNumber elementPage = BufferGetBlockNumber(buf);
|
||||||
BlockNumber neighborPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
BlockNumber neighborPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
||||||
OffsetNumber neighborOffno = ItemPointerGetOffsetNumber(&etup->neighbortid);
|
OffsetNumber neighborOffno = ItemPointerGetOffsetNumber(&etup->neighbortid);
|
||||||
ItemId itemid;
|
ItemId itemid;
|
||||||
|
|
||||||
if (!BlockNumberIsValid(*firstFreePage))
|
if (!BlockNumberIsValid(*newInsertPage))
|
||||||
*firstFreePage = neighborPage;
|
*newInsertPage = elementPage;
|
||||||
|
|
||||||
if (neighborPage == BufferGetBlockNumber(buf))
|
if (neighborPage == elementPage)
|
||||||
{
|
{
|
||||||
*nbuf = buf;
|
*nbuf = buf;
|
||||||
*npage = page;
|
*npage = page;
|
||||||
@@ -110,7 +111,7 @@ HnswInsertAppendPage(Relation index, Buffer *nbuf, Page *npage, GenericXLogState
|
|||||||
* Add to element and neighbor pages
|
* Add to element and neighbor pages
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPage, BlockNumber *newInsertPage)
|
WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPage, BlockNumber *updatedInsertPage)
|
||||||
{
|
{
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
@@ -119,6 +120,7 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
Size ntupSize;
|
Size ntupSize;
|
||||||
Size combinedSize;
|
Size combinedSize;
|
||||||
Size maxSize;
|
Size maxSize;
|
||||||
|
Size minCombinedSize;
|
||||||
HnswElementTuple etup;
|
HnswElementTuple etup;
|
||||||
BlockNumber originalInsertPage = insertPage;
|
BlockNumber originalInsertPage = insertPage;
|
||||||
int dimensions = e->vec->dim;
|
int dimensions = e->vec->dim;
|
||||||
@@ -127,13 +129,14 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
Page npage;
|
Page npage;
|
||||||
OffsetNumber freeOffno = InvalidOffsetNumber;
|
OffsetNumber freeOffno = InvalidOffsetNumber;
|
||||||
OffsetNumber freeNeighborOffno = InvalidOffsetNumber;
|
OffsetNumber freeNeighborOffno = InvalidOffsetNumber;
|
||||||
BlockNumber firstFreePage = InvalidBlockNumber;
|
BlockNumber newInsertPage = InvalidBlockNumber;
|
||||||
|
|
||||||
/* Calculate sizes */
|
/* Calculate sizes */
|
||||||
etupSize = HNSW_ELEMENT_TUPLE_SIZE(dimensions);
|
etupSize = HNSW_ELEMENT_TUPLE_SIZE(dimensions);
|
||||||
ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(e->level, m);
|
ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(e->level, m);
|
||||||
combinedSize = etupSize + ntupSize + sizeof(ItemIdData);
|
combinedSize = etupSize + ntupSize + sizeof(ItemIdData);
|
||||||
maxSize = BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(HnswPageOpaqueData));
|
maxSize = BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(HnswPageOpaqueData));
|
||||||
|
minCombinedSize = etupSize + HNSW_NEIGHBOR_TUPLE_SIZE(0, m) + sizeof(ItemIdData);
|
||||||
|
|
||||||
/* Prepare element tuple */
|
/* Prepare element tuple */
|
||||||
etup = palloc0(etupSize);
|
etup = palloc0(etupSize);
|
||||||
@@ -152,6 +155,10 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
state = GenericXLogStart(index);
|
state = GenericXLogStart(index);
|
||||||
page = GenericXLogRegisterBuffer(state, buf, 0);
|
page = GenericXLogRegisterBuffer(state, buf, 0);
|
||||||
|
|
||||||
|
/* Check for size for element at level 0 */
|
||||||
|
if (!BlockNumberIsValid(newInsertPage) && PageGetFreeSpace(page) >= minCombinedSize)
|
||||||
|
newInsertPage = insertPage;
|
||||||
|
|
||||||
/* First, try the fastest path */
|
/* First, try the fastest path */
|
||||||
/* Space for both tuples on the current page */
|
/* Space for both tuples on the current page */
|
||||||
/* This can split existing tuples in rare cases */
|
/* This can split existing tuples in rare cases */
|
||||||
@@ -163,7 +170,7 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Next, try space from a deleted element */
|
/* Next, try space from a deleted element */
|
||||||
if (HnswFreeOffset(index, buf, page, e, ntupSize, &nbuf, &npage, &freeOffno, &freeNeighborOffno, &firstFreePage))
|
if (HnswFreeOffset(index, buf, page, e, ntupSize, &nbuf, &npage, &freeOffno, &freeNeighborOffno, &newInsertPage))
|
||||||
{
|
{
|
||||||
if (nbuf != buf)
|
if (nbuf != buf)
|
||||||
npage = GenericXLogRegisterBuffer(state, nbuf, 0);
|
npage = GenericXLogRegisterBuffer(state, nbuf, 0);
|
||||||
@@ -223,7 +230,8 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
e->blkno = BufferGetBlockNumber(buf);
|
e->blkno = BufferGetBlockNumber(buf);
|
||||||
e->neighborPage = BufferGetBlockNumber(nbuf);
|
e->neighborPage = BufferGetBlockNumber(nbuf);
|
||||||
|
|
||||||
insertPage = e->neighborPage;
|
if (!BlockNumberIsValid(newInsertPage))
|
||||||
|
newInsertPage = e->neighborPage;
|
||||||
|
|
||||||
if (OffsetNumberIsValid(freeOffno))
|
if (OffsetNumberIsValid(freeOffno))
|
||||||
{
|
{
|
||||||
@@ -269,8 +277,8 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
UnlockReleaseBuffer(nbuf);
|
UnlockReleaseBuffer(nbuf);
|
||||||
|
|
||||||
/* Update the insert page */
|
/* Update the insert page */
|
||||||
if (insertPage != originalInsertPage && (!OffsetNumberIsValid(freeOffno) || firstFreePage == insertPage))
|
if (BlockNumberIsValid(newInsertPage) && newInsertPage != originalInsertPage)
|
||||||
*newInsertPage = insertPage;
|
*updatedInsertPage = newInsertPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
{
|
{
|
||||||
/* Set to first free page */
|
/* Set to first free page */
|
||||||
if (!BlockNumberIsValid(insertPage))
|
if (!BlockNumberIsValid(insertPage))
|
||||||
insertPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
insertPage = blkno;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -479,7 +479,7 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
|
|
||||||
/* Set to first free page */
|
/* Set to first free page */
|
||||||
if (!BlockNumberIsValid(insertPage))
|
if (!BlockNumberIsValid(insertPage))
|
||||||
insertPage = neighborPage;
|
insertPage = blkno;
|
||||||
|
|
||||||
/* Prepare new xlog */
|
/* Prepare new xlog */
|
||||||
state = GenericXLogStart(index);
|
state = GenericXLogStart(index);
|
||||||
|
|||||||
Reference in New Issue
Block a user