mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-10 06:40:57 +08:00
Improved inserts for HNSW
This commit is contained in:
@@ -118,6 +118,7 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
Size etupSize;
|
Size etupSize;
|
||||||
Size ntupSize;
|
Size ntupSize;
|
||||||
Size combinedSize;
|
Size combinedSize;
|
||||||
|
Size maxSize;
|
||||||
HnswElementTuple etup;
|
HnswElementTuple etup;
|
||||||
BlockNumber originalInsertPage = insertPage;
|
BlockNumber originalInsertPage = insertPage;
|
||||||
int dimensions = e->vec->dim;
|
int dimensions = e->vec->dim;
|
||||||
@@ -132,6 +133,7 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
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));
|
||||||
|
|
||||||
/* Prepare element tuple */
|
/* Prepare element tuple */
|
||||||
etup = palloc0(etupSize);
|
etup = palloc0(etupSize);
|
||||||
@@ -141,7 +143,7 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
ntup = palloc0(ntupSize);
|
ntup = palloc0(ntupSize);
|
||||||
HnswSetNeighborTuple(ntup, e, m);
|
HnswSetNeighborTuple(ntup, e, m);
|
||||||
|
|
||||||
/* Find a page to insert the item */
|
/* Find a page (or two if needed) to insert the tuples */
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
buf = ReadBuffer(index, insertPage);
|
buf = ReadBuffer(index, insertPage);
|
||||||
@@ -150,7 +152,8 @@ 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);
|
||||||
|
|
||||||
/* Space for both */
|
/* First, try the fastest path */
|
||||||
|
/* Space for both tuples on the current page */
|
||||||
if (PageGetFreeSpace(page) >= combinedSize)
|
if (PageGetFreeSpace(page) >= combinedSize)
|
||||||
{
|
{
|
||||||
nbuf = buf;
|
nbuf = buf;
|
||||||
@@ -158,14 +161,7 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Space for element but not neighbors and last page */
|
/* Next, try space from a deleted element */
|
||||||
if (PageGetFreeSpace(page) >= etupSize && !BlockNumberIsValid(HnswPageGetOpaque(page)->nextblkno))
|
|
||||||
{
|
|
||||||
HnswInsertAppendPage(index, &nbuf, &npage, state, page);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Space from deleted item */
|
|
||||||
if (HnswFreeOffset(index, buf, page, e, ntupSize, &nbuf, &npage, &freeOffno, &freeNeighborOffno, &firstFreePage))
|
if (HnswFreeOffset(index, buf, page, e, ntupSize, &nbuf, &npage, &freeOffno, &freeNeighborOffno, &firstFreePage))
|
||||||
{
|
{
|
||||||
if (nbuf != buf)
|
if (nbuf != buf)
|
||||||
@@ -174,6 +170,14 @@ WriteNewElementPages(Relation index, HnswElement e, int m, BlockNumber insertPag
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Finally, try space for element only if last page */
|
||||||
|
/* Skip if element and neighbor can fit on the same page */
|
||||||
|
if (combinedSize > maxSize && PageGetFreeSpace(page) >= etupSize && !BlockNumberIsValid(HnswPageGetOpaque(page)->nextblkno))
|
||||||
|
{
|
||||||
|
HnswInsertAppendPage(index, &nbuf, &npage, state, page);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
insertPage = HnswPageGetOpaque(page)->nextblkno;
|
insertPage = HnswPageGetOpaque(page)->nextblkno;
|
||||||
|
|
||||||
if (BlockNumberIsValid(insertPage))
|
if (BlockNumberIsValid(insertPage))
|
||||||
|
|||||||
Reference in New Issue
Block a user