📄 gist.c
字号:
InsertIndexResult res; GISTENTRY tmpentry; IndexTuple newtup; b = ReadBuffer(r, stk->gs_blk); p = BufferGetPage(b); if (gistnospace(p, ltup)) { res = gistSplit(r, b, stk->gs_parent, ltup, giststate); WriteBuffer(b); /* don't forget to release buffer! - * 01/31/94 */ pfree(res); gistdoinsert(r, rtup, giststate); } else { gistPageAddItem(giststate, r, p, (Item) ltup, IndexTupleSize(ltup), InvalidOffsetNumber, LP_USED, &tmpentry, &newtup); WriteBuffer(b); gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred, tmpentry.bytes, giststate); /* be tidy */ if (tmpentry.pred != (((char *) ltup) + sizeof(IndexTupleData))) pfree(tmpentry.pred); if (ltup != newtup) pfree(newtup); gistentryinsert(r, stk, rtup, giststate); }}/*** Insert an entry onto a page*/static InsertIndexResultgistentryinsert(Relation r, GISTSTACK *stk, IndexTuple tup, GISTSTATE *giststate){ Buffer b; Page p; InsertIndexResult res; OffsetNumber off; GISTENTRY tmpentry; IndexTuple newtup; b = ReadBuffer(r, stk->gs_blk); p = BufferGetPage(b); if (gistnospace(p, tup)) { res = gistSplit(r, b, stk->gs_parent, tup, giststate); WriteBuffer(b); /* don't forget to release buffer! - * 01/31/94 */ return res; } else { res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); off = gistPageAddItem(giststate, r, p, (Item) tup, IndexTupleSize(tup), InvalidOffsetNumber, LP_USED, &tmpentry, &newtup); WriteBuffer(b); ItemPointerSet(&(res->pointerData), stk->gs_blk, off); gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred, tmpentry.bytes, giststate); /* be tidy */ if (tmpentry.pred != (((char *) tup) + sizeof(IndexTupleData))) pfree(tmpentry.pred); if (tup != newtup) pfree(newtup); return res; }}static voidgistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt, IndexTuple rt){ Buffer b; Page p; GISTENTRY tmpentry; IndexTuple newtup; b = ReadBuffer(r, GISTP_ROOT); GISTInitBuffer(b, 0); p = BufferGetPage(b); gistPageAddItem(giststate, r, p, (Item) lt, IndexTupleSize(lt), FirstOffsetNumber, LP_USED, &tmpentry, &newtup); /* be tidy */ if (tmpentry.pred != (((char *) lt) + sizeof(IndexTupleData))) pfree(tmpentry.pred); if (lt != newtup) pfree(newtup); gistPageAddItem(giststate, r, p, (Item) rt, IndexTupleSize(rt), OffsetNumberNext(FirstOffsetNumber), LP_USED, &tmpentry, &newtup); /* be tidy */ if (tmpentry.pred != (((char *) rt) + sizeof(IndexTupleData))) pfree(tmpentry.pred); if (rt != newtup) pfree(newtup); WriteBuffer(b);}static voidGISTInitBuffer(Buffer b, uint32 f){ GISTPageOpaque opaque; Page page; Size pageSize; pageSize = BufferGetPageSize(b); page = BufferGetPage(b); MemSet(page, 0, (int) pageSize); PageInit(page, pageSize, sizeof(GISTPageOpaqueData)); opaque = (GISTPageOpaque) PageGetSpecialPointer(page); opaque->flags = f;}/*** find entry with lowest penalty*/static OffsetNumbergistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */ GISTSTATE *giststate){ OffsetNumber maxoff; OffsetNumber i; char *id; char *datum; float usize; OffsetNumber which; float which_grow; GISTENTRY entry, identry; int size, idsize; idsize = IndexTupleSize(it) - sizeof(IndexTupleData); id = ((char *) it) + sizeof(IndexTupleData); maxoff = PageGetMaxOffsetNumber(p); which_grow = -1.0; which = -1; gistdentryinit(giststate, &identry, id, (Relation) NULL, (Page) NULL, (OffsetNumber) 0, idsize, FALSE); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { datum = (char *) PageGetItem(p, PageGetItemId(p, i)); size = IndexTupleSize(datum) - sizeof(IndexTupleData); datum += sizeof(IndexTupleData); gistdentryinit(giststate, &entry, datum, r, p, i, size, FALSE); (*fmgr_faddr(&giststate->penaltyFn)) (&entry, &identry, &usize); if (which_grow < 0 || usize < which_grow) { which = i; which_grow = usize; if (which_grow == 0) break; } if (entry.pred != datum) pfree(entry.pred); } if (identry.pred != id) pfree(identry.pred); return which;}static intgistnospace(Page p, IndexTuple it){ return PageGetFreeSpace(p) < IndexTupleSize(it);}voidgistfreestack(GISTSTACK *s){ GISTSTACK *p; while (s != (GISTSTACK *) NULL) { p = s->gs_parent; pfree(s); s = p; }}/*** remove an entry from a page*/voidgistdelete(Relation r, ItemPointer tid){ BlockNumber blkno; OffsetNumber offnum; Buffer buf; Page page; /* * Notes in ExecUtils:ExecOpenIndices() Also note that only vacuum * deletes index tuples now... * * RelationSetLockForWrite(r); */ blkno = ItemPointerGetBlockNumber(tid); offnum = ItemPointerGetOffsetNumber(tid); /* adjust any scans that will be affected by this deletion */ gistadjscans(r, GISTOP_DEL, blkno, offnum); /* delete the index tuple */ buf = ReadBuffer(r, blkno); page = BufferGetPage(buf); PageIndexTupleDelete(page, offnum); WriteBuffer(buf);}voidinitGISTstate(GISTSTATE *giststate, Relation index){ RegProcedure consistent_proc, union_proc, compress_proc, decompress_proc; RegProcedure penalty_proc, picksplit_proc, equal_proc; HeapTuple htup; Form_pg_index itupform; consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC); union_proc = index_getprocid(index, 1, GIST_UNION_PROC); compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC); decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC); penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC); picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC); equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC); fmgr_info(consistent_proc, &giststate->consistentFn); fmgr_info(union_proc, &giststate->unionFn); fmgr_info(compress_proc, &giststate->compressFn); fmgr_info(decompress_proc, &giststate->decompressFn); fmgr_info(penalty_proc, &giststate->penaltyFn); fmgr_info(picksplit_proc, &giststate->picksplitFn); fmgr_info(equal_proc, &giststate->equalFn); /* see if key type is different from type of attribute being indexed */ htup = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(RelationGetRelid(index)), 0, 0, 0); itupform = (Form_pg_index) GETSTRUCT(htup); if (!HeapTupleIsValid(htup)) elog(ERROR, "initGISTstate: index %u not found", RelationGetRelid(index)); giststate->haskeytype = itupform->indhaskeytype; if (giststate->haskeytype) { /* key type is different -- is it byval? */ htup = SearchSysCacheTuple(ATTNUM, ObjectIdGetDatum(itupform->indexrelid), UInt16GetDatum(FirstOffsetNumber), 0, 0); if (!HeapTupleIsValid(htup)) { elog(ERROR, "initGISTstate: no attribute tuple %u %d", itupform->indexrelid, FirstOffsetNumber); return; } giststate->keytypbyval = (((Form_pg_attribute) htup)->attbyval); } else giststate->keytypbyval = FALSE; return;}/*** Given an IndexTuple to be inserted on a page, this routine replaces** the key with another key, which may involve generating a new IndexTuple** if the sizes don't match*/static IndexTuplegist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t){ char *datum = (((char *) t) + sizeof(IndexTupleData)); /* if new entry fits in index tuple, copy it in */ if (entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData)) { memcpy(datum, entry.pred, entry.bytes); /* clear out old size */ t->t_info &= 0xe000; /* or in new size */ t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData)); return t; } else { /* generate a new index tuple for the compressed entry */ TupleDesc tupDesc = r->rd_att; IndexTuple newtup; char *isnull; int blank; isnull = (char *) palloc(r->rd_rel->relnatts); for (blank = 0; blank < r->rd_rel->relnatts; blank++) isnull[blank] = ' '; newtup = (IndexTuple) index_formtuple(tupDesc, (Datum *) &(entry.pred), isnull); newtup->t_tid = t->t_tid; pfree(isnull); return newtup; }}/*** initialize a GiST entry with a decompressed version of pred*/voidgistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, Page pg, OffsetNumber o, int b, bool l){ GISTENTRY *dep; gistentryinit(*e, pr, r, pg, o, b, l); if (giststate->haskeytype) { dep = (GISTENTRY *) ((*fmgr_faddr(&giststate->decompressFn)) (e)); gistentryinit(*e, dep->pred, dep->rel, dep->page, dep->offset, dep->bytes, dep->leafkey); if (dep != e) pfree(dep); }}/*** initialize a GiST entry with a compressed version of pred*/static voidgistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, Page pg, OffsetNumber o, int b, bool l){ GISTENTRY *cep; gistentryinit(*e, pr, r, pg, o, b, l); if (giststate->haskeytype) { cep = (GISTENTRY *) ((*fmgr_faddr(&giststate->compressFn)) (e)); gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes, cep->leafkey); if (cep != e) pfree(cep); }}#ifdef GISTDEBUG/*** sloppy debugging support routine, requires recompilation with appropriate** "out" method for the index keys. Could be fixed to find that info** in the catalogs...*/void_gistdump(Relation r){ Buffer buf; Page page; OffsetNumber offnum, maxoff; BlockNumber blkno; BlockNumber nblocks; GISTPageOpaque po; IndexTuple itup; BlockNumber itblkno; OffsetNumber itoffno; char *datum; char *itkey; nblocks = RelationGetNumberOfBlocks(r); for (blkno = 0; blkno < nblocks; blkno++) { buf = ReadBuffer(r, blkno); page = BufferGetPage(buf); po = (GISTPageOpaque) PageGetSpecialPointer(page); maxoff = PageGetMaxOffsetNumber(page); printf("Page %d maxoff %d <%s>\n", blkno, maxoff, (po->flags & F_LEAF ? "LEAF" : "INTERNAL")); if (PageIsEmpty(page)) { ReleaseBuffer(buf); continue; } for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) { itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); itblkno = ItemPointerGetBlockNumber(&(itup->t_tid)); itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid)); datum = ((char *) itup); datum += sizeof(IndexTupleData); /* get out function for type of key, and out it! */ itkey = (char *) int_range_out((INTRANGE *) datum); /* itkey = " unable to print"; */ printf("\t[%d] size %d heap <%d,%d> key:%s\n", offnum, IndexTupleSize(itup), itblkno, itoffno, itkey); pfree(itkey); } ReleaseBuffer(buf); }}static char *int_range_out(INTRANGE *r){ char *result; if (r == NULL) return NULL; result = (char *) palloc(80); snprintf(result, 80, "[%d,%d): %d", r->lower, r->upper, r->flag); return result;}#endif /* defined GISTDEBUG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -