2021SC@SDUSC
本篇博客继续讲解GIN索引创建和插入相关的函数,并讲解GIN索引的查询过程
GIN索引的创建
ginbuild
由于该函数调用了其他的大量函数,在这里不一一分析,我将GIN索引的创建过程概括如下
1)调用initGinState初始化创建状态变量buildstate ( GinBuildState类型)的ginstate字段,初始化GIN索引的元页,并初始化buildstate的其他字段,包括置indtuples为0、创建临时内存上下文和函数调用内存上下文。
2)初始化“ 蓄积池”。
3)对基表扫描,并将ginBuildCallback函数的指针传递给IndexBuild- HeapScan。每扫描到一个基 表元组,IndexBuildHeapScan 都将其被索引属性的值解析出来然后传递给ginBuildallback处理,在ginBuildCallback中将进行以下处理:
①对于每一个被索引属性的值,调用ginHeapTupleBulkInsert 对其进行处理,该函数会调用GIN 索引的extractValue方法将被索引|属性的值解析成若千个Entry (一个属性值中可能包含多个关键 词),并将这些获得的Entry 插人到“蓄积池”中( ginInsertRecordBA兩数),该函数值将返回获得 的Entry 的个数,这个数量将被累加到buildstate 的indtuples 字段中。
②对“蓄积池”的填充情况进行检查,如果allocatedMemory或maxdepth字段的值超过阙值则循环调用ginGetEntry从“蓄积池”中取出一个Entry,并将其用ginEntryInsert插人到GIN索引中。
③当“蓄积池”中的Entry都已经被插入到GIN索引中后,通过重置buildstate中的临时内存上 下文来清空“蓄积池”,然后调用ginInitBA重新初始化“ 蓄积池”。
5)当IndexBuildHeapScan扫描完成后,“ 蓄积池”中有可能还有一部分Entry 没有被插人到 GIN索引中,同样循环调用ginGetEntry获取Entry再通过ginEntryInsert插入CIN索引中。
6)返回统计信息
IndexBuildResult *
ginbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
IndexBuildResult *result;
double reltuples;
GinBuildState buildstate;
Buffer RootBuffer,
MetaBuffer;
ItemPointerData *list;
Datum key;
GinNullCategory category;
uint32 nlist;
MemoryContext oldCtx;
OffsetNumber attnum;
if (RelationGetNumberOfBlocks(index) != 0)
elog(ERROR, "index \"%s\" already contains data",
RelationGetRelationName(index));
initGinState(&buildstate.ginstate, index);
buildstate.indtuples = 0;
memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
/* 初始化元页 */
MetaBuffer = GinNewBuffer(index);
/* 初始化根节点 */
RootBuffer = GinNewBuffer(index);
START_CRIT_SECTION();
GinInitMetabuffer(MetaBuffer);
MarkBufferDirty