📄 rtree.c
字号:
rightbuf = ReadBuffer(r, P_NEW); RTInitBuffer(rightbuf, opaque->flags); rbknum = BufferGetBlockNumber(rightbuf); right = (Page) BufferGetPage(rightbuf); picksplit(r, p, &v, itup, rtstate); leftoff = rightoff = FirstOffsetNumber; maxoff = PageGetMaxOffsetNumber(p); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { itemid = PageGetItemId(p, i); item = (IndexTuple) PageGetItem(p, itemid); if (i == *(v.spl_left)) { PageAddItem(left, (Item) item, IndexTupleSize(item), leftoff, LP_USED); leftoff = OffsetNumberNext(leftoff); v.spl_left++; /* advance in left split vector */ } else { PageAddItem(right, (Item) item, IndexTupleSize(item), rightoff, LP_USED); rightoff = OffsetNumberNext(rightoff); v.spl_right++; /* advance in right split vector */ } } /* build an InsertIndexResult for this insertion */ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); /* now insert the new index tuple */ if (*(v.spl_left) != FirstOffsetNumber) { PageAddItem(left, (Item) itup, IndexTupleSize(itup), leftoff, LP_USED); leftoff = OffsetNumberNext(leftoff); ItemPointerSet(&(res->pointerData), lbknum, leftoff); } else { PageAddItem(right, (Item) itup, IndexTupleSize(itup), rightoff, LP_USED); rightoff = OffsetNumberNext(rightoff); ItemPointerSet(&(res->pointerData), rbknum, rightoff); } if ((bufblock = BufferGetBlockNumber(buffer)) != P_ROOT) PageRestoreTempPage(left, p); WriteBuffer(leftbuf); WriteBuffer(rightbuf); /* * Okay, the page is split. We have three things left to do: * * 1) Adjust any active scans on this index to cope with changes we * introduced in its structure by splitting this page. * * 2) "Tighten" the bounding box of the pointer to the left page in the * parent node in the tree, if any. Since we moved a bunch of stuff * off the left page, we expect it to get smaller. This happens in * the internal insertion routine. * * 3) Insert a pointer to the right page in the parent. This may cause * the parent to split. If it does, we need to repeat steps one and * two for each split node in the tree. */ /* adjust active scans */ rtadjscans(r, RTOP_SPLIT, bufblock, FirstOffsetNumber); tupDesc = r->rd_att; ltup = (IndexTuple) index_formtuple(tupDesc, (Datum *) &(v.spl_ldatum), isnull); rtup = (IndexTuple) index_formtuple(tupDesc, (Datum *) &(v.spl_rdatum), isnull); pfree(isnull); /* set pointers to new child pages in the internal index tuples */ ItemPointerSet(&(ltup->t_tid), lbknum, 1); ItemPointerSet(&(rtup->t_tid), rbknum, 1); rtintinsert(r, stack, ltup, rtup, rtstate); pfree(ltup); pfree(rtup); return res;}static voidrtintinsert(Relation r, RTSTACK *stk, IndexTuple ltup, IndexTuple rtup, RTSTATE *rtstate){ IndexTuple old; Buffer b; Page p; char *ldatum, *rdatum, *newdatum; InsertIndexResult res; if (stk == (RTSTACK *) NULL) { rtnewroot(r, ltup, rtup); return; } b = ReadBuffer(r, stk->rts_blk); p = BufferGetPage(b); old = (IndexTuple) PageGetItem(p, PageGetItemId(p, stk->rts_child)); /* * This is a hack. Right now, we force rtree keys to be constant * size. To fix this, need delete the old key and add both left and * right for the two new pages. The insertion of left may force a * split if the new left key is bigger than the old key. */ if (IndexTupleSize(old) != IndexTupleSize(ltup)) elog(ERROR, "Variable-length rtree keys are not supported."); /* install pointer to left child */ memmove(old, ltup, IndexTupleSize(ltup)); if (nospace(p, rtup)) { newdatum = (((char *) ltup) + sizeof(IndexTupleData)); rttighten(r, stk->rts_parent, newdatum, (IndexTupleSize(ltup) - sizeof(IndexTupleData)), rtstate); res = dosplit(r, b, stk->rts_parent, rtup, rtstate); WriteBuffer(b); /* don't forget to release buffer! - * 01/31/94 */ pfree(res); } else { PageAddItem(p, (Item) rtup, IndexTupleSize(rtup), PageGetMaxOffsetNumber(p), LP_USED); WriteBuffer(b); ldatum = (((char *) ltup) + sizeof(IndexTupleData)); rdatum = (((char *) rtup) + sizeof(IndexTupleData)); newdatum = (char *) (*fmgr_faddr(&rtstate->unionFn)) (ldatum, rdatum); rttighten(r, stk->rts_parent, newdatum, (IndexTupleSize(rtup) - sizeof(IndexTupleData)), rtstate); pfree(newdatum); }}static voidrtnewroot(Relation r, IndexTuple lt, IndexTuple rt){ Buffer b; Page p; b = ReadBuffer(r, P_ROOT); RTInitBuffer(b, 0); p = BufferGetPage(b); PageAddItem(p, (Item) lt, IndexTupleSize(lt), FirstOffsetNumber, LP_USED); PageAddItem(p, (Item) rt, IndexTupleSize(rt), OffsetNumberNext(FirstOffsetNumber), LP_USED); WriteBuffer(b);}static voidpicksplit(Relation r, Page page, SPLITVEC *v, IndexTuple itup, RTSTATE *rtstate){ OffsetNumber maxoff; OffsetNumber i, j; IndexTuple item_1, item_2; char *datum_alpha, *datum_beta; char *datum_l, *datum_r; char *union_d, *union_dl, *union_dr; char *inter_d; bool firsttime; float size_alpha, size_beta, size_union, size_inter; float size_waste, waste; float size_l, size_r; int nbytes; OffsetNumber seed_1 = 0, seed_2 = 0; OffsetNumber *left, *right; maxoff = PageGetMaxOffsetNumber(page); nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_right = (OffsetNumber *) palloc(nbytes); firsttime = true; waste = 0.0; for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) { item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i)); datum_alpha = ((char *) item_1) + sizeof(IndexTupleData); for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) { item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, j)); datum_beta = ((char *) item_2) + sizeof(IndexTupleData); /* compute the wasted space by unioning these guys */ union_d = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_alpha, datum_beta); (*fmgr_faddr(&rtstate->sizeFn)) (union_d, &size_union); inter_d = (char *) (*fmgr_faddr(&rtstate->interFn)) (datum_alpha, datum_beta); (*fmgr_faddr(&rtstate->sizeFn)) (inter_d, &size_inter); size_waste = size_union - size_inter; pfree(union_d); if (inter_d != (char *) NULL) pfree(inter_d); /* * are these a more promising split that what we've already * seen? */ if (size_waste > waste || firsttime) { waste = size_waste; seed_1 = i; seed_2 = j; firsttime = false; } } } left = v->spl_left; v->spl_nleft = 0; right = v->spl_right; v->spl_nright = 0; item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_1)); datum_alpha = ((char *) item_1) + sizeof(IndexTupleData); datum_l = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_alpha, datum_alpha); (*fmgr_faddr(&rtstate->sizeFn)) (datum_l, &size_l); item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_2)); datum_beta = ((char *) item_2) + sizeof(IndexTupleData); datum_r = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_beta, datum_beta); (*fmgr_faddr(&rtstate->sizeFn)) (datum_r, &size_r); /* * Now split up the regions between the two seeds. An important * property of this split algorithm is that the split vector v has the * indices of items to be split in order in its left and right * vectors. We exploit this property by doing a merge in the code * that actually splits the page. * * For efficiency, we also place the new index tuple in this loop. This * is handled at the very end, when we have placed all the existing * tuples and i == maxoff + 1. */ maxoff = OffsetNumberNext(maxoff); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { /* * If we've already decided where to place this item, just put it * on the right list. Otherwise, we need to figure out which page * needs the least enlargement in order to store the item. */ if (i == seed_1) { *left++ = i; v->spl_nleft++; continue; } else if (i == seed_2) { *right++ = i; v->spl_nright++; continue; } /* okay, which page needs least enlargement? */ if (i == maxoff) item_1 = itup; else item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i)); datum_alpha = ((char *) item_1) + sizeof(IndexTupleData); union_dl = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_l, datum_alpha); union_dr = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_r, datum_alpha); (*fmgr_faddr(&rtstate->sizeFn)) (union_dl, &size_alpha); (*fmgr_faddr(&rtstate->sizeFn)) (union_dr, &size_beta); /* pick which page to add it to */ if (size_alpha - size_l < size_beta - size_r) { pfree(datum_l); pfree(union_dr); datum_l = union_dl; size_l = size_alpha; *left++ = i; v->spl_nleft++; } else { pfree(datum_r); pfree(union_dl); datum_r = union_dr; size_r = size_alpha; *right++ = i; v->spl_nright++; } } *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ v->spl_ldatum = datum_l; v->spl_rdatum = datum_r;}static voidRTInitBuffer(Buffer b, uint32 f){ RTreePageOpaque opaque; Page page; Size pageSize; pageSize = BufferGetPageSize(b); page = BufferGetPage(b); MemSet(page, 0, (int) pageSize); PageInit(page, pageSize, sizeof(RTreePageOpaqueData)); opaque = (RTreePageOpaque) PageGetSpecialPointer(page); opaque->flags = f;}static OffsetNumberchoose(Relation r, Page p, IndexTuple it, RTSTATE *rtstate){ OffsetNumber maxoff; OffsetNumber i; char *ud, *id; char *datum; float usize, dsize; OffsetNumber which; float which_grow; id = ((char *) it) + sizeof(IndexTupleData); maxoff = PageGetMaxOffsetNumber(p); which_grow = -1.0; which = -1; for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { datum = (char *) PageGetItem(p, PageGetItemId(p, i)); datum += sizeof(IndexTupleData); (*fmgr_faddr(&rtstate->sizeFn)) (datum, &dsize); ud = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum, id); (*fmgr_faddr(&rtstate->sizeFn)) (ud, &usize); pfree(ud); if (which_grow < 0 || usize - dsize < which_grow) { which = i; which_grow = usize - dsize; if (which_grow == 0) break; } } return which;}static intnospace(Page p, IndexTuple it){ return PageGetFreeSpace(p) < IndexTupleSize(it);}voidfreestack(RTSTACK *s){ RTSTACK *p; while (s != (RTSTACK *) NULL) { p = s->rts_parent; pfree(s); s = p; }}char *rtdelete(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 */ rtadjscans(r, RTOP_DEL, blkno, offnum); /* delete the index tuple */ buf = ReadBuffer(r, blkno); page = BufferGetPage(buf); PageIndexTupleDelete(page, offnum); WriteBuffer(buf); return (char *) NULL;}static voidinitRtstate(RTSTATE *rtstate, Relation index){ RegProcedure union_proc, size_proc, inter_proc; union_proc = index_getprocid(index, 1, RT_UNION_PROC); size_proc = index_getprocid(index, 1, RT_SIZE_PROC); inter_proc = index_getprocid(index, 1, RT_INTER_PROC); fmgr_info(union_proc, &rtstate->unionFn); fmgr_info(size_proc, &rtstate->sizeFn); fmgr_info(inter_proc, &rtstate->interFn); return;}#ifdef RTDEBUGvoid_rtdump(Relation r){ Buffer buf; Page page; OffsetNumber offnum, maxoff; BlockNumber blkno; BlockNumber nblocks; RTreePageOpaque 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 = (RTreePageOpaque) 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); itkey = (char *) box_out((BOX *) datum); printf("\t[%d] size %d heap <%d,%d> key:%s\n", offnum, IndexTupleSize(itup), itblkno, itoffno, itkey); pfree(itkey); } ReleaseBuffer(buf); }}#endif /* defined RTDEBUG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -