Skip to content

Commit d5e8fc9

Browse files
committed
Changed HnswPairingHeapNode to HnswSearchCandidate to reduce allocations and improve code
1 parent 6d2af6d commit d5e8fc9

File tree

3 files changed

+41
-46
lines changed

3 files changed

+41
-46
lines changed

src/hnsw.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,13 @@ struct HnswNeighborArray
155155
HnswCandidate items[FLEXIBLE_ARRAY_MEMBER];
156156
};
157157

158-
typedef struct HnswPairingHeapNode
158+
typedef struct HnswSearchCandidate
159159
{
160-
HnswCandidate *inner;
161160
pairingheap_node c_node;
162161
pairingheap_node w_node;
163-
} HnswPairingHeapNode;
162+
HnswElementPtr element;
163+
float distance;
164+
} HnswSearchCandidate;
164165

165166
/* HNSW index options */
166167
typedef struct HnswOptions
@@ -381,7 +382,7 @@ void *HnswAlloc(HnswAllocator * allocator, Size size);
381382
HnswElement HnswInitElement(char *base, ItemPointer tid, int m, double ml, int maxLevel, HnswAllocator * alloc);
382383
HnswElement HnswInitElementFromBlock(BlockNumber blkno, OffsetNumber offno);
383384
void HnswFindElementNeighbors(char *base, HnswElement element, HnswElement entryPoint, Relation index, FmgrInfo *procinfo, Oid collation, int m, int efConstruction, bool existing);
384-
HnswCandidate *HnswEntryCandidate(char *base, HnswElement em, Datum q, Relation rel, FmgrInfo *procinfo, Oid collation, bool loadVec);
385+
HnswSearchCandidate *HnswEntryCandidate(char *base, HnswElement em, Datum q, Relation rel, FmgrInfo *procinfo, Oid collation, bool loadVec);
385386
void HnswUpdateMetaPage(Relation index, int updateEntry, HnswElement entryPoint, BlockNumber insertPage, ForkNumber forkNum, bool building);
386387
void HnswSetNeighborTuple(char *base, HnswNeighborTuple ntup, HnswElement e, int m);
387388
void HnswAddHeapTid(HnswElement element, ItemPointer heaptid);

src/hnswscan.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,14 @@ hnswgettuple(IndexScanDesc scan, ScanDirection dir)
161161
so->first = false;
162162

163163
#if defined(HNSW_MEMORY)
164-
elog(INFO, "memory: %zu MB", MemoryContextMemAllocated(so->tmpCtx, false) / (1024 * 1024));
164+
elog(INFO, "memory: %zu KB", MemoryContextMemAllocated(so->tmpCtx, false) / 1024);
165165
#endif
166166
}
167167

