@@ -112,6 +112,12 @@ typedef union
112
112
tidhash_hash * tids ;
113
113
}visited_hash ;
114
114
115
+ typedef union
116
+ {
117
+ HnswElement element ;
118
+ ItemPointerData indextid ;
119
+ }HnswUnvisited ;
120
+
115
121
/*
116
122
* Get the max number of connections in an upper layer for each element in the index
117
123
*/
@@ -547,19 +553,19 @@ HnswLoadElementFromTuple(HnswElement element, HnswElementTuple etup, bool loadHe
547
553
/*
548
554
* Load an element and optionally get its distance from q
549
555
*/
550
- void
551
- HnswLoadElement ( HnswElement element , float * distance ,Datum * q ,Relation index ,FmgrInfo * procinfo ,Oid collation ,bool loadVec ,float * maxDistance )
556
+ static void
557
+ HnswLoadElementImpl ( BlockNumber blkno , OffsetNumber offno , float * distance ,Datum * q ,Relation index ,FmgrInfo * procinfo ,Oid collation ,bool loadVec ,float * maxDistance , HnswElement * element )
552
558
{
553
559
Buffer buf ;
554
560
Page page ;
555
561
HnswElementTuple etup ;
556
562
557
563
/* Read vector */
558
- buf = ReadBuffer (index ,element -> blkno );
564
+ buf = ReadBuffer (index ,blkno );
559
565
LockBuffer (buf ,BUFFER_LOCK_SHARE );
560
566
page = BufferGetPage (buf );
561
567
562
- etup = (HnswElementTuple )PageGetItem (page ,PageGetItemId (page ,element -> offno ));
568
+ etup = (HnswElementTuple )PageGetItem (page ,PageGetItemId (page ,offno ));
563
569
564
570
Assert (HnswIsElementTuple (etup ));
565
571
@@ -574,11 +580,25 @@ HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index,
574
580
575
581
/* Load element */
576
582
if (distance == NULL || maxDistance == NULL || * distance < * maxDistance )
577
- HnswLoadElementFromTuple (element ,etup , true,loadVec );
583
+ {
584
+ if (* element == NULL )
585
+ * element = HnswInitElementFromBlock (blkno ,offno );
586
+
587
+ HnswLoadElementFromTuple (* element ,etup , true,loadVec );
588
+ }
578
589
579
590
UnlockReleaseBuffer (buf );
580
591
}
581
592
593
+ /*
594
+ * Load an element and optionally get its distance from q
595
+ */
596
+ void
597
+ HnswLoadElement (HnswElement element ,float * distance ,Datum * q ,Relation index ,FmgrInfo * procinfo ,Oid collation ,bool loadVec ,float * maxDistance )
598
+ {
599
+ HnswLoadElementImpl (element -> blkno ,element -> offno ,distance ,q ,index ,procinfo ,collation ,loadVec ,maxDistance ,& element );
600
+ }
601
+
582
602
/*
583
603
* Get the distance for an element
584
604
*/
@@ -720,7 +740,7 @@ CountElement(char *base, HnswElement skipElement, HnswElement e)
720
740
* Load unvisited neighbors from memory
721
741
*/
722
742
static void
723
- HnswLoadUnvisitedFromMemory (char * base ,HnswElement element ,HnswElement * unvisited ,int * unvisitedLength ,visited_hash * v ,int lc ,HnswNeighborArray * neighborhoodData ,Size neighborhoodSize )
743
+ HnswLoadUnvisitedFromMemory (char * base ,HnswElement element ,HnswUnvisited * unvisited ,int * unvisitedLength ,visited_hash * v ,int lc ,HnswNeighborArray * neighborhoodData ,Size neighborhoodSize )
724
744
{
725
745
/* Get the neighborhood at layer lc */
726
746
HnswNeighborArray * neighborhood = HnswGetNeighbors (base ,element ,lc );
@@ -741,15 +761,15 @@ HnswLoadUnvisitedFromMemory(char *base, HnswElement element, HnswElement * unvis
741
761
AddToVisited (base ,v ,hc -> element ,NULL ,& found );
742
762
743
763
if (!found )
744
- unvisited [(* unvisitedLength )++ ]= HnswPtrAccess (base ,hc -> element );
764
+ unvisited [(* unvisitedLength )++ ]. element = HnswPtrAccess (base ,hc -> element );
745
765
}
746
766
}
747
767
748
768
/*
749
769
* Load unvisited neighbors from disk
750
770
*/
751
771
static void
752
- HnswLoadUnvisitedFromDisk (HnswElement element ,HnswElement * unvisited ,int * unvisitedLength ,visited_hash * v ,Relation index ,int m ,int lm ,int lc )
772
+ HnswLoadUnvisitedFromDisk (HnswElement element ,HnswUnvisited * unvisited ,int * unvisitedLength ,visited_hash * v ,Relation index ,int m ,int lm ,int lc )
753
773
{
754
774
Buffer buf ;
755
775
Page page ;
@@ -782,7 +802,7 @@ HnswLoadUnvisitedFromDisk(HnswElement element, HnswElement * unvisited, int *unv
782
802
tidhash_insert (v -> tids ,* indextid ,& found );
783
803
784
804
if (!found )
785
- unvisited [(* unvisitedLength )++ ]= HnswInitElementFromBlock ( ItemPointerGetBlockNumber ( indextid ), ItemPointerGetOffsetNumber ( indextid )) ;
805
+ unvisited [(* unvisitedLength )++ ]. indextid = * indextid ;
786
806
}
787
807
}
788
808
@@ -801,7 +821,7 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
801
821
HnswNeighborArray * neighborhoodData = NULL ;
802
822
Size neighborhoodSize = 0 ;
803
823
int lm = HnswGetLayerM (m ,lc );
804
- HnswElement * unvisited = palloc (lm * sizeof (HnswElement ));
824
+ HnswUnvisited * unvisited = palloc (lm * sizeof (HnswUnvisited ));
805
825
int unvisitedLength ;
806
826
807
827
InitVisited (base ,& v ,index ,ef ,m );
@@ -853,16 +873,27 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
853
873
854
874
for (int i = 0 ;i < unvisitedLength ;i ++ )
855
875
{
856
- HnswElement eElement = unvisited [ i ] ;
876
+ HnswElement eElement ;
857
877
float eDistance ;
858
878
bool alwaysAdd = wlen < ef ;
859
879
860
880
f = HnswGetPairingHeapCandidate (w_node ,pairingheap_first (W ));
861
881
862
882
if (index == NULL )
883
+ {
884
+ eElement = unvisited [i ].element ;
863
885
eDistance = GetElementDistance (base ,eElement ,q ,procinfo ,collation );
886
+ }
864
887
else
865
- HnswLoadElement (eElement ,& eDistance ,& q ,index ,procinfo ,collation ,inserting ,alwaysAdd ?NULL :& f -> distance );
888
+ {
889
+ ItemPointer indextid = & unvisited [i ].indextid ;
890
+ BlockNumber blkno = ItemPointerGetBlockNumber (indextid );
891
+ OffsetNumber offno = ItemPointerGetOffsetNumber (indextid );
892
+
893
+ /* Avoid any allocations if not adding */
894
+ eElement = NULL ;
895
+ HnswLoadElementImpl (blkno ,offno ,& eDistance ,& q ,index ,procinfo ,collation ,inserting ,alwaysAdd ?NULL :& f -> distance ,& eElement );
896
+ }
866
897
867
898
if (eDistance < f -> distance || alwaysAdd )
868
899
{