PostgreSQL的simplehash.h文件中的内容是什么
这篇文章主要介绍“PostgreSQL的simplehash.h文件中的内容是什么”,在日常操作中,相信很多人在PostgreSQL的simplehash.h文件中的内容是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL的simplehash.h文件中的内容是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
一、数据结构TupleHashTable
哈希表定义
typedefstructTupleHashTableData*TupleHashTable;typedefstructTupleHashTableData{//底层Hash表tuplehash_hash*hashtab;/*underlyinghashtable*///在检索键中的列数intnumCols;/*numberofcolumnsinlookupkey*///键列中的属性格式AttrNumber*keyColIdx;/*attrnumbersofkeycolumns*///数据类型的哈希函数FmgrInfo*tab_hash_funcs;/*hashfunctionsfortabledatatype(s)*///数据类型比较器ExprState*tab_eq_func;/*comparatorfortabledatatype(s)*///包含数据表的内存上下文MemoryContexttablecxt;/*memorycontextcontainingtable*///函数解析上下文MemoryContexttempcxt;/*contextforfunctionevaluations*///构造每个哈希条目的实际大小Sizeentrysize;/*actualsizetomakeeachhashentry*///依赖数据表条目的slotTupleTableSlot*tableslot;/*slotforreferencingtableentries*//*Thefollowingfieldsaresettransientlyforeachtablesearch:*///下面字段为每一个表检索时临时设置//当前输入tupleslotTupleTableSlot*inputslot;/*currentinputtuple'sslot*///输入数据类型的哈希函数FmgrInfo*in_hash_funcs;/*hashfunctionsforinputdatatype(s)*///inputvstable的比较器ExprState*cur_eq_func;/*comparatorforinputvs.table*///哈希函数IVuint32hash_iv;/*hash-functionIV*///表达式上下文ExprContext*exprcontext;/*expressioncontext*/}TupleHashTableData;typedeftuplehash_iteratorTupleHashIterator;/*typedefinitions*///哈希表类型定义typedefstructSH_TYPE//tuplehash_hash{/**Sizeofdata/bucketarray,64bitstohandleUINT32_MAXsizedhash*tables.Notethatthemaximumnumberofelementsislower*(SH_MAX_FILLFACTOR)*数据/桶数组大小,64bit用于处理UINT32_MAX哈希表.*注意元素最大格式小于(SH_MAX_FILLFACTOR)*/uint64size;/*howmanyelementshavevalidcontents*///有多少个元素具有有效内容uint32members;/*maskforbucketandsizecalculations,basedonsize*///基于大小,用于计算桶和大小的掩码uint32sizemask;/*boundaryafterwhichtogrowhashtable*///哈希表增长的阈值uint32grow_threshold;/*hashbuckets*///哈希桶SH_ELEMENT_TYPE*data;/*memorycontexttouseforallocations*///用于分配的内存上下文MemoryContextctx;/*userdefineddata,usefulforcallbacks*///用户自定义的数据,通常用于回调函数void*private_data;}SH_TYPE;//实际是tuplehash_hash
TupleHashEntryData
哈希表条目
typedefstructTupleHashEntryData*TupleHashEntry;typedefstructTupleHashTableData*TupleHashTable;typedefstructTupleHashEntryData{//该组第一个元组的拷贝MinimalTuplefirstTuple;/*copyoffirsttupleinthisgroup*///用户数据void*additional;/*userdata*///状态(见SH_STATUS)uint32status;/*hashstatus*///哈希值(已缓存)uint32hash;/*hashvalue(cached)*/}TupleHashEntryData;typedefenumSH_STATUS{SH_STATUS_EMPTY=0x00,SH_STATUS_IN_USE=0x01}SH_STATUS;
MinimalTuple
最小化的元组定义
/**MinimalTupleisanalternativerepresentationthatisusedfortransient*tuplesinsidetheexecutor,inplaceswheretransactionstatusinformation*isnotrequired,thetuplerowtypeisknown,andshavingoffafewbytes*isworthwhilebecauseweneedtostoremanytuples.Therepresentation*ischosensothattupleaccessroutinescanworkwitheitherfullor*minimaltuplesviaaHeapTupleDatapointerstructure.Theaccessroutines*seenodifference,exceptthattheymustnotaccessthetransactionstatus*ort_ctidfieldsbecausethosearen'tthere.**Forthemostpart,MinimalTuplesshouldbeaccessedviaTupleTableSlot*routines.Theseroutineswillpreventaccesstothe"systemcolumns"*andtherebypreventaccidentaluseofthenonexistentfields.**MinimalTupleDatacontainsalengthword,somepadding,andfieldsmatching*HeapTupleHeaderDatabeginningwitht_infomask2.Thepaddingischosenso*thatoffsetof(t_infomask2)isthesamemoduloMAXIMUM_ALIGNOFinboth*structs.Thismakesdataalignmentrulesequivalentinbothcases.**WhenaminimaltupleisaccessedviaaHeapTupleDatapointer,t_datais*settopointMINIMAL_TUPLE_OFFSETbytesbeforetheactualstartofthe*minimaltuple---thatis,whereafulltuplematchingtheminimaltuple's*datawouldstart.Thistrickiswhatmakesthestructsseemequivalent.**Notethatt_hoffiscomputedthesameasinafulltuple,henceitincludes*theMINIMAL_TUPLE_OFFSETdistance.t_lendoesnotincludethat,however.**MINIMAL_TUPLE_DATA_OFFSETistheoffsettothefirstuseful(non-pad)data*otherthanthelengthword.tuplesort.candtuplestore.cusethistoavoid*writingthepaddingtodisk.*/#defineMINIMAL_TUPLE_OFFSET\((offsetof(HeapTupleHeaderData,t_infomask2)-sizeof(uint32))/MAXIMUM_ALIGNOF*MAXIMUM_ALIGNOF)#defineMINIMAL_TUPLE_PADDING\((offsetof(HeapTupleHeaderData,t_infomask2)-sizeof(uint32))%MAXIMUM_ALIGNOF)#defineMINIMAL_TUPLE_DATA_OFFSET\offsetof(MinimalTupleData,t_infomask2)structMinimalTupleData{uint32t_len;/*actuallengthofminimaltuple*/charmt_padding[MINIMAL_TUPLE_PADDING];/*FieldsbelowheremustmatchHeapTupleHeaderData!*/uint16t_infomask2;/*numberofattributes+variousflags*/uint16t_infomask;/*variousflagbits,seebelow*/uint8t_hoff;/*sizeofheaderincl.bitmap,padding*//*^-23bytes-^*/bits8t_bits[FLEXIBLE_ARRAY_MEMBER];/*bitmapofNULLs*//*MOREDATAFOLLOWSATENDOFSTRUCT*/};/*typedefappearsinhtup.h*/#defineSizeofMinimalTupleHeaderoffsetof(MinimalTupleData,t_bits)typedefstructMinimalTupleDataMinimalTupleData;typedefMinimalTupleData*MinimalTuple;二、源码解读
simplehash.h定义了一系列的宏,比如SH_MAKE_PREFIX/SH_TYPE等等,在聚合函数实现(文件:src/backend/executor/execGrouping.c)中,具体定义了SH_PREFIX这些宏在聚合函数实现场景下的实际值.
如:
#define SH_PREFIX tuplehash
在聚合函数实现中,均以tuplehash打头,最终的实现函数为tuplehash_insert等.
//-----------------------------------------------------------------------------------//src/backend/executor/execGrouping.c/**Defineparametersfortuplehashtablecodegeneration.Theinterfaceis**also*declaredinexecnodes.h(togeneratethetypes,whichareexternally*visible).*/#defineSH_PREFIXtuplehash//以tuplehash打头,如tuplehash_insert等#defineSH_ELEMENT_TYPETupleHashEntryData//条目类型#defineSH_KEY_TYPEMinimalTuple//Key类型#defineSH_KEYfirstTuple//KEY#defineSH_HASH_KEY(tb,key)TupleHashTableHash(tb,key)//SH_HASH_KEY-->TupleHashTableHash#defineSH_EQUAL(tb,a,b)TupleHashTableMatch(tb,a,b)==0//SH_EQUAL-->TupleHashTableMatch#defineSH_SCOPEextern//外部LIB#defineSH_STORE_HASH#defineSH_GET_HASH(tb,a)a->hash#defineSH_DEFINE#include"lib/simplehash.h"//-----------------------------------------------------------------------------------//-----------------------------------------------------------------------------------//src/include/nodes/execnodes.h/*defineparametersnecessarytogeneratethetuplehashtableinterface*/#defineSH_PREFIXtuplehash#defineSH_ELEMENT_TYPETupleHashEntryData#defineSH_KEY_TYPEMinimalTuple#defineSH_SCOPEextern#defineSH_DECLARE#include"lib/simplehash.h"//-----------------------------------------------------------------------------------//-----------------------------------------------------------------------------------//src/backend/nodes/tidbitmap.c/*definehashtablemappingblocknumberstoPagetableEntry's*/#defineSH_USE_NONDEFAULT_ALLOCATOR#defineSH_PREFIXpagetable#defineSH_ELEMENT_TYPEPagetableEntry#defineSH_KEY_TYPEBlockNumber#defineSH_KEYblockno#defineSH_HASH_KEY(tb,key)murmurhash42(key)#defineSH_EQUAL(tb,a,b)a==b#defineSH_SCOPEstaticinline#defineSH_DEFINE#defineSH_DECLARE#include"lib/simplehash.h"//-----------------------------------------------------------------------------------/**simplehash.h**Hashtableimplementationwhichwillbespecializedtouser-defined*types,byincludingthisfiletogeneratetherequiredcode.It's*probablynotworthwhiletodosoforhashtablesthataren'tperformance*orspacesensitive.*用户自定义类型Hash表实现,包含此文件用于产生相应的代码.*对于那些空间和性能都不敏感的哈希表,可能不值得这样做.**Usagenotes:**Togenerateahash-tableandassociatedfunctionsforausecaseseveral*macroshavetobe#define'edbeforethisfileisincluded.Including*thefile#undef'sallthose,soanewhashtablecanbegenerated*afterwards.*Therelevantparametersare:*-SH_PREFIX-prefixforallsymbolnamesgenerated.Aprefixof'foo'*willresultinhashtabletype'foo_hash'andfunctionslike*'foo_insert'/'foo_lookup'andsoforth.*-SH_ELEMENT_TYPE-typeofthecontainedelements*-SH_KEY_TYPE-typeofthehashtable'skey*-SH_DECLARE-ifdefinedfunctionprototypesandtypedeclarationsare*generated*-SH_DEFINE-ifdefinedfunctiondefinitionsaregenerated*-SH_SCOPE-inwhichscope(e.g.extern,staticinline)dofunction*declarationsreside*-SH_USE_NONDEFAULT_ALLOCATOR-ifdefinednoelementallocatorfunctions*aredefined,soyoucansupplyyourown*ThefollowingparametersareonlyrelevantwhenSH_DEFINEisdefined:*-SH_KEY-nameoftheelementinSH_ELEMENT_TYPEcontainingthehashkey*-SH_EQUAL(table,a,b)-comparetwotablekeys*-SH_HASH_KEY(table,key)-generatehashforthekey*-SH_STORE_HASH-ifdefinedthehashisstoredintheelements*-SH_GET_HASH(tb,a)-returnthefieldtostorethehashin**Forexamplesofusagelookatsimplehash.c(filelocaldefinition)and*execnodes.h/execGrouping.c(exposeddeclaration,filelocal*implementation).**使用提示:*在该文件被包含前,自行定义相应的宏,用于生成哈希表和相关的函数.*相关的参数包括:*-SH_PREFIX-所有标识符名称的前缀.比如前缀'foo',产生的哈希表类型为foo_hash,函数为foo_insert/foo_lookup等.-SH_ELEMENT_TYPE-哈希表元素类型-SH_KEY_TYPE-哈希表键类型-SH_DECLARE-如存在此宏定义,则生成函数原型和类型声明-SH_DEFINE-如存在此宏定义,则生成函数定义-SH_SCOPE-函数作用域(如extern,staticinline等)-SH_USE_NONDEFAULT_ALLOCATOR-如存在此宏定义,则不会定义元素分配器函数,自行提供下面这些参数在定义了SH_DEFINE宏时才会生效:-SH_KEY-包含了hashkey的SH_ELEMENT_TYPE的元素名称-SH_EQUAL(table,a,b)-比较两个键-SH_HASH_KEY(table,key)-为键生成哈希值-SH_STORE_HASH-如存在此宏定义,哈希值存储在元素中-SH_GET_HASH(tb,a)-返回存储哈希值的字段**Hashtabledesign:**Thehashtabledesignchosenisavariantoflinearopen-addressing.The*reasonfordoingsoisthatlinearaddressingisCPUcache&pipeline*friendly.Thebiggestdisadvantageofsimplelinearaddressingschemes*arehighlyvariablelookuptimesduetoclustering,anddeletions*leavingalotoftombstonesaround.Toaddresstheseissuesavariant*of"robinhood"hashingisemployed.Robinhoodhashingoptimizes*chaininglengthsbymovingelementsclosetotheiroptimalbucket*("rich"elements),outofthewayifato-be-insertedelementisfurther*awayfromitsoptimalposition(i.e.it's"poor").Whilethatcanmake*insertionsslower,theaveragelookupperformanceisalotbetter,and*higherfillfactorscanbeusedinastillperformantmanner.Toavoid*tombstones-whichnormallysolvetheissuethatadeletednode's*presenceisrelevanttodeterminewhetheralookupneedstocontinue*lookingorisdone-bucketsfollowingadeletedelementareshifted*backwards,unlessthey'reemptyoralreadyattheiroptimalposition.**哈希表设计:*我们选择的哈希表设计是线性开放寻址的一种变体.*之所以选择这种设计是因为线性寻址是CPUcache&pipeline友好的.*简单线性寻址模式最大的缺点是由于集群导致查找时间会高度可变,而且删除操作会留下大量的无用位置.*为了解决这些问题,使用了"robinhood"哈希变体.*"robinhood"哈希通过将元素移动到最优bucket("rich"元素)附近来优化链长度,*如果要插入的元素离它的最优位置较远的话.*虽然这会导致插入变慢,但平均检索的性能则会大幅提升,而且天有更高的填充因子.*为了避免无用位置-用于解决删除节点的存在与否以及确定是否需要是否继续检索或执行查找相关的问题*-随着删除的元素的变换,buckents会向后移动,除非它们是空的或者已经处于最佳位置.*//*helpers*///助手宏定义,比如组装名称等等#defineSH_MAKE_PREFIX(a)CppConcat(a,_)#defineSH_MAKE_NAME(name)SH_MAKE_NAME_(SH_MAKE_PREFIX(SH_PREFIX),name)#defineSH_MAKE_NAME_(a,b)CppConcat(a,b)/*namemacrosfor:*//*typedeclarations*///类型声明#defineSH_TYPESH_MAKE_NAME(hash)#defineSH_STATUSSH_MAKE_NAME(status)#defineSH_STATUS_EMPTYSH_MAKE_NAME(EMPTY)#defineSH_STATUS_IN_USESH_MAKE_NAME(IN_USE)#defineSH_ITERATORSH_MAKE_NAME(iterator)/*functiondeclarations*///函数声明#defineSH_CREATESH_MAKE_NAME(create)#defineSH_DESTROYSH_MAKE_NAME(destroy)#defineSH_RESETSH_MAKE_NAME(reset)#defineSH_INSERTSH_MAKE_NAME(insert)#defineSH_DELETESH_MAKE_NAME(delete)#defineSH_LOOKUPSH_MAKE_NAME(lookup)#defineSH_GROWSH_MAKE_NAME(grow)#defineSH_START_ITERATESH_MAKE_NAME(start_iterate)#defineSH_START_ITERATE_ATSH_MAKE_NAME(start_iterate_at)#defineSH_ITERATESH_MAKE_NAME(iterate)#defineSH_ALLOCATESH_MAKE_NAME(allocate)#defineSH_FREESH_MAKE_NAME(free)#defineSH_STATSH_MAKE_NAME(stat)/*internalhelperfunctions(noexternallyvisibleprototypes)*///内部助手函数(非外部可见原型)#defineSH_COMPUTE_PARAMETERSSH_MAKE_NAME(compute_parameters)#defineSH_NEXTSH_MAKE_NAME(next)#defineSH_PREVSH_MAKE_NAME(prev)#defineSH_DISTANCE_FROM_OPTIMALSH_MAKE_NAME(distance)#defineSH_INITIAL_BUCKETSH_MAKE_NAME(initial_bucket)#defineSH_ENTRY_HASHSH_MAKE_NAME(entry_hash)/*generateforwarddeclarationsnecessarytousethehashtable*///如定义了SH_DECLARE,则生成使用哈希表所需的声明#ifdefSH_DECLARE/*typedefinitions*/typedefstructSH_TYPE{/**Sizeofdata/bucketarray,64bitstohandleUINT32_MAXsizedhash*tables.Notethatthemaximumnumberofelementsislower*(SH_MAX_FILLFACTOR)*/uint64size;/*howmanyelementshavevalidcontents*/uint32members;/*maskforbucketandsizecalculations,basedonsize*/uint32sizemask;/*boundaryafterwhichtogrowhashtable*/uint32grow_threshold;/*hashbuckets*/SH_ELEMENT_TYPE*data;/*memorycontexttouseforallocations*/MemoryContextctx;/*userdefineddata,usefulforcallbacks*/void*private_data;}SH_TYPE;//实际是tuplehash_hashtypedefenumSH_STATUS{SH_STATUS_EMPTY=0x00,SH_STATUS_IN_USE=0x01}SH_STATUS;typedefstructSH_ITERATOR{uint32cur;/*currentelement*/uint32end;booldone;/*iteratorexhausted?*/}SH_ITERATOR;/*externallyvisiblefunctionprototypes*/SH_SCOPESH_TYPE*SH_CREATE(MemoryContextctx,uint32nelements,void*private_data);SH_SCOPEvoidSH_DESTROY(SH_TYPE*tb);SH_SCOPEvoidSH_RESET(SH_TYPE*tb);SH_SCOPEvoidSH_GROW(SH_TYPE*tb,uint32newsize);SH_SCOPESH_ELEMENT_TYPE*SH_INSERT(SH_TYPE*tb,SH_KEY_TYPEkey,bool*found);SH_SCOPESH_ELEMENT_TYPE*SH_LOOKUP(SH_TYPE*tb,SH_KEY_TYPEkey);SH_SCOPEboolSH_DELETE(SH_TYPE*tb,SH_KEY_TYPEkey);SH_SCOPEvoidSH_START_ITERATE(SH_TYPE*tb,SH_ITERATOR*iter);SH_SCOPEvoidSH_START_ITERATE_AT(SH_TYPE*tb,SH_ITERATOR*iter,uint32at);SH_SCOPESH_ELEMENT_TYPE*SH_ITERATE(SH_TYPE*tb,SH_ITERATOR*iter);SH_SCOPEvoidSH_STAT(SH_TYPE*tb);#endif/*SH_DECLARE*//*generateimplementationofthehashtable*///如定义了宏SH_DEFINE,则生成Hash表的实现#ifdefSH_DEFINE#include"utils/memutils.h"/*maxdataarraysize,weallowuptoPG_UINT32_MAXbuckets,including0*/#defineSH_MAX_SIZE(((uint64)PG_UINT32_MAX)+1)/*normalfillfactor,unlessalreadyclosetomaximum*/#ifndefSH_FILLFACTOR#defineSH_FILLFACTOR(0.9)#endif/*increasefillfactorifweotherwisewoulderrorout*/#defineSH_MAX_FILLFACTOR(0.98)/*growifactualandoptimallocationbiggerthan*/#ifndefSH_GROW_MAX_DIB#defineSH_GROW_MAX_DIB25#endif/*growifmorethanelementstomovewheninserting*/#ifndefSH_GROW_MAX_MOVE#defineSH_GROW_MAX_MOVE150#endif#ifndefSH_GROW_MIN_FILLFACTOR/*butdonotgrowduetoSH_GROW_MAX_*ifbelow*/#defineSH_GROW_MIN_FILLFACTOR0.1#endif#ifdefSH_STORE_HASH#defineSH_COMPARE_KEYS(tb,ahash,akey,b)(ahash==SH_GET_HASH(tb,b)&&SH_EQUAL(tb,b->SH_KEY,akey))#else#defineSH_COMPARE_KEYS(tb,ahash,akey,b)(SH_EQUAL(tb,b->SH_KEY,akey))#endif/*FIXME:canwemovethesetoacentrallocation?*//*calculateceil(logbase2)ofnum*/staticinlineuint64sh_log2(uint64num){inti;uint64limit;for(i=0,limit=1;limit<num;i++,limit<<=1);returni;}/*calculatefirstpowerof2>=num*/staticinlineuint64sh_pow2(uint64num){return((uint64)1)<<sh_log2(num);}/**Computesizingparametersforhashtable.Calledwhencreatingandgrowing*thehashtable.*/staticinlinevoidSH_COMPUTE_PARAMETERS(SH_TYPE*tb,uint32newsize){uint64size;/*supportingzerosizedhasheswouldcomplicatematters*/size=Max(newsize,2);/*roundupsizetothenextpowerof2,that'showbucketingworks*/size=sh_pow2(size);Assert(size<=SH_MAX_SIZE);/**Verifythatallocationof->dataispossibleonthisplatform,without*overflowingSize.*/if((((uint64)sizeof(SH_ELEMENT_TYPE))*size)>=MaxAllocHugeSize)elog(ERROR,"hashtabletoolarge");/*nowsetsize*/tb->size=size;if(tb->size==SH_MAX_SIZE)tb->sizemask=0;elsetb->sizemask=tb->size-1;/**Computethenextthresholdatwhichweneedtogrowthehashtable*again.*/if(tb->size==SH_MAX_SIZE)tb->grow_threshold=((double)tb->size)*SH_MAX_FILLFACTOR;elsetb->grow_threshold=((double)tb->size)*SH_FILLFACTOR;}/*returntheoptimalbucketforthehash*/staticinlineuint32SH_INITIAL_BUCKET(SH_TYPE*tb,uint32hash){returnhash&tb->sizemask;}/*returnnextbucketafterthecurrent,handlingwraparound*/staticinlineuint32SH_NEXT(SH_TYPE*tb,uint32curelem,uint32startelem){curelem=(curelem+1)&tb->sizemask;Assert(curelem!=startelem);returncurelem;}/*returnbucketbeforethecurrent,handlingwraparound*/staticinlineuint32SH_PREV(SH_TYPE*tb,uint32curelem,uint32startelem){curelem=(curelem-1)&tb->sizemask;Assert(curelem!=startelem);returncurelem;}/*returndistancebetweenbucketanditsoptimalposition*/staticinlineuint32SH_DISTANCE_FROM_OPTIMAL(SH_TYPE*tb,uint32optimal,uint32bucket){if(optimal<=bucket)returnbucket-optimal;elsereturn(tb->size+bucket)-optimal;}staticinlineuint32SH_ENTRY_HASH(SH_TYPE*tb,SH_ELEMENT_TYPE*entry){#ifdefSH_STORE_HASHreturnSH_GET_HASH(tb,entry);#elsereturnSH_HASH_KEY(tb,entry->SH_KEY);#endif}/*defaultmemoryallocatorfunction*/staticinlinevoid*SH_ALLOCATE(SH_TYPE*type,Sizesize);staticinlinevoidSH_FREE(SH_TYPE*type,void*pointer);#ifndefSH_USE_NONDEFAULT_ALLOCATOR/*defaultmemoryallocatorfunction*/staticinlinevoid*SH_ALLOCATE(SH_TYPE*type,Sizesize){returnMemoryContextAllocExtended(type->ctx,size,MCXT_ALLOC_HUGE|MCXT_ALLOC_ZERO);}/*defaultmemoryfreefunction*/staticinlinevoidSH_FREE(SH_TYPE*type,void*pointer){pfree(pointer);}#endif/**Createahashtablewithenoughspacefor`nelements`distinctmembers.*Memoryforthehashtableisallocatedfromthepassed-incontext.If*desired,thearrayofelementscanbeallocatedusingapassed-inallocator;*thiscouldbeusefulinordertoplacethearrayofelementsinashared*memory,orinacontextthatwilloutlivetherestofthehashtable.*Memoryotherthanforthearrayofelementswillstillbeallocatedfrom*thepassed-incontext.*/SH_SCOPESH_TYPE*SH_CREATE(MemoryContextctx,uint32nelements,void*private_data){SH_TYPE*tb;uint64size;tb=MemoryContextAllocZero(ctx,sizeof(SH_TYPE));tb->ctx=ctx;tb->private_data=private_data;/*increasenelementsbyfillfactor,wanttostorenelementselements*/size=Min((double)SH_MAX_SIZE,((double)nelements)/SH_FILLFACTOR);SH_COMPUTE_PARAMETERS(tb,size);tb->data=SH_ALLOCATE(tb,sizeof(SH_ELEMENT_TYPE)*tb->size);returntb;}/*destroyapreviouslycreatedhashtable*/SH_SCOPEvoidSH_DESTROY(SH_TYPE*tb){SH_FREE(tb,tb->data);pfree(tb);}/*resetthecontentsofapreviouslycreatedhashtable*/SH_SCOPEvoidSH_RESET(SH_TYPE*tb){memset(tb->data,0,sizeof(SH_ELEMENT_TYPE)*tb->size);tb->members=0;}/**Growahashtabletoatleast`newsize`buckets.**Usuallythiswillautomaticallybecalledbyinsertions/deletions,when*necessary.Butresizingtotheexactinputsizecanbeadvantageous*performance-wise,whenknownatsomepoint.*/SH_SCOPEvoidSH_GROW(SH_TYPE*tb,uint32newsize){uint64oldsize=tb->size;SH_ELEMENT_TYPE*olddata=tb->data;SH_ELEMENT_TYPE*newdata;uint32i;uint32startelem=0;uint32copyelem;Assert(oldsize==sh_pow2(oldsize));Assert(oldsize!=SH_MAX_SIZE);Assert(oldsize<newsize);/*computeparametersfornewtable*/SH_COMPUTE_PARAMETERS(tb,newsize);tb->data=SH_ALLOCATE(tb,sizeof(SH_ELEMENT_TYPE)*tb->size);newdata=tb->data;/**Copyentriesfromtheolddatatonewdata.Wetheoreticallycoulduse*SH_INSERThere,toavoidcodeduplication,butthat'smoregeneralthan*weneed.Weneitherwanttb->membersincreased,nordoweneedtodo*dealwithdeletedelements,nordoweneedtocomparekeys.Soa*special-casedimplementationislotfaster.Asresizingcanbetime*consumingandfrequent,that'sworthwhiletooptimize.**Tobeabletosimplymoveentriesover,wehavetostartnotatthe*firstbucket(i.eolddata[0]),butfindthefirstbucketthat'seither*empty,orisoccupiedbyanentryatitsoptimalposition.Sucha*buckethastoexistinanytablewithaloadfactorunder1,asnotall*bucketsareoccupied,i.e.therealwayshastobeanemptybucket.By*startingatsuchabucketwecanmovetheentriestothelargertable,*withouthavingtodealwithconflicts.*//*searchforthefirstelementinthehashthat'snotwrappedaround*/for(i=0;i<oldsize;i++){SH_ELEMENT_TYPE*oldentry=&olddata[i];uint32hash;uint32optimal;if(oldentry->status!=SH_STATUS_IN_USE){startelem=i;break;}hash=SH_ENTRY_HASH(tb,oldentry);optimal=SH_INITIAL_BUCKET(tb,hash);if(optimal==i){startelem=i;break;}}/*andcopyallelementsintheoldtable*/copyelem=startelem;for(i=0;i<oldsize;i++){SH_ELEMENT_TYPE*oldentry=&olddata[copyelem];if(oldentry->status==SH_STATUS_IN_USE){uint32hash;uint32startelem;uint32curelem;SH_ELEMENT_TYPE*newentry;hash=SH_ENTRY_HASH(tb,oldentry);startelem=SH_INITIAL_BUCKET(tb,hash);curelem=startelem;/*findemptyelementtoputdatainto*/while(true){newentry=&newdata[curelem];if(newentry->status==SH_STATUS_EMPTY){break;}curelem=SH_NEXT(tb,curelem,startelem);}/*copyentrytonewslot*/memcpy(newentry,oldentry,sizeof(SH_ELEMENT_TYPE));}/*can'tuseSH_NEXThere,wouldusenewsize*/copyelem++;if(copyelem>=oldsize){copyelem=0;}}SH_FREE(tb,olddata);}/**Insertthekeykeyintothehash-table,set*foundtotrueifthekey*alreadyexists,falseotherwise.Returnsthehash-tableentryineither*case.*插入Key到哈希表中,如Key已存在则设置*found为T,否则为F.*返回哈希表条目.*在聚合运算场景中:*SH_ELEMENT_TYPE-->TupleHashEntryData*SH_INSERT-->tuplehash_insert*/SH_SCOPESH_ELEMENT_TYPE*SH_INSERT(SH_TYPE*tb,SH_KEY_TYPEkey,bool*found){uint32hash=SH_HASH_KEY(tb,key);//TupleHashTableHash,Key类型为MinimalTupleuint32startelem;uint32curelem;SH_ELEMENT_TYPE*data;uint32insertdist;restart:insertdist=0;/**Wedothegrowcheckevenifthekeyisactuallypresent,toavoid*doingthecheckinsidetheloop.Thisalsoletsusavoidhavingto*re-findourpositioninthehashtableafterresizing.*就算Key实际存在但我们也会执行扩展检查以避免在循环中进行检查.*这同时可以让我们避免不得不在调整空间后重新在哈希表中检索位置.**Notethatthisalsoreachedwhenresizingthetabledueto*SH_GROW_MAX_DIB/SH_GROW_MAX_MOVE.*因为SH_GROW_MAX_DIB/SH_GROW_MAX_MOVE而调整空间时也会执行这些逻辑.*/if(unlikely(tb->members>=tb->grow_threshold)){if(tb->size==SH_MAX_SIZE){elog(ERROR,"hashtablesizeexceeded");}/**Whenoptimizing,itcanbeveryusefultoprinttheseout.*在优化的时候,打印这些信息会很有用.*//*SH_STAT(tb);*/SH_GROW(tb,tb->size*2);/*SH_STAT(tb);*/}/*performinsert,startbucketsearchatoptimallocation*///执行插入,在优化的位置开始bucket搜索data=tb->data;startelem=SH_INITIAL_BUCKET(tb,hash);//开始位置curelem=startelem;//当前哈希表中的元素while(true){uint32curdist;uint32curhash;uint32curoptimal;SH_ELEMENT_TYPE*entry=&data[curelem];//SH_ELEMENT_TYPE-->TupleHashEntryData/*anyemptybucketcandirectlybeused*///是否有空bucket可以直接使用?if(entry->status==SH_STATUS_EMPTY){//---------条目状态为空//成员加1tb->members++;//Key赋值entry->SH_KEY=key;#ifdefSH_STORE_HASH//是否存在hash值?SH_GET_HASH(tb,entry)=hash;#endif//调整条目状态entry->status=SH_STATUS_IN_USE;//设置相关变量*found=false;//返回entryreturnentry;}/**Ifthebucketisnotempty,weeitherfoundamatch(inwhichcase*we'redone),orwehavetodecidewhethertoskipoverormovethe*collidingentry.Whenthecollidingelement'sdistancetoits*optimalpositionissmallerthantheto-be-insertedentry's,we*shiftthecollidingentry(anditsfollowers)forwardbyone.*如果bucket非空,这时候要么会发现匹配Key,要么确定是否跳过或者移动出现冲突的etnry.*如果出现出现冲突的元素距离优化位置小于即将插入的条目,则切换冲突条目.*//*#ifdefSH_STORE_HASH#defineSH_COMPARE_KEYS(tb,ahash,akey,b)(ahash==SH_GET_HASH(tb,b)&&SH_EQUAL(tb,b->SH_KEY,akey))#else#defineSH_COMPARE_KEYS(tb,ahash,akey,b)(SH_EQUAL(tb,b->SH_KEY,akey))#endifSH_EQUAL-->TupleHashTableMatch*/if(SH_COMPARE_KEYS(tb,hash,key,entry))//TupleHashTableMatch{//找到了相应的KeyAssert(entry->status==SH_STATUS_IN_USE);*found=true;//返回条目returnentry;}//当前的哈希值curhash=SH_ENTRY_HASH(tb,entry);//当前优化的位置curoptimal=SH_INITIAL_BUCKET(tb,curhash);//距离curdist=SH_DISTANCE_FROM_OPTIMAL(tb,curoptimal,curelem);if(insertdist>curdist){SH_ELEMENT_TYPE*lastentry=entry;uint32emptyelem=curelem;uint32moveelem;int32emptydist=0;/*findnextemptybucket*/while(true){SH_ELEMENT_TYPE*emptyentry;emptyelem=SH_NEXT(tb,emptyelem,startelem);emptyentry=&data[emptyelem];if(emptyentry->status==SH_STATUS_EMPTY){lastentry=emptyentry;break;}/**Toavoidnegativeconsequencesfromoverlyimbalanced*hashtables,growthehashtableifcollisionswouldrequire*ustomovealotofentries.Themostlikelycauseofsuch*imbalanceisfillinga(currently)smalltable,froma*currentlybigone,inhash-tableorder.Don'tgrowifthe*hashtablewouldbetooempty,topreventquickspace*explosionforsomeweirdedgecases.*/if(unlikely(++emptydist>SH_GROW_MAX_MOVE)&&((double)tb->members/tb->size)>=SH_GROW_MIN_FILLFACTOR){tb->grow_threshold=0;gotorestart;}}/*shiftforward,startingatlastoccupiedelement*//**TODO:Thiscouldbeoptimizedtobeonememcpyinmaycases,*exceptingwrappingaroundattheendof->data.Hasn'tshownup*inprofilessofarthough.*/moveelem=emptyelem;while(moveelem!=curelem){SH_ELEMENT_TYPE*moveentry;moveelem=SH_PREV(tb,moveelem,startelem);moveentry=&data[moveelem];memcpy(lastentry,moveentry,sizeof(SH_ELEMENT_TYPE));lastentry=moveentry;}/*andfillthenowemptyspot*/tb->members++;entry->SH_KEY=key;#ifdefSH_STORE_HASHSH_GET_HASH(tb,entry)=hash;#endifentry->status=SH_STATUS_IN_USE;*found=false;returnentry;}curelem=SH_NEXT(tb,curelem,startelem);insertdist++;/**Toavoidnegativeconsequencesfromoverlyimbalancedhashtables,*growthehashtableifcollisionsleadtolargeruns.Themost*likelycauseofsuchimbalanceisfillinga(currently)small*table,fromacurrentlybigone,inhash-tableorder.Don'tgrow*ifthehashtablewouldbetooempty,topreventquickspace*explosionforsomeweirdedgecases.*/if(unlikely(insertdist>SH_GROW_MAX_DIB)&&((double)tb->members/tb->size)>=SH_GROW_MIN_FILLFACTOR){tb->grow_threshold=0;gotorestart;}}}/**Lookupupentryinhashtable.ReturnsNULLifkeynotpresent.*/SH_SCOPESH_ELEMENT_TYPE*SH_LOOKUP(SH_TYPE*tb,SH_KEY_TYPEkey){uint32hash=SH_HASH_KEY(tb,key);constuint32startelem=SH_INITIAL_BUCKET(tb,hash);uint32curelem=startelem;while(true){SH_ELEMENT_TYPE*entry=&tb->data[curelem];if(entry->status==SH_STATUS_EMPTY){returnNULL;}Assert(entry->status==SH_STATUS_IN_USE);if(SH_COMPARE_KEYS(tb,hash,key,entry))returnentry;/**TODO:wecouldstopsearchbasedondistance.Ifthecurrent*buckets'sdistance-from-optimalissmallerthanwhatwe'veskipped*already,theentrydoesn'texist.Probablyonlydosoif*SH_STORE_HASHisdefined,toavoidre-computinghashes?*/curelem=SH_NEXT(tb,curelem,startelem);}}/**Deleteentryfromhashtable.Returnswhetherto-be-deletedkeywas*present.*/SH_SCOPEboolSH_DELETE(SH_TYPE*tb,SH_KEY_TYPEkey){uint32hash=SH_HASH_KEY(tb,key);uint32startelem=SH_INITIAL_BUCKET(tb,hash);uint32curelem=startelem;while(true){SH_ELEMENT_TYPE*entry=&tb->data[curelem];if(entry->status==SH_STATUS_EMPTY)returnfalse;if(entry->status==SH_STATUS_IN_USE&&SH_COMPARE_KEYS(tb,hash,key,entry)){SH_ELEMENT_TYPE*lastentry=entry;tb->members--;/**Backwardshiftfollowingelementstilleitheranemptyelement*oranelementatitsoptimalpositionisencountered.**Whilethatsoundsexpensive,theaveragechainlengthisshort,*anddeletionswouldotherwiserequiretombstones.*/while(true){SH_ELEMENT_TYPE*curentry;uint32curhash;uint32curoptimal;curelem=SH_NEXT(tb,curelem,startelem);curentry=&tb->data[curelem];if(curentry->status!=SH_STATUS_IN_USE){lastentry->status=SH_STATUS_EMPTY;break;}curhash=SH_ENTRY_HASH(tb,curentry);curoptimal=SH_INITIAL_BUCKET(tb,curhash);/*currentisatoptimalposition,done*/if(curoptimal==curelem){lastentry->status=SH_STATUS_EMPTY;break;}/*shift*/memcpy(lastentry,curentry,sizeof(SH_ELEMENT_TYPE));lastentry=curentry;}returntrue;}/*TODO:returnfalse;ifdistancetoobig*/curelem=SH_NEXT(tb,curelem,startelem);}}/**Initializeiterator.*/SH_SCOPEvoidSH_START_ITERATE(SH_TYPE*tb,SH_ITERATOR*iter){inti;uint64startelem=PG_UINT64_MAX;/**Searchforthefirstemptyelement.Asdeletionsduringiterationsare*supported,wewanttostart/endatanelementthatcannotbeaffected*byelementsbeingshifted.*/for(i=0;i<tb->size;i++){SH_ELEMENT_TYPE*entry=&tb->data[i];if(entry->status!=SH_STATUS_IN_USE){startelem=i;break;}}Assert(startelem<SH_MAX_SIZE);/**Iteratebackwards,thatallowsthecurrentelementtobedeleted,even*iftherearebackwardshifts*/iter->cur=startelem;iter->end=iter->cur;iter->done=false;}/**Initializeiteratortoaspecificbucket.That'sreallyonlyusefulfor*caseswherecallersarepartiallyiteratingoverthehashspace,andthat*iterationdeletesandinsertselementsbasedonvisitedentries.Doingthat*repeatedlycouldleadtoanunbalancedkeyspacewhenalwaysstartingatthe*sameposition.*/SH_SCOPEvoidSH_START_ITERATE_AT(SH_TYPE*tb,SH_ITERATOR*iter,uint32at){/**Iteratebackwards,thatallowsthecurrentelementtobedeleted,even*iftherearebackwardshifts.*/iter->cur=at&tb->sizemask;/*ensureatiswithinavalidrange*/iter->end=iter->cur;iter->done=false;}/**Iterateoverallentriesinthehash-table.Returnthenextoccupiedentry,*orNULLifdone.**Duringiterationthecurrententryinthehashtablemaybedeleted,*withoutleadingtoelementsbeingskippedorreturnedtwice.Additionally*therestofthetablemaybemodified(i.e.therecanbeinsertionsor*deletions),butifso,there'sneitheraguaranteethatallnodesare*visitedatleastonce,noraguaranteethatanodeisvisitedatmostonce.*/SH_SCOPESH_ELEMENT_TYPE*SH_ITERATE(SH_TYPE*tb,SH_ITERATOR*iter){while(!iter->done){SH_ELEMENT_TYPE*elem;elem=&tb->data[iter->cur];/*nextelementinbackwarddirection*/iter->cur=(iter->cur-1)&tb->sizemask;if((iter->cur&tb->sizemask)==(iter->end&tb->sizemask))iter->done=true;if(elem->status==SH_STATUS_IN_USE){returnelem;}}returnNULL;}/**Reportsomestatisticsaboutthestateofthehashtable.For*debugging/profilingpurposesonly.*/SH_SCOPEvoidSH_STAT(SH_TYPE*tb){uint32max_chain_length=0;uint32total_chain_length=0;doubleavg_chain_length;doublefillfactor;uint32i;uint32*collisions=palloc0(tb->size*sizeof(uint32));uint32total_collisions=0;uint32max_collisions=0;doubleavg_collisions;for(i=0;i<tb->size;i++){uint32hash;uint32optimal;uint32dist;SH_ELEMENT_TYPE*elem;elem=&tb->data[i];if(elem->status!=SH_STATUS_IN_USE)continue;hash=SH_ENTRY_HASH(tb,elem);optimal=SH_INITIAL_BUCKET(tb,hash);dist=SH_DISTANCE_FROM_OPTIMAL(tb,optimal,i);if(dist>max_chain_length)max_chain_length=dist;total_chain_length+=dist;collisions[optimal]++;}for(i=0;i<tb->size;i++){uint32curcoll=collisions[i];if(curcoll==0)continue;/*singlecontainedelementisnotacollision*/curcoll--;total_collisions+=curcoll;if(curcoll>max_collisions)max_collisions=curcoll;}if(tb->members>0){fillfactor=tb->members/((double)tb->size);avg_chain_length=((double)total_chain_length)/tb->members;avg_collisions=((double)total_collisions)/tb->members;}else{fillfactor=0;avg_chain_length=0;avg_collisions=0;}elog(LOG,"size:"UINT64_FORMAT",members:%u,filled:%f,totalchain:%u,maxchain:%u,avgchain:%f,total_collisions:%u,max_collisions:%i,avg_collisions:%f",tb->size,tb->members,fillfactor,total_chain_length,max_chain_length,avg_chain_length,total_collisions,max_collisions,avg_collisions);}#endif/*SH_DEFINE*//*undefineexternalparameters,sonexthashtablecanbedefined*/#undefSH_PREFIX#undefSH_KEY_TYPE#undefSH_KEY#undefSH_ELEMENT_TYPE#undefSH_HASH_KEY#undefSH_SCOPE#undefSH_DECLARE#undefSH_DEFINE#undefSH_GET_HASH#undefSH_STORE_HASH#undefSH_USE_NONDEFAULT_ALLOCATOR/*undefinelocallydeclaredmacros*/#undefSH_MAKE_PREFIX#undefSH_MAKE_NAME#undefSH_MAKE_NAME_#undefSH_FILLFACTOR#undefSH_MAX_FILLFACTOR#undefSH_GROW_MAX_DIB#undefSH_GROW_MAX_MOVE#undefSH_GROW_MIN_FILLFACTOR#undefSH_MAX_SIZE/*types*/#undefSH_TYPE#undefSH_STATUS#undefSH_STATUS_EMPTY#undefSH_STATUS_IN_USE#undefSH_ITERATOR/*externalfunctionnames*/#undefSH_CREATE#undefSH_DESTROY#undefSH_RESET#undefSH_INSERT#undefSH_DELETE#undefSH_LOOKUP#undefSH_GROW#undefSH_START_ITERATE#undefSH_START_ITERATE_AT#undefSH_ITERATE#undefSH_ALLOCATE#undefSH_FREE#undefSH_STAT/*internalfunctionnames*/#undefSH_COMPUTE_PARAMETERS#undefSH_COMPARE_KEYS#undefSH_INITIAL_BUCKET#undefSH_NEXT#undefSH_PREV#undefSH_DISTANCE_FROM_OPTIMAL#undefSH_ENTRY_HASH三、跟踪分析
下面以tuplehash_insert为例,分析simplehash插入哈希表的实现.
测试脚本
--禁用并行setmax_parallel_workers_per_gather=0;selectbh,avg(c1),min(c1),max(c2)fromt_agg_simplegroupbybh;
跟踪分析
(gdb)btuplehash_insertBreakpoint1at0x6d2a27:file../../../src/include/lib/simplehash.h,line490.(gdb)
输入参数
(gdb)p*tb$1={size=256,members=0,sizemask=255,grow_threshold=230,data=0x1cc2a10,ctx=0x1c9b320,private_data=0x1cb88a0}(gdb)
判断是否需要增长
(gdb)n497insertdist=0;(gdb)507if(unlikely(tb->members>=tb->grow_threshold))(gdb)ptb->members$2=0(gdb)ptb->grow_threshold$3=230
执行插入,在优化的位置开始bucket搜索
获取条目数组(TupleHashEntryData *指针),初始化开始元素和当前元素
(gdb)n523data=tb->data;(gdb)524startelem=SH_INITIAL_BUCKET(tb,hash);(gdb)p*data$4={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)n525curelem=startelem;(gdb)pstartelem$5=114(gdb)phash$6=443809650(gdb)
进入循环,寻找空闲的bucket执行插入
(gdb)n531SH_ELEMENT_TYPE*entry=&data[curelem];(gdb)n534if(entry->status==SH_STATUS_EMPTY)(gdb)p*entry$7={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)p*data$8={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)pdata[255]$9={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)n536tb->members++;(gdb)537entry->SH_KEY=key;(gdb)p*tb$10={size=256,members=1,sizemask=255,grow_threshold=230,data=0x1cc2a10,ctx=0x1c9b320,private_data=0x1cb88a0}(gdb)n539SH_GET_HASH(tb,entry)=hash;(gdb)541entry->status=SH_STATUS_IN_USE;(gdb)p*entry$11={firstTuple=0x0,additional=0x0,status=0,hash=443809650}(gdb)n542*found=false;(gdb)543returnentry;(gdb)p*entry$12={firstTuple=0x0,additional=0x0,status=1,hash=443809650}(gdb)
完成函数调用,返回entry
(gdb)n652}(gdb)LookupTupleHashEntry(hashtable=0x1cb88a0,slot=0x1c9d248,isnew=0x7ffd1348e797)atexecGrouping.c:303303if(found)(gdb)
回到LookupTupleHashEntry
(gdb)LookupTupleHashEntry(hashtable=0x1cb88a0,slot=0x1c9d248,isnew=0x7ffd1348e797)atexecGrouping.c:303303if(found)(gdb)n311*isnew=true;(gdb)313entry->additional=NULL;(gdb)314MemoryContextSwitchTo(hashtable->tablecxt);(gdb)316entry->firstTuple=ExecCopySlotMinimalTuple(slot);(gdb)324MemoryContextSwitchTo(oldContext);
查看tuple数据
(gdb)p*entry$13={firstTuple=0x1cb2498,additional=0x0,status=1,hash=443809650}(gdb)x/7xentry->firstTuple->t_bits0x1cb24a7:0x000x0b0x470x5a0x300x310x7e(gdb)x/7centry->firstTuple->t_bits0x1cb24a7:0'\000'11'\v'71'G'90'Z'48'0'49'1'126'~'
下一次调用,这次出现了碰撞
(gdb)cContinuing.Breakpoint1,tuplehash_insert(tb=0x1cb8730,key=0x0,found=0x7ffd1348e757)at../../../src/include/lib/simplehash.h:490490uint32hash=SH_HASH_KEY(tb,key);(gdb)n497insertdist=0;(gdb)phash$15=4237773170(gdb)n507if(unlikely(tb->members>=tb->grow_threshold))(gdb)523data=tb->data;(gdb)524startelem=SH_INITIAL_BUCKET(tb,hash);(gdb)pdata[0]$16={firstTuple=0x0,additional=0x0,status=0,hash=0}(gdb)n525curelem=startelem;(gdb)531SH_ELEMENT_TYPE*entry=&data[curelem];(gdb)pstartelem$17=114(gdb)pcurelem$18=114(gdb)pdata[curelem]$19={firstTuple=0x1cb2498,additional=0x1cb24d0,status=1,hash=443809650}(gdb)n534if(entry->status==SH_STATUS_EMPTY)(gdb)554if(SH_COMPARE_KEYS(tb,hash,key,entry))(gdb)561curhash=SH_ENTRY_HASH(tb,entry);(gdb)562curoptimal=SH_INITIAL_BUCKET(tb,curhash);(gdb)pcurhash$20=443809650(gdb)n563curdist=SH_DISTANCE_FROM_OPTIMAL(tb,curoptimal,curelem);(gdb)565if(insertdist>curdist)(gdb)pcuroptimal$21=114(gdb)pcurdist$22=0(gdb)n634curelem=SH_NEXT(tb,curelem,startelem);(gdb)pinsertdist$23=0(gdb)n635insertdist++;(gdb)pcurelem$24=115(gdb)n645if(unlikely(insertdist>SH_GROW_MAX_DIB)&&(gdb)651}(gdb)531SH_ELEMENT_TYPE*entry=&data[curelem];(gdb)534if(entry->status==SH_STATUS_EMPTY)(gdb)536tb->members++;(gdb)537entry->SH_KEY=key;(gdb)539SH_GET_HASH(tb,entry)=hash;(gdb)541entry->status=SH_STATUS_IN_USE;(gdb)542*found=false;(gdb)543returnentry;(gdb)p*entry$25={firstTuple=0x0,additional=0x0,status=1,hash=4237773170}(gdb)
回到LookupTupleHashEntry,查看tuple
(gdb)LookupTupleHashEntry(hashtable=0x1cb88a0,slot=0x1c9d248,isnew=0x7ffd1348e797)atexecGrouping.c:303303if(found)(gdb)311*isnew=true;(gdb)313entry->additional=NULL;(gdb)314MemoryContextSwitchTo(hashtable->tablecxt);(gdb)316entry->firstTuple=ExecCopySlotMinimalTuple(slot);(gdb)324MemoryContextSwitchTo(oldContext);(gdb)p*entry$26={firstTuple=0x1cb2580,additional=0x0,status=1,hash=4237773170}(gdb)p*entry->firstTuple$27={t_len=21,mt_padding="\000\000\000\000\000",t_infomask2=1,t_infomask=2,t_hoff=24'\030',t_bits=0x1cb258f""}(gdb)x/7xentry->firstTuple->t_bits0x1cb258f:0x000x0b0x470x5a0x300x320x7e(gdb)x/7centry->firstTuple->t_bits0x1cb258f:0'\000'11'\v'71'G'90'Z'48'0'50'2'126'~'(gdb)
到此,关于“PostgreSQL的simplehash.h文件中的内容是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。