diff --git a/CHANGELOG.md b/CHANGELOG.md index 34af92e..bf81eb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.2 (unreleased) + +- Reduced lock contention with parallel HNSW index builds + ## 0.6.1 (2024-03-04) - Fixed error with `ANALYZE` and vectors with different dimensions diff --git a/src/hnsw.h b/src/hnsw.h index 7d2ae19..ee8f926 100644 --- a/src/hnsw.h +++ b/src/hnsw.h @@ -185,6 +185,7 @@ typedef struct HnswGraph /* Entry state */ LWLock entryLock; + LWLock entryWaitLock; HnswElementPtr entryPoint; /* Allocations state */ diff --git a/src/hnswbuild.c b/src/hnswbuild.c index 1a2a96c..990fb7f 100644 --- a/src/hnswbuild.c +++ b/src/hnswbuild.c @@ -431,10 +431,15 @@ InsertTupleInMemory(HnswBuildState * buildstate, HnswElement element) HnswGraph *graph = buildstate->graph; HnswElement entryPoint; LWLock *entryLock = &graph->entryLock; + LWLock *entryWaitLock = &graph->entryWaitLock; int efConstruction = buildstate->efConstruction; int m = buildstate->m; char *base = buildstate->hnswarea; + /* Wait if another process needs exclusive lock */ + LWLockAcquire(entryWaitLock, LW_EXCLUSIVE); + LWLockRelease(entryWaitLock); + /* Get entry point */ LWLockAcquire(entryLock, LW_SHARED); entryPoint = HnswPtrAccess(base, graph->entryPoint); @@ -446,7 +451,9 @@ InsertTupleInMemory(HnswBuildState * buildstate, HnswElement element) LWLockRelease(entryLock); /* Get exclusive lock */ + LWLockAcquire(entryWaitLock, LW_EXCLUSIVE); LWLockAcquire(entryLock, LW_EXCLUSIVE); + LWLockRelease(entryWaitLock); /* Get latest entry point after lock is acquired */ entryPoint = HnswPtrAccess(base, graph->entryPoint); @@ -612,6 +619,7 @@ InitGraph(HnswGraph * graph, char *base, long memoryTotal) graph->indtuples = 0; SpinLockInit(&graph->lock); LWLockInitialize(&graph->entryLock, hnsw_lock_tranche_id); + LWLockInitialize(&graph->entryWaitLock, hnsw_lock_tranche_id); LWLockInitialize(&graph->allocatorLock, hnsw_lock_tranche_id); LWLockInitialize(&graph->flushLock, hnsw_lock_tranche_id); }