mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-27 22:32:42 +08:00
Compare commits
9 Commits
hnsw-vacuu
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
281d4fcf60 | ||
|
|
5b43aaad5a | ||
|
|
797ce8034c | ||
|
|
cad9e22d9a | ||
|
|
a7d43904f7 | ||
|
|
ded649891b | ||
|
|
2d092016fc | ||
|
|
86b31fdf96 | ||
|
|
5023269f0d |
@@ -1,11 +1,11 @@
|
|||||||
## 0.6.0 (unreleased)
|
## 0.6.0 (2024-01-29)
|
||||||
|
|
||||||
If upgrading with Postgres 12 or Docker, see [these notes](https://github.com/pgvector/pgvector#060-unreleased).
|
If upgrading with Postgres 12 or Docker, see [these notes](https://github.com/pgvector/pgvector#060).
|
||||||
|
|
||||||
- Changed storage for vector from `extended` to `external`
|
- Changed storage for vector from `extended` to `external`
|
||||||
- Improved performance of HNSW
|
|
||||||
- Added support for parallel index builds for HNSW
|
- Added support for parallel index builds for HNSW
|
||||||
- Added validation for GUC parameters
|
- Added validation for GUC parameters
|
||||||
|
- Improved performance of HNSW
|
||||||
- Reduced memory usage for HNSW index builds
|
- Reduced memory usage for HNSW index builds
|
||||||
- Reduced WAL generation for HNSW index builds
|
- Reduced WAL generation for HNSW index builds
|
||||||
- Fixed error with logical replication
|
- Fixed error with logical replication
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
ARG PG_MAJOR=15
|
ARG PG_MAJOR=16
|
||||||
FROM postgres:$PG_MAJOR
|
FROM postgres:$PG_MAJOR
|
||||||
ARG PG_MAJOR
|
ARG PG_MAJOR
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "vector",
|
"name": "vector",
|
||||||
"abstract": "Open-source vector similarity search for Postgres",
|
"abstract": "Open-source vector similarity search for Postgres",
|
||||||
"description": "Supports L2 distance, inner product, and cosine distance",
|
"description": "Supports L2 distance, inner product, and cosine distance",
|
||||||
"version": "0.5.1",
|
"version": "0.6.0",
|
||||||
"maintainer": [
|
"maintainer": [
|
||||||
"Andrew Kane <andrew@ankane.org>"
|
"Andrew Kane <andrew@ankane.org>"
|
||||||
],
|
],
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"vector": {
|
"vector": {
|
||||||
"file": "sql/vector.sql",
|
"file": "sql/vector.sql",
|
||||||
"docfile": "README.md",
|
"docfile": "README.md",
|
||||||
"version": "0.5.1",
|
"version": "0.6.0",
|
||||||
"abstract": "Open-source vector similarity search for Postgres"
|
"abstract": "Open-source vector similarity search for Postgres"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.5.1
|
EXTVERSION = 0.6.0
|
||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.5.1
|
EXTVERSION = 0.6.0
|
||||||
|
|
||||||
OBJS = src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\vector.obj
|
OBJS = src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\vector.obj
|
||||||
HEADERS = src\vector.h
|
HEADERS = src\vector.h
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -20,7 +20,7 @@ Compile and install the extension (supports Postgres 11+)
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd /tmp
|
cd /tmp
|
||||||
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.6.0 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
make
|
make
|
||||||
make install # may need sudo
|
make install # may need sudo
|
||||||
@@ -44,7 +44,7 @@ Then use `nmake` to build:
|
|||||||
|
|
||||||
```cmd
|
```cmd
|
||||||
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
||||||
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.6.0 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
nmake /F Makefile.win
|
nmake /F Makefile.win
|
||||||
nmake /F Makefile.win install
|
nmake /F Makefile.win install
|
||||||
@@ -264,7 +264,7 @@ HINT: Increase maintenance_work_mem to speed up builds.
|
|||||||
|
|
||||||
Note: Do not set `maintenance_work_mem` so high that it exhausts the memory on the server
|
Note: Do not set `maintenance_work_mem` so high that it exhausts the memory on the server
|
||||||
|
|
||||||
Starting with 0.6.0 [unreleased], you can also speed up index creation by increasing the number of parallel workers (2 by default)
|
Starting with 0.6.0, you can also speed up index creation by increasing the number of parallel workers (2 by default)
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SET max_parallel_maintenance_workers = 7; -- plus leader
|
SET max_parallel_maintenance_workers = 7; -- plus leader
|
||||||
@@ -651,10 +651,10 @@ If compilation fails and the output includes `warning: no such sysroot directory
|
|||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
Get the [Docker image](https://hub.docker.com/r/ankane/pgvector) with:
|
Get the [Docker image](https://hub.docker.com/r/pgvector/pgvector) with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker pull ankane/pgvector
|
docker pull pgvector/pgvector:pg16
|
||||||
```
|
```
|
||||||
|
|
||||||
This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (run it the same way).
|
This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (run it the same way).
|
||||||
@@ -662,9 +662,9 @@ This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (r
|
|||||||
You can also build the image manually:
|
You can also build the image manually:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.6.0 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
docker build --build-arg PG_MAJOR=15 -t myuser/pgvector .
|
docker build --build-arg PG_MAJOR=16 -t myuser/pgvector .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
@@ -741,7 +741,7 @@ SELECT extversion FROM pg_extension WHERE extname = 'vector';
|
|||||||
|
|
||||||
## Upgrade Notes
|
## Upgrade Notes
|
||||||
|
|
||||||
### 0.6.0 [unreleased]
|
### 0.6.0
|
||||||
|
|
||||||
#### Postgres 12
|
#### Postgres 12
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
#define PROGRESS_HNSW_PHASE_LOAD 2
|
#define PROGRESS_HNSW_PHASE_LOAD 2
|
||||||
|
|
||||||
#define HNSW_MAX_SIZE (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(HnswPageOpaqueData)) - sizeof(ItemIdData))
|
#define HNSW_MAX_SIZE (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(HnswPageOpaqueData)) - sizeof(ItemIdData))
|
||||||
|
#define HNSW_TUPLE_ALLOC_SIZE BLCKSZ
|
||||||
|
|
||||||
#define HNSW_ELEMENT_TUPLE_SIZE(size) MAXALIGN(offsetof(HnswElementTupleData, data) + (size))
|
#define HNSW_ELEMENT_TUPLE_SIZE(size) MAXALIGN(offsetof(HnswElementTupleData, data) + (size))
|
||||||
#define HNSW_NEIGHBOR_TUPLE_SIZE(level, m) MAXALIGN(offsetof(HnswNeighborTupleData, indextids) + ((level) + 2) * (m) * sizeof(ItemPointerData))
|
#define HNSW_NEIGHBOR_TUPLE_SIZE(level, m) MAXALIGN(offsetof(HnswNeighborTupleData, indextids) + ((level) + 2) * (m) * sizeof(ItemPointerData))
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
{
|
{
|
||||||
Relation index = buildstate->index;
|
Relation index = buildstate->index;
|
||||||
ForkNumber forkNum = buildstate->forkNum;
|
ForkNumber forkNum = buildstate->forkNum;
|
||||||
Size etupAllocSize;
|
|
||||||
Size maxSize;
|
Size maxSize;
|
||||||
HnswElementTuple etup;
|
HnswElementTuple etup;
|
||||||
HnswNeighborTuple ntup;
|
HnswNeighborTuple ntup;
|
||||||
@@ -160,12 +159,11 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
char *base = buildstate->hnswarea;
|
char *base = buildstate->hnswarea;
|
||||||
|
|
||||||
/* Calculate sizes */
|
/* Calculate sizes */
|
||||||
etupAllocSize = BLCKSZ;
|
|
||||||
maxSize = HNSW_MAX_SIZE;
|
maxSize = HNSW_MAX_SIZE;
|
||||||
|
|
||||||
/* Allocate once */
|
/* Allocate once */
|
||||||
etup = palloc0(etupAllocSize);
|
etup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
||||||
ntup = palloc0(BLCKSZ);
|
ntup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
||||||
|
|
||||||
/* Prepare first page */
|
/* Prepare first page */
|
||||||
buf = HnswNewBuffer(index, forkNum);
|
buf = HnswNewBuffer(index, forkNum);
|
||||||
@@ -184,7 +182,7 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
iter = element->next;
|
iter = element->next;
|
||||||
|
|
||||||
/* Zero memory for each element */
|
/* Zero memory for each element */
|
||||||
MemSet(etup, 0, etupAllocSize);
|
MemSet(etup, 0, HNSW_TUPLE_ALLOC_SIZE);
|
||||||
|
|
||||||
/* Calculate sizes */
|
/* Calculate sizes */
|
||||||
etupSize = HNSW_ELEMENT_TUPLE_SIZE(VARSIZE_ANY(valuePtr));
|
etupSize = HNSW_ELEMENT_TUPLE_SIZE(VARSIZE_ANY(valuePtr));
|
||||||
@@ -192,7 +190,7 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
combinedSize = etupSize + ntupSize + sizeof(ItemIdData);
|
combinedSize = etupSize + ntupSize + sizeof(ItemIdData);
|
||||||
|
|
||||||
/* Initial size check */
|
/* Initial size check */
|
||||||
if (etupSize > etupAllocSize)
|
if (etupSize > HNSW_TUPLE_ALLOC_SIZE)
|
||||||
elog(ERROR, "index tuple too large");
|
elog(ERROR, "index tuple too large");
|
||||||
|
|
||||||
HnswSetElementTuple(base, etup, element);
|
HnswSetElementTuple(base, etup, element);
|
||||||
@@ -254,38 +252,43 @@ WriteNeighborTuples(HnswBuildState * buildstate)
|
|||||||
int m = buildstate->m;
|
int m = buildstate->m;
|
||||||
HnswElementPtr iter = buildstate->graph->head;
|
HnswElementPtr iter = buildstate->graph->head;
|
||||||
char *base = buildstate->hnswarea;
|
char *base = buildstate->hnswarea;
|
||||||
|
HnswNeighborTuple ntup;
|
||||||
|
|
||||||
|
/* Allocate once */
|
||||||
|
ntup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
||||||
|
|
||||||
while (!HnswPtrIsNull(base, iter))
|
while (!HnswPtrIsNull(base, iter))
|
||||||
{
|
{
|
||||||
HnswElement e = HnswPtrAccess(base, iter);
|
HnswElement element = HnswPtrAccess(base, iter);
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
ItemId itemid;
|
Size ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(element->level, m);
|
||||||
HnswNeighborTuple ntup;
|
|
||||||
|
|
||||||
/* Update iterator */
|
/* Update iterator */
|
||||||
iter = e->next;
|
iter = element->next;
|
||||||
|
|
||||||
|
/* Zero memory for each element */
|
||||||
|
MemSet(ntup, 0, HNSW_TUPLE_ALLOC_SIZE);
|
||||||
|
|
||||||
/* Can take a while, so ensure we can interrupt */
|
/* Can take a while, so ensure we can interrupt */
|
||||||
/* Needs to be called when no buffer locks are held */
|
/* Needs to be called when no buffer locks are held */
|
||||||
CHECK_FOR_INTERRUPTS();
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
buf = ReadBufferExtended(index, forkNum, e->neighborPage, RBM_NORMAL, NULL);
|
buf = ReadBufferExtended(index, forkNum, element->neighborPage, RBM_NORMAL, NULL);
|
||||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
itemid = PageGetItemId(page, e->neighborOffno);
|
|
||||||
ntup = (HnswNeighborTuple) PageGetItem(page, itemid);
|
|
||||||
|
|
||||||
/* Check expected size */
|
HnswSetNeighborTuple(base, ntup, element, m);
|
||||||
Assert(ItemIdGetLength(itemid) == HNSW_NEIGHBOR_TUPLE_SIZE(e->level, m));
|
|
||||||
|
|
||||||
/* Update page in-place */
|
if (!PageIndexTupleOverwrite(page, element->neighborOffno, (Item) ntup, ntupSize))
|
||||||
HnswSetNeighborTuple(base, ntup, e, m);
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
UnlockReleaseBuffer(buf);
|
UnlockReleaseBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pfree(ntup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -355,9 +355,7 @@ HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, Hns
|
|||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
GenericXLogState *state;
|
GenericXLogState *state;
|
||||||
ItemId itemid;
|
|
||||||
HnswNeighborTuple ntup;
|
HnswNeighborTuple ntup;
|
||||||
Size ntupSize;
|
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
int startIdx;
|
int startIdx;
|
||||||
HnswElement neighborElement = HnswPtrAccess(base, hc->element);
|
HnswElement neighborElement = HnswPtrAccess(base, hc->element);
|
||||||
@@ -396,9 +394,7 @@ HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, Hns
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get tuple */
|
/* Get tuple */
|
||||||
itemid = PageGetItemId(page, offno);
|
ntup = (HnswNeighborTuple) PageGetItem(page, PageGetItemId(page, offno));
|
||||||
ntup = (HnswNeighborTuple) PageGetItem(page, itemid);
|
|
||||||
ntupSize = ItemIdGetLength(itemid);
|
|
||||||
|
|
||||||
/* Calculate index for update */
|
/* Calculate index for update */
|
||||||
startIdx = (neighborElement->level - lc) * m;
|
startIdx = (neighborElement->level - lc) * m;
|
||||||
@@ -427,13 +423,9 @@ HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, Hns
|
|||||||
{
|
{
|
||||||
ItemPointer indextid = &ntup->indextids[idx];
|
ItemPointer indextid = &ntup->indextids[idx];
|
||||||
|
|
||||||
/* Update neighbor */
|
/* Update neighbor on the buffer */
|
||||||
ItemPointerSet(indextid, e->blkno, e->offno);
|
ItemPointerSet(indextid, e->blkno, e->offno);
|
||||||
|
|
||||||
/* Overwrite tuple */
|
|
||||||
if (!PageIndexTupleOverwrite(page, offno, (Item) ntup, ntupSize))
|
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
if (building)
|
if (building)
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
@@ -457,9 +449,7 @@ AddDuplicateOnDisk(Relation index, HnswElement element, HnswElement dup, bool bu
|
|||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
GenericXLogState *state;
|
GenericXLogState *state;
|
||||||
ItemId itemid;
|
|
||||||
HnswElementTuple etup;
|
HnswElementTuple etup;
|
||||||
Size etupSize;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Read page */
|
/* Read page */
|
||||||
@@ -477,9 +467,7 @@ AddDuplicateOnDisk(Relation index, HnswElement element, HnswElement dup, bool bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find space */
|
/* Find space */
|
||||||
itemid = PageGetItemId(page, dup->offno);
|
etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, dup->offno));
|
||||||
etup = (HnswElementTuple) PageGetItem(page, itemid);
|
|
||||||
etupSize = ItemIdGetLength(itemid);
|
|
||||||
for (i = 0; i < HNSW_HEAPTIDS; i++)
|
for (i = 0; i < HNSW_HEAPTIDS; i++)
|
||||||
{
|
{
|
||||||
if (!ItemPointerIsValid(&etup->heaptids[i]))
|
if (!ItemPointerIsValid(&etup->heaptids[i]))
|
||||||
@@ -495,13 +483,9 @@ AddDuplicateOnDisk(Relation index, HnswElement element, HnswElement dup, bool bu
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add heap TID */
|
/* Add heap TID, modifying the tuple on the page directly */
|
||||||
etup->heaptids[i] = element->heaptids[0];
|
etup->heaptids[i] = element->heaptids[0];
|
||||||
|
|
||||||
/* Overwrite tuple */
|
|
||||||
if (!PageIndexTupleOverwrite(page, dup->offno, (Item) etup, etupSize))
|
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
if (building)
|
if (building)
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ RemoveHeapTids(HnswVacuumState * vacuumstate)
|
|||||||
/* Iterate over nodes */
|
/* Iterate over nodes */
|
||||||
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
||||||
{
|
{
|
||||||
ItemId itemid = PageGetItemId(page, offno);
|
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, offno));
|
||||||
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, itemid);
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
bool itemUpdated = false;
|
bool itemUpdated = false;
|
||||||
|
|
||||||
@@ -92,15 +91,10 @@ RemoveHeapTids(HnswVacuumState * vacuumstate)
|
|||||||
|
|
||||||
if (itemUpdated)
|
if (itemUpdated)
|
||||||
{
|
{
|
||||||
Size etupSize = ItemIdGetLength(itemid);
|
|
||||||
|
|
||||||
/* Mark rest as invalid */
|
/* Mark rest as invalid */
|
||||||
for (int i = idx; i < HNSW_HEAPTIDS; i++)
|
for (int i = idx; i < HNSW_HEAPTIDS; i++)
|
||||||
ItemPointerSetInvalid(&etup->heaptids[i]);
|
ItemPointerSetInvalid(&etup->heaptids[i]);
|
||||||
|
|
||||||
if (!PageIndexTupleOverwrite(page, offno, (Item) etup, etupSize))
|
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,6 +207,9 @@ RepairGraphElement(HnswVacuumState * vacuumstate, HnswElement element, HnswEleme
|
|||||||
/* Find neighbors for element, skipping itself */
|
/* Find neighbors for element, skipping itself */
|
||||||
HnswFindElementNeighbors(base, element, entryPoint, index, procinfo, collation, m, efConstruction, true);
|
HnswFindElementNeighbors(base, element, entryPoint, index, procinfo, collation, m, efConstruction, true);
|
||||||
|
|
||||||
|
/* Zero memory for each element */
|
||||||
|
MemSet(ntup, 0, HNSW_TUPLE_ALLOC_SIZE);
|
||||||
|
|
||||||
/* Update neighbor tuple */
|
/* Update neighbor tuple */
|
||||||
/* Do this before getting page to minimize locking */
|
/* Do this before getting page to minimize locking */
|
||||||
HnswSetNeighborTuple(base, ntup, element, m);
|
HnswSetNeighborTuple(base, ntup, element, m);
|
||||||
@@ -479,11 +476,8 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
/* Update element and neighbors together */
|
/* Update element and neighbors together */
|
||||||
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
||||||
{
|
{
|
||||||
ItemId itemid = PageGetItemId(page, offno);
|
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, offno));
|
||||||
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, itemid);
|
|
||||||
HnswNeighborTuple ntup;
|
HnswNeighborTuple ntup;
|
||||||
Size etupSize;
|
|
||||||
Size ntupSize;
|
|
||||||
Buffer nbuf;
|
Buffer nbuf;
|
||||||
Page npage;
|
Page npage;
|
||||||
BlockNumber neighborPage;
|
BlockNumber neighborPage;
|
||||||
@@ -507,10 +501,6 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
if (ItemPointerIsValid(&etup->heaptids[0]))
|
if (ItemPointerIsValid(&etup->heaptids[0]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Calculate sizes */
|
|
||||||
etupSize = ItemIdGetLength(itemid);
|
|
||||||
ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(etup->level, vacuumstate->m);
|
|
||||||
|
|
||||||
/* Get neighbor page */
|
/* Get neighbor page */
|
||||||
neighborPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
neighborPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
||||||
neighborOffno = ItemPointerGetOffsetNumber(&etup->neighbortid);
|
neighborOffno = ItemPointerGetOffsetNumber(&etup->neighbortid);
|
||||||
@@ -537,13 +527,10 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
for (int i = 0; i < ntup->count; i++)
|
for (int i = 0; i < ntup->count; i++)
|
||||||
ItemPointerSetInvalid(&ntup->indextids[i]);
|
ItemPointerSetInvalid(&ntup->indextids[i]);
|
||||||
|
|
||||||
/* Overwrite element tuple */
|
/*
|
||||||
if (!PageIndexTupleOverwrite(page, offno, (Item) etup, etupSize))
|
* We modified the tuples in place, no need to call
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
* PageIndexTupleOverwrite
|
||||||
|
*/
|
||||||
/* Overwrite neighbor tuple */
|
|
||||||
if (!PageIndexTupleOverwrite(npage, neighborOffno, (Item) ntup, ntupSize))
|
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
GenericXLogFinish(state);
|
GenericXLogFinish(state);
|
||||||
@@ -588,7 +575,7 @@ InitVacuumState(HnswVacuumState * vacuumstate, IndexVacuumInfo *info, IndexBulkD
|
|||||||
vacuumstate->bas = GetAccessStrategy(BAS_BULKREAD);
|
vacuumstate->bas = GetAccessStrategy(BAS_BULKREAD);
|
||||||
vacuumstate->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
vacuumstate->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
||||||
vacuumstate->collation = index->rd_indcollation[0];
|
vacuumstate->collation = index->rd_indcollation[0];
|
||||||
vacuumstate->ntup = palloc0(BLCKSZ);
|
vacuumstate->ntup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
||||||
vacuumstate->tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
|
vacuumstate->tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
"Hnsw vacuum temporary context",
|
"Hnsw vacuum temporary context",
|
||||||
ALLOCSET_DEFAULT_SIZES);
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
comment = 'vector data type and ivfflat and hnsw access methods'
|
comment = 'vector data type and ivfflat and hnsw access methods'
|
||||||
default_version = '0.5.1'
|
default_version = '0.6.0'
|
||||||
module_pathname = '$libdir/vector'
|
module_pathname = '$libdir/vector'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
|||||||
Reference in New Issue
Block a user