Skip to content

Commit 53a8734

Browse files
committed
Added IndexTuple to HNSW elements (first step to support multiple attributes)
1 parent 7484625 commit 53a8734

File tree

4 files changed

+51
-23
lines changed

4 files changed

+51
-23
lines changed

src/hnsw.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ HnswPtrDeclare(HnswElementData, HnswElementRelptr, HnswElementPtr);
133133
HnswPtrDeclare(HnswNeighborArray, HnswNeighborArrayRelptr, HnswNeighborArrayPtr);
134134
HnswPtrDeclare(HnswNeighborArrayPtr, HnswNeighborsRelptr, HnswNeighborsPtr);
135135
HnswPtrDeclare(char, DatumRelptr, DatumPtr);
136+
HnswPtrDeclare(IndexTupleData, IndexTupleRelptr, IndexTuplePtr);
136137

137138
struct HnswElementData
138139
{
@@ -149,6 +150,7 @@ struct HnswElementData
149150
OffsetNumber neighborOffno;
150151
BlockNumber neighborPage;
151152
DatumPtr value;
153+
IndexTuplePtr itup;
152154
LWLock lock;
153155
};
154156

@@ -288,6 +290,7 @@ typedef struct HnswBuildState
288290
HnswGraph *graph;
289291
double ml;
290292
int maxLevel;
293+
TupleDesc tupdesc;
291294

292295
/* Memory */
293296
MemoryContext graphCtx;
@@ -428,11 +431,12 @@ void HnswSetNeighborTuple(char *base, HnswNeighborTuple ntup, HnswElement e, in
428431
void HnswAddHeapTid(HnswElement element, ItemPointer heaptid);
429432
HnswNeighborArray *HnswInitNeighborArray(int lm, HnswAllocator * allocator);
430433
void HnswInitNeighbors(char *base, HnswElement element, int m, HnswAllocator * alloc);
431-
bool HnswInsertTupleOnDisk(Relation index, HnswSupport * support, Datum value, ItemPointer heaptid, bool building);
434+
bool HnswInsertTupleOnDisk(Relation index, HnswSupport * support, TupleDesc tupdesc, IndexTuple itup, ItemPointer heaptid, bool building);
432435
void HnswUpdateNeighborsOnDisk(Relation index, HnswSupport * support, HnswElement e, int m, bool checkExisting, bool building);
433436
void HnswLoadElementFromTuple(HnswElement element, HnswElementTuple etup, bool loadHeaptids, bool loadVec);
434437
void HnswLoadElement(HnswElement element, double *distance, HnswQuery * q, Relation index, HnswSupport * support, bool loadVec, double *maxDistance);
435-
bool HnswFormIndexValue(Datum *out, Datum *values, bool *isnull, const HnswTypeInfo * typeInfo, HnswSupport * support);
438+
TupleDesc HnswTupleDesc(Relation index);
439+
bool HnswFormIndexTuple(IndexTuple *out, Datum *values, bool *isnull, const HnswTypeInfo * typeInfo, HnswSupport * support, TupleDesc tupdesc);
436440
void HnswSetElementTuple(char *base, HnswElementTuple etup, HnswElement element);
437441
void HnswUpdateConnection(char *base, HnswNeighborArray * neighbors, HnswElement newElement, float distance, int lm, int *updateIdx, Relation index, HnswSupport * support);
438442
bool HnswLoadNeighborTids(HnswElement element, ItemPointerData *indextids, Relation index, int m, int lm, int lc);

src/hnswbuild.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -476,18 +476,20 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heaptid, Hn
476476
HnswElement element;
477477
HnswAllocator *allocator = &buildstate->allocator;
478478
HnswSupport *support = &buildstate->support;
479-
Size valueSize;
480-
Pointer valuePtr;
481479
LWLock *flushLock = &graph->flushLock;
482480
char *base = buildstate->hnswarea;
483-
Datum value;
481+
TupleDesc tupdesc = buildstate->tupdesc;
482+
IndexTuple itup;
483+
Size itupSize;
484+
IndexTuple itupShared;
485+
bool unused;
484486

485487
/* Form index value */
486-
if (!HnswFormIndexValue(&value, values, isnull, buildstate->typeInfo, support))
488+
if (!HnswFormIndexTuple(&itup, values, isnull, buildstate->typeInfo, support, tupdesc))
487489
return false;
488490

489-
/* Get datum size */
490-
valueSize = VARSIZE_ANY(DatumGetPointer(value));
491+
/* Get tuple size */
492+
itupSize = IndexTupleSize(itup);
491493

492494
/* Ensure graph not flushed when inserting */
493495
LWLockAcquire(flushLock, LW_SHARED);
@@ -497,7 +499,7 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heaptid, Hn
497499
{
498500
LWLockRelease(flushLock);
499501

500-
return HnswInsertTupleOnDisk(index, support, value, heaptid, true);
502+
return HnswInsertTupleOnDisk(index, support, tupdesc, itup, heaptid, true);
501503
}
502504

503505
/*
@@ -529,12 +531,12 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heaptid, Hn
529531

530532
LWLockRelease(flushLock);
531533

532-
return HnswInsertTupleOnDisk(index, support, value, heaptid, true);
534+
return HnswInsertTupleOnDisk(index, support, tupdesc, itup, heaptid, true);
533535
}
534536

535537
/* Ok, we can proceed to allocate the element */
536538
element = HnswInitElement(base, heaptid, buildstate->m, buildstate->ml, buildstate->maxLevel, allocator);
537-
valuePtr = HnswAlloc(allocator, valueSize);
539+
itupShared = HnswAlloc(allocator, itupSize);
538540

539541
/*
540542
* We have now allocated the space needed for the element, so we don't
@@ -543,9 +545,10 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heaptid, Hn
543545
*/
544546
LWLockRelease(&graph->allocatorLock);
545547

546-
/* Copy the datum */
547-
memcpy(valuePtr, DatumGetPointer(value), valueSize);
548-
HnswPtrStore(base, element->value, valuePtr);
548+
/* Copy the tuple */
549+
memcpy(itupShared, itup, itupSize);
550+
HnswPtrStore(base, element->itup, itupShared);
551+
HnswPtrStore(base, element->value, DatumGetPointer(index_getattr(itupShared, 1, tupdesc, &unused)));
549552

550553
/* Create a lock for the element */
551554
LWLockInitialize(&element->lock, hnsw_lock_tranche_id);
@@ -698,6 +701,7 @@ InitBuildState(HnswBuildState * buildstate, Relation heap, Relation index, Index
698701
buildstate->graph = &buildstate->graphData;
699702
buildstate->ml = HnswGetMl(buildstate->m);
700703
buildstate->maxLevel = HnswGetMaxLevel(buildstate->m);
704+
buildstate->tupdesc = HnswTupleDesc(index);
701705

702706
buildstate->graphCtx = GenerationContextCreate(CurrentMemoryContext,
703707
"Hnsw build graph context",
@@ -722,6 +726,7 @@ InitBuildState(HnswBuildState * buildstate, Relation heap, Relation index, Index
722726
static void
723727
FreeBuildState(HnswBuildState * buildstate)
724728
{
729+
pfree(buildstate->tupdesc);
725730
MemoryContextDelete(buildstate->graphCtx);
726731
MemoryContextDelete(buildstate->tmpCtx);
727732
}

src/hnswinsert.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -687,14 +687,15 @@ UpdateGraphOnDisk(Relation index, HnswSupport * support, HnswElement element, in
687687
* Insert a tuple into the index
688688
*/
689689
bool
690-
HnswInsertTupleOnDisk(Relation index, HnswSupport * support, Datum value, ItemPointer heaptid, bool building)
690+
HnswInsertTupleOnDisk(Relation index, HnswSupport * support, TupleDesc tupdesc, IndexTuple itup, ItemPointer heaptid, bool building)
691691
{
692692
HnswElement entryPoint;
693693
HnswElement element;
694694
int m;
695695
int efConstruction = HnswGetEfConstruction(index);
696696
LOCKMODE lockmode = ShareLock;
697697
char *base = NULL;
698+
bool unused;
698699

699700
/*
700701
* Get a shared lock. This allows vacuum to ensure no in-flight inserts
@@ -708,7 +709,8 @@ HnswInsertTupleOnDisk(Relation index, HnswSupport * support, Datum value, ItemPo
708709

709710
/* Create an element */
710711
element = HnswInitElement(base, heaptid, m, HnswGetMl(m), HnswGetMaxLevel(m), NULL);
711-
HnswPtrStore(base, element->value, DatumGetPointer(value));
712+
HnswPtrStore(base, element->itup, itup);
713+
HnswPtrStore(base, element->value, DatumGetPointer(index_getattr(itup, 1, tupdesc, &unused)));
712714

713715
/* Prevent concurrent inserts when likely updating entry point */
714716
if (entryPoint == NULL || element->level > entryPoint->level)
@@ -742,17 +744,18 @@ HnswInsertTupleOnDisk(Relation index, HnswSupport * support, Datum value, ItemPo
742744
static void
743745
HnswInsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heaptid)
744746
{
745-
Datum value;
747+
IndexTuple itup;
746748
const HnswTypeInfo *typeInfo = HnswGetTypeInfo(index);
747749
HnswSupport support;
750+
TupleDesc tupdesc = HnswTupleDesc(index);
748751

749752
HnswInitSupport(&support, index);
750753

751-
/* Form index value */
752-
if (!HnswFormIndexValue(&value, values, isnull, typeInfo, &support))
754+
/* Form index tuple */
755+
if (!HnswFormIndexTuple(&itup, values, isnull, typeInfo, &support, tupdesc))
753756
return;
754757

755-
HnswInsertTupleOnDisk(index, &support, value, heaptid, false);
758+
HnswInsertTupleOnDisk(index, &support, tupdesc, itup, heaptid, false);
756759
}
757760

758761
/*

src/hnswutils.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,24 @@ HnswUpdateMetaPage(Relation index, int updateEntry, HnswElement entryPoint, Bloc
395395
}
396396

397397
/*
398-
* Form index value
398+
* Get the tuple descriptor
399+
*/
400+
TupleDesc
401+
HnswTupleDesc(Relation index)
402+
{
403+
TupleDesc tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(index));
404+
405+
/* Prevent compression */
406+
TupleDescAttr(tupdesc, 0)->attstorage = TYPSTORAGE_PLAIN;
407+
408+
return tupdesc;
409+
}
410+
411+
/*
412+
* Form index tuple
399413
*/
400414
bool
401-
HnswFormIndexValue(Datum *out, Datum *values, bool *isnull, const HnswTypeInfo * typeInfo, HnswSupport * support)
415+
HnswFormIndexTuple(IndexTuple *out, Datum *values, bool *isnull, const HnswTypeInfo * typeInfo, HnswSupport * support, TupleDesc tupdesc)
402416
{
403417
/* Detoast once for all calls */
404418
Datum value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
@@ -416,7 +430,9 @@ HnswFormIndexValue(Datum *out, Datum *values, bool *isnull, const HnswTypeInfo *
416430
value = HnswNormValue(typeInfo, support->collation, value);
417431
}
418432

419-
*out = value;
433+
/* TODO Combine value with values to support multiple attributes */
434+
Assert(tupdesc->natts == 1);
435+
*out = index_form_tuple(tupdesc, &value, isnull);
420436

421437
return true;
422438
}

0 commit comments

Comments
 (0)