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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  * btsort.c
  3.  *
  4.  * Copyright (c) 1994, Regents of the University of California
  5.  *
  6.  *
  7.  * IDENTIFICATION
  8.  *   $Id: nbtsort.c,v 1.40.2.1 1999/08/02 05:24:41 scrappy Exp $
  9.  *
  10.  * NOTES
  11.  *
  12.  * what we do is:
  13.  * - generate a set of initial one-block runs, distributed round-robin
  14.  *  between the output tapes.
  15.  * - for each pass,
  16.  *  - swap input and output tape sets, rewinding both and truncating
  17.  *    the output tapes.
  18.  *  - merge the current run in each input tape to the current output
  19.  *    tape.
  20.  *    - when each input run has been exhausted, switch to another output
  21.  *  tape and start processing another run.
  22.  * - when we have fewer runs than tapes, we know we are ready to start
  23.  *  merging into the btree leaf pages.  (i.e., we do not have to wait
  24.  *  until we have exactly one tape.)
  25.  * - as we extract tuples from the final runs, we build the pages for
  26.  *  each level.  when we have only one page on a level, it must be the
  27.  *  root -- it can be attached to the btree metapage and we are done.
  28.  *
  29.  * conventions:
  30.  * - external interface routines take in and return "void *" for their
  31.  *  opaque handles.  this is for modularity reasons.
  32.  *
  33.  * this code is moderately slow (~10% slower) compared to the regular
  34.  * btree (insertion) build code on sorted or well-clustered data.  on
  35.  * random data, however, the insertion build code is unusable -- the
  36.  * difference on a 60MB heap is a factor of 15 because the random
  37.  * probes into the btree thrash the buffer pool.
  38.  *
  39.  * this code currently packs the pages to 100% of capacity.  this is
  40.  * not wise, since *any* insertion will cause splitting.  filling to
  41.  * something like the standard 70% steady-state load factor for btrees
  42.  * would probably be better.
  43.  *
  44.  * somebody desperately needs to figure out how to do a better job of
  45.  * balancing the merge passes -- the fan-in on the final merges can be
  46.  * pretty poor, which is bad for performance.
  47.  *-------------------------------------------------------------------------
  48.  */
  49. #include <fcntl.h>
  50. #include "postgres.h"
  51. #include "access/nbtree.h"
  52. #ifdef BTREE_BUILD_STATS
  53. #define ShowExecutorStats pg_options[TRACE_EXECUTORSTATS]
  54. #endif
  55. static BTItem _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags);
  56. static BTItem _bt_minitem(Page opage, BlockNumber oblkno, int atend);
  57. static void *_bt_pagestate(Relation index, int flags, int level, bool doupper);
  58. static void _bt_uppershutdown(Relation index, BTPageState *state);
  59. /*
  60.  * turn on debugging output.
  61.  *
  62.  * XXX this code just does a numeric printf of the index key, so it's
  63.  * only really useful for integer keys.
  64.  */
  65. /*#define FASTBUILD_DEBUG*/
  66. #define FASTBUILD_SPOOL
  67. #define FASTBUILD_MERGE
  68. #define MAXTAPES (7)
  69. #define TAPEBLCKSZ (BLCKSZ << 2)
  70. extern int NDirectFileRead;
  71. extern int NDirectFileWrite;
  72. /*
  73.  * this is what we use to shovel BTItems in and out of memory. it's
  74.  * bigger than a standard block because we are doing a lot of strictly
  75.  * sequential i/o. this is obviously something of a tradeoff since we
  76.  * are potentially reading a bunch of zeroes off of disk in many
  77.  * cases.
  78.  *
  79.  * BTItems are packed in and MAXALIGN'd.
  80.  *
  81.  * the fd should not be going out to disk, strictly speaking, but it's
  82.  * the only thing like that so i'm not going to worry about wasting a
  83.  * few bytes.
  84.  */
  85. typedef struct
  86. {
  87. int bttb_magic; /* magic number */
  88. File bttb_fd; /* file descriptor */
  89. int bttb_top; /* top of free space within bttb_data */
  90. short bttb_ntup; /* number of tuples in this block */
  91. short bttb_eor; /* End-Of-Run marker */
  92. char bttb_data[TAPEBLCKSZ - 2 * sizeof(double)];
  93. } BTTapeBlock;
  94. /*
  95.  * this structure holds the bookkeeping for a simple balanced multiway
  96.  * merge.  (polyphase merging is hairier than i want to get into right
  97.  * now, and i don't see why i have to care how many "tapes" i use
  98.  * right now.  though if psort was in a condition that i could hack it
  99.  * to do this, you bet i would.)
  100.  */
  101. typedef struct
  102. {
  103. int bts_ntapes;
  104. int bts_tape;
  105. BTTapeBlock **bts_itape; /* input tape blocks */
  106. BTTapeBlock **bts_otape; /* output tape blocks */
  107. bool isunique;
  108. } BTSpool;
  109. /*-------------------------------------------------------------------------
  110.  * sorting comparison routine - returns {-1,0,1} depending on whether
  111.  * the key in the left BTItem is {<,=,>} the key in the right BTItem.
  112.  *
  113.  * we want to use _bt_isortcmp as a comparison function for qsort(3),
  114.  * but it needs extra arguments, so we "pass them in" as global
  115.  * variables.  ick.  fortunately, they are the same throughout the
  116.  * build, so we need do this only once.  this is why you must call
  117.  * _bt_isortcmpinit before the call to qsort(3).
  118.  *
  119.  * a NULL BTItem is always assumed to be greater than any actual
  120.  * value; our heap routines (see below) assume that the smallest
  121.  * element in the heap is returned.  that way, NULL values from the
  122.  * exhausted tapes can sift down to the bottom of the heap.  in point
  123.  * of fact we just don't replace the elements of exhausted tapes, but
  124.  * what the heck.
  125.  * *-------------------------------------------------------------------------
  126.  */
  127. typedef struct
  128. {
  129. Datum    *btsk_datum;
  130. char    *btsk_nulls;
  131. BTItem btsk_item;
  132. } BTSortKey;
  133. static Relation _bt_sortrel;
  134. static int _bt_nattr;
  135. static BTSpool *_bt_inspool;
  136. static void
  137. _bt_isortcmpinit(Relation index, BTSpool *spool)
  138. {
  139. _bt_sortrel = index;
  140. _bt_inspool = spool;
  141. _bt_nattr = index->rd_att->natts;
  142. }
  143. static int
  144. _bt_isortcmp(BTSortKey *k1, BTSortKey *k2)
  145. {
  146. Datum    *k1_datum = k1->btsk_datum;
  147. Datum    *k2_datum = k2->btsk_datum;
  148. char    *k1_nulls = k1->btsk_nulls;
  149. char    *k2_nulls = k2->btsk_nulls;
  150. bool equal_isnull = false;
  151. int i;
  152. if (k1->btsk_item == (BTItem) NULL)
  153. {
  154. if (k2->btsk_item == (BTItem) NULL)
  155. return 0; /* 1 = 2 */
  156. return 1; /* 1 > 2 */
  157. }
  158. else if (k2->btsk_item == (BTItem) NULL)
  159. return -1; /* 1 < 2 */
  160. for (i = 0; i < _bt_nattr; i++)
  161. {
  162. if (k1_nulls[i] != ' ') /* k1 attr is NULL */
  163. {
  164. if (k2_nulls[i] != ' ') /* the same for k2 */
  165. {
  166. equal_isnull = true;
  167. continue;
  168. }
  169. return 1; /* NULL ">" NOT_NULL */
  170. }
  171. else if (k2_nulls[i] != ' ') /* k2 attr is NULL */
  172. return -1; /* NOT_NULL "<" NULL */
  173. if (_bt_invokestrat(_bt_sortrel, i + 1, BTGreaterStrategyNumber,
  174. k1_datum[i], k2_datum[i]))
  175. return 1; /* 1 > 2 */
  176. else if (_bt_invokestrat(_bt_sortrel, i + 1, BTGreaterStrategyNumber,
  177.  k2_datum[i], k1_datum[i]))
  178. return -1; /* 1 < 2 */
  179. }
  180. if (_bt_inspool->isunique && !equal_isnull)
  181. {
  182. _bt_spooldestroy((void *) _bt_inspool);
  183. elog(ERROR, "Cannot create unique index. Table contains non-unique values");
  184. }
  185. return 0; /* 1 = 2 */
  186. }
  187. static void
  188. _bt_setsortkey(Relation index, BTItem bti, BTSortKey *sk)
  189. {
  190. sk->btsk_item = (BTItem) NULL;
  191. sk->btsk_datum = (Datum *) NULL;
  192. sk->btsk_nulls = (char *) NULL;
  193. if (bti != (BTItem) NULL)
  194. {
  195. IndexTuple it = &(bti->bti_itup);
  196. TupleDesc itdesc = index->rd_att;
  197. Datum    *dp = (Datum *) palloc(_bt_nattr * sizeof(Datum));
  198. char    *np = (char *) palloc(_bt_nattr * sizeof(char));
  199. bool isnull;
  200. int i;
  201. for (i = 0; i < _bt_nattr; i++)
  202. {
  203. dp[i] = index_getattr(it, i + 1, itdesc, &isnull);
  204. if (isnull)
  205. np[i] = 'n';
  206. else
  207. np[i] = ' ';
  208. }
  209. sk->btsk_item = bti;
  210. sk->btsk_datum = dp;
  211. sk->btsk_nulls = np;
  212. }
  213. }
  214. /*-------------------------------------------------------------------------
  215.  * priority queue methods
  216.  *
  217.  * these were more-or-less lifted from the heap section of the 1984
  218.  * edition of gonnet's book on algorithms and data structures.  they
  219.  * are coded so that the smallest element in the heap is returned (we
  220.  * use them for merging sorted runs).
  221.  *
  222.  * XXX these probably ought to be generic library functions.
  223.  *-------------------------------------------------------------------------
  224.  */
  225. typedef struct
  226. {
  227. int btpqe_tape; /* tape identifier */
  228. BTSortKey btpqe_item; /* pointer to BTItem in tape buffer */
  229. } BTPriQueueElem;
  230. #define MAXELEM MAXTAPES
  231. typedef struct
  232. {
  233. int btpq_nelem;
  234. BTPriQueueElem btpq_queue[MAXELEM];
  235. Relation btpq_rel;
  236. } BTPriQueue;
  237. /* be sure to call _bt_isortcmpinit first */
  238. #define GREATER(a, b) 
  239. (_bt_isortcmp(&((a)->btpqe_item), &((b)->btpqe_item)) > 0)
  240. static void
  241. _bt_pqsift(BTPriQueue *q, int parent)
  242. {
  243. int child;
  244. BTPriQueueElem e;
  245. for (child = parent * 2 + 1;
  246.  child < q->btpq_nelem;
  247.  child = parent * 2 + 1)
  248. {
  249. if (child < q->btpq_nelem - 1)
  250. {
  251. if (GREATER(&(q->btpq_queue[child]), &(q->btpq_queue[child + 1])))
  252. ++child;
  253. }
  254. if (GREATER(&(q->btpq_queue[parent]), &(q->btpq_queue[child])))
  255. {
  256. e = q->btpq_queue[child]; /* struct = */
  257. q->btpq_queue[child] = q->btpq_queue[parent]; /* struct = */
  258. q->btpq_queue[parent] = e; /* struct = */
  259. parent = child;
  260. }
  261. else
  262. parent = child + 1;
  263. }
  264. }
  265. static int
  266. _bt_pqnext(BTPriQueue *q, BTPriQueueElem *e)
  267. {
  268. if (q->btpq_nelem < 1)
  269. { /* already empty */
  270. return -1;
  271. }
  272. *e = q->btpq_queue[0]; /* struct = */
  273. if (--q->btpq_nelem < 1)
  274. { /* now empty, don't sift */
  275. return 0;
  276. }
  277. q->btpq_queue[0] = q->btpq_queue[q->btpq_nelem]; /* struct = */
  278. _bt_pqsift(q, 0);
  279. return 0;
  280. }
  281. static void
  282. _bt_pqadd(BTPriQueue *q, BTPriQueueElem *e)
  283. {
  284. int child,
  285. parent;
  286. if (q->btpq_nelem >= MAXELEM)
  287. elog(ERROR, "_bt_pqadd: queue overflow");
  288. child = q->btpq_nelem++;
  289. while (child > 0)
  290. {
  291. parent = child / 2;
  292. if (GREATER(e, &(q->btpq_queue[parent])))
  293. break;
  294. else
  295. {
  296. q->btpq_queue[child] = q->btpq_queue[parent]; /* struct = */
  297. child = parent;
  298. }
  299. }
  300. q->btpq_queue[child] = *e; /* struct = */
  301. }
  302. /*-------------------------------------------------------------------------
  303.  * tape methods
  304.  *-------------------------------------------------------------------------
  305.  */
  306. #define BTITEMSZ(btitem) 
  307. ((btitem) ? 
  308.  (IndexTupleDSize((btitem)->bti_itup) + 
  309.   (sizeof(BTItemData) - sizeof(IndexTupleData))) : 
  310.  0)
  311. #define SPCLEFT(tape) 
  312. (sizeof((tape)->bttb_data) - (tape)->bttb_top)
  313. #define EMPTYTAPE(tape) 
  314. ((tape)->bttb_ntup <= 0)
  315. #define BTTAPEMAGIC 0x19660226
  316. /*
  317.  * reset the tape header for its next use without doing anything to
  318.  * the physical tape file. (setting bttb_top to 0 makes the block
  319.  * empty.)
  320.  */
  321. static void
  322. _bt_tapereset(BTTapeBlock *tape)
  323. {
  324. tape->bttb_eor = 0;
  325. tape->bttb_top = 0;
  326. tape->bttb_ntup = 0;
  327. }
  328. /*
  329.  * rewind the physical tape file.
  330.  */
  331. static void
  332. _bt_taperewind(BTTapeBlock *tape)
  333. {
  334. FileSeek(tape->bttb_fd, 0L, SEEK_SET);
  335. }
  336. /*
  337.  * destroy the contents of the physical tape file without destroying
  338.  * the tape data structure or removing the physical tape file.
  339.  *
  340.  * we use the VFD version of ftruncate(2) to do this rather than
  341.  * unlinking and recreating the file.  you still have to wait while
  342.  * the OS frees up all of the file system blocks and stuff, but at
  343.  * least you don't have to delete and reinsert the directory entries.
  344.  */
  345. static void
  346. _bt_tapeclear(BTTapeBlock *tape)
  347. {
  348. /* blow away the contents of the old file */
  349. _bt_taperewind(tape);
  350. #ifdef NOT_USED
  351. FileSync(tape->bttb_fd);
  352. #endif
  353. FileTruncate(tape->bttb_fd, 0);
  354. /* reset the buffer */
  355. _bt_tapereset(tape);
  356. }
  357. /*
  358.  * create a new BTTapeBlock, allocating memory for the data structure
  359.  * as well as opening a physical tape file.
  360.  */
  361. static BTTapeBlock *
  362. _bt_tapecreate(void)
  363. {
  364. BTTapeBlock *tape = (BTTapeBlock *) palloc(sizeof(BTTapeBlock));
  365. if (tape == (BTTapeBlock *) NULL)
  366. elog(ERROR, "_bt_tapecreate: out of memory");
  367. tape->bttb_magic = BTTAPEMAGIC;
  368. tape->bttb_fd = OpenTemporaryFile();
  369. Assert(tape->bttb_fd >= 0);
  370. /* initialize the buffer */
  371. _bt_tapereset(tape);
  372. return tape;
  373. }
  374. /*
  375.  * destroy the BTTapeBlock structure and its physical tape file.
  376.  */
  377. static void
  378. _bt_tapedestroy(BTTapeBlock *tape)
  379. {
  380. FileUnlink(tape->bttb_fd);
  381. pfree((void *) tape);
  382. }
  383. /*
  384.  * flush the tape block to the file, marking End-Of-Run if requested.
  385.  */
  386. static void
  387. _bt_tapewrite(BTTapeBlock *tape, int eor)
  388. {
  389. tape->bttb_eor = eor;
  390. FileWrite(tape->bttb_fd, (char *) tape, TAPEBLCKSZ);
  391. NDirectFileWrite += TAPEBLCKSZ / BLCKSZ;
  392. _bt_tapereset(tape);
  393. }
  394. /*
  395.  * read a tape block from the file, overwriting the current contents
  396.  * of the buffer.
  397.  *
  398.  * returns:
  399.  * - 0 if there are no more blocks in the tape or in this run (call
  400.  *  _bt_tapereset to clear the End-Of-Run marker)
  401.  * - 1 if a valid block was read
  402.  */
  403. static int
  404. _bt_taperead(BTTapeBlock *tape)
  405. {
  406. File fd;
  407. int nread;
  408. if (tape->bttb_eor)
  409. {
  410. return 0; /* we are already at End-Of-Run */
  411. }
  412. /*
  413.  * we're clobbering the old tape block, but we do need to save the VFD
  414.  * (the one in the block we're reading is bogus).
  415.  */
  416. fd = tape->bttb_fd;
  417. nread = FileRead(fd, (char *) tape, TAPEBLCKSZ);
  418. tape->bttb_fd = fd;
  419. if (nread != TAPEBLCKSZ)
  420. {
  421. Assert(nread == 0); /* we are at EOF */
  422. return 0;
  423. }
  424. Assert(tape->bttb_magic == BTTAPEMAGIC);
  425. NDirectFileRead += TAPEBLCKSZ / BLCKSZ;
  426. return 1;
  427. }
  428. /*
  429.  * get the next BTItem from a tape block.
  430.  *
  431.  * returns:
  432.  * - NULL if we have run out of BTItems
  433.  * - a pointer to the BTItemData in the block otherwise
  434.  *
  435.  * side effects:
  436.  * - sets 'pos' to the current position within the block.
  437.  */
  438. static BTItem
  439. _bt_tapenext(BTTapeBlock *tape, char **pos)
  440. {
  441. Size itemsz;
  442. BTItem bti;
  443. if (*pos >= tape->bttb_data + tape->bttb_top)
  444. return (BTItem) NULL;
  445. bti = (BTItem) *pos;
  446. itemsz = BTITEMSZ(bti);
  447. *pos += MAXALIGN(itemsz);
  448. return bti;
  449. }
  450. /*
  451.  * copy a BTItem into a tape block.
  452.  *
  453.  * assumes that we have already checked to see if the block has enough
  454.  * space for the item.
  455.  *
  456.  * side effects:
  457.  *
  458.  * - advances the 'top' pointer in the tape block header to point to
  459.  * the beginning of free space.
  460.  */
  461. static void
  462. _bt_tapeadd(BTTapeBlock *tape, BTItem item, int itemsz)
  463. {
  464. memcpy(tape->bttb_data + tape->bttb_top, item, itemsz);
  465. ++tape->bttb_ntup;
  466. tape->bttb_top += MAXALIGN(itemsz);
  467. }
  468. /*-------------------------------------------------------------------------
  469.  * spool methods
  470.  *-------------------------------------------------------------------------
  471.  */
  472. /*
  473.  * create and initialize a spool structure, including the underlying
  474.  * files.
  475.  */
  476. void *
  477. _bt_spoolinit(Relation index, int ntapes, bool isunique)
  478. {
  479. BTSpool    *btspool = (BTSpool *) palloc(sizeof(BTSpool));
  480. int i;
  481. if (btspool == (BTSpool *) NULL)
  482. elog(ERROR, "_bt_spoolinit: out of memory");
  483. MemSet((char *) btspool, 0, sizeof(BTSpool));
  484. btspool->bts_ntapes = ntapes;
  485. btspool->bts_tape = 0;
  486. btspool->isunique = isunique;
  487. btspool->bts_itape = (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
  488. btspool->bts_otape = (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
  489. if (btspool->bts_itape == (BTTapeBlock **) NULL ||
  490. btspool->bts_otape == (BTTapeBlock **) NULL)
  491. elog(ERROR, "_bt_spoolinit: out of memory");
  492. for (i = 0; i < ntapes; ++i)
  493. {
  494. btspool->bts_itape[i] = _bt_tapecreate();
  495. btspool->bts_otape[i] = _bt_tapecreate();
  496. }
  497. _bt_isortcmpinit(index, btspool);
  498. return (void *) btspool;
  499. }
  500. /*
  501.  * clean up a spool structure and its substructures.
  502.  */
  503. void
  504. _bt_spooldestroy(void *spool)
  505. {
  506. BTSpool    *btspool = (BTSpool *) spool;
  507. int i;
  508. for (i = 0; i < btspool->bts_ntapes; ++i)
  509. {
  510. _bt_tapedestroy(btspool->bts_otape[i]);
  511. _bt_tapedestroy(btspool->bts_itape[i]);
  512. }
  513. pfree((void *) btspool);
  514. }
  515. /*
  516.  * flush out any dirty output tape blocks
  517.  */
  518. static void
  519. _bt_spoolflush(BTSpool *btspool)
  520. {
  521. int i;
  522. for (i = 0; i < btspool->bts_ntapes; ++i)
  523. {
  524. if (!EMPTYTAPE(btspool->bts_otape[i]))
  525. _bt_tapewrite(btspool->bts_otape[i], 1);
  526. }
  527. }
  528. /*
  529.  * swap input tapes and output tapes by swapping their file
  530.  * descriptors.  additional preparation for the next merge pass
  531.  * includes rewinding the new input tapes and clearing out the new
  532.  * output tapes.
  533.  */
  534. static void
  535. _bt_spoolswap(BTSpool *btspool)
  536. {
  537. File tmpfd;
  538. BTTapeBlock *itape;
  539. BTTapeBlock *otape;
  540. int i;
  541. for (i = 0; i < btspool->bts_ntapes; ++i)
  542. {
  543. itape = btspool->bts_itape[i];
  544. otape = btspool->bts_otape[i];
  545. /*
  546.  * swap the input and output VFDs.
  547.  */
  548. tmpfd = itape->bttb_fd;
  549. itape->bttb_fd = otape->bttb_fd;
  550. otape->bttb_fd = tmpfd;
  551. /*
  552.  * rewind the new input tape.
  553.  */
  554. _bt_taperewind(itape);
  555. _bt_tapereset(itape);
  556. /*
  557.  * clear the new output tape -- it's ok to throw away the old
  558.  * inputs.
  559.  */
  560. _bt_tapeclear(otape);
  561. }
  562. }
  563. /*-------------------------------------------------------------------------
  564.  * sorting routines
  565.  *-------------------------------------------------------------------------
  566.  */
  567. /*
  568.  * spool 'btitem' into an initial run. as tape blocks are filled, the
  569.  * block BTItems are qsorted and written into some output tape (it
  570.  * doesn't matter which; we go round-robin for simplicity).  the
  571.  * initial runs are therefore always just one block.
  572.  */
  573. void
  574. _bt_spool(Relation index, BTItem btitem, void *spool)
  575. {
  576. BTSpool    *btspool = (BTSpool *) spool;
  577. BTTapeBlock *itape;
  578. Size itemsz;
  579. _bt_isortcmpinit(index, btspool);
  580. itape = btspool->bts_itape[btspool->bts_tape];
  581. itemsz = BTITEMSZ(btitem);
  582. itemsz = MAXALIGN(itemsz);
  583. /*
  584.  * if this buffer is too full for this BTItemData, or if we have run
  585.  * out of BTItems, we need to sort the buffer and write it out.  in
  586.  * this case, the BTItemData will go into the next tape's buffer.
  587.  */
  588. if (btitem == (BTItem) NULL || SPCLEFT(itape) < itemsz)
  589. {
  590. BTSortKey  *parray = (BTSortKey *) NULL;
  591. BTTapeBlock *otape;
  592. BTItem bti;
  593. char    *pos;
  594. int btisz;
  595. int it_ntup = itape->bttb_ntup;
  596. int i;
  597. /*
  598.  * build an array of pointers to the BTItemDatas on the input
  599.  * block.
  600.  */
  601. if (it_ntup > 0)
  602. {
  603. parray = (BTSortKey *) palloc(it_ntup * sizeof(BTSortKey));
  604. pos = itape->bttb_data;
  605. for (i = 0; i < it_ntup; ++i)
  606. _bt_setsortkey(index, _bt_tapenext(itape, &pos), &(parray[i]));
  607. /*
  608.  * qsort the pointer array.
  609.  */
  610. qsort((void *) parray, it_ntup, sizeof(BTSortKey),
  611.   (int (*) (const void *, const void *)) _bt_isortcmp);
  612. }
  613. /*
  614.  * write the spooled run into the output tape. we copy the
  615.  * BTItemDatas in the order dictated by the sorted array of
  616.  * BTItems, not the original order.
  617.  *
  618.  * (since everything was MAXALIGN'd and is all on a single tape
  619.  * block, everything had *better* still fit on one tape block..)
  620.  */
  621. otape = btspool->bts_otape[btspool->bts_tape];
  622. for (i = 0; i < it_ntup; ++i)
  623. {
  624. bti = parray[i].btsk_item;
  625. btisz = BTITEMSZ(bti);
  626. btisz = MAXALIGN(btisz);
  627. _bt_tapeadd(otape, bti, btisz);
  628. #if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_SPOOL)
  629. {
  630. bool isnull;
  631. Datum d = index_getattr(&(bti->bti_itup), 1, index->rd_att,
  632.   &isnull);
  633. printf("_bt_spool: inserted <%x> into output tape %dn",
  634.    d, btspool->bts_tape);
  635. }
  636. #endif  /* FASTBUILD_DEBUG && FASTBUILD_SPOOL */
  637. }
  638. /*
  639.  * the initial runs are always single tape blocks. flush the
  640.  * output block, marking End-Of-Run.
  641.  */
  642. _bt_tapewrite(otape, 1);
  643. /*
  644.  * reset the input buffer for the next run.  we don't have to
  645.  * write it out or anything -- we only use it to hold the unsorted
  646.  * BTItemDatas, the output tape contains all the sorted stuff.
  647.  *
  648.  * changing bts_tape changes the output tape and input tape; we
  649.  * change itape for the code below.
  650.  */
  651. _bt_tapereset(itape);
  652. btspool->bts_tape = (btspool->bts_tape + 1) % btspool->bts_ntapes;
  653. itape = btspool->bts_itape[btspool->bts_tape];
  654. /*
  655.  * destroy the pointer array.
  656.  */
  657. if (parray != (BTSortKey *) NULL)
  658. {
  659. for (i = 0; i < it_ntup; i++)
  660. {
  661. if (parray[i].btsk_datum != (Datum *) NULL)
  662. pfree((void *) (parray[i].btsk_datum));
  663. if (parray[i].btsk_nulls != (char *) NULL)
  664. pfree((void *) (parray[i].btsk_nulls));
  665. }
  666. pfree((void *) parray);
  667. }
  668. }
  669. /* insert this item into the current buffer */
  670. if (btitem != (BTItem) NULL)
  671. _bt_tapeadd(itape, btitem, itemsz);
  672. }
  673. /*
  674.  * allocate a new, clean btree page, not linked to any siblings.
  675.  */
  676. static void
  677. _bt_blnewpage(Relation index, Buffer *buf, Page *page, int flags)
  678. {
  679. BTPageOpaque opaque;
  680. *buf = _bt_getbuf(index, P_NEW, BT_WRITE);
  681. #ifdef NOT_USED
  682. printf("tblk=%dn", BufferGetBlockNumber(*buf));
  683. #endif
  684. *page = BufferGetPage(*buf);
  685. _bt_pageinit(*page, BufferGetPageSize(*buf));
  686. opaque = (BTPageOpaque) PageGetSpecialPointer(*page);
  687. opaque->btpo_prev = opaque->btpo_next = P_NONE;
  688. opaque->btpo_flags = flags;
  689. }
  690. /*
  691.  * slide an array of ItemIds back one slot (from P_FIRSTKEY to
  692.  * P_HIKEY, overwriting P_HIKEY).  we need to do this when we discover
  693.  * that we have built an ItemId array in what has turned out to be a
  694.  * P_RIGHTMOST page.
  695.  */
  696. static void
  697. _bt_slideleft(Relation index, Buffer buf, Page page)
  698. {
  699. OffsetNumber off;
  700. OffsetNumber maxoff;
  701. ItemId previi;
  702. ItemId thisii;
  703. if (!PageIsEmpty(page))
  704. {
  705. maxoff = PageGetMaxOffsetNumber(page);
  706. previi = PageGetItemId(page, P_HIKEY);
  707. for (off = P_FIRSTKEY; off <= maxoff; off = OffsetNumberNext(off))
  708. {
  709. thisii = PageGetItemId(page, off);
  710. *previi = *thisii;
  711. previi = thisii;
  712. }
  713. ((PageHeader) page)->pd_lower -= sizeof(ItemIdData);
  714. }
  715. }
  716. /*
  717.  * allocate and initialize a new BTPageState.  the returned structure
  718.  * is suitable for immediate use by _bt_buildadd.
  719.  */
  720. static void *
  721. _bt_pagestate(Relation index, int flags, int level, bool doupper)
  722. {
  723. BTPageState *state = (BTPageState *) palloc(sizeof(BTPageState));
  724. MemSet((char *) state, 0, sizeof(BTPageState));
  725. _bt_blnewpage(index, &(state->btps_buf), &(state->btps_page), flags);
  726. state->btps_firstoff = InvalidOffsetNumber;
  727. state->btps_lastoff = P_HIKEY;
  728. state->btps_lastbti = (BTItem) NULL;
  729. state->btps_next = (BTPageState *) NULL;
  730. state->btps_level = level;
  731. state->btps_doupper = doupper;
  732. return (void *) state;
  733. }
  734. /*
  735.  * return a copy of the minimum (P_HIKEY or P_FIRSTKEY) item on
  736.  * 'opage'.  the copy is modified to point to 'opage' (as opposed to
  737.  * the page to which the item used to point, e.g., a heap page if
  738.  * 'opage' is a leaf page).
  739.  */
  740. static BTItem
  741. _bt_minitem(Page opage, BlockNumber oblkno, int atend)
  742. {
  743. OffsetNumber off;
  744. BTItem obti;
  745. BTItem nbti;
  746. off = atend ? P_HIKEY : P_FIRSTKEY;
  747. obti = (BTItem) PageGetItem(opage, PageGetItemId(opage, off));
  748. nbti = _bt_formitem(&(obti->bti_itup));
  749. ItemPointerSet(&(nbti->bti_itup.t_tid), oblkno, P_HIKEY);
  750. return nbti;
  751. }
  752. /*
  753.  * add an item to a disk page from a merge tape block.
  754.  *
  755.  * we must be careful to observe the following restrictions, placed
  756.  * upon us by the conventions in nbtsearch.c:
  757.  * - rightmost pages start data items at P_HIKEY instead of at
  758.  *  P_FIRSTKEY.
  759.  * - duplicates cannot be split among pages unless the chain of
  760.  *  duplicates starts at the first data item.
  761.  *
  762.  * a leaf page being built looks like:
  763.  *
  764.  * +----------------+---------------------------------+
  765.  * | PageHeaderData | linp0 linp1 linp2 ...   |
  766.  * +-----------+----+---------------------------------+
  767.  * | ... linpN |   ^ first   |
  768.  * +-----------+--------------------------------------+
  769.  * |  ^ last   |
  770.  * |   |
  771.  * |    v last   |
  772.  * +-------------+------------------------------------+
  773.  * |  | itemN ...   |
  774.  * +-------------+------------------+-----------------+
  775.  * |   ... item3 item2 item1 | "special space" |
  776.  * +--------------------------------+-----------------+
  777.  * ^ first
  778.  *
  779.  * contrast this with the diagram in bufpage.h; note the mismatch
  780.  * between linps and items.  this is because we reserve linp0 as a
  781.  * placeholder for the pointer to the "high key" item; when we have
  782.  * filled up the page, we will set linp0 to point to itemN and clear
  783.  * linpN.
  784.  *
  785.  * 'last' pointers indicate the last offset/item added to the page.
  786.  * 'first' pointers indicate the first offset/item that is part of a
  787.  * chain of duplicates extending from 'first' to 'last'.
  788.  *
  789.  * if all keys are unique, 'first' will always be the same as 'last'.
  790.  */
  791. static BTItem
  792. _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags)
  793. {
  794. BTPageState *state = (BTPageState *) pstate;
  795. Buffer nbuf;
  796. Page npage;
  797. BTItem last_bti;
  798. OffsetNumber first_off;
  799. OffsetNumber last_off;
  800. OffsetNumber off;
  801. Size pgspc;
  802. Size btisz;
  803. nbuf = state->btps_buf;
  804. npage = state->btps_page;
  805. first_off = state->btps_firstoff;
  806. last_off = state->btps_lastoff;
  807. last_bti = state->btps_lastbti;
  808. pgspc = PageGetFreeSpace(npage);
  809. btisz = BTITEMSZ(bti);
  810. btisz = MAXALIGN(btisz);
  811. if (pgspc < btisz)
  812. {
  813. Buffer obuf = nbuf;
  814. Page opage = npage;
  815. OffsetNumber o,
  816. n;
  817. ItemId ii;
  818. ItemId hii;
  819. _bt_blnewpage(index, &nbuf, &npage, flags);
  820. /*
  821.  * if 'last' is part of a chain of duplicates that does not start
  822.  * at the beginning of the old page, the entire chain is copied to
  823.  * the new page; we delete all of the duplicates from the old page
  824.  * except the first, which becomes the high key item of the old
  825.  * page.
  826.  *
  827.  * if the chain starts at the beginning of the page or there is no
  828.  * chain ('first' == 'last'), we need only copy 'last' to the new
  829.  * page.  again, 'first' (== 'last') becomes the high key of the
  830.  * old page.
  831.  *
  832.  * note that in either case, we copy at least one item to the new
  833.  * page, so 'last_bti' will always be valid.  'bti' will never be
  834.  * the first data item on the new page.
  835.  */
  836. if (first_off == P_FIRSTKEY)
  837. {
  838. Assert(last_off != P_FIRSTKEY);
  839. first_off = last_off;
  840. }
  841. for (o = first_off, n = P_FIRSTKEY;
  842.  o <= last_off;
  843.  o = OffsetNumberNext(o), n = OffsetNumberNext(n))
  844. {
  845. ii = PageGetItemId(opage, o);
  846. if (PageAddItem(npage, PageGetItem(opage, ii),
  847.   ii->lp_len, n, LP_USED) == InvalidOffsetNumber)
  848. elog(FATAL, "btree: failed to add item to the page in _bt_sort (1)");
  849. #ifdef NOT_USED
  850. #if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
  851. {
  852. bool isnull;
  853. BTItem tmpbti =
  854. (BTItem) PageGetItem(npage, PageGetItemId(npage, n));
  855. Datum d = index_getattr(&(tmpbti->bti_itup), 1,
  856.   index->rd_att, &isnull);
  857. printf("_bt_buildadd: moved <%x> to offset %d at level %dn",
  858.    d, n, state->btps_level);
  859. }
  860. #endif  /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
  861. #endif
  862. }
  863. /*
  864.  * this loop is backward because PageIndexTupleDelete shuffles the
  865.  * tuples to fill holes in the page -- by starting at the end and
  866.  * working back, we won't create holes (and thereby avoid
  867.  * shuffling).
  868.  */
  869. for (o = last_off; o > first_off; o = OffsetNumberPrev(o))
  870. PageIndexTupleDelete(opage, o);
  871. hii = PageGetItemId(opage, P_HIKEY);
  872. ii = PageGetItemId(opage, first_off);
  873. *hii = *ii;
  874. ii->lp_flags &= ~LP_USED;
  875. ((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
  876. first_off = P_FIRSTKEY;
  877. last_off = PageGetMaxOffsetNumber(npage);
  878. last_bti = (BTItem) PageGetItem(npage, PageGetItemId(npage, last_off));
  879. /*
  880.  * set the page (side link) pointers.
  881.  */
  882. {
  883. BTPageOpaque oopaque = (BTPageOpaque) PageGetSpecialPointer(opage);
  884. BTPageOpaque nopaque = (BTPageOpaque) PageGetSpecialPointer(npage);
  885. oopaque->btpo_next = BufferGetBlockNumber(nbuf);
  886. nopaque->btpo_prev = BufferGetBlockNumber(obuf);
  887. nopaque->btpo_next = P_NONE;
  888. if (_bt_itemcmp(index, _bt_nattr,
  889.   (BTItem) PageGetItem(opage, PageGetItemId(opage, P_HIKEY)),
  890. (BTItem) PageGetItem(opage, PageGetItemId(opage, P_FIRSTKEY)),
  891. BTEqualStrategyNumber))
  892. oopaque->btpo_flags |= BTP_CHAIN;
  893. }
  894. /*
  895.  * copy the old buffer's minimum key to its parent.  if we don't
  896.  * have a parent, we have to create one; this adds a new btree
  897.  * level.
  898.  */
  899. if (state->btps_doupper)
  900. {
  901. BTItem nbti;
  902. if (state->btps_next == (BTPageState *) NULL)
  903. {
  904. state->btps_next =
  905. _bt_pagestate(index, 0, state->btps_level + 1, true);
  906. }
  907. nbti = _bt_minitem(opage, BufferGetBlockNumber(obuf), 0);
  908. _bt_buildadd(index, state->btps_next, nbti, 0);
  909. pfree((void *) nbti);
  910. }
  911. /*
  912.  * write out the old stuff.  we never want to see it again, so we
  913.  * can give up our lock (if we had one; BuildingBtree is set, so
  914.  * we aren't locking).
  915.  */
  916. _bt_wrtbuf(index, obuf);
  917. }
  918. /*
  919.  * if this item is different from the last item added, we start a new
  920.  * chain of duplicates.
  921.  */
  922. off = OffsetNumberNext(last_off);
  923. if (PageAddItem(npage, (Item) bti, btisz, off, LP_USED) == InvalidOffsetNumber)
  924. elog(FATAL, "btree: failed to add item to the page in _bt_sort (2)");
  925. #ifdef NOT_USED
  926. #if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
  927. {
  928. bool isnull;
  929. Datum d = index_getattr(&(bti->bti_itup), 1, index->rd_att, &isnull);
  930. printf("_bt_buildadd: inserted <%x> at offset %d at level %dn",
  931.    d, off, state->btps_level);
  932. }
  933. #endif  /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
  934. #endif
  935. if (last_bti == (BTItem) NULL)
  936. first_off = P_FIRSTKEY;
  937. else if (!_bt_itemcmp(index, _bt_nattr,
  938.   bti, last_bti, BTEqualStrategyNumber))
  939. first_off = off;
  940. last_off = off;
  941. last_bti = (BTItem) PageGetItem(npage, PageGetItemId(npage, off));
  942. state->btps_buf = nbuf;
  943. state->btps_page = npage;
  944. state->btps_lastbti = last_bti;
  945. state->btps_lastoff = last_off;
  946. state->btps_firstoff = first_off;
  947. return last_bti;
  948. }
  949. static void
  950. _bt_uppershutdown(Relation index, BTPageState *state)
  951. {
  952. BTPageState *s;
  953. BlockNumber blkno;
  954. BTPageOpaque opaque;
  955. BTItem bti;
  956. for (s = state; s != (BTPageState *) NULL; s = s->btps_next)
  957. {
  958. blkno = BufferGetBlockNumber(s->btps_buf);
  959. opaque = (BTPageOpaque) PageGetSpecialPointer(s->btps_page);
  960. /*
  961.  * if this is the root, attach it to the metapage. otherwise,
  962.  * stick the minimum key of the last page on this level (which has
  963.  * not been split, or else it wouldn't be the last page) into its
  964.  * parent. this may cause the last page of upper levels to split,
  965.  * but that's not a problem -- we haven't gotten to them yet.
  966.  */
  967. if (s->btps_doupper)
  968. {
  969. if (s->btps_next == (BTPageState *) NULL)
  970. {
  971. opaque->btpo_flags |= BTP_ROOT;
  972. _bt_metaproot(index, blkno, s->btps_level + 1);
  973. }
  974. else
  975. {
  976. bti = _bt_minitem(s->btps_page, blkno, 0);
  977. _bt_buildadd(index, s->btps_next, bti, 0);
  978. pfree((void *) bti);
  979. }
  980. }
  981. /*
  982.  * this is the rightmost page, so the ItemId array needs to be
  983.  * slid back one slot.
  984.  */
  985. _bt_slideleft(index, s->btps_buf, s->btps_page);
  986. _bt_wrtbuf(index, s->btps_buf);
  987. }
  988. }
  989. /*
  990.  * take the input tapes stored by 'btspool' and perform successive
  991.  * merging passes until at most one run is left in each tape.  at that
  992.  * point, merge the final tape runs into a set of btree leaves.
  993.  *
  994.  * XXX three nested loops? gross. cut me up into smaller routines.
  995.  */
  996. static void
  997. _bt_merge(Relation index, BTSpool *btspool)
  998. {
  999. BTPageState *state;
  1000. BTPriQueue q;
  1001. BTPriQueueElem e;
  1002. BTSortKey btsk;
  1003. BTItem bti;
  1004. BTTapeBlock *itape;
  1005. BTTapeBlock *otape;
  1006. char    *tapepos[MAXTAPES];
  1007. int tapedone[MAXTAPES];
  1008. int t;
  1009. int goodtapes;
  1010. int npass;
  1011. int nruns;
  1012. Size btisz;
  1013. bool doleaf = false;
  1014. /*
  1015.  * initialize state needed for the merge into the btree leaf pages.
  1016.  */
  1017. state = (BTPageState *) _bt_pagestate(index, BTP_LEAF, 0, true);
  1018. npass = 0;
  1019. do
  1020. { /* pass */
  1021. /*
  1022.  * each pass starts by flushing the previous outputs and swapping
  1023.  * inputs and outputs. flushing sets End-of-Run for any dirty
  1024.  * output tapes.  swapping clears the new output tapes and rewinds
  1025.  * the new input tapes.
  1026.  */
  1027. btspool->bts_tape = btspool->bts_ntapes - 1;
  1028. _bt_spoolflush(btspool);
  1029. _bt_spoolswap(btspool);
  1030. ++npass;
  1031. nruns = 0;
  1032. for (;;)
  1033. { /* run */
  1034. /*
  1035.  * each run starts by selecting a new output tape. the merged
  1036.  * results of a given run are always sent to this one tape.
  1037.  */
  1038. btspool->bts_tape = (btspool->bts_tape + 1) % btspool->bts_ntapes;
  1039. otape = btspool->bts_otape[btspool->bts_tape];
  1040. /*
  1041.  * initialize the priority queue by loading it with the first
  1042.  * element of the given run in each tape.  since we are
  1043.  * starting a new run, we reset the tape (clearing the
  1044.  * End-Of-Run marker) before reading it.  this means that
  1045.  * _bt_taperead will return 0 only if the tape is actually at
  1046.  * EOF.
  1047.  */
  1048. MemSet((char *) &q, 0, sizeof(BTPriQueue));
  1049. goodtapes = 0;
  1050. for (t = 0; t < btspool->bts_ntapes; ++t)
  1051. {
  1052. itape = btspool->bts_itape[t];
  1053. tapepos[t] = itape->bttb_data;
  1054. tapedone[t] = 0;
  1055. _bt_tapereset(itape);
  1056. do
  1057. {
  1058. if (_bt_taperead(itape) == 0)
  1059. tapedone[t] = 1;
  1060. } while (!tapedone[t] && EMPTYTAPE(itape));
  1061. if (!tapedone[t])
  1062. {
  1063. ++goodtapes;
  1064. e.btpqe_tape = t;
  1065. _bt_setsortkey(index, _bt_tapenext(itape, &tapepos[t]),
  1066.    &(e.btpqe_item));
  1067. if (e.btpqe_item.btsk_item != (BTItem) NULL)
  1068. _bt_pqadd(&q, &e);
  1069. }
  1070. }
  1071. /*
  1072.  * if we don't have any tapes with any input (i.e., they are
  1073.  * all at EOF), there is no work to do in this run -- we must
  1074.  * be done with this pass.
  1075.  */
  1076. if (goodtapes == 0)
  1077. {
  1078. break; /* for */
  1079. }
  1080. ++nruns;
  1081. /*
  1082.  * output the smallest element from the queue until there are
  1083.  * no more.
  1084.  */
  1085. while (_bt_pqnext(&q, &e) >= 0)
  1086. { /* item */
  1087. /*
  1088.  * replace the element taken from priority queue, fetching
  1089.  * a new block if needed.  a tape can run out if it hits
  1090.  * either End-Of-Run or EOF.
  1091.  */
  1092. t = e.btpqe_tape;
  1093. btsk = e.btpqe_item;
  1094. bti = btsk.btsk_item;
  1095. if (bti != (BTItem) NULL)
  1096. {
  1097. btisz = BTITEMSZ(bti);
  1098. btisz = MAXALIGN(btisz);
  1099. if (doleaf)
  1100. {
  1101. _bt_buildadd(index, state, bti, BTP_LEAF);
  1102. #if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
  1103. {
  1104. bool isnull;
  1105. Datum d = index_getattr(&(bti->bti_itup), 1,
  1106.  index->rd_att, &isnull);
  1107. printf("_bt_merge: [pass %d run %d] inserted <%x> from tape %d into block %dn",
  1108.    npass, nruns, d, t,
  1109.    BufferGetBlockNumber(state->btps_buf));
  1110. }
  1111. #endif  /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
  1112. }
  1113. else
  1114. {
  1115. if (SPCLEFT(otape) < btisz)
  1116. {
  1117. /*
  1118.  * if it's full, write it out and add the item
  1119.  * to the next block.  (since we will be
  1120.  * adding another tuple immediately after
  1121.  * this, we can be sure that there will be at
  1122.  * least one more block in this run and so we
  1123.  * know we do *not* want to set End-Of-Run
  1124.  * here.)
  1125.  */
  1126. _bt_tapewrite(otape, 0);
  1127. }
  1128. _bt_tapeadd(otape, bti, btisz);
  1129. #if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
  1130. {
  1131. bool isnull;
  1132. Datum d = index_getattr(&(bti->bti_itup), 1,
  1133.  index->rd_att, &isnull);
  1134. printf("_bt_merge: [pass %d run %d] inserted <%x> from tape %d into output tape %dn",
  1135.    npass, nruns, d, t,
  1136.    btspool->bts_tape);
  1137. }
  1138. #endif  /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
  1139. }
  1140. if (btsk.btsk_datum != (Datum *) NULL)
  1141. pfree((void *) (btsk.btsk_datum));
  1142. if (btsk.btsk_nulls != (char *) NULL)
  1143. pfree((void *) (btsk.btsk_nulls));
  1144. }
  1145. itape = btspool->bts_itape[t];
  1146. if (!tapedone[t])
  1147. {
  1148. BTItem newbti = _bt_tapenext(itape, &tapepos[t]);
  1149. if (newbti == (BTItem) NULL)
  1150. {
  1151. do
  1152. {
  1153. if (_bt_taperead(itape) == 0)
  1154. tapedone[t] = 1;
  1155. } while (!tapedone[t] && EMPTYTAPE(itape));
  1156. if (!tapedone[t])
  1157. {
  1158. tapepos[t] = itape->bttb_data;
  1159. newbti = _bt_tapenext(itape, &tapepos[t]);
  1160. }
  1161. }
  1162. if (newbti != (BTItem) NULL)
  1163. {
  1164. BTPriQueueElem nexte;
  1165. nexte.btpqe_tape = t;
  1166. _bt_setsortkey(index, newbti, &(nexte.btpqe_item));
  1167. _bt_pqadd(&q, &nexte);
  1168. }
  1169. }
  1170. } /* item */
  1171. /*
  1172.  * that's it for this run.  flush the output tape, marking
  1173.  * End-of-Run.
  1174.  */
  1175. _bt_tapewrite(otape, 1);
  1176. } /* run */
  1177. /*
  1178.  * we are here because we ran out of input on all of the input
  1179.  * tapes.
  1180.  *
  1181.  * if this pass did not generate more actual output runs than we have
  1182.  * tapes, we know we have at most one run in each tape.  this
  1183.  * means that we are ready to merge into the final btree leaf
  1184.  * pages instead of merging into a tape file.
  1185.  */
  1186. if (nruns <= btspool->bts_ntapes)
  1187. doleaf = true;
  1188. } while (nruns > 0); /* pass */
  1189. _bt_uppershutdown(index, state);
  1190. }
  1191. /*
  1192.  * given the (appropriately side-linked) leaf pages of a btree,
  1193.  * construct the corresponding upper levels.  we do this by inserting
  1194.  * minimum keys from each page into parent pages as needed.  the
  1195.  * format of the internal pages is otherwise the same as for leaf
  1196.  * pages.
  1197.  *
  1198.  * this routine is not called during conventional bulk-loading (in
  1199.  * which case we can just build the upper levels as we create the
  1200.  * sorted bottom level).  it is only used for index recycling.
  1201.  */
  1202. #ifdef NOT_USED
  1203. void
  1204. _bt_upperbuild(Relation index)
  1205. {
  1206. Buffer rbuf;
  1207. BlockNumber blk;
  1208. Page rpage;
  1209. BTPageOpaque ropaque;
  1210. BTPageState *state;
  1211. BTItem nbti;
  1212. /*
  1213.  * find the first leaf block.  while we're at it, clear the BTP_ROOT
  1214.  * flag that we set while building it (so we could find it later).
  1215.  */
  1216. rbuf = _bt_getroot(index, BT_WRITE);
  1217. blk = BufferGetBlockNumber(rbuf);
  1218. rpage = BufferGetPage(rbuf);
  1219. ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
  1220. ropaque->btpo_flags &= ~BTP_ROOT;
  1221. _bt_wrtbuf(index, rbuf);
  1222. state = (BTPageState *) _bt_pagestate(index, 0, 0, true);
  1223. /* for each page... */
  1224. do
  1225. {
  1226. #ifdef NOT_USED
  1227. printf("ttblk=%dn", blk);
  1228. #endif
  1229. rbuf = _bt_getbuf(index, blk, BT_READ);
  1230. rpage = BufferGetPage(rbuf);
  1231. ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
  1232. /* for each item... */
  1233. if (!PageIsEmpty(rpage))
  1234. {
  1235. /*
  1236.  * form a new index tuple corresponding to the minimum key of
  1237.  * the lower page and insert it into a page at this level.
  1238.  */
  1239. nbti = _bt_minitem(rpage, blk, P_RIGHTMOST(ropaque));
  1240. #if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
  1241. {
  1242. bool isnull;
  1243. Datum d = index_getattr(&(nbti->bti_itup), 1, index->rd_att,
  1244.   &isnull);
  1245. printf("_bt_upperbuild: inserting <%x> at %dn",
  1246.    d, state->btps_level);
  1247. }
  1248. #endif  /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
  1249. _bt_buildadd(index, state, nbti, 0);
  1250. pfree((void *) nbti);
  1251. }
  1252. blk = ropaque->btpo_next;
  1253. _bt_relbuf(index, rbuf, BT_READ);
  1254. } while (blk != P_NONE);
  1255. _bt_uppershutdown(index, state);
  1256. }
  1257. #endif
  1258. /*
  1259.  * given a spool loading by successive calls to _bt_spool, create an
  1260.  * entire btree.
  1261.  */
  1262. void
  1263. _bt_leafbuild(Relation index, void *spool)
  1264. {
  1265. _bt_isortcmpinit(index, (BTSpool *) spool);
  1266. #ifdef BTREE_BUILD_STATS
  1267. if (ShowExecutorStats)
  1268. {
  1269. fprintf(stderr, "! BtreeBuild (Spool) Stats:n");
  1270. ShowUsage();
  1271. ResetUsage();
  1272. }
  1273. #endif
  1274. _bt_merge(index, (BTSpool *) spool);
  1275. }