168168
while (list_length(so->w) > 0)
169169
{
170170
char *base = NULL;
171-
HnswCandidate *hc = llast(so->w);
171+
HnswSearchCandidate *hc = llast(so->w);
172172
HnswElement element = HnswPtrAccess(base, hc->element);
173173
ItemPointer heaptid;
174174

src/hnswutils.c

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -608,10 +608,10 @@ GetElementDistance(char *base, HnswElement element, Datum q, FmgrInfo *procinfo,
608608
/*
609609
* Create a candidate for the entry point
610610
*/
611-
HnswCandidate *
611+
HnswSearchCandidate *
612612
HnswEntryCandidate(char *base, HnswElement entryPoint, Datum q, Relation index, FmgrInfo *procinfo, Oid collation, bool loadVec)
613613
{
614-
HnswCandidate *hc = palloc(sizeof(HnswCandidate));
614+
HnswSearchCandidate *hc = palloc(sizeof(HnswSearchCandidate));
615615

616616
HnswPtrStore(base, hc->element, entryPoint);
617617
if (index == NULL)
@@ -621,19 +621,19 @@ HnswEntryCandidate(char *base, HnswElement entryPoint, Datum q, Relation index,
621621
return hc;
622622
}
623623

624-
#define HnswGetPairingHeapCandidate(membername, ptr) (pairingheap_container(HnswPairingHeapNode, membername, ptr)->inner)
625-
#define HnswGetPairingHeapCandidateConst(membername, ptr) (pairingheap_const_container(HnswPairingHeapNode, membername, ptr)->inner)
624+
#define HnswGetSearchCandidate(membername, ptr) pairingheap_container(HnswSearchCandidate, membername, ptr)
625+
#define HnswGetSearchCandidateConst(membername, ptr) pairingheap_const_container(HnswSearchCandidate, membername, ptr)
626626

627627
/*
628628
* Compare candidate distances
629629
*/
630630
static int
631631
CompareNearestCandidates(const pairingheap_node *a, const pairingheap_node *b, void *arg)
632632
{
633-
if (HnswGetPairingHeapCandidateConst(c_node, a)->distance < HnswGetPairingHeapCandidateConst(c_node, b)->distance)
633+
if (HnswGetSearchCandidateConst(c_node, a)->distance < HnswGetSearchCandidateConst(c_node, b)->distance)
634634
return 1;
635635

636-
if (HnswGetPairingHeapCandidateConst(c_node, a)->distance > HnswGetPairingHeapCandidateConst(c_node, b)->distance)
636+
if (HnswGetSearchCandidateConst(c_node, a)->distance > HnswGetSearchCandidateConst(c_node, b)->distance)
637637
return -1;
638638

639639
return 0;
@@ -645,27 +645,15 @@ CompareNearestCandidates(const pairingheap_node *a, const pairingheap_node *b, v
645645
static int
646646
CompareFurthestCandidates(const pairingheap_node *a, const pairingheap_node *b, void *arg)
647647
{
648-
if (HnswGetPairingHeapCandidateConst(w_node, a)->distance < HnswGetPairingHeapCandidateConst(w_node, b)->distance)
648+
if (HnswGetSearchCandidateConst(w_node, a)->distance < HnswGetSearchCandidateConst(w_node, b)->distance)
649649
return -1;
650650

651-
if (HnswGetPairingHeapCandidateConst(w_node, a)->distance > HnswGetPairingHeapCandidateConst(w_node, b)->distance)
651+
if (HnswGetSearchCandidateConst(w_node, a)->distance > HnswGetSearchCandidateConst(w_node, b)->distance)
652652
return 1;
653653

654654
return 0;
655655
}
656656

657-
/*
658-
* Create a pairing heap node for a candidate
659-
*/
660-
static HnswPairingHeapNode *
661-
CreatePairingHeapNode(HnswCandidate * c)
662-
{
663-
HnswPairingHeapNode *node = palloc(sizeof(HnswPairingHeapNode));
664-
665-
node->inner = c;
666-
return node;
667-
}
668-
669657
/*
670658
* Init visited
671659
*/
@@ -825,15 +813,13 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
825813
/* Add entry points to v, C, and W */
826814
foreach(lc2, ep)
827815
{
828-
HnswCandidate *hc = (HnswCandidate *) lfirst(lc2);
816+
HnswSearchCandidate *hc = (HnswSearchCandidate *) lfirst(lc2);
829817
bool found;
830-
HnswPairingHeapNode *node;
831818

832819
AddToVisited(base, &v, hc->element, index, &found);
833820

834-
node = CreatePairingHeapNode(hc);
835-
pairingheap_add(C, &node->c_node);
836-
pairingheap_add(W, &node->w_node);
821+
pairingheap_add(C, &hc->c_node);
822+
pairingheap_add(W, &hc->w_node);
837823

838824
/*
839825
* Do not count elements being deleted towards ef when vacuuming. It
@@ -846,8 +832,8 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
846832

847833
while (!pairingheap_is_empty(C))
848834
{
849-
HnswCandidate *c = HnswGetPairingHeapCandidate(c_node, pairingheap_remove_first(C));
850-
HnswCandidate *f = HnswGetPairingHeapCandidate(w_node, pairingheap_first(W));
835+
HnswSearchCandidate *c = HnswGetSearchCandidate(c_node, pairingheap_remove_first(C));
836+
HnswSearchCandidate *f = HnswGetSearchCandidate(w_node, pairingheap_first(W));
851837
HnswElement cElement;
852838

853839
if (c->distance > f->distance)
@@ -863,12 +849,11 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
863849
for (int i = 0; i < unvisitedLength; i++)
864850
{
865851
HnswElement eElement;
866-
HnswCandidate *e;
867-
HnswPairingHeapNode *node;
852+
HnswSearchCandidate *e;
868853
float eDistance;
869854
bool alwaysAdd = wlen < ef;
870855

871-
f = HnswGetPairingHeapCandidate(w_node, pairingheap_first(W));
856+
f = HnswGetSearchCandidate(w_node, pairingheap_first(W));
872857

873858
if (index == NULL)
874859
{
@@ -899,13 +884,11 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
899884
continue;
900885

901886
/* Create a new candidate */
902-
e = palloc(sizeof(HnswCandidate));
887+
e = palloc(sizeof(HnswSearchCandidate));
903888
HnswPtrStore(base, e->element, eElement);
904889
e->distance = eDistance;
905-
906-
node = CreatePairingHeapNode(e);
907-
pairingheap_add(C, &node->c_node);
908-
pairingheap_add(W, &node->w_node);
890+
pairingheap_add(C, &e->c_node);
891+
pairingheap_add(W, &e->w_node);
909892

910893
/*
911894
* Do not count elements being deleted towards ef when vacuuming.
@@ -926,7 +909,7 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
926909
/* Add each element of W to w */
927910
while (!pairingheap_is_empty(W))
928911
{
929-
HnswCandidate *hc = HnswGetPairingHeapCandidate(w_node, pairingheap_remove_first(W));
912+
HnswSearchCandidate *hc = HnswGetSearchCandidate(w_node, pairingheap_remove_first(W));
930913

931914
w = lappend(w, hc);
932915
}
@@ -1307,16 +1290,27 @@ HnswFindElementNeighbors(char *base, HnswElement element, HnswElement entryPoint
13071290
{
13081291
int lm = HnswGetLayerM(m, lc);
13091292
List *neighbors;
1310-
List *lw;
1293+
List *lw = NIL;
1294+
ListCell *lc2;
13111295

13121296
w = HnswSearchLayer(base, q, ep, efConstruction, lc, index, procinfo, collation, m, true, skipElement);
13131297

1298+
/* Convert search candidates to candidates */
1299+
foreach(lc2, w)
1300+
{
1301+
HnswSearchCandidate *sc = lfirst(lc2);
1302+
HnswCandidate *hc = palloc(sizeof(HnswCandidate));
1303+
1304+
hc->element = sc->element;
1305+
hc->distance = sc->distance;
1306+
1307+
lw = lappend(lw, hc);
1308+
}
1309+
13141310
/* Elements being deleted or skipped can help with search */
13151311
/* but should be removed before selecting neighbors */
13161312
if (index != NULL)
1317-
lw = RemoveElements(base, w, skipElement);
1318-
else
1319-
lw = w;
1313+
lw = RemoveElements(base, lw, skipElement);
13201314

13211315
/*
13221316
* Candidates are sorted, but not deterministically. Could set

0 commit comments

Comments
 (0)