mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-10 22:56:55 +08:00
Fixed failed to add index item error with sparsevec - fixes #625
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
## 0.7.3 (unreleased)
|
## 0.7.3 (unreleased)
|
||||||
|
|
||||||
|
- Fixed `failed to add index item` error with `sparsevec`
|
||||||
- Fixed compilation error with FreeBSD ARM
|
- Fixed compilation error with FreeBSD ARM
|
||||||
- Fixed compilation warning with MSVC and Postgres 16
|
- Fixed compilation warning with MSVC and Postgres 16
|
||||||
|
|
||||||
|
|||||||
@@ -36,14 +36,15 @@ 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 *newInsertPage)
|
HnswFreeOffset(Relation index, Buffer buf, Page page, HnswElement element, Size etupSize, Size ntupSize, Buffer *nbuf, Page *npage, OffsetNumber *freeOffno, OffsetNumber *freeNeighborOffno, BlockNumber *newInsertPage)
|
||||||
{
|
{
|
||||||
OffsetNumber offno;
|
OffsetNumber offno;
|
||||||
OffsetNumber maxoffno = PageGetMaxOffsetNumber(page);
|
OffsetNumber maxoffno = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
||||||
{
|
{
|
||||||
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, offno));
|
ItemId eitemid = PageGetItemId(page, offno);
|
||||||
|
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, eitemid);
|
||||||
|
|
||||||
/* Skip neighbor tuples */
|
/* Skip neighbor tuples */
|
||||||
if (!HnswIsElementTuple(etup))
|
if (!HnswIsElementTuple(etup))
|
||||||
@@ -54,7 +55,9 @@ HnswFreeOffset(Relation index, Buffer buf, Page page, HnswElement element, Size
|
|||||||
BlockNumber elementPage = BufferGetBlockNumber(buf);
|
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 nitemid;
|
||||||
|
Size pageFree;
|
||||||
|
Size npageFree;
|
||||||
|
|
||||||
if (!BlockNumberIsValid(*newInsertPage))
|
if (!BlockNumberIsValid(*newInsertPage))
|
||||||
*newInsertPage = elementPage;
|
*newInsertPage = elementPage;
|
||||||
@@ -73,10 +76,21 @@ HnswFreeOffset(Relation index, Buffer buf, Page page, HnswElement element, Size
|
|||||||
*npage = BufferGetPage(*nbuf);
|
*npage = BufferGetPage(*nbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemid = PageGetItemId(*npage, neighborOffno);
|
nitemid = PageGetItemId(*npage, neighborOffno);
|
||||||
|
|
||||||
/* Check for space on neighbor tuple page */
|
/*
|
||||||
if (PageGetFreeSpace(*npage) + ItemIdGetLength(itemid) - sizeof(ItemIdData) >= ntupSize)
|
* Calculate free space individually since tuples are overwritten
|
||||||
|
* individually (in separate calls to PageIndexTupleOverwrite)
|
||||||
|
*/
|
||||||
|
pageFree = ItemIdGetLength(eitemid) + PageGetExactFreeSpace(page);
|
||||||
|
npageFree = ItemIdGetLength(nitemid);
|
||||||
|
if (neighborPage != elementPage)
|
||||||
|
npageFree += PageGetExactFreeSpace(*npage);
|
||||||
|
else if (pageFree >= etupSize)
|
||||||
|
npageFree += pageFree - etupSize;
|
||||||
|
|
||||||
|
/* Check for space */
|
||||||
|
if (pageFree >= etupSize && npageFree >= ntupSize)
|
||||||
{
|
{
|
||||||
*freeOffno = offno;
|
*freeOffno = offno;
|
||||||
*freeNeighborOffno = neighborOffno;
|
*freeNeighborOffno = neighborOffno;
|
||||||
@@ -184,7 +198,7 @@ AddElementOnDisk(Relation index, HnswElement e, int m, BlockNumber insertPage, B
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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, &newInsertPage))
|
if (HnswFreeOffset(index, buf, page, e, etupSize, ntupSize, &nbuf, &npage, &freeOffno, &freeNeighborOffno, &newInsertPage))
|
||||||
{
|
{
|
||||||
if (nbuf != buf)
|
if (nbuf != buf)
|
||||||
{
|
{
|
||||||
|
|||||||
38
test/t/038_hnsw_sparsevec_vacuum_insert.pl
Normal file
38
test/t/038_hnsw_sparsevec_vacuum_insert.pl
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use PostgresNode;
|
||||||
|
use TestLib;
|
||||||
|
use Test::More;
|
||||||
|
|
||||||
|
# Initialize node
|
||||||
|
my $node = get_new_node('node');
|
||||||
|
$node->init;
|
||||||
|
$node->start;
|
||||||
|
|
||||||
|
# Create table and index
|
||||||
|
$node->safe_psql("postgres", "CREATE EXTENSION vector;");
|
||||||
|
$node->safe_psql("postgres", "CREATE TABLE tst (i serial, v sparsevec(100000));");
|
||||||
|
$node->safe_psql("postgres", "CREATE INDEX ON tst USING hnsw (v sparsevec_l2_ops);");
|
||||||
|
|
||||||
|
for (1 .. 3) {
|
||||||
|
for (1 .. 100) {
|
||||||
|
my @elements;
|
||||||
|
my %indices;
|
||||||
|
for (1 .. int(rand() * 100)) {
|
||||||
|
my $index = int(rand() * (100000 - 1)) + 1;
|
||||||
|
if (!exists($indices{$index})) {
|
||||||
|
my $value = rand();
|
||||||
|
push(@elements, "$index:$value");
|
||||||
|
$indices{$index} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $embedding = "{" . join(",", @elements) . "}/100000";
|
||||||
|
$node->safe_psql("postgres", "INSERT INTO tst (v) VALUES ('$embedding');");
|
||||||
|
}
|
||||||
|
|
||||||
|
$node->safe_psql("postgres", "DELETE FROM tst WHERE i % 2 = 0;");
|
||||||
|
$node->safe_psql("postgres", "VACUUM tst;");
|
||||||
|
is(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing();
|
||||||
Reference in New Issue
Block a user