@@ -374,14 +374,32 @@ RepairGraph(HnswVacuumState * vacuumstate)
374
374
{
375
375
HnswElement element = (HnswElement ) lfirst (lc2 );
376
376
HnswElement entryPoint ;
377
+ LOCKMODE lockmode = ShareLock ;
377
378
378
379
/* Check if any neighbors point to deleted values */
379
380
if (!NeedsUpdated (vacuumstate , element ))
380
381
continue ;
381
382
383
+ /* Get a shared lock */
384
+ LockPage (index , HNSW_UPDATE_LOCK , lockmode );
385
+
382
386
/* Refresh entry point for each element */
383
387
entryPoint = HnswGetEntryPoint (index );
384
388
389
+ /* Prevent concurrent inserts when likely updating entry point */
390
+ if (entryPoint == NULL || element -> level > entryPoint -> level )
391
+ {
392
+ /* Release shared lock */
393
+ UnlockPage (index , HNSW_UPDATE_LOCK , lockmode );
394
+
395
+ /* Get exclusive lock */
396
+ lockmode = ExclusiveLock ;
397
+ LockPage (index , HNSW_UPDATE_LOCK , lockmode );
398
+
399
+ /* Get latest entry point after lock is acquired */
400
+ entryPoint = HnswGetEntryPoint (index );
401
+ }
402
+
385
403
/* Repair connections */
386
404
RepairGraphElement (vacuumstate , element , entryPoint );
387
405
@@ -391,6 +409,9 @@ RepairGraph(HnswVacuumState * vacuumstate)
391
409
*/
392
410
if (entryPoint == NULL || element -> level > entryPoint -> level )
393
411
HnswUpdateMetaPage (index , HNSW_UPDATE_ENTRY_GREATER , element , InvalidBlockNumber , MAIN_FORKNUM );
412
+
413
+ /* Release lock */
414
+ UnlockPage (index , HNSW_UPDATE_LOCK , lockmode );
394
415
}
395
416
396
417
/* Reset memory context */
0 commit comments