rtree.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:25k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * rtree.c
  4.  *   interface routines for the postgres rtree indexed access method.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/rtree/rtree.c,v 1.32.2.1 1999/08/02 05:24:44 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/genam.h"
  16. #include "access/heapam.h"
  17. #include "access/rtree.h"
  18. #include "catalog/index.h"
  19. #include "executor/executor.h"
  20. #include "utils/geo_decls.h"
  21. typedef struct SPLITVEC
  22. {
  23. OffsetNumber *spl_left;
  24. int spl_nleft;
  25. char    *spl_ldatum;
  26. OffsetNumber *spl_right;
  27. int spl_nright;
  28. char    *spl_rdatum;
  29. } SPLITVEC;
  30. typedef struct RTSTATE
  31. {
  32. FmgrInfo unionFn; /* union function */
  33. FmgrInfo sizeFn; /* size function */
  34. FmgrInfo interFn; /* intersection function */
  35. } RTSTATE;
  36. /* non-export function prototypes */
  37. static InsertIndexResult rtdoinsert(Relation r, IndexTuple itup,
  38.    RTSTATE *rtstate);
  39. static void rttighten(Relation r, RTSTACK *stk, char *datum, int att_size,
  40.   RTSTATE *rtstate);
  41. static InsertIndexResult dosplit(Relation r, Buffer buffer, RTSTACK *stack,
  42. IndexTuple itup, RTSTATE *rtstate);
  43. static void rtintinsert(Relation r, RTSTACK *stk, IndexTuple ltup,
  44. IndexTuple rtup, RTSTATE *rtstate);
  45. static void rtnewroot(Relation r, IndexTuple lt, IndexTuple rt);
  46. static void picksplit(Relation r, Page page, SPLITVEC *v, IndexTuple itup,
  47.   RTSTATE *rtstate);
  48. static void RTInitBuffer(Buffer b, uint32 f);
  49. static OffsetNumber choose(Relation r, Page p, IndexTuple it,
  50.    RTSTATE *rtstate);
  51. static int nospace(Page p, IndexTuple it);
  52. static void initRtstate(RTSTATE *rtstate, Relation index);
  53. void
  54. rtbuild(Relation heap,
  55. Relation index,
  56. int natts,
  57. AttrNumber *attnum,
  58. IndexStrategy istrat,
  59. uint16 pcount,
  60. Datum *params,
  61. FuncIndexInfo *finfo,
  62. PredInfo *predInfo)
  63. {
  64. HeapScanDesc scan;
  65. AttrNumber i;
  66. HeapTuple htup;
  67. IndexTuple itup;
  68. TupleDesc hd,
  69. id;
  70. InsertIndexResult res;
  71. Datum    *d;
  72. bool    *nulls;
  73. Buffer buffer = InvalidBuffer;
  74. int nb,
  75. nh,
  76. ni;
  77. #ifndef OMIT_PARTIAL_INDEX
  78. ExprContext *econtext;
  79. TupleTable tupleTable;
  80. TupleTableSlot *slot;
  81. #endif
  82. Oid hrelid,
  83. irelid;
  84. Node    *pred,
  85.    *oldPred;
  86. RTSTATE rtState;
  87. initRtstate(&rtState, index);
  88. pred = predInfo->pred;
  89. oldPred = predInfo->oldPred;
  90. /*
  91.  * We expect to be called exactly once for any index relation. If
  92.  * that's not the case, big trouble's what we have.
  93.  */
  94. if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
  95. elog(ERROR, "%s already contains data", index->rd_rel->relname.data);
  96. /* initialize the root page (if this is a new index) */
  97. if (oldPred == NULL)
  98. {
  99. buffer = ReadBuffer(index, P_NEW);
  100. RTInitBuffer(buffer, F_LEAF);
  101. WriteBuffer(buffer);
  102. }
  103. /* init the tuple descriptors and get set for a heap scan */
  104. hd = RelationGetDescr(heap);
  105. id = RelationGetDescr(index);
  106. d = (Datum *) palloc(natts * sizeof(*d));
  107. nulls = (bool *) palloc(natts * sizeof(*nulls));
  108. /*
  109.  * If this is a predicate (partial) index, we will need to evaluate
  110.  * the predicate using ExecQual, which requires the current tuple to
  111.  * be in a slot of a TupleTable.  In addition, ExecQual must have an
  112.  * ExprContext referring to that slot. Here, we initialize dummy
  113.  * TupleTable and ExprContext objects for this purpose. --Nels, Feb
  114.  * '92
  115.  */
  116. #ifndef OMIT_PARTIAL_INDEX
  117. if (pred != NULL || oldPred != NULL)
  118. {
  119. tupleTable = ExecCreateTupleTable(1);
  120. slot = ExecAllocTableSlot(tupleTable);
  121. econtext = makeNode(ExprContext);
  122. FillDummyExprContext(econtext, slot, hd, buffer);
  123. }
  124. else
  125. {
  126. econtext = NULL;
  127. tupleTable = NULL;
  128. slot = NULL;
  129. }
  130. #endif  /* OMIT_PARTIAL_INDEX */
  131. /* count the tuples as we insert them */
  132. nh = ni = 0;
  133. scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
  134. while (HeapTupleIsValid(htup = heap_getnext(scan, 0)))
  135. {
  136. nh++;
  137. /*
  138.  * If oldPred != NULL, this is an EXTEND INDEX command, so skip
  139.  * this tuple if it was already in the existing partial index
  140.  */
  141. if (oldPred != NULL)
  142. {
  143. #ifndef OMIT_PARTIAL_INDEX
  144. /* SetSlotContents(slot, htup); */
  145. slot->val = htup;
  146. if (ExecQual((List *) oldPred, econtext) == true)
  147. {
  148. ni++;
  149. continue;
  150. }
  151. #endif  /* OMIT_PARTIAL_INDEX */
  152. }
  153. /*
  154.  * Skip this tuple if it doesn't satisfy the partial-index
  155.  * predicate
  156.  */
  157. if (pred != NULL)
  158. {
  159. #ifndef OMIT_PARTIAL_INDEX
  160. /* SetSlotContents(slot, htup); */
  161. slot->val = htup;
  162. if (ExecQual((List *) pred, econtext) == false)
  163. continue;
  164. #endif  /* OMIT_PARTIAL_INDEX */
  165. }
  166. ni++;
  167. /*
  168.  * For the current heap tuple, extract all the attributes we use
  169.  * in this index, and note which are null.
  170.  */
  171. for (i = 1; i <= natts; i++)
  172. {
  173. int attoff;
  174. bool attnull;
  175. /*
  176.  * Offsets are from the start of the tuple, and are
  177.  * zero-based; indices are one-based.  The next call returns i
  178.  * - 1.  That's data hiding for you.
  179.  */
  180. attoff = AttrNumberGetAttrOffset(i);
  181. /*
  182.  * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
  183.  */
  184. d[attoff] = GetIndexValue(htup,
  185.   hd,
  186.   attoff,
  187.   attnum,
  188.   finfo,
  189.   &attnull);
  190. nulls[attoff] = (attnull ? 'n' : ' ');
  191. }
  192. /* form an index tuple and point it at the heap tuple */
  193. itup = index_formtuple(id, &d[0], nulls);
  194. itup->t_tid = htup->t_self;
  195. /*
  196.  * Since we already have the index relation locked, we call
  197.  * rtdoinsert directly.  Normal access method calls dispatch
  198.  * through rtinsert, which locks the relation for write.  This is
  199.  * the right thing to do if you're inserting single tups, but not
  200.  * when you're initializing the whole index at once.
  201.  */
  202. res = rtdoinsert(index, itup, &rtState);
  203. pfree(itup);
  204. pfree(res);
  205. }
  206. /* okay, all heap tuples are indexed */
  207. heap_endscan(scan);
  208. if (pred != NULL || oldPred != NULL)
  209. {
  210. #ifndef OMIT_PARTIAL_INDEX
  211. ExecDestroyTupleTable(tupleTable, true);
  212. pfree(econtext);
  213. #endif  /* OMIT_PARTIAL_INDEX */
  214. }
  215. /*
  216.  * Since we just counted the tuples in the heap, we update its stats
  217.  * in pg_relation to guarantee that the planner takes advantage of the
  218.  * index we just created.  UpdateStats() does a
  219.  * CommandCounterIncrement(), which flushes changed entries from the
  220.  * system relcache.  The act of constructing an index changes these
  221.  * heap and index tuples in the system catalogs, so they need to be
  222.  * flushed.  We close them to guarantee that they will be.
  223.  */
  224. hrelid = RelationGetRelid(heap);
  225. irelid = RelationGetRelid(index);
  226. heap_close(heap);
  227. index_close(index);
  228. UpdateStats(hrelid, nh, true);
  229. UpdateStats(irelid, ni, false);
  230. if (oldPred != NULL)
  231. {
  232. if (ni == nh)
  233. pred = NULL;
  234. UpdateIndexPredicate(irelid, oldPred, pred);
  235. }
  236. /* be tidy */
  237. pfree(nulls);
  238. pfree(d);
  239. }
  240. /*
  241.  * rtinsert -- wrapper for rtree tuple insertion.
  242.  *
  243.  *   This is the public interface routine for tuple insertion in rtrees.
  244.  *   It doesn't do any work; just locks the relation and passes the buck.
  245.  */
  246. InsertIndexResult
  247. rtinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
  248. {
  249. InsertIndexResult res;
  250. IndexTuple itup;
  251. RTSTATE rtState;
  252. /* generate an index tuple */
  253. itup = index_formtuple(RelationGetDescr(r), datum, nulls);
  254. itup->t_tid = *ht_ctid;
  255. initRtstate(&rtState, r);
  256. /*
  257.  * Notes in ExecUtils:ExecOpenIndices()
  258.  *
  259.  * RelationSetLockForWrite(r);
  260.  */
  261. res = rtdoinsert(r, itup, &rtState);
  262. return res;
  263. }
  264. static InsertIndexResult
  265. rtdoinsert(Relation r, IndexTuple itup, RTSTATE *rtstate)
  266. {
  267. Page page;
  268. Buffer buffer;
  269. BlockNumber blk;
  270. IndexTuple which;
  271. OffsetNumber l;
  272. RTSTACK    *stack;
  273. InsertIndexResult res;
  274. RTreePageOpaque opaque;
  275. char    *datum;
  276. blk = P_ROOT;
  277. buffer = InvalidBuffer;
  278. stack = (RTSTACK *) NULL;
  279. do
  280. {
  281. /* let go of current buffer before getting next */
  282. if (buffer != InvalidBuffer)
  283. ReleaseBuffer(buffer);
  284. /* get next buffer */
  285. buffer = ReadBuffer(r, blk);
  286. page = (Page) BufferGetPage(buffer);
  287. opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
  288. if (!(opaque->flags & F_LEAF))
  289. {
  290. RTSTACK    *n;
  291. ItemId iid;
  292. n = (RTSTACK *) palloc(sizeof(RTSTACK));
  293. n->rts_parent = stack;
  294. n->rts_blk = blk;
  295. n->rts_child = choose(r, page, itup, rtstate);
  296. stack = n;
  297. iid = PageGetItemId(page, n->rts_child);
  298. which = (IndexTuple) PageGetItem(page, iid);
  299. blk = ItemPointerGetBlockNumber(&(which->t_tid));
  300. }
  301. } while (!(opaque->flags & F_LEAF));
  302. if (nospace(page, itup))
  303. {
  304. /* need to do a split */
  305. res = dosplit(r, buffer, stack, itup, rtstate);
  306. freestack(stack);
  307. WriteBuffer(buffer); /* don't forget to release buffer! */
  308. return res;
  309. }
  310. /* add the item and write the buffer */
  311. if (PageIsEmpty(page))
  312. {
  313. l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
  314. FirstOffsetNumber,
  315. LP_USED);
  316. }
  317. else
  318. {
  319. l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
  320. OffsetNumberNext(PageGetMaxOffsetNumber(page)),
  321. LP_USED);
  322. }
  323. WriteBuffer(buffer);
  324. datum = (((char *) itup) + sizeof(IndexTupleData));
  325. /* now expand the page boundary in the parent to include the new child */
  326. rttighten(r, stack, datum,
  327.   (IndexTupleSize(itup) - sizeof(IndexTupleData)), rtstate);
  328. freestack(stack);
  329. /* build and return an InsertIndexResult for this insertion */
  330. res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
  331. ItemPointerSet(&(res->pointerData), blk, l);
  332. return res;
  333. }
  334. static void
  335. rttighten(Relation r,
  336.   RTSTACK *stk,
  337.   char *datum,
  338.   int att_size,
  339.   RTSTATE *rtstate)
  340. {
  341. char    *oldud;
  342. char    *tdatum;
  343. Page p;
  344. float old_size,
  345. newd_size;
  346. Buffer b;
  347. if (stk == (RTSTACK *) NULL)
  348. return;
  349. b = ReadBuffer(r, stk->rts_blk);
  350. p = BufferGetPage(b);
  351. oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->rts_child));
  352. oldud += sizeof(IndexTupleData);
  353. (*fmgr_faddr(&rtstate->sizeFn)) (oldud, &old_size);
  354. datum = (char *) (*fmgr_faddr(&rtstate->unionFn)) (oldud, datum);
  355. (*fmgr_faddr(&rtstate->sizeFn)) (datum, &newd_size);
  356. if (newd_size != old_size)
  357. {
  358. TupleDesc td = RelationGetDescr(r);
  359. if (td->attrs[0]->attlen < 0)
  360. {
  361. /*
  362.  * This is an internal page, so 'oldud' had better be a union
  363.  * (constant-length) key, too. (See comment below.)
  364.  */
  365. Assert(VARSIZE(datum) == VARSIZE(oldud));
  366. memmove(oldud, datum, VARSIZE(datum));
  367. }
  368. else
  369. memmove(oldud, datum, att_size);
  370. WriteBuffer(b);
  371. /*
  372.  * The user may be defining an index on variable-sized data (like
  373.  * polygons).  If so, we need to get a constant-sized datum for
  374.  * insertion on the internal page. We do this by calling the
  375.  * union proc, which is guaranteed to return a rectangle.
  376.  */
  377. tdatum = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum, datum);
  378. rttighten(r, stk->rts_parent, tdatum, att_size, rtstate);
  379. pfree(tdatum);
  380. }
  381. else
  382. ReleaseBuffer(b);
  383. pfree(datum);
  384. }
  385. /*
  386.  * dosplit -- split a page in the tree.
  387.  *
  388.  *   This is the quadratic-cost split algorithm Guttman describes in
  389.  *   his paper.  The reason we chose it is that you can implement this
  390.  *   with less information about the data types on which you're operating.
  391.  */
  392. static InsertIndexResult
  393. dosplit(Relation r,
  394. Buffer buffer,
  395. RTSTACK *stack,
  396. IndexTuple itup,
  397. RTSTATE *rtstate)
  398. {
  399. Page p;
  400. Buffer leftbuf,
  401. rightbuf;
  402. Page left,
  403. right;
  404. ItemId itemid;
  405. IndexTuple item;
  406. IndexTuple ltup,
  407. rtup;
  408. OffsetNumber maxoff;
  409. OffsetNumber i;
  410. OffsetNumber leftoff,
  411. rightoff;
  412. BlockNumber lbknum,
  413. rbknum;
  414. BlockNumber bufblock;
  415. RTreePageOpaque opaque;
  416. int blank;
  417. InsertIndexResult res;
  418. char    *isnull;
  419. SPLITVEC v;
  420. TupleDesc tupDesc;
  421. isnull = (char *) palloc(r->rd_rel->relnatts);
  422. for (blank = 0; blank < r->rd_rel->relnatts; blank++)
  423. isnull[blank] = ' ';
  424. p = (Page) BufferGetPage(buffer);
  425. opaque = (RTreePageOpaque) PageGetSpecialPointer(p);
  426. /*
  427.  * The root of the tree is the first block in the relation.  If we're
  428.  * about to split the root, we need to do some hocus-pocus to enforce
  429.  * this guarantee.
  430.  */
  431. if (BufferGetBlockNumber(buffer) == P_ROOT)
  432. {
  433. leftbuf = ReadBuffer(r, P_NEW);
  434. RTInitBuffer(leftbuf, opaque->flags);
  435. lbknum = BufferGetBlockNumber(leftbuf);
  436. left = (Page) BufferGetPage(leftbuf);
  437. }
  438. else
  439. {
  440. leftbuf = buffer;
  441. IncrBufferRefCount(buffer);
  442. lbknum = BufferGetBlockNumber(buffer);
  443. left = (Page) PageGetTempPage(p, sizeof(RTreePageOpaqueData));
  444. }
  445. rightbuf = ReadBuffer(r, P_NEW);
  446. RTInitBuffer(rightbuf, opaque->flags);
  447. rbknum = BufferGetBlockNumber(rightbuf);
  448. right = (Page) BufferGetPage(rightbuf);
  449. picksplit(r, p, &v, itup, rtstate);
  450. leftoff = rightoff = FirstOffsetNumber;
  451. maxoff = PageGetMaxOffsetNumber(p);
  452. for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
  453. {
  454. itemid = PageGetItemId(p, i);
  455. item = (IndexTuple) PageGetItem(p, itemid);
  456. if (i == *(v.spl_left))
  457. {
  458. PageAddItem(left, (Item) item, IndexTupleSize(item),
  459. leftoff, LP_USED);
  460. leftoff = OffsetNumberNext(leftoff);
  461. v.spl_left++; /* advance in left split vector */
  462. }
  463. else
  464. {
  465. PageAddItem(right, (Item) item, IndexTupleSize(item),
  466. rightoff, LP_USED);
  467. rightoff = OffsetNumberNext(rightoff);
  468. v.spl_right++; /* advance in right split vector */
  469. }
  470. }
  471. /* build an InsertIndexResult for this insertion */
  472. res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
  473. /* now insert the new index tuple */
  474. if (*(v.spl_left) != FirstOffsetNumber)
  475. {
  476. PageAddItem(left, (Item) itup, IndexTupleSize(itup),
  477. leftoff, LP_USED);
  478. leftoff = OffsetNumberNext(leftoff);
  479. ItemPointerSet(&(res->pointerData), lbknum, leftoff);
  480. }
  481. else
  482. {
  483. PageAddItem(right, (Item) itup, IndexTupleSize(itup),
  484. rightoff, LP_USED);
  485. rightoff = OffsetNumberNext(rightoff);
  486. ItemPointerSet(&(res->pointerData), rbknum, rightoff);
  487. }
  488. if ((bufblock = BufferGetBlockNumber(buffer)) != P_ROOT)
  489. PageRestoreTempPage(left, p);
  490. WriteBuffer(leftbuf);
  491. WriteBuffer(rightbuf);
  492. /*
  493.  * Okay, the page is split.  We have three things left to do:
  494.  *
  495.  * 1)  Adjust any active scans on this index to cope with changes we
  496.  * introduced in its structure by splitting this page.
  497.  *
  498.  * 2)  "Tighten" the bounding box of the pointer to the left page in the
  499.  * parent node in the tree, if any.  Since we moved a bunch of stuff
  500.  * off the left page, we expect it to get smaller. This happens in
  501.  * the internal insertion routine.
  502.  *
  503.  * 3)  Insert a pointer to the right page in the parent.  This may cause
  504.  * the parent to split.  If it does, we need to repeat steps one and
  505.  * two for each split node in the tree.
  506.  */
  507. /* adjust active scans */
  508. rtadjscans(r, RTOP_SPLIT, bufblock, FirstOffsetNumber);
  509. tupDesc = r->rd_att;
  510. ltup = (IndexTuple) index_formtuple(tupDesc,
  511.   (Datum *) &(v.spl_ldatum), isnull);
  512. rtup = (IndexTuple) index_formtuple(tupDesc,
  513.   (Datum *) &(v.spl_rdatum), isnull);
  514. pfree(isnull);
  515. /* set pointers to new child pages in the internal index tuples */
  516. ItemPointerSet(&(ltup->t_tid), lbknum, 1);
  517. ItemPointerSet(&(rtup->t_tid), rbknum, 1);
  518. rtintinsert(r, stack, ltup, rtup, rtstate);
  519. pfree(ltup);
  520. pfree(rtup);
  521. return res;
  522. }
  523. static void
  524. rtintinsert(Relation r,
  525. RTSTACK *stk,
  526. IndexTuple ltup,
  527. IndexTuple rtup,
  528. RTSTATE *rtstate)
  529. {
  530. IndexTuple old;
  531. Buffer b;
  532. Page p;
  533. char    *ldatum,
  534.    *rdatum,
  535.    *newdatum;
  536. InsertIndexResult res;
  537. if (stk == (RTSTACK *) NULL)
  538. {
  539. rtnewroot(r, ltup, rtup);
  540. return;
  541. }
  542. b = ReadBuffer(r, stk->rts_blk);
  543. p = BufferGetPage(b);
  544. old = (IndexTuple) PageGetItem(p, PageGetItemId(p, stk->rts_child));
  545. /*
  546.  * This is a hack. Right now, we force rtree keys to be constant
  547.  * size. To fix this, need delete the old key and add both left and
  548.  * right for the two new pages.  The insertion of left may force a
  549.  * split if the new left key is bigger than the old key.
  550.  */
  551. if (IndexTupleSize(old) != IndexTupleSize(ltup))
  552. elog(ERROR, "Variable-length rtree keys are not supported.");
  553. /* install pointer to left child */
  554. memmove(old, ltup, IndexTupleSize(ltup));
  555. if (nospace(p, rtup))
  556. {
  557. newdatum = (((char *) ltup) + sizeof(IndexTupleData));
  558. rttighten(r, stk->rts_parent, newdatum,
  559.    (IndexTupleSize(ltup) - sizeof(IndexTupleData)), rtstate);
  560. res = dosplit(r, b, stk->rts_parent, rtup, rtstate);
  561. WriteBuffer(b); /* don't forget to release buffer!  -
  562.  * 01/31/94 */
  563. pfree(res);
  564. }
  565. else
  566. {
  567. PageAddItem(p, (Item) rtup, IndexTupleSize(rtup),
  568. PageGetMaxOffsetNumber(p), LP_USED);
  569. WriteBuffer(b);
  570. ldatum = (((char *) ltup) + sizeof(IndexTupleData));
  571. rdatum = (((char *) rtup) + sizeof(IndexTupleData));
  572. newdatum = (char *) (*fmgr_faddr(&rtstate->unionFn)) (ldatum, rdatum);
  573. rttighten(r, stk->rts_parent, newdatum,
  574.    (IndexTupleSize(rtup) - sizeof(IndexTupleData)), rtstate);
  575. pfree(newdatum);
  576. }
  577. }
  578. static void
  579. rtnewroot(Relation r, IndexTuple lt, IndexTuple rt)
  580. {
  581. Buffer b;
  582. Page p;
  583. b = ReadBuffer(r, P_ROOT);
  584. RTInitBuffer(b, 0);
  585. p = BufferGetPage(b);
  586. PageAddItem(p, (Item) lt, IndexTupleSize(lt),
  587. FirstOffsetNumber, LP_USED);
  588. PageAddItem(p, (Item) rt, IndexTupleSize(rt),
  589. OffsetNumberNext(FirstOffsetNumber), LP_USED);
  590. WriteBuffer(b);
  591. }
  592. static void
  593. picksplit(Relation r,
  594.   Page page,
  595.   SPLITVEC *v,
  596.   IndexTuple itup,
  597.   RTSTATE *rtstate)
  598. {
  599. OffsetNumber maxoff;
  600. OffsetNumber i,
  601. j;
  602. IndexTuple item_1,
  603. item_2;
  604. char    *datum_alpha,
  605.    *datum_beta;
  606. char    *datum_l,
  607.    *datum_r;
  608. char    *union_d,
  609.    *union_dl,
  610.    *union_dr;
  611. char    *inter_d;
  612. bool firsttime;
  613. float size_alpha,
  614. size_beta,
  615. size_union,
  616. size_inter;
  617. float size_waste,
  618. waste;
  619. float size_l,
  620. size_r;
  621. int nbytes;
  622. OffsetNumber seed_1 = 0,
  623. seed_2 = 0;
  624. OffsetNumber *left,
  625.    *right;
  626. maxoff = PageGetMaxOffsetNumber(page);
  627. nbytes = (maxoff + 2) * sizeof(OffsetNumber);
  628. v->spl_left = (OffsetNumber *) palloc(nbytes);
  629. v->spl_right = (OffsetNumber *) palloc(nbytes);
  630. firsttime = true;
  631. waste = 0.0;
  632. for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
  633. {
  634. item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
  635. datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
  636. for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
  637. {
  638. item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, j));
  639. datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
  640. /* compute the wasted space by unioning these guys */
  641. union_d = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_alpha, datum_beta);
  642. (*fmgr_faddr(&rtstate->sizeFn)) (union_d, &size_union);
  643. inter_d = (char *) (*fmgr_faddr(&rtstate->interFn)) (datum_alpha, datum_beta);
  644. (*fmgr_faddr(&rtstate->sizeFn)) (inter_d, &size_inter);
  645. size_waste = size_union - size_inter;
  646. pfree(union_d);
  647. if (inter_d != (char *) NULL)
  648. pfree(inter_d);
  649. /*
  650.  * are these a more promising split that what we've already
  651.  * seen?
  652.  */
  653. if (size_waste > waste || firsttime)
  654. {
  655. waste = size_waste;
  656. seed_1 = i;
  657. seed_2 = j;
  658. firsttime = false;
  659. }
  660. }
  661. }
  662. left = v->spl_left;
  663. v->spl_nleft = 0;
  664. right = v->spl_right;
  665. v->spl_nright = 0;
  666. item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_1));
  667. datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
  668. datum_l = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_alpha, datum_alpha);
  669. (*fmgr_faddr(&rtstate->sizeFn)) (datum_l, &size_l);
  670. item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_2));
  671. datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
  672. datum_r = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_beta, datum_beta);
  673. (*fmgr_faddr(&rtstate->sizeFn)) (datum_r, &size_r);
  674. /*
  675.  * Now split up the regions between the two seeds. An important
  676.  * property of this split algorithm is that the split vector v has the
  677.  * indices of items to be split in order in its left and right
  678.  * vectors.  We exploit this property by doing a merge in the code
  679.  * that actually splits the page.
  680.  *
  681.  * For efficiency, we also place the new index tuple in this loop. This
  682.  * is handled at the very end, when we have placed all the existing
  683.  * tuples and i == maxoff + 1.
  684.  */
  685. maxoff = OffsetNumberNext(maxoff);
  686. for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
  687. {
  688. /*
  689.  * If we've already decided where to place this item, just put it
  690.  * on the right list.  Otherwise, we need to figure out which page
  691.  * needs the least enlargement in order to store the item.
  692.  */
  693. if (i == seed_1)
  694. {
  695. *left++ = i;
  696. v->spl_nleft++;
  697. continue;
  698. }
  699. else if (i == seed_2)
  700. {
  701. *right++ = i;
  702. v->spl_nright++;
  703. continue;
  704. }
  705. /* okay, which page needs least enlargement? */
  706. if (i == maxoff)
  707. item_1 = itup;
  708. else
  709. item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
  710. datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
  711. union_dl = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_l, datum_alpha);
  712. union_dr = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum_r, datum_alpha);
  713. (*fmgr_faddr(&rtstate->sizeFn)) (union_dl, &size_alpha);
  714. (*fmgr_faddr(&rtstate->sizeFn)) (union_dr, &size_beta);
  715. /* pick which page to add it to */
  716. if (size_alpha - size_l < size_beta - size_r)
  717. {
  718. pfree(datum_l);
  719. pfree(union_dr);
  720. datum_l = union_dl;
  721. size_l = size_alpha;
  722. *left++ = i;
  723. v->spl_nleft++;
  724. }
  725. else
  726. {
  727. pfree(datum_r);
  728. pfree(union_dl);
  729. datum_r = union_dr;
  730. size_r = size_alpha;
  731. *right++ = i;
  732. v->spl_nright++;
  733. }
  734. }
  735. *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
  736. v->spl_ldatum = datum_l;
  737. v->spl_rdatum = datum_r;
  738. }
  739. static void
  740. RTInitBuffer(Buffer b, uint32 f)
  741. {
  742. RTreePageOpaque opaque;
  743. Page page;
  744. Size pageSize;
  745. pageSize = BufferGetPageSize(b);
  746. page = BufferGetPage(b);
  747. MemSet(page, 0, (int) pageSize);
  748. PageInit(page, pageSize, sizeof(RTreePageOpaqueData));
  749. opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
  750. opaque->flags = f;
  751. }
  752. static OffsetNumber
  753. choose(Relation r, Page p, IndexTuple it, RTSTATE *rtstate)
  754. {
  755. OffsetNumber maxoff;
  756. OffsetNumber i;
  757. char    *ud,
  758.    *id;
  759. char    *datum;
  760. float usize,
  761. dsize;
  762. OffsetNumber which;
  763. float which_grow;
  764. id = ((char *) it) + sizeof(IndexTupleData);
  765. maxoff = PageGetMaxOffsetNumber(p);
  766. which_grow = -1.0;
  767. which = -1;
  768. for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
  769. {
  770. datum = (char *) PageGetItem(p, PageGetItemId(p, i));
  771. datum += sizeof(IndexTupleData);
  772. (*fmgr_faddr(&rtstate->sizeFn)) (datum, &dsize);
  773. ud = (char *) (*fmgr_faddr(&rtstate->unionFn)) (datum, id);
  774. (*fmgr_faddr(&rtstate->sizeFn)) (ud, &usize);
  775. pfree(ud);
  776. if (which_grow < 0 || usize - dsize < which_grow)
  777. {
  778. which = i;
  779. which_grow = usize - dsize;
  780. if (which_grow == 0)
  781. break;
  782. }
  783. }
  784. return which;
  785. }
  786. static int
  787. nospace(Page p, IndexTuple it)
  788. {
  789. return PageGetFreeSpace(p) < IndexTupleSize(it);
  790. }
  791. void
  792. freestack(RTSTACK *s)
  793. {
  794. RTSTACK    *p;
  795. while (s != (RTSTACK *) NULL)
  796. {
  797. p = s->rts_parent;
  798. pfree(s);
  799. s = p;
  800. }
  801. }
  802. char *
  803. rtdelete(Relation r, ItemPointer tid)
  804. {
  805. BlockNumber blkno;
  806. OffsetNumber offnum;
  807. Buffer buf;
  808. Page page;
  809. /*
  810.  * Notes in ExecUtils:ExecOpenIndices() Also note that only vacuum
  811.  * deletes index tuples now...
  812.  *
  813.  * RelationSetLockForWrite(r);
  814.  */
  815. blkno = ItemPointerGetBlockNumber(tid);
  816. offnum = ItemPointerGetOffsetNumber(tid);
  817. /* adjust any scans that will be affected by this deletion */
  818. rtadjscans(r, RTOP_DEL, blkno, offnum);
  819. /* delete the index tuple */
  820. buf = ReadBuffer(r, blkno);
  821. page = BufferGetPage(buf);
  822. PageIndexTupleDelete(page, offnum);
  823. WriteBuffer(buf);
  824. return (char *) NULL;
  825. }
  826. static void
  827. initRtstate(RTSTATE *rtstate, Relation index)
  828. {
  829. RegProcedure union_proc,
  830. size_proc,
  831. inter_proc;
  832. union_proc = index_getprocid(index, 1, RT_UNION_PROC);
  833. size_proc = index_getprocid(index, 1, RT_SIZE_PROC);
  834. inter_proc = index_getprocid(index, 1, RT_INTER_PROC);
  835. fmgr_info(union_proc, &rtstate->unionFn);
  836. fmgr_info(size_proc, &rtstate->sizeFn);
  837. fmgr_info(inter_proc, &rtstate->interFn);
  838. return;
  839. }
  840. #ifdef RTDEBUG
  841. void
  842. _rtdump(Relation r)
  843. {
  844. Buffer buf;
  845. Page page;
  846. OffsetNumber offnum,
  847. maxoff;
  848. BlockNumber blkno;
  849. BlockNumber nblocks;
  850. RTreePageOpaque po;
  851. IndexTuple itup;
  852. BlockNumber itblkno;
  853. OffsetNumber itoffno;
  854. char    *datum;
  855. char    *itkey;
  856. nblocks = RelationGetNumberOfBlocks(r);
  857. for (blkno = 0; blkno < nblocks; blkno++)
  858. {
  859. buf = ReadBuffer(r, blkno);
  860. page = BufferGetPage(buf);
  861. po = (RTreePageOpaque) PageGetSpecialPointer(page);
  862. maxoff = PageGetMaxOffsetNumber(page);
  863. printf("Page %d maxoff %d <%s>n", blkno, maxoff,
  864.    (po->flags & F_LEAF ? "LEAF" : "INTERNAL"));
  865. if (PageIsEmpty(page))
  866. {
  867. ReleaseBuffer(buf);
  868. continue;
  869. }
  870. for (offnum = FirstOffsetNumber;
  871.  offnum <= maxoff;
  872.  offnum = OffsetNumberNext(offnum))
  873. {
  874. itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
  875. itblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
  876. itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid));
  877. datum = ((char *) itup);
  878. datum += sizeof(IndexTupleData);
  879. itkey = (char *) box_out((BOX *) datum);
  880. printf("t[%d] size %d heap <%d,%d> key:%sn",
  881.    offnum, IndexTupleSize(itup), itblkno, itoffno, itkey);
  882. pfree(itkey);
  883. }
  884. ReleaseBuffer(buf);
  885. }
  886. }
  887. #endif  /* defined RTDEBUG */