home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / db-1.6 / part06 < prev    next >
Encoding:
Text File  |  1993-07-05  |  73.7 KB  |  2,707 lines

  1. Newsgroups: comp.sources.unix
  2. From: bostic@cs.berkeley.edu (Keith Bostic)
  3. Subject: v26i285: db-1.6 - A New Hashing Package for UNIX(tm) (updates dbm/ndbm), Part06/09
  4. Sender: unix-sources-moderator@gw.home.vix.com
  5. Approved: vixie@gw.home.vix.com
  6.  
  7. Submitted-By: bostic@cs.berkeley.edu (Keith Bostic)
  8. Posting-Number: Volume 26, Issue 285
  9. Archive-Name: db-1.6/part06
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 6 (of 9)."
  18. # Contents:  btree/bt_split.c doc/btree.3.ps hash/hash_bigkey.c
  19. #   test/btree.tests/main.c
  20. # Wrapped by vixie@gw.home.vix.com on Mon Jul  5 15:27:27 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'btree/bt_split.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'btree/bt_split.c'\"
  24. else
  25. echo shar: Extracting \"'btree/bt_split.c'\" \(22158 characters\)
  26. sed "s/^X//" >'btree/bt_split.c' <<'END_OF_FILE'
  27. X/*-
  28. X * Copyright (c) 1990, 1993
  29. X *    The Regents of the University of California.  All rights reserved.
  30. X *
  31. X * This code is derived from software contributed to Berkeley by
  32. X * Mike Olson.
  33. X *
  34. X * Redistribution and use in source and binary forms, with or without
  35. X * modification, are permitted provided that the following conditions
  36. X * are met:
  37. X * 1. Redistributions of source code must retain the above copyright
  38. X *    notice, this list of conditions and the following disclaimer.
  39. X * 2. Redistributions in binary form must reproduce the above copyright
  40. X *    notice, this list of conditions and the following disclaimer in the
  41. X *    documentation and/or other materials provided with the distribution.
  42. X * 3. All advertising materials mentioning features or use of this software
  43. X *    must display the following acknowledgement:
  44. X *    This product includes software developed by the University of
  45. X *    California, Berkeley and its contributors.
  46. X * 4. Neither the name of the University nor the names of its contributors
  47. X *    may be used to endorse or promote products derived from this software
  48. X *    without specific prior written permission.
  49. X *
  50. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  51. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  52. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  53. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  54. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  55. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  56. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  57. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  58. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  59. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  60. X * SUCH DAMAGE.
  61. X */
  62. X
  63. X#if defined(LIBC_SCCS) && !defined(lint)
  64. Xstatic char sccsid[] = "@(#)bt_split.c    8.1 (Berkeley) 6/4/93";
  65. X#endif /* LIBC_SCCS and not lint */
  66. X
  67. X#include <sys/types.h>
  68. X
  69. X#define    __DBINTERFACE_PRIVATE
  70. X#include <limits.h>
  71. X#include <stdio.h>
  72. X#include <stdlib.h>
  73. X#include <string.h>
  74. X
  75. X#include <db.h>
  76. X#include "btree.h"
  77. X
  78. Xstatic int     bt_broot __P((BTREE *, PAGE *, PAGE *, PAGE *));
  79. Xstatic PAGE    *bt_page
  80. X            __P((BTREE *, PAGE *, PAGE **, PAGE **, u_int *, size_t));
  81. Xstatic int     bt_preserve __P((BTREE *, pgno_t));
  82. Xstatic PAGE    *bt_psplit
  83. X            __P((BTREE *, PAGE *, PAGE *, PAGE *, u_int *, size_t));
  84. Xstatic PAGE    *bt_root
  85. X            __P((BTREE *, PAGE *, PAGE **, PAGE **, u_int *, size_t));
  86. Xstatic int     bt_rroot __P((BTREE *, PAGE *, PAGE *, PAGE *));
  87. Xstatic recno_t     rec_total __P((PAGE *));
  88. X
  89. X#ifdef STATISTICS
  90. Xu_long    bt_rootsplit, bt_split, bt_sortsplit, bt_pfxsaved;
  91. X#endif
  92. X
  93. X/*
  94. X * __BT_SPLIT -- Split the tree.
  95. X *
  96. X * Parameters:
  97. X *    t:    tree
  98. X *    sp:    page to split
  99. X *    key:    key to insert
  100. X *    data:    data to insert
  101. X *    flags:    BIGKEY/BIGDATA flags
  102. X *    ilen:    insert length
  103. X *    skip:    index to leave open
  104. X *
  105. X * Returns:
  106. X *    RET_ERROR, RET_SUCCESS
  107. X */
  108. Xint
  109. X__bt_split(t, sp, key, data, flags, ilen, skip)
  110. X    BTREE *t;
  111. X    PAGE *sp;
  112. X    const DBT *key, *data;
  113. X    u_long flags;
  114. X    size_t ilen;
  115. X    u_int skip;
  116. X{
  117. X    BINTERNAL *bi;
  118. X    BLEAF *bl, *tbl;
  119. X    DBT a, b;
  120. X    EPGNO *parent;
  121. X    PAGE *h, *l, *r, *lchild, *rchild;
  122. X    indx_t nxtindex;
  123. X    size_t n, nbytes, nksize;
  124. X    int parentsplit;
  125. X    char *dest;
  126. X
  127. X    /*
  128. X     * Split the page into two pages, l and r.  The split routines return
  129. X     * a pointer to the page into which the key should be inserted and with
  130. X     * skip set to the offset which should be used.  Additionally, l and r
  131. X     * are pinned.
  132. X     */
  133. X    h = sp->pgno == P_ROOT ?
  134. X        bt_root(t, sp, &l, &r, &skip, ilen) :
  135. X        bt_page(t, sp, &l, &r, &skip, ilen);
  136. X    if (h == NULL)
  137. X        return (RET_ERROR);
  138. X
  139. X    /*
  140. X     * Insert the new key/data pair into the leaf page.  (Key inserts
  141. X     * always cause a leaf page to split first.)
  142. X     */
  143. X    h->linp[skip] = h->upper -= ilen;
  144. X    dest = (char *)h + h->upper;
  145. X    if (ISSET(t, R_RECNO))
  146. X        WR_RLEAF(dest, data, flags)
  147. X    else
  148. X        WR_BLEAF(dest, key, data, flags)
  149. X
  150. X    /* If the root page was split, make it look right. */
  151. X    if (sp->pgno == P_ROOT &&
  152. X        (ISSET(t, R_RECNO) ?
  153. X        bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
  154. X        goto err2;
  155. X
  156. X    /*
  157. X     * Now we walk the parent page stack -- a LIFO stack of the pages that
  158. X     * were traversed when we searched for the page that split.  Each stack
  159. X     * entry is a page number and a page index offset.  The offset is for
  160. X     * the page traversed on the search.  We've just split a page, so we
  161. X     * have to insert a new key into the parent page.
  162. X     *
  163. X     * If the insert into the parent page causes it to split, may have to
  164. X     * continue splitting all the way up the tree.  We stop if the root
  165. X     * splits or the page inserted into didn't have to split to hold the
  166. X     * new key.  Some algorithms replace the key for the old page as well
  167. X     * as the new page.  We don't, as there's no reason to believe that the
  168. X     * first key on the old page is any better than the key we have, and,
  169. X     * in the case of a key being placed at index 0 causing the split, the
  170. X     * key is unavailable.
  171. X     *
  172. X     * There are a maximum of 5 pages pinned at any time.  We keep the left
  173. X     * and right pages pinned while working on the parent.   The 5 are the
  174. X     * two children, left parent and right parent (when the parent splits)
  175. X     * and the root page or the overflow key page when calling bt_preserve.
  176. X     * This code must make sure that all pins are released other than the
  177. X     * root page or overflow page which is unlocked elsewhere.
  178. X     */
  179. X    while ((parent = BT_POP(t)) != NULL) {
  180. X        lchild = l;
  181. X        rchild = r;
  182. X
  183. X        /* Get the parent page. */
  184. X        if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
  185. X            goto err2;
  186. X
  187. X         /*
  188. X         * The new key goes ONE AFTER the index, because the split
  189. X         * was to the right.
  190. X         */
  191. X        skip = parent->index + 1;
  192. X
  193. X        /*
  194. X         * Calculate the space needed on the parent page.
  195. X         *
  196. X         * Prefix trees: space hack when inserting into BINTERNAL
  197. X         * pages.  Retain only what's needed to distinguish between
  198. X         * the new entry and the LAST entry on the page to its left.
  199. X         * If the keys compare equal, retain the entire key.  Note,
  200. X         * we don't touch overflow keys, and the entire key must be
  201. X         * retained for the next-to-left most key on the leftmost
  202. X         * page of each level, or the search will fail.  Applicable
  203. X         * ONLY to internal pages that have leaf pages as children.
  204. X         * Further reduction of the key between pairs of internal
  205. X         * pages loses too much information.
  206. X         */
  207. X        switch (rchild->flags & P_TYPE) {
  208. X        case P_BINTERNAL:
  209. X            bi = GETBINTERNAL(rchild, 0);
  210. X            nbytes = NBINTERNAL(bi->ksize);
  211. X            break;
  212. X        case P_BLEAF:
  213. X            bl = GETBLEAF(rchild, 0);
  214. X            nbytes = NBINTERNAL(bl->ksize);
  215. X            if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
  216. X                (h->prevpg != P_INVALID || skip > 1)) {
  217. X                tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
  218. X                a.size = tbl->ksize;
  219. X                a.data = tbl->bytes;
  220. X                b.size = bl->ksize;
  221. X                b.data = bl->bytes;
  222. X                nksize = t->bt_pfx(&a, &b);
  223. X                n = NBINTERNAL(nksize);
  224. X                if (n < nbytes) {
  225. X#ifdef STATISTICS
  226. X                    bt_pfxsaved += nbytes - n;
  227. X#endif
  228. X                    nbytes = n;
  229. X                } else
  230. X                    nksize = 0;
  231. X            } else
  232. X                nksize = 0;
  233. X            break;
  234. X        case P_RINTERNAL:
  235. X        case P_RLEAF:
  236. X            nbytes = NRINTERNAL;
  237. X            break;
  238. X        default:
  239. X            abort();
  240. X        }
  241. X
  242. X        /* Split the parent page if necessary or shift the indices. */
  243. X        if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
  244. X            sp = h;
  245. X            h = h->pgno == P_ROOT ?
  246. X                bt_root(t, h, &l, &r, &skip, nbytes) :
  247. X                bt_page(t, h, &l, &r, &skip, nbytes);
  248. X            if (h == NULL)
  249. X                goto err1;
  250. X            parentsplit = 1;
  251. X        } else {
  252. X            if (skip < (nxtindex = NEXTINDEX(h)))
  253. X                memmove(h->linp + skip + 1, h->linp + skip,
  254. X                    (nxtindex - skip) * sizeof(indx_t));
  255. X            h->lower += sizeof(indx_t);
  256. X            parentsplit = 0;
  257. X        }
  258. X
  259. X        /* Insert the key into the parent page. */
  260. X        switch(rchild->flags & P_TYPE) {
  261. X        case P_BINTERNAL:
  262. X            h->linp[skip] = h->upper -= nbytes;
  263. X            dest = (char *)h + h->linp[skip];
  264. X            memmove(dest, bi, nbytes);
  265. X            ((BINTERNAL *)dest)->pgno = rchild->pgno;
  266. X            break;
  267. X        case P_BLEAF:
  268. X            h->linp[skip] = h->upper -= nbytes;
  269. X            dest = (char *)h + h->linp[skip];
  270. X            WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
  271. X                rchild->pgno, bl->flags & P_BIGKEY);
  272. X            memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
  273. X            if (bl->flags & P_BIGKEY &&
  274. X                bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
  275. X                goto err1;
  276. X            break;
  277. X        case P_RINTERNAL:
  278. X            /*
  279. X             * Update the left page count.  If split
  280. X             * added at index 0, fix the correct page.
  281. X             */
  282. X            if (skip > 0)
  283. X                dest = (char *)h + h->linp[skip - 1];
  284. X            else
  285. X                dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
  286. X            ((RINTERNAL *)dest)->nrecs = rec_total(lchild);
  287. X            ((RINTERNAL *)dest)->pgno = lchild->pgno;
  288. X
  289. X            /* Update the right page count. */
  290. X            h->linp[skip] = h->upper -= nbytes;
  291. X            dest = (char *)h + h->linp[skip];
  292. X            ((RINTERNAL *)dest)->nrecs = rec_total(rchild);
  293. X            ((RINTERNAL *)dest)->pgno = rchild->pgno;
  294. X            break;
  295. X        case P_RLEAF:
  296. X            /*
  297. X             * Update the left page count.  If split
  298. X             * added at index 0, fix the correct page.
  299. X             */
  300. X            if (skip > 0)
  301. X                dest = (char *)h + h->linp[skip - 1];
  302. X            else
  303. X                dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
  304. X            ((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
  305. X            ((RINTERNAL *)dest)->pgno = lchild->pgno;
  306. X
  307. X            /* Update the right page count. */
  308. X            h->linp[skip] = h->upper -= nbytes;
  309. X            dest = (char *)h + h->linp[skip];
  310. X            ((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
  311. X            ((RINTERNAL *)dest)->pgno = rchild->pgno;
  312. X            break;
  313. X        default:
  314. X            abort();
  315. X        }
  316. X
  317. X        /* Unpin the held pages. */
  318. X        if (!parentsplit) {
  319. X            mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  320. X            break;
  321. X        }
  322. X
  323. X        /* If the root page was split, make it look right. */
  324. X        if (sp->pgno == P_ROOT &&
  325. X            (ISSET(t, R_RECNO) ?
  326. X            bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
  327. X            goto err1;
  328. X
  329. X        mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
  330. X        mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
  331. X    }
  332. X
  333. X    /* Unpin the held pages. */
  334. X    mpool_put(t->bt_mp, l, MPOOL_DIRTY);
  335. X    mpool_put(t->bt_mp, r, MPOOL_DIRTY);
  336. X
  337. X    /* Clear any pages left on the stack. */
  338. X    return (RET_SUCCESS);
  339. X
  340. X    /*
  341. X     * If something fails in the above loop we were already walking back
  342. X     * up the tree and the tree is now inconsistent.  Nothing much we can
  343. X     * do about it but release any memory we're holding.
  344. X     */
  345. Xerr1:    mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
  346. X    mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
  347. X
  348. Xerr2:    mpool_put(t->bt_mp, l, 0);
  349. X    mpool_put(t->bt_mp, r, 0);
  350. X    __dbpanic(t->bt_dbp);
  351. X    return (RET_ERROR);
  352. X}
  353. X
  354. X/*
  355. X * BT_PAGE -- Split a non-root page of a btree.
  356. X *
  357. X * Parameters:
  358. X *    t:    tree
  359. X *    h:    root page
  360. X *    lp:    pointer to left page pointer
  361. X *    rp:    pointer to right page pointer
  362. X *    skip:    pointer to index to leave open
  363. X *    ilen:    insert length
  364. X *
  365. X * Returns:
  366. X *    Pointer to page in which to insert or NULL on error.
  367. X */
  368. Xstatic PAGE *
  369. Xbt_page(t, h, lp, rp, skip, ilen)
  370. X    BTREE *t;
  371. X    PAGE *h, **lp, **rp;
  372. X    u_int *skip;
  373. X    size_t ilen;
  374. X{
  375. X    PAGE *l, *r, *tp;
  376. X    pgno_t npg;
  377. X
  378. X#ifdef STATISTICS
  379. X    ++bt_split;
  380. X#endif
  381. X    /* Put the new right page for the split into place. */
  382. X    if ((r = __bt_new(t, &npg)) == NULL)
  383. X        return (NULL);
  384. X    r->pgno = npg;
  385. X    r->lower = BTDATAOFF;
  386. X    r->upper = t->bt_psize;
  387. X    r->nextpg = h->nextpg;
  388. X    r->prevpg = h->pgno;
  389. X    r->flags = h->flags & P_TYPE;
  390. X
  391. X    /*
  392. X     * If we're splitting the last page on a level because we're appending
  393. X     * a key to it (skip is NEXTINDEX()), it's likely that the data is
  394. X     * sorted.  Adding an empty page on the side of the level is less work
  395. X     * and can push the fill factor much higher than normal.  If we're
  396. X     * wrong it's no big deal, we'll just do the split the right way next
  397. X     * time.  It may look like it's equally easy to do a similar hack for
  398. X     * reverse sorted data, that is, split the tree left, but it's not.
  399. X     * Don't even try.
  400. X     */
  401. X    if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
  402. X#ifdef STATISTICS
  403. X        ++bt_sortsplit;
  404. X#endif
  405. X        h->nextpg = r->pgno;
  406. X        r->lower = BTDATAOFF + sizeof(indx_t);
  407. X        *skip = 0;
  408. X        *lp = h;
  409. X        *rp = r;
  410. X        return (r);
  411. X    }
  412. X
  413. X    /* Put the new left page for the split into place. */
  414. X    if ((l = malloc(t->bt_psize)) == NULL) {
  415. X        mpool_put(t->bt_mp, r, 0);
  416. X        return (NULL);
  417. X    }
  418. X    l->pgno = h->pgno;
  419. X    l->nextpg = r->pgno;
  420. X    l->prevpg = h->prevpg;
  421. X    l->lower = BTDATAOFF;
  422. X    l->upper = t->bt_psize;
  423. X    l->flags = h->flags & P_TYPE;
  424. X
  425. X    /* Fix up the previous pointer of the page after the split page. */
  426. X    if (h->nextpg != P_INVALID) {
  427. X        if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
  428. X            free(l);
  429. X            /* XXX mpool_free(t->bt_mp, r->pgno); */
  430. X            return (NULL);
  431. X        }
  432. X        tp->prevpg = r->pgno;
  433. X        mpool_put(t->bt_mp, tp, 0);
  434. X    }
  435. X
  436. X    /*
  437. X     * Split right.  The key/data pairs aren't sorted in the btree page so
  438. X     * it's simpler to copy the data from the split page onto two new pages
  439. X     * instead of copying half the data to the right page and compacting
  440. X     * the left page in place.  Since the left page can't change, we have
  441. X     * to swap the original and the allocated left page after the split.
  442. X     */
  443. X    tp = bt_psplit(t, h, l, r, skip, ilen);
  444. X
  445. X    /* Move the new left page onto the old left page. */
  446. X    memmove(h, l, t->bt_psize);
  447. X    if (tp == l)
  448. X        tp = h;
  449. X    free(l);
  450. X
  451. X    *lp = h;
  452. X    *rp = r;
  453. X    return (tp);
  454. X}
  455. X
  456. X/*
  457. X * BT_ROOT -- Split the root page of a btree.
  458. X *
  459. X * Parameters:
  460. X *    t:    tree
  461. X *    h:    root page
  462. X *    lp:    pointer to left page pointer
  463. X *    rp:    pointer to right page pointer
  464. X *    skip:    pointer to index to leave open
  465. X *    ilen:    insert length
  466. X *
  467. X * Returns:
  468. X *    Pointer to page in which to insert or NULL on error.
  469. X */
  470. Xstatic PAGE *
  471. Xbt_root(t, h, lp, rp, skip, ilen)
  472. X    BTREE *t;
  473. X    PAGE *h, **lp, **rp;
  474. X    u_int *skip;
  475. X    size_t ilen;
  476. X{
  477. X    PAGE *l, *r, *tp;
  478. X    pgno_t lnpg, rnpg;
  479. X
  480. X#ifdef STATISTICS
  481. X    ++bt_split;
  482. X    ++bt_rootsplit;
  483. X#endif
  484. X    /* Put the new left and right pages for the split into place. */
  485. X    if ((l = __bt_new(t, &lnpg)) == NULL ||
  486. X        (r = __bt_new(t, &rnpg)) == NULL)
  487. X        return (NULL);
  488. X    l->pgno = lnpg;
  489. X    r->pgno = rnpg;
  490. X    l->nextpg = r->pgno;
  491. X    r->prevpg = l->pgno;
  492. X    l->prevpg = r->nextpg = P_INVALID;
  493. X    l->lower = r->lower = BTDATAOFF;
  494. X    l->upper = r->upper = t->bt_psize;
  495. X    l->flags = r->flags = h->flags & P_TYPE;
  496. X
  497. X    /* Split the root page. */
  498. X    tp = bt_psplit(t, h, l, r, skip, ilen);
  499. X
  500. X    *lp = l;
  501. X    *rp = r;
  502. X    return (tp);
  503. X}
  504. X
  505. X/*
  506. X * BT_RROOT -- Fix up the recno root page after it has been split.
  507. X *
  508. X * Parameters:
  509. X *    t:    tree
  510. X *    h:    root page
  511. X *    l:    left page
  512. X *    r:    right page
  513. X *
  514. X * Returns:
  515. X *    RET_ERROR, RET_SUCCESS
  516. X */
  517. Xstatic int
  518. Xbt_rroot(t, h, l, r)
  519. X    BTREE *t;
  520. X    PAGE *h, *l, *r;
  521. X{
  522. X    char *dest;
  523. X
  524. X    /* Insert the left and right keys, set the header information. */
  525. X    h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;
  526. X    dest = (char *)h + h->upper;
  527. X    WR_RINTERNAL(dest,
  528. X        l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
  529. X
  530. X    h->linp[1] = h->upper -= NRINTERNAL;
  531. X    dest = (char *)h + h->upper;
  532. X    WR_RINTERNAL(dest,
  533. X        r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
  534. X
  535. X    h->lower = BTDATAOFF + 2 * sizeof(indx_t);
  536. X
  537. X    /* Unpin the root page, set to recno internal page. */
  538. X    h->flags &= ~P_TYPE;
  539. X    h->flags |= P_RINTERNAL;
  540. X    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  541. X
  542. X    return (RET_SUCCESS);
  543. X}
  544. X
  545. X/*
  546. X * BT_BROOT -- Fix up the btree root page after it has been split.
  547. X *
  548. X * Parameters:
  549. X *    t:    tree
  550. X *    h:    root page
  551. X *    l:    left page
  552. X *    r:    right page
  553. X *
  554. X * Returns:
  555. X *    RET_ERROR, RET_SUCCESS
  556. X */
  557. Xstatic int
  558. Xbt_broot(t, h, l, r)
  559. X    BTREE *t;
  560. X    PAGE *h, *l, *r;
  561. X{
  562. X    BINTERNAL *bi;
  563. X    BLEAF *bl;
  564. X    size_t nbytes;
  565. X    char *dest;
  566. X
  567. X    /*
  568. X     * If the root page was a leaf page, change it into an internal page.
  569. X     * We copy the key we split on (but not the key's data, in the case of
  570. X     * a leaf page) to the new root page.
  571. X     *
  572. X     * The btree comparison code guarantees that the left-most key on any
  573. X     * level of the tree is never used, so it doesn't need to be filled in.
  574. X     */
  575. X    nbytes = NBINTERNAL(0);
  576. X    h->linp[0] = h->upper = t->bt_psize - nbytes;
  577. X    dest = (char *)h + h->upper;
  578. X    WR_BINTERNAL(dest, 0, l->pgno, 0);
  579. X
  580. X    switch(h->flags & P_TYPE) {
  581. X    case P_BLEAF:
  582. X        bl = GETBLEAF(r, 0);
  583. X        nbytes = NBINTERNAL(bl->ksize);
  584. X        h->linp[1] = h->upper -= nbytes;
  585. X        dest = (char *)h + h->upper;
  586. X        WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
  587. X        memmove(dest, bl->bytes, bl->ksize);
  588. X
  589. X        /*
  590. X         * If the key is on an overflow page, mark the overflow chain
  591. X         * so it isn't deleted when the leaf copy of the key is deleted.
  592. X         */
  593. X        if (bl->flags & P_BIGKEY &&
  594. X            bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
  595. X            return (RET_ERROR);
  596. X        break;
  597. X    case P_BINTERNAL:
  598. X        bi = GETBINTERNAL(r, 0);
  599. X        nbytes = NBINTERNAL(bi->ksize);
  600. X        h->linp[1] = h->upper -= nbytes;
  601. X        dest = (char *)h + h->upper;
  602. X        memmove(dest, bi, nbytes);
  603. X        ((BINTERNAL *)dest)->pgno = r->pgno;
  604. X        break;
  605. X    default:
  606. X        abort();
  607. X    }
  608. X
  609. X    /* There are two keys on the page. */
  610. X    h->lower = BTDATAOFF + 2 * sizeof(indx_t);
  611. X
  612. X    /* Unpin the root page, set to btree internal page. */
  613. X    h->flags &= ~P_TYPE;
  614. X    h->flags |= P_BINTERNAL;
  615. X    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  616. X
  617. X    return (RET_SUCCESS);
  618. X}
  619. X
  620. X/*
  621. X * BT_PSPLIT -- Do the real work of splitting the page.
  622. X *
  623. X * Parameters:
  624. X *    t:    tree
  625. X *    h:    page to be split
  626. X *    l:    page to put lower half of data
  627. X *    r:    page to put upper half of data
  628. X *    pskip:    pointer to index to leave open
  629. X *    ilen:    insert length
  630. X *
  631. X * Returns:
  632. X *    Pointer to page in which to insert.
  633. X */
  634. Xstatic PAGE *
  635. Xbt_psplit(t, h, l, r, pskip, ilen)
  636. X    BTREE *t;
  637. X    PAGE *h, *l, *r;
  638. X    u_int *pskip;
  639. X    size_t ilen;
  640. X{
  641. X    BINTERNAL *bi;
  642. X    BLEAF *bl;
  643. X    RLEAF *rl;
  644. X    EPGNO *c;
  645. X    PAGE *rval;
  646. X    void *src;
  647. X    indx_t full, half, nxt, off, skip, top, used;
  648. X    size_t nbytes;
  649. X    int bigkeycnt, isbigkey;
  650. X
  651. X    /*
  652. X     * Split the data to the left and right pages.  Leave the skip index
  653. X     * open.  Additionally, make some effort not to split on an overflow
  654. X     * key.  This makes internal page processing faster and can save
  655. X     * space as overflow keys used by internal pages are never deleted.
  656. X     */
  657. X    bigkeycnt = 0;
  658. X    skip = *pskip;
  659. X    full = t->bt_psize - BTDATAOFF;
  660. X    half = full / 2;
  661. X    used = 0;
  662. X    for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
  663. X        if (skip == off) {
  664. X            nbytes = ilen;
  665. X            isbigkey = 0;        /* XXX: not really known. */
  666. X        } else
  667. X            switch (h->flags & P_TYPE) {
  668. X            case P_BINTERNAL:
  669. X                src = bi = GETBINTERNAL(h, nxt);
  670. X                nbytes = NBINTERNAL(bi->ksize);
  671. X                isbigkey = bi->flags & P_BIGKEY;
  672. X                break;
  673. X            case P_BLEAF:
  674. X                src = bl = GETBLEAF(h, nxt);
  675. X                nbytes = NBLEAF(bl);
  676. X                isbigkey = bl->flags & P_BIGKEY;
  677. X                break;
  678. X            case P_RINTERNAL:
  679. X                src = GETRINTERNAL(h, nxt);
  680. X                nbytes = NRINTERNAL;
  681. X                isbigkey = 0;
  682. X                break;
  683. X            case P_RLEAF:
  684. X                src = rl = GETRLEAF(h, nxt);
  685. X                nbytes = NRLEAF(rl);
  686. X                isbigkey = 0;
  687. X                break;
  688. X            default:
  689. X                abort();
  690. X            }
  691. X
  692. X        /*
  693. X         * If the key/data pairs are substantial fractions of the max
  694. X         * possible size for the page, it's possible to get situations
  695. X         * where we decide to try and copy too much onto the left page.
  696. X         * Make sure that doesn't happen.
  697. X         */
  698. X        if (skip <= off && used + nbytes >= full) {
  699. X            --off;
  700. X            break;
  701. X        }
  702. X
  703. X        /* Copy the key/data pair, if not the skipped index. */
  704. X        if (skip != off) {
  705. X            ++nxt;
  706. X
  707. X            l->linp[off] = l->upper -= nbytes;
  708. X            memmove((char *)l + l->upper, src, nbytes);
  709. X        }
  710. X
  711. X        used += nbytes;
  712. X        if (used >= half) {
  713. X            if (!isbigkey || bigkeycnt == 3)
  714. X                break;
  715. X            else
  716. X                ++bigkeycnt;
  717. X        }
  718. X    }
  719. X
  720. X    /*
  721. X     * Off is the last offset that's valid for the left page.
  722. X     * Nxt is the first offset to be placed on the right page.
  723. X     */
  724. X    l->lower += (off + 1) * sizeof(indx_t);
  725. X
  726. X    /*
  727. X     * If splitting the page that the cursor was on, the cursor has to be
  728. X     * adjusted to point to the same record as before the split.  If the
  729. X     * cursor is at or past the skipped slot, the cursor is incremented by
  730. X     * one.  If the cursor is on the right page, it is decremented by the
  731. X     * number of records split to the left page.
  732. X     *
  733. X     * Don't bother checking for the B_SEQINIT flag, the page number will
  734. X     * be P_INVALID.
  735. X     */
  736. X    c = &t->bt_bcursor;
  737. X    if (c->pgno == h->pgno) {
  738. X        if (c->index >= skip)
  739. X            ++c->index;
  740. X        if (c->index < nxt)            /* Left page. */
  741. X            c->pgno = l->pgno;
  742. X        else {                    /* Right page. */
  743. X            c->pgno = r->pgno;
  744. X            c->index -= nxt;
  745. X        }
  746. X    }
  747. X
  748. X    /*
  749. X     * If the skipped index was on the left page, just return that page.
  750. X     * Otherwise, adjust the skip index to reflect the new position on
  751. X     * the right page.
  752. X     */
  753. X    if (skip <= off) {
  754. X        skip = 0;
  755. X        rval = l;
  756. X    } else {
  757. X        rval = r;
  758. X        *pskip -= nxt;
  759. X    }
  760. X
  761. X    for (off = 0; nxt < top; ++off) {
  762. X        if (skip == nxt) {
  763. X            ++off;
  764. X            skip = 0;
  765. X        }
  766. X        switch (h->flags & P_TYPE) {
  767. X        case P_BINTERNAL:
  768. X            src = bi = GETBINTERNAL(h, nxt);
  769. X            nbytes = NBINTERNAL(bi->ksize);
  770. X            break;
  771. X        case P_BLEAF:
  772. X            src = bl = GETBLEAF(h, nxt);
  773. X            nbytes = NBLEAF(bl);
  774. X            break;
  775. X        case P_RINTERNAL:
  776. X            src = GETRINTERNAL(h, nxt);
  777. X            nbytes = NRINTERNAL;
  778. X            break;
  779. X        case P_RLEAF:
  780. X            src = rl = GETRLEAF(h, nxt);
  781. X            nbytes = NRLEAF(rl);
  782. X            break;
  783. X        default:
  784. X            abort();
  785. X        }
  786. X        ++nxt;
  787. X        r->linp[off] = r->upper -= nbytes;
  788. X        memmove((char *)r + r->upper, src, nbytes);
  789. X    }
  790. X    r->lower += off * sizeof(indx_t);
  791. X
  792. X    /* If the key is being appended to the page, adjust the index. */
  793. X    if (skip == top)
  794. X        r->lower += sizeof(indx_t);
  795. X
  796. X    return (rval);
  797. X}
  798. X
  799. X/*
  800. X * BT_PRESERVE -- Mark a chain of pages as used by an internal node.
  801. X *
  802. X * Chains of indirect blocks pointed to by leaf nodes get reclaimed when the
  803. X * record that references them gets deleted.  Chains pointed to by internal
  804. X * pages never get deleted.  This routine marks a chain as pointed to by an
  805. X * internal page.
  806. X *
  807. X * Parameters:
  808. X *    t:    tree
  809. X *    pg:    page number of first page in the chain.
  810. X *
  811. X * Returns:
  812. X *    RET_SUCCESS, RET_ERROR.
  813. X */
  814. Xstatic int
  815. Xbt_preserve(t, pg)
  816. X    BTREE *t;
  817. X    pgno_t pg;
  818. X{
  819. X    PAGE *h;
  820. X
  821. X    if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  822. X        return (RET_ERROR);
  823. X    h->flags |= P_PRESERVE;
  824. X    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  825. X    return (RET_SUCCESS);
  826. X}
  827. X
  828. X/*
  829. X * REC_TOTAL -- Return the number of recno entries below a page.
  830. X *
  831. X * Parameters:
  832. X *    h:    page
  833. X *
  834. X * Returns:
  835. X *    The number of recno entries below a page.
  836. X *
  837. X * XXX
  838. X * These values could be set by the bt_psplit routine.  The problem is that the
  839. X * entry has to be popped off of the stack etc. or the values have to be passed
  840. X * all the way back to bt_split/bt_rroot and it's not very clean.
  841. X */
  842. Xstatic recno_t
  843. Xrec_total(h)
  844. X    PAGE *h;
  845. X{
  846. X    recno_t recs;
  847. X    indx_t nxt, top;
  848. X
  849. X    for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
  850. X        recs += GETRINTERNAL(h, nxt)->nrecs;
  851. X    return (recs);
  852. X}
  853. END_OF_FILE
  854. if test 22158 -ne `wc -c <'btree/bt_split.c'`; then
  855.     echo shar: \"'btree/bt_split.c'\" unpacked with wrong size!
  856. fi
  857. # end of 'btree/bt_split.c'
  858. fi
  859. if test -f 'doc/btree.3.ps' -a "${1}" != "-c" ; then 
  860.   echo shar: Will not clobber existing file \"'doc/btree.3.ps'\"
  861. else
  862. echo shar: Extracting \"'doc/btree.3.ps'\" \(16545 characters\)
  863. sed "s/^X//" >'doc/btree.3.ps' <<'END_OF_FILE'
  864. X%!PS-Adobe-3.0
  865. X%%Creator: groff version 1.08
  866. X%%DocumentNeededResources: font Times-Roman
  867. X%%+ font Times-Bold
  868. X%%+ font Times-Italic
  869. X%%DocumentSuppliedResources: procset grops 1.08 0
  870. X%%Pages: 2
  871. X%%PageOrder: Ascend
  872. X%%Orientation: Portrait
  873. X%%EndComments
  874. X%%BeginProlog
  875. X%%BeginResource: procset grops 1.08 0
  876. X/setpacking where{
  877. Xpop
  878. Xcurrentpacking
  879. Xtrue setpacking
  880. X}if
  881. X/grops 120 dict dup begin
  882. X/SC 32 def
  883. X/A/show load def
  884. X/B{0 SC 3 -1 roll widthshow}bind def
  885. X/C{0 exch ashow}bind def
  886. X/D{0 exch 0 SC 5 2 roll awidthshow}bind def
  887. X/E{0 rmoveto show}bind def
  888. X/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
  889. X/G{0 rmoveto 0 exch ashow}bind def
  890. X/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  891. X/I{0 exch rmoveto show}bind def
  892. X/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
  893. X/K{0 exch rmoveto 0 exch ashow}bind def
  894. X/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  895. X/M{rmoveto show}bind def
  896. X/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
  897. X/O{rmoveto 0 exch ashow}bind def
  898. X/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  899. X/Q{moveto show}bind def
  900. X/R{moveto 0 SC 3 -1 roll widthshow}bind def
  901. X/S{moveto 0 exch ashow}bind def
  902. X/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  903. X/SF{
  904. Xfindfont exch
  905. X[exch dup 0 exch 0 exch neg 0 0]makefont
  906. Xdup setfont
  907. X[exch/setfont cvx]cvx bind def
  908. X}bind def
  909. X/MF{
  910. Xfindfont
  911. X[5 2 roll
  912. X0 3 1 roll 
  913. Xneg 0 0]makefont
  914. Xdup setfont
  915. X[exch/setfont cvx]cvx bind def
  916. X}bind def
  917. X/level0 0 def
  918. X/RES 0 def
  919. X/PL 0 def
  920. X/LS 0 def
  921. X/PLG{
  922. Xgsave newpath clippath pathbbox grestore
  923. Xexch pop add exch pop
  924. X}bind def
  925. X/BP{
  926. X/level0 save def
  927. X1 setlinecap
  928. X1 setlinejoin
  929. X72 RES div dup scale
  930. XLS{
  931. X90 rotate
  932. X}{
  933. X0 PL translate
  934. X}ifelse
  935. X1 -1 scale
  936. X}bind def
  937. X/EP{
  938. Xlevel0 restore
  939. Xshowpage
  940. X}bind def
  941. X/DA{
  942. Xnewpath arcn stroke
  943. X}bind def
  944. X/SN{
  945. Xtransform
  946. X.25 sub exch .25 sub exch
  947. Xround .25 add exch round .25 add exch
  948. Xitransform
  949. X}bind def
  950. X/DL{
  951. XSN
  952. Xmoveto
  953. XSN
  954. Xlineto stroke
  955. X}bind def
  956. X/DC{
  957. Xnewpath 0 360 arc closepath
  958. X}bind def
  959. X/TM matrix def
  960. X/DE{
  961. XTM currentmatrix pop
  962. Xtranslate scale newpath 0 0 .5 0 360 arc closepath
  963. XTM setmatrix
  964. X}bind def
  965. X/RC/rcurveto load def
  966. X/RL/rlineto load def
  967. X/ST/stroke load def
  968. X/MT/moveto load def
  969. X/CL/closepath load def
  970. X/FL{
  971. Xcurrentgray exch setgray fill setgray
  972. X}bind def
  973. X/BL/fill load def
  974. X/LW/setlinewidth load def
  975. X/RE{
  976. Xfindfont
  977. Xdup maxlength 1 index/FontName known not{1 add}if dict begin
  978. X{
  979. X1 index/FID ne{def}{pop pop}ifelse
  980. X}forall
  981. X/Encoding exch def
  982. Xdup/FontName exch def
  983. Xcurrentdict end definefont pop
  984. X}bind def
  985. X/DEFS 0 def
  986. X/EBEGIN{
  987. Xmoveto
  988. XDEFS begin
  989. X}bind def
  990. X/EEND/end load def
  991. X/CNT 0 def
  992. X/level1 0 def
  993. X/PBEGIN{
  994. X/level1 save def
  995. Xtranslate
  996. Xdiv 3 1 roll div exch scale
  997. Xneg exch neg exch translate
  998. X0 setgray
  999. X0 setlinecap
  1000. X1 setlinewidth
  1001. X0 setlinejoin
  1002. X10 setmiterlimit
  1003. X[]0 setdash
  1004. X/setstrokeadjust where{
  1005. Xpop
  1006. Xfalse setstrokeadjust
  1007. X}if
  1008. X/setoverprint where{
  1009. Xpop
  1010. Xfalse setoverprint
  1011. X}if
  1012. Xnewpath
  1013. X/CNT countdictstack def
  1014. Xuserdict begin
  1015. X/showpage{}def
  1016. X}bind def
  1017. X/PEND{
  1018. Xclear
  1019. Xcountdictstack CNT sub{end}repeat
  1020. Xlevel1 restore
  1021. X}bind def
  1022. Xend def
  1023. X/setpacking where{
  1024. Xpop
  1025. Xsetpacking
  1026. X}if
  1027. X%%EndResource
  1028. X%%IncludeResource: font Times-Roman
  1029. X%%IncludeResource: font Times-Bold
  1030. X%%IncludeResource: font Times-Italic
  1031. Xgrops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
  1032. X792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
  1033. X/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
  1034. X/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
  1035. X/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
  1036. X/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
  1037. X/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
  1038. X/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
  1039. X/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
  1040. X/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
  1041. X/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
  1042. X/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
  1043. X/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
  1044. X/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
  1045. X/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
  1046. X/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
  1047. X/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
  1048. X/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
  1049. X/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
  1050. X/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
  1051. X/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
  1052. X/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
  1053. X/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
  1054. X/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
  1055. X/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
  1056. X/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
  1057. X/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
  1058. X%%EndProlog
  1059. X%%Page: 1 1
  1060. X%%BeginPageSetup
  1061. XBP
  1062. X%%EndPageSetup
  1063. X/F0 10/Times-Roman@0 SF 378.84(BTREE\(3\) BTREE\(3\))72 48 R/F1 9/Times-Bold@0
  1064. XSF -.18(NA)72 84 S(ME).18 E F0(btree \255 btree database access method)108 96 Q
  1065. XF1(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(#include <sys/types.h>)108 124.8 Q
  1066. X(#include <db)108 136.8 Q(.h>)-.4 E F1(DESCRIPTION)72 153.6 Q F0 .198
  1067. X(The routine)108 165.6 R/F3 10/Times-Italic@0 SF(dbopen)2.698 E F0 .198
  1068. X(is the library interf)2.698 F .198(ace to database \214les.)-.1 F .198
  1069. X(One of the supported \214le formats is btree \214les.)5.198 F .974
  1070. X(The general description of the database access methods is in)108 177.6 R F3
  1071. X(dbopen)3.475 E F0 .975(\(3\), this manual page describes only).24 F
  1072. X(the btree speci\214c information.)108 189.6 Q(The btree data structure is a s\
  1073. Xorted, balanced tree structure storing associated k)108 206.4 Q -.15(ey)-.1 G
  1074. X(/data pairs.).15 E .504(The btree access method speci\214c data structure pro)
  1075. X108 223.2 R .504(vided to)-.15 F F3(dbopen)3.004 E F0 .503
  1076. X(is de\214ned in the <db)3.003 F .503(.h> include \214le as)-.4 F(follo)108
  1077. X235.2 Q(ws:)-.25 E(typedef struct {)108 252 Q(u_long \215ags;)144 264 Q
  1078. X(u_int cachesize;)144 276 Q(inde)144 288 Q(x_t psize;)-.15 E(int lorder;)144
  1079. X300 Q(int mink)144 312 Q -.15(ey)-.1 G(page;).15 E
  1080. X(int \(*compare\)\(const DBT *k)144 324 Q -.15(ey)-.1 G(1, const DBT *k).15 E
  1081. X-.15(ey)-.1 G(2\);).15 E(int \(*pre\214x\)\(const DBT *k)144 336 Q -.15(ey)-.1
  1082. XG(1, const DBT *k).15 E -.15(ey)-.1 G(2\);).15 E 2.5(}B)108 348 S(TREEINFO;)
  1083. X121.97 348 Q(The elements of this structure are as follo)108 364.8 Q(ws:)-.25 E
  1084. X14.61(\215ags The)108 381.6 R(\215ag v)2.5 E(alue is speci\214ed by)-.25 E F3
  1085. X(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)313.2 381.6 S(he follo)321.81
  1086. X381.6 Q(wing v)-.25 E(alues:)-.25 E(R_DUP)144 398.4 Q 1.296(Permit duplicate k)
  1087. X180 410.4 R -.15(ey)-.1 G 3.796(si).15 G 3.796(nt)275.578 410.4 S 1.296
  1088. X(he tree, i.e. permit insertion if the k)287.154 410.4 R 1.596 -.15(ey t)-.1 H
  1089. X3.796(ob).15 G 3.796(ei)466.878 410.4 S 1.296(nserted already)477.894 410.4 R
  1090. X-.15(ex)180 422.4 S 1.935(ists in the tree.).15 F 1.935(The def)6.935 F 1.935
  1091. X(ault beha)-.1 F(vior)-.2 E 4.435(,a)-.4 G 4.435(sd)358.215 422.4 S 1.935
  1092. X(escribed in)371.54 422.4 R F3(dbopen)4.435 E F0 1.935(\(3\), is to o).24 F
  1093. X-.15(ve)-.15 G 1.935(rwrite a).15 F .148(matching k)180 434.4 R .448 -.15(ey w)
  1094. X-.1 H .148(hen inserting a ne).15 F 2.649(wk)-.25 G .449 -.15(ey o)329.709
  1095. X434.4 T 2.649(rt).15 G 2.649(of)355.407 434.4 S .149(ail if the R_NOO)366.286
  1096. X434.4 R(VER)-.5 E .149(WRITE \215ag is speci-)-.55 F 5.972(\214ed. The)180
  1097. X446.4 R 3.472(R_DUP \215ag is o)5.972 F -.15(ve)-.15 G 3.472
  1098. X(rridden by the R_NOO).15 F(VER)-.5 E 3.471(WRITE \215ag, and if the)-.55 F
  1099. X(R_NOO)180 458.4 Q(VER)-.5 E .781
  1100. X(WRITE \215ag is speci\214ed, attempts to insert duplicate k)-.55 F -.15(ey)-.1
  1101. XG 3.282(si).15 G .782(nto the tree will)474.604 458.4 R -.1(fa)180 470.4 S(il.)
  1102. X.1 E 1.13(If the database contains duplicate k)180 487.2 R -.15(ey)-.1 G 1.129
  1103. X(s, the order of retrie).15 F -.25(va)-.25 G 3.629(lo).25 G 3.629(fk)439.644
  1104. X487.2 S -.15(ey)451.503 487.2 S 1.129(/data pairs is unde-).15 F .837
  1105. X(\214ned if the)180 499.2 R F3 -.1(ge)3.337 G(t).1 E F0 .837
  1106. X(routine is used, ho)3.337 F(we)-.25 E -.15(ve)-.25 G -.4(r,).15 G F3(seq)3.737
  1107. XE F0 .838(routine calls with the R_CURSOR \215ag set)3.337 F(will al)180 511.2
  1108. XQ -.1(wa)-.1 G(ys return the logical `).1 E(`\214rst')-.74 E 2.5('o)-.74 G 2.5
  1109. X(fa)333.85 511.2 S .3 -.15(ny g)344.12 511.2 T(roup of duplicate k).15 E -.15
  1110. X(ey)-.1 G(s.).15 E(cachesize)108 528 Q 3.056(As)144 540 S .556
  1111. X(uggested maximum size \(in bytes\) of the memory cache.)158.166 540 R .555
  1112. X(This v)5.556 F .555(alue is)-.25 F F2(only)3.055 E F0(advisory)3.055 E 3.055
  1113. X(,a)-.65 G .555(nd the)514.725 540 R .759
  1114. X(access method will allocate more memory rather than f)144 552 R 3.259
  1115. X(ail. Since)-.1 F -2.15 -.25(ev e)3.259 H .76(ry search e).25 F .76
  1116. X(xamines the root)-.15 F .055
  1117. X(page of the tree, caching the most recently used pages substantially impro)144
  1118. X564 R -.15(ve)-.15 G 2.554(sa).15 G .054(ccess time.)459.578 564 R .054
  1119. X(In addi-)5.054 F .661(tion, ph)144 576 R .662(ysical writes are delayed as lo\
  1120. Xng as possible, so a moderate cache can reduce the number)-.05 F .601
  1121. X(of I/O operations signi\214cantly)144 588 R 5.601(.O)-.65 G -.15(bv)280.744
  1122. X588 S(iously).15 E 3.101(,u)-.65 G .601(sing a cache increases \(b)324.995 588
  1123. XR .6(ut only increases\) the lik)-.2 F(eli-)-.1 E .19(hood of corruption or lo\
  1124. Xst data if the system crashes while a tree is being modi\214ed.)144 600 R(If)
  1125. X5.191 E F3(cac)2.691 E(hesize)-.15 E F0(is)2.691 E 2.5(0\()144 612 S
  1126. X(no size is speci\214ed\) a def)154.83 612 Q(ault cache is used.)-.1 E 12.95
  1127. X(psize P)108 628.8 R .45
  1128. X(age size is the size \(in bytes\) of the pages used for nodes in the tree.)
  1129. X-.15 F .449(The minimum page size is)5.449 F .442
  1130. X(512 bytes and the maximum page size is 64K.)144 640.8 R(If)5.442 E F3(psize)
  1131. X2.942 E F0 .442(is 0 \(no page size is speci\214ed\) a page size)2.942 F
  1132. X(is chosen based on the underlying \214le system I/O block size.)144 652.8 Q
  1133. X9.62(lorder The)108 669.6 R 1.597(byte order for inte)4.097 F 1.596
  1134. X(gers in the stored database metadata.)-.15 F 1.596
  1135. X(The number should represent the)6.596 F .688(order as an inte)144 681.6 R .689
  1136. X(ger; for e)-.15 F .689(xample, big endian order w)-.15 F .689
  1137. X(ould be the number 4,321.)-.1 F(If)5.689 E F3(lor)3.189 E(der)-.37 E F0 .689
  1138. X(is 0 \(no)3.189 F(order is speci\214ed\) the current host order is used.)144
  1139. X693.6 Q(1)535 768 Q EP
  1140. X%%Page: 2 2
  1141. X%%BeginPageSetup
  1142. XBP
  1143. X%%EndPageSetup
  1144. X/F0 10/Times-Roman@0 SF 378.84(BTREE\(3\) BTREE\(3\))72 48 R(mink)108 84 Q -.15
  1145. X(ey)-.1 G(page).15 E 1.423(The minimum number of k)144 96 R -.15(ey)-.1 G 3.923
  1146. X(sw).15 G 1.422(hich will be stored on an)282.245 96 R 3.922(ys)-.15 G 1.422
  1147. X(ingle page.)400.618 96 R 1.422(This v)6.422 F 1.422(alue is used to)-.25 F
  1148. X.257(determine which k)144 108 R -.15(ey)-.1 G 2.757(sw).15 G .257
  1149. X(ill be stored on o)242.001 108 R -.15(ve)-.15 G(r\215o).15 E 2.757(wp)-.25 G
  1150. X.257(ages, i.e. if a k)348.006 108 R .558 -.15(ey o)-.1 H 2.758(rd).15 G .258
  1151. X(ata item is longer than the)435.11 108 R 1.102(pagesize di)144 120 R 1.102
  1152. X(vided by the mink)-.25 F -.15(ey)-.1 G 1.102(page v).15 F 1.102
  1153. X(alue, it will be stored on o)-.25 F -.15(ve)-.15 G(r\215o).15 E 3.602(wp)-.25
  1154. XG 1.102(ages instead of in the)451.164 120 R(page itself.)144 132 Q(If)5 E/F1
  1155. X10/Times-Italic@0 SF(mink)2.5 E -.3(ey)-.1 G(pa).3 E -.1(ge)-.1 G F0
  1156. X(is 0 \(no minimum number of k)2.6 E -.15(ey)-.1 G 2.5(si).15 G 2.5(ss)392.84
  1157. X132 S(peci\214ed\) a v)403.12 132 Q(alue of 2 is used.)-.25 E(compare)108 148.8
  1158. XQ .751(Compare is the k)144 160.8 R 1.051 -.15(ey c)-.1 H .751
  1159. X(omparison function.).15 F .751(It must return an inte)5.751 F .752
  1160. X(ger less than, equal to, or greater)-.15 F .913(than zero if the \214rst k)144
  1161. X172.8 R 1.213 -.15(ey a)-.1 H -.18(rg).15 G .913
  1162. X(ument is considered to be respecti).18 F -.15(ve)-.25 G .913
  1163. X(ly less than, equal to, or greater).15 F .352(than the second k)144 184.8 R
  1164. X.652 -.15(ey a)-.1 H -.18(rg).15 G 2.852(ument. The).18 F .353
  1165. X(same comparison function must be used on a gi)2.852 F -.15(ve)-.25 G 2.853(nt)
  1166. X.15 G .353(ree e)503.127 184.8 R -.15(ve)-.25 G(ry).15 E .817
  1167. X(time it is opened.)144 196.8 R(If)5.817 E F1(compar)3.317 E(e)-.37 E F0 .817
  1168. X(is NULL \(no comparison function is speci\214ed\), the k)3.317 F -.15(ey)-.1 G
  1169. X3.316(sa).15 G .816(re com-)508.364 196.8 R(pared le)144 208.8 Q(xically)-.15 E
  1170. X2.5(,w)-.65 G(ith shorter k)214.57 208.8 Q -.15(ey)-.1 G 2.5(sc).15 G
  1171. X(onsidered less than longer k)282.92 208.8 Q -.15(ey)-.1 G(s.).15 E 10.17
  1172. X(pre\214x Pre\214x)108 225.6 R .291(is the pre\214x comparison function.)2.791
  1173. XF .292(If speci\214ed, this routine must return the number of bytes)5.291 F
  1174. X.937(of the second k)144 237.6 R 1.237 -.15(ey a)-.1 H -.18(rg).15 G .937
  1175. X(ument which are necessary to determine that it is greater than the \214rst k)
  1176. X.18 F -.15(ey)-.1 G(ar)144 249.6 Q 3.477(gument. If)-.18 F .977(the k)3.477 F
  1177. X-.15(ey)-.1 G 3.477(sa).15 G .977(re equal, the k)241.898 249.6 R 1.277 -.15
  1178. X(ey l)-.1 H .978(ength should be returned.).15 F .978
  1179. X(Note, the usefulness of this)5.978 F .558(routine is v)144 261.6 R .558
  1180. X(ery data dependent, b)-.15 F .558
  1181. X(ut, in some data sets can produce signi\214cantly reduced tree sizes)-.2 F
  1182. X.354(and search times.)144 273.6 R(If)5.354 E F1(pr)2.854 E(e\214x)-.37 E F0
  1183. X.354(is NULL \(no pre\214x function is speci\214ed\),)2.854 F/F2 10
  1184. X/Times-Bold@0 SF(and)2.854 E F0 .354(no comparison function)2.854 F .193
  1185. X(is speci\214ed, a def)144 285.6 R .193(ault le)-.1 F .193
  1186. X(xical comparison routine is used.)-.15 F(If)5.192 E F1(pr)2.692 E(e\214x)-.37
  1187. XE F0 .192(is NULL and a comparison rou-)2.692 F
  1188. X(tine is speci\214ed, no pre\214x comparison is done.)144 297.6 Q .79
  1189. X(If the \214le already e)108 314.4 R .79(xists \(and the O_TR)-.15 F .79
  1190. X(UNC \215ag is not speci\214ed\), the v)-.4 F .79
  1191. X(alues speci\214ed for the parameters)-.25 F
  1192. X(\215ags, lorder and psize are ignored in f)108 326.4 Q -.2(avo)-.1 G 2.5(ro).2
  1193. XG 2.5(ft)284.4 326.4 S(he v)293.01 326.4 Q(alues used when the tree w)-.25 E
  1194. X(as created.)-.1 E -.15(Fo)108 343.2 S(rw).15 E
  1195. X(ard sequential scans of a tree are from the least k)-.1 E .3 -.15(ey t)-.1 H
  1196. X2.5(ot).15 G(he greatest.)348.55 343.2 Q 1.043(Space freed up by deleting k)108
  1197. X360 R -.15(ey)-.1 G 1.043(/data pairs from the tree is ne).15 F -.15(ve)-.25 G
  1198. X3.543(rr).15 G 1.043(eclaimed, although it is normally made)378.686 360 R -.2
  1199. X(av)108 372 S 1.394(ailable for reuse.)-.05 F 1.394
  1200. X(This means that the btree storage structure is gro)6.394 F(w-only)-.25 E 6.395
  1201. X(.T)-.65 G 1.395(he only solutions are to)441.09 372 R -.2(avo)108 384 S(id e)
  1202. X.2 E(xcessi)-.15 E .3 -.15(ve d)-.25 H
  1203. X(eletions, or to create a fresh tree periodically from a scan of an e).15 E
  1204. X(xisting one.)-.15 E .344(Searches, insertions, and deletions in a btree will \
  1205. Xall complete in O lg base N where base is the a)108 400.8 R -.15(ve)-.2 G .343
  1206. X(rage \214ll).15 F -.1(fa)108 412.8 S(ctor).1 E 5.798(.O)-.55 G .799
  1207. X(ften, inserting ordered data into btrees results in a lo)146.188 412.8 R 3.299
  1208. X<778c>-.25 G .799(ll f)377.505 412.8 R(actor)-.1 E 5.799(.T)-.55 G .799
  1209. X(his implementation has been)423.443 412.8 R(modi\214ed to mak)108 424.8 Q 2.5
  1210. X(eo)-.1 G(rdered insertion the best case, resulting in a much better than norm\
  1211. Xal page \214ll f)185.4 424.8 Q(actor)-.1 E(.)-.55 E/F3 9/Times-Bold@0 SF
  1212. X(SEE ALSO)72 441.6 Q F1(dbopen)108 453.6 Q F0(\(3\),).24 E F1(hash)2.5 E F0
  1213. X(\(3\),).28 E F1(mpool)2.5 E F0(\(3\),).51 E F1 -.37(re)2.5 G(cno).37 E F0
  1214. X(\(3\)).18 E F1(The Ubiquitous B-tr)108 477.6 Q(ee)-.37 E F0 2.5(,D).18 G
  1215. X(ouglas Comer)209.47 477.6 Q 2.5(,A)-.4 G(CM Comput. Surv)276.72 477.6 Q 2.5
  1216. X(.1)-.65 G(1, 2 \(June 1979\), 121-138.)360.25 477.6 Q F1(Pr)108 501.6 Q 1.588
  1217. X(e\214x B-tr)-.37 F(ees)-.37 E F0 4.088(,B).27 G 1.587(ayer and Unterauer)
  1218. X177.636 501.6 R 4.087(,A)-.4 G 1.587(CM T)270.447 501.6 R 1.587
  1219. X(ransactions on Database Systems, V)-.35 F 1.587(ol. 2, 1 \(March 1977\),)-1.29
  1220. XF(11-26.)108 513.6 Q F1(The Art of Computer Pr)108 537.6 Q -.1(og)-.45 G -.15
  1221. X(ra).1 G(mming V).15 E(ol. 3: Sorting and Sear)-1.11 E -.15(ch)-.37 G(ing).15 E
  1222. XF0 2.5(,D).22 G(.E. Knuth, 1968, pp 471-480.)382 537.6 Q F3 -.09(BU)72 554.4 S
  1223. X(GS).09 E F0(Only big and little endian byte order is supported.)108 566.4 Q(2)
  1224. X535 768 Q EP
  1225. X%%Trailer
  1226. Xend
  1227. X%%EOF
  1228. END_OF_FILE
  1229. if test 16545 -ne `wc -c <'doc/btree.3.ps'`; then
  1230.     echo shar: \"'doc/btree.3.ps'\" unpacked with wrong size!
  1231. fi
  1232. # end of 'doc/btree.3.ps'
  1233. fi
  1234. if test -f 'hash/hash_bigkey.c' -a "${1}" != "-c" ; then 
  1235.   echo shar: Will not clobber existing file \"'hash/hash_bigkey.c'\"
  1236. else
  1237. echo shar: Extracting \"'hash/hash_bigkey.c'\" \(16249 characters\)
  1238. sed "s/^X//" >'hash/hash_bigkey.c' <<'END_OF_FILE'
  1239. X/*-
  1240. X * Copyright (c) 1990, 1993
  1241. X *    The Regents of the University of California.  All rights reserved.
  1242. X *
  1243. X * This code is derived from software contributed to Berkeley by
  1244. X * Margo Seltzer.
  1245. X *
  1246. X * Redistribution and use in source and binary forms, with or without
  1247. X * modification, are permitted provided that the following conditions
  1248. X * are met:
  1249. X * 1. Redistributions of source code must retain the above copyright
  1250. X *    notice, this list of conditions and the following disclaimer.
  1251. X * 2. Redistributions in binary form must reproduce the above copyright
  1252. X *    notice, this list of conditions and the following disclaimer in the
  1253. X *    documentation and/or other materials provided with the distribution.
  1254. X * 3. All advertising materials mentioning features or use of this software
  1255. X *    must display the following acknowledgement:
  1256. X *    This product includes software developed by the University of
  1257. X *    California, Berkeley and its contributors.
  1258. X * 4. Neither the name of the University nor the names of its contributors
  1259. X *    may be used to endorse or promote products derived from this software
  1260. X *    without specific prior written permission.
  1261. X *
  1262. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1263. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1264. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1265. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1266. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1267. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1268. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1269. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1270. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1271. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1272. X * SUCH DAMAGE.
  1273. X */
  1274. X
  1275. X#if defined(LIBC_SCCS) && !defined(lint)
  1276. Xstatic char sccsid[] = "@(#)hash_bigkey.c    8.1 (Berkeley) 6/4/93";
  1277. X#endif /* LIBC_SCCS and not lint */
  1278. X
  1279. X/*
  1280. X * PACKAGE: hash
  1281. X * DESCRIPTION:
  1282. X *    Big key/data handling for the hashing package.
  1283. X *
  1284. X * ROUTINES:
  1285. X * External
  1286. X *    __big_keydata
  1287. X *    __big_split
  1288. X *    __big_insert
  1289. X *    __big_return
  1290. X *    __big_delete
  1291. X *    __find_last_page
  1292. X * Internal
  1293. X *    collect_key
  1294. X *    collect_data
  1295. X */
  1296. X
  1297. X#include <sys/param.h>
  1298. X
  1299. X#include <errno.h>
  1300. X#include <stdio.h>
  1301. X#include <stdlib.h>
  1302. X#include <string.h>
  1303. X
  1304. X#ifdef DEBUG
  1305. X#include <assert.h>
  1306. X#endif
  1307. X
  1308. X#include <db.h>
  1309. X#include "hash.h"
  1310. X#include "page.h"
  1311. X#include "extern.h"
  1312. X
  1313. Xstatic int collect_key __P((HTAB *, BUFHEAD *, int, DBT *, int));
  1314. Xstatic int collect_data __P((HTAB *, BUFHEAD *, int, int));
  1315. X
  1316. X/*
  1317. X * Big_insert
  1318. X *
  1319. X * You need to do an insert and the key/data pair is too big
  1320. X *
  1321. X * Returns:
  1322. X * 0 ==> OK
  1323. X *-1 ==> ERROR
  1324. X */
  1325. Xextern int
  1326. X__big_insert(hashp, bufp, key, val)
  1327. X    HTAB *hashp;
  1328. X    BUFHEAD *bufp;
  1329. X    const DBT *key, *val;
  1330. X{
  1331. X    register u_short *p;
  1332. X    int key_size, n, val_size;
  1333. X    u_short space, move_bytes, off;
  1334. X    char *cp, *key_data, *val_data;
  1335. X
  1336. X    cp = bufp->page;        /* Character pointer of p. */
  1337. X    p = (u_short *)cp;
  1338. X
  1339. X    key_data = (char *)key->data;
  1340. X    key_size = key->size;
  1341. X    val_data = (char *)val->data;
  1342. X    val_size = val->size;
  1343. X
  1344. X    /* First move the Key */
  1345. X    for (space = FREESPACE(p) - BIGOVERHEAD; key_size;
  1346. X        space = FREESPACE(p) - BIGOVERHEAD) {
  1347. X        move_bytes = MIN(space, key_size);
  1348. X        off = OFFSET(p) - move_bytes;
  1349. X        memmove(cp + off, key_data, move_bytes);
  1350. X        key_size -= move_bytes;
  1351. X        key_data += move_bytes;
  1352. X        n = p[0];
  1353. X        p[++n] = off;
  1354. X        p[0] = ++n;
  1355. X        FREESPACE(p) = off - PAGE_META(n);
  1356. X        OFFSET(p) = off;
  1357. X        p[n] = PARTIAL_KEY;
  1358. X        bufp = __add_ovflpage(hashp, bufp);
  1359. X        if (!bufp)
  1360. X            return (-1);
  1361. X        n = p[0];
  1362. X        if (!key_size)
  1363. X            if (FREESPACE(p)) {
  1364. X                move_bytes = MIN(FREESPACE(p), val_size);
  1365. X                off = OFFSET(p) - move_bytes;
  1366. X                p[n] = off;
  1367. X                memmove(cp + off, val_data, move_bytes);
  1368. X                val_data += move_bytes;
  1369. X                val_size -= move_bytes;
  1370. X                p[n - 2] = FULL_KEY_DATA;
  1371. X                FREESPACE(p) = FREESPACE(p) - move_bytes;
  1372. X                OFFSET(p) = off;
  1373. X            } else
  1374. X                p[n - 2] = FULL_KEY;
  1375. X        p = (u_short *)bufp->page;
  1376. X        cp = bufp->page;
  1377. X        bufp->flags |= BUF_MOD;
  1378. X    }
  1379. X
  1380. X    /* Now move the data */
  1381. X    for (space = FREESPACE(p) - BIGOVERHEAD; val_size;
  1382. X        space = FREESPACE(p) - BIGOVERHEAD) {
  1383. X        move_bytes = MIN(space, val_size);
  1384. X        /*
  1385. X         * Here's the hack to make sure that if the data ends on the
  1386. X         * same page as the key ends, FREESPACE is at least one.
  1387. X         */
  1388. X        if (space == val_size && val_size == val->size)
  1389. X            move_bytes--;
  1390. X        off = OFFSET(p) - move_bytes;
  1391. X        memmove(cp + off, val_data, move_bytes);
  1392. X        val_size -= move_bytes;
  1393. X        val_data += move_bytes;
  1394. X        n = p[0];
  1395. X        p[++n] = off;
  1396. X        p[0] = ++n;
  1397. X        FREESPACE(p) = off - PAGE_META(n);
  1398. X        OFFSET(p) = off;
  1399. X        if (val_size) {
  1400. X            p[n] = FULL_KEY;
  1401. X            bufp = __add_ovflpage(hashp, bufp);
  1402. X            if (!bufp)
  1403. X                return (-1);
  1404. X            cp = bufp->page;
  1405. X            p = (u_short *)cp;
  1406. X        } else
  1407. X            p[n] = FULL_KEY_DATA;
  1408. X        bufp->flags |= BUF_MOD;
  1409. X    }
  1410. X    return (0);
  1411. X}
  1412. X
  1413. X/*
  1414. X * Called when bufp's page  contains a partial key (index should be 1)
  1415. X *
  1416. X * All pages in the big key/data pair except bufp are freed.  We cannot
  1417. X * free bufp because the page pointing to it is lost and we can't get rid
  1418. X * of its pointer.
  1419. X *
  1420. X * Returns:
  1421. X * 0 => OK
  1422. X *-1 => ERROR
  1423. X */
  1424. Xextern int
  1425. X__big_delete(hashp, bufp)
  1426. X    HTAB *hashp;
  1427. X    BUFHEAD *bufp;
  1428. X{
  1429. X    register BUFHEAD *last_bfp, *rbufp;
  1430. X    u_short *bp, pageno;
  1431. X    int key_done, n;
  1432. X
  1433. X    rbufp = bufp;
  1434. X    last_bfp = NULL;
  1435. X    bp = (u_short *)bufp->page;
  1436. X    pageno = 0;
  1437. X    key_done = 0;
  1438. X
  1439. X    while (!key_done || (bp[2] != FULL_KEY_DATA)) {
  1440. X        if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA)
  1441. X            key_done = 1;
  1442. X
  1443. X        /*
  1444. X         * If there is freespace left on a FULL_KEY_DATA page, then
  1445. X         * the data is short and fits entirely on this page, and this
  1446. X         * is the last page.
  1447. X         */
  1448. X        if (bp[2] == FULL_KEY_DATA && FREESPACE(bp))
  1449. X            break;
  1450. X        pageno = bp[bp[0] - 1];
  1451. X        rbufp->flags |= BUF_MOD;
  1452. X        rbufp = __get_buf(hashp, pageno, rbufp, 0);
  1453. X        if (last_bfp)
  1454. X            __free_ovflpage(hashp, last_bfp);
  1455. X        last_bfp = rbufp;
  1456. X        if (!rbufp)
  1457. X            return (-1);        /* Error. */
  1458. X        bp = (u_short *)rbufp->page;
  1459. X    }
  1460. X
  1461. X    /*
  1462. X     * If we get here then rbufp points to the last page of the big
  1463. X     * key/data pair.  Bufp points to the first one -- it should now be
  1464. X     * empty pointing to the next page after this pair.  Can't free it
  1465. X     * because we don't have the page pointing to it.
  1466. X     */
  1467. X
  1468. X    /* This is information from the last page of the pair. */
  1469. X    n = bp[0];
  1470. X    pageno = bp[n - 1];
  1471. X
  1472. X    /* Now, bp is the first page of the pair. */
  1473. X    bp = (u_short *)bufp->page;
  1474. X    if (n > 2) {
  1475. X        /* There is an overflow page. */
  1476. X        bp[1] = pageno;
  1477. X        bp[2] = OVFLPAGE;
  1478. X        bufp->ovfl = rbufp->ovfl;
  1479. X    } else
  1480. X        /* This is the last page. */
  1481. X        bufp->ovfl = NULL;
  1482. X    n -= 2;
  1483. X    bp[0] = n;
  1484. X    FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
  1485. X    OFFSET(bp) = hashp->BSIZE - 1;
  1486. X
  1487. X    bufp->flags |= BUF_MOD;
  1488. X    if (rbufp)
  1489. X        __free_ovflpage(hashp, rbufp);
  1490. X    if (last_bfp != rbufp)
  1491. X        __free_ovflpage(hashp, last_bfp);
  1492. X
  1493. X    hashp->NKEYS--;
  1494. X    return (0);
  1495. X}
  1496. X/*
  1497. X * Returns:
  1498. X *  0 = key not found
  1499. X * -1 = get next overflow page
  1500. X * -2 means key not found and this is big key/data
  1501. X * -3 error
  1502. X */
  1503. Xextern int
  1504. X__find_bigpair(hashp, bufp, ndx, key, size)
  1505. X    HTAB *hashp;
  1506. X    BUFHEAD *bufp;
  1507. X    int ndx;
  1508. X    char *key;
  1509. X    int size;
  1510. X{
  1511. X    register u_short *bp;
  1512. X    register char *p;
  1513. X    int ksize;
  1514. X    u_short bytes;
  1515. X    char *kkey;
  1516. X
  1517. X    bp = (u_short *)bufp->page;
  1518. X    p = bufp->page;
  1519. X    ksize = size;
  1520. X    kkey = key;
  1521. X
  1522. X    for (bytes = hashp->BSIZE - bp[ndx];
  1523. X        bytes <= size && bp[ndx + 1] == PARTIAL_KEY;
  1524. X        bytes = hashp->BSIZE - bp[ndx]) {
  1525. X        if (memcmp(p + bp[ndx], kkey, bytes))
  1526. X            return (-2);
  1527. X        kkey += bytes;
  1528. X        ksize -= bytes;
  1529. X        bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0);
  1530. X        if (!bufp)
  1531. X            return (-3);
  1532. X        p = bufp->page;
  1533. X        bp = (u_short *)p;
  1534. X        ndx = 1;
  1535. X    }
  1536. X
  1537. X    if (bytes != ksize || memcmp(p + bp[ndx], kkey, bytes)) {
  1538. X#ifdef HASH_STATISTICS
  1539. X        ++hash_collisions;
  1540. X#endif
  1541. X        return (-2);
  1542. X    } else
  1543. X        return (ndx);
  1544. X}
  1545. X
  1546. X/*
  1547. X * Given the buffer pointer of the first overflow page of a big pair,
  1548. X * find the end of the big pair
  1549. X *
  1550. X * This will set bpp to the buffer header of the last page of the big pair.
  1551. X * It will return the pageno of the overflow page following the last page
  1552. X * of the pair; 0 if there isn't any (i.e. big pair is the last key in the
  1553. X * bucket)
  1554. X */
  1555. Xextern u_short
  1556. X__find_last_page(hashp, bpp)
  1557. X    HTAB *hashp;
  1558. X    BUFHEAD **bpp;
  1559. X{
  1560. X    BUFHEAD *bufp;
  1561. X    u_short *bp, pageno;
  1562. X    int n;
  1563. X
  1564. X    bufp = *bpp;
  1565. X    bp = (u_short *)bufp->page;
  1566. X    for (;;) {
  1567. X        n = bp[0];
  1568. X
  1569. X        /*
  1570. X         * This is the last page if: the tag is FULL_KEY_DATA and
  1571. X         * either only 2 entries OVFLPAGE marker is explicit there
  1572. X         * is freespace on the page.
  1573. X         */
  1574. X        if (bp[2] == FULL_KEY_DATA &&
  1575. X            ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp))))
  1576. X            break;
  1577. X
  1578. X        pageno = bp[n - 1];
  1579. X        bufp = __get_buf(hashp, pageno, bufp, 0);
  1580. X        if (!bufp)
  1581. X            return (0);    /* Need to indicate an error! */
  1582. X        bp = (u_short *)bufp->page;
  1583. X    }
  1584. X
  1585. X    *bpp = bufp;
  1586. X    if (bp[0] > 2)
  1587. X        return (bp[3]);
  1588. X    else
  1589. X        return (0);
  1590. X}
  1591. X
  1592. X/*
  1593. X * Return the data for the key/data pair that begins on this page at this
  1594. X * index (index should always be 1).
  1595. X */
  1596. Xextern int
  1597. X__big_return(hashp, bufp, ndx, val, set_current)
  1598. X    HTAB *hashp;
  1599. X    BUFHEAD *bufp;
  1600. X    int ndx;
  1601. X    DBT *val;
  1602. X    int set_current;
  1603. X{
  1604. X    BUFHEAD *save_p;
  1605. X    u_short *bp, len, off, save_addr;
  1606. X    char *tp;
  1607. X
  1608. X    bp = (u_short *)bufp->page;
  1609. X    while (bp[ndx + 1] == PARTIAL_KEY) {
  1610. X        bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
  1611. X        if (!bufp)
  1612. X            return (-1);
  1613. X        bp = (u_short *)bufp->page;
  1614. X        ndx = 1;
  1615. X    }
  1616. X
  1617. X    if (bp[ndx + 1] == FULL_KEY) {
  1618. X        bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
  1619. X        if (!bufp)
  1620. X            return (-1);
  1621. X        bp = (u_short *)bufp->page;
  1622. X        save_p = bufp;
  1623. X        save_addr = save_p->addr;
  1624. X        off = bp[1];
  1625. X        len = 0;
  1626. X    } else
  1627. X        if (!FREESPACE(bp)) {
  1628. X            /*
  1629. X             * This is a hack.  We can't distinguish between
  1630. X             * FULL_KEY_DATA that contains complete data or
  1631. X             * incomplete data, so we require that if the data
  1632. X             * is complete, there is at least 1 byte of free
  1633. X             * space left.
  1634. X             */
  1635. X            off = bp[bp[0]];
  1636. X            len = bp[1] - off;
  1637. X            save_p = bufp;
  1638. X            save_addr = bufp->addr;
  1639. X            bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
  1640. X            if (!bufp)
  1641. X                return (-1);
  1642. X            bp = (u_short *)bufp->page;
  1643. X        } else {
  1644. X            /* The data is all on one page. */
  1645. X            tp = (char *)bp;
  1646. X            off = bp[bp[0]];
  1647. X            val->data = (u_char *)tp + off;
  1648. X            val->size = bp[1] - off;
  1649. X            if (set_current) {
  1650. X                if (bp[0] == 2) {    /* No more buckets in
  1651. X                             * chain */
  1652. X                    hashp->cpage = NULL;
  1653. X                    hashp->cbucket++;
  1654. X                    hashp->cndx = 1;
  1655. X                } else {
  1656. X                    hashp->cpage = __get_buf(hashp,
  1657. X                        bp[bp[0] - 1], bufp, 0);
  1658. X                    if (!hashp->cpage)
  1659. X                        return (-1);
  1660. X                    hashp->cndx = 1;
  1661. X                    if (!((u_short *)
  1662. X                        hashp->cpage->page)[0]) {
  1663. X                        hashp->cbucket++;
  1664. X                        hashp->cpage = NULL;
  1665. X                    }
  1666. X                }
  1667. X            }
  1668. X            return (0);
  1669. X        }
  1670. X
  1671. X    val->size = collect_data(hashp, bufp, (int)len, set_current);
  1672. X    if (val->size == -1)
  1673. X        return (-1);
  1674. X    if (save_p->addr != save_addr) {
  1675. X        /* We are pretty short on buffers. */
  1676. X        errno = EINVAL;            /* OUT OF BUFFERS */
  1677. X        return (-1);
  1678. X    }
  1679. X    memmove(hashp->tmp_buf, (save_p->page) + off, len);
  1680. X    val->data = (u_char *)hashp->tmp_buf;
  1681. X    return (0);
  1682. X}
  1683. X/*
  1684. X * Count how big the total datasize is by recursing through the pages.  Then
  1685. X * allocate a buffer and copy the data as you recurse up.
  1686. X */
  1687. Xstatic int
  1688. Xcollect_data(hashp, bufp, len, set)
  1689. X    HTAB *hashp;
  1690. X    BUFHEAD *bufp;
  1691. X    int len, set;
  1692. X{
  1693. X    register u_short *bp;
  1694. X    register char *p;
  1695. X    BUFHEAD *xbp;
  1696. X    u_short save_addr;
  1697. X    int mylen, totlen;
  1698. X
  1699. X    p = bufp->page;
  1700. X    bp = (u_short *)p;
  1701. X    mylen = hashp->BSIZE - bp[1];
  1702. X    save_addr = bufp->addr;
  1703. X
  1704. X    if (bp[2] == FULL_KEY_DATA) {        /* End of Data */
  1705. X        totlen = len + mylen;
  1706. X        if (hashp->tmp_buf)
  1707. X            free(hashp->tmp_buf);
  1708. X        hashp->tmp_buf = malloc(totlen);
  1709. X        if (!hashp->tmp_buf)
  1710. X            return (-1);
  1711. X        if (set) {
  1712. X            hashp->cndx = 1;
  1713. X            if (bp[0] == 2) {    /* No more buckets in chain */
  1714. X                hashp->cpage = NULL;
  1715. X                hashp->cbucket++;
  1716. X            } else {
  1717. X                hashp->cpage =
  1718. X                    __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
  1719. X                if (!hashp->cpage)
  1720. X                    return (-1);
  1721. X                else if (!((u_short *)hashp->cpage->page)[0]) {
  1722. X                    hashp->cbucket++;
  1723. X                    hashp->cpage = NULL;
  1724. X                }
  1725. X            }
  1726. X        }
  1727. X    } else {
  1728. X        xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
  1729. X        if (!xbp || ((totlen =
  1730. X            collect_data(hashp, xbp, len + mylen, set)) < 1))
  1731. X            return (-1);
  1732. X    }
  1733. X    if (bufp->addr != save_addr) {
  1734. X        errno = EINVAL;            /* Out of buffers. */
  1735. X        return (-1);
  1736. X    }
  1737. X    memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], mylen);
  1738. X    return (totlen);
  1739. X}
  1740. X
  1741. X/*
  1742. X * Fill in the key and data for this big pair.
  1743. X */
  1744. Xextern int
  1745. X__big_keydata(hashp, bufp, key, val, set)
  1746. X    HTAB *hashp;
  1747. X    BUFHEAD *bufp;
  1748. X    DBT *key, *val;
  1749. X    int set;
  1750. X{
  1751. X    key->size = collect_key(hashp, bufp, 0, val, set);
  1752. X    if (key->size == -1)
  1753. X        return (-1);
  1754. X    key->data = (u_char *)hashp->tmp_key;
  1755. X    return (0);
  1756. X}
  1757. X
  1758. X/*
  1759. X * Count how big the total key size is by recursing through the pages.  Then
  1760. X * collect the data, allocate a buffer and copy the key as you recurse up.
  1761. X */
  1762. Xstatic int
  1763. Xcollect_key(hashp, bufp, len, val, set)
  1764. X    HTAB *hashp;
  1765. X    BUFHEAD *bufp;
  1766. X    int len;
  1767. X    DBT *val;
  1768. X    int set;
  1769. X{
  1770. X    BUFHEAD *xbp;
  1771. X    char *p;
  1772. X    int mylen, totlen;
  1773. X    u_short *bp, save_addr;
  1774. X
  1775. X    p = bufp->page;
  1776. X    bp = (u_short *)p;
  1777. X    mylen = hashp->BSIZE - bp[1];
  1778. X
  1779. X    save_addr = bufp->addr;
  1780. X    totlen = len + mylen;
  1781. X    if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) {    /* End of Key. */
  1782. X        if (hashp->tmp_key)
  1783. X            free(hashp->tmp_key);
  1784. X        hashp->tmp_key = malloc(totlen);
  1785. X        if (!hashp->tmp_key)
  1786. X            return (-1);
  1787. X        if (__big_return(hashp, bufp, 1, val, set))
  1788. X            return (-1);
  1789. X    } else {
  1790. X        xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
  1791. X        if (!xbp || ((totlen =
  1792. X            collect_key(hashp, xbp, totlen, val, set)) < 1))
  1793. X            return (-1);
  1794. X    }
  1795. X    if (bufp->addr != save_addr) {
  1796. X        errno = EINVAL;        /* MIS -- OUT OF BUFFERS */
  1797. X        return (-1);
  1798. X    }
  1799. X    memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], mylen);
  1800. X    return (totlen);
  1801. X}
  1802. X
  1803. X/*
  1804. X * Returns:
  1805. X *  0 => OK
  1806. X * -1 => error
  1807. X */
  1808. Xextern int
  1809. X__big_split(hashp, op, np, big_keyp, addr, obucket, ret)
  1810. X    HTAB *hashp;
  1811. X    BUFHEAD *op;    /* Pointer to where to put keys that go in old bucket */
  1812. X    BUFHEAD *np;    /* Pointer to new bucket page */
  1813. X            /* Pointer to first page containing the big key/data */
  1814. X    BUFHEAD *big_keyp;
  1815. X    int addr;    /* Address of big_keyp */
  1816. X    u_int   obucket;/* Old Bucket */
  1817. X    SPLIT_RETURN *ret;
  1818. X{
  1819. X    register BUFHEAD *tmpp;
  1820. X    register u_short *tp;
  1821. X    BUFHEAD *bp;
  1822. X    DBT key, val;
  1823. X    u_int change;
  1824. X    u_short free_space, n, off;
  1825. X
  1826. X    bp = big_keyp;
  1827. X
  1828. X    /* Now figure out where the big key/data goes */
  1829. X    if (__big_keydata(hashp, big_keyp, &key, &val, 0))
  1830. X        return (-1);
  1831. X    change = (__call_hash(hashp, key.data, key.size) != obucket);
  1832. X
  1833. X    if (ret->next_addr = __find_last_page(hashp, &big_keyp)) {
  1834. X        if (!(ret->nextp =
  1835. X            __get_buf(hashp, ret->next_addr, big_keyp, 0)))
  1836. X            return (-1);;
  1837. X    } else
  1838. X        ret->nextp = NULL;
  1839. X
  1840. X    /* Now make one of np/op point to the big key/data pair */
  1841. X#ifdef DEBUG
  1842. X    assert(np->ovfl == NULL);
  1843. X#endif
  1844. X    if (change)
  1845. X        tmpp = np;
  1846. X    else
  1847. X        tmpp = op;
  1848. X
  1849. X    tmpp->flags |= BUF_MOD;
  1850. X#ifdef DEBUG1
  1851. X    (void)fprintf(stderr,
  1852. X        "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
  1853. X        (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0));
  1854. X#endif
  1855. X    tmpp->ovfl = bp;    /* one of op/np point to big_keyp */
  1856. X    tp = (u_short *)tmpp->page;
  1857. X#ifdef DEBUG
  1858. X    assert(FREESPACE(tp) >= OVFLSIZE);
  1859. X#endif
  1860. X    n = tp[0];
  1861. X    off = OFFSET(tp);
  1862. X    free_space = FREESPACE(tp);
  1863. X    tp[++n] = (u_short)addr;
  1864. X    tp[++n] = OVFLPAGE;
  1865. X    tp[0] = n;
  1866. X    OFFSET(tp) = off;
  1867. X    FREESPACE(tp) = free_space - OVFLSIZE;
  1868. X
  1869. X    /*
  1870. X     * Finally, set the new and old return values. BIG_KEYP contains a
  1871. X     * pointer to the last page of the big key_data pair. Make sure that
  1872. X     * big_keyp has no following page (2 elements) or create an empty
  1873. X     * following page.
  1874. X     */
  1875. X
  1876. X    ret->newp = np;
  1877. X    ret->oldp = op;
  1878. X
  1879. X    tp = (u_short *)big_keyp->page;
  1880. X    big_keyp->flags |= BUF_MOD;
  1881. X    if (tp[0] > 2) {
  1882. X        /*
  1883. X         * There may be either one or two offsets on this page.  If
  1884. X         * there is one, then the overflow page is linked on normally
  1885. X         * and tp[4] is OVFLPAGE.  If there are two, tp[4] contains
  1886. X         * the second offset and needs to get stuffed in after the
  1887. X         * next overflow page is added.
  1888. X         */
  1889. X        n = tp[4];
  1890. X        free_space = FREESPACE(tp);
  1891. X        off = OFFSET(tp);
  1892. X        tp[0] -= 2;
  1893. X        FREESPACE(tp) = free_space + OVFLSIZE;
  1894. X        OFFSET(tp) = off;
  1895. X        tmpp = __add_ovflpage(hashp, big_keyp);
  1896. X        if (!tmpp)
  1897. X            return (-1);
  1898. X        tp[4] = n;
  1899. X    } else
  1900. X        tmpp = big_keyp;
  1901. X
  1902. X    if (change)
  1903. X        ret->newp = tmpp;
  1904. X    else
  1905. X        ret->oldp = tmpp;
  1906. X    return (0);
  1907. X}
  1908. END_OF_FILE
  1909. if test 16249 -ne `wc -c <'hash/hash_bigkey.c'`; then
  1910.     echo shar: \"'hash/hash_bigkey.c'\" unpacked with wrong size!
  1911. fi
  1912. # end of 'hash/hash_bigkey.c'
  1913. fi
  1914. if test -f 'test/btree.tests/main.c' -a "${1}" != "-c" ; then 
  1915.   echo shar: Will not clobber existing file \"'test/btree.tests/main.c'\"
  1916. else
  1917. echo shar: Extracting \"'test/btree.tests/main.c'\" \(14829 characters\)
  1918. sed "s/^X//" >'test/btree.tests/main.c' <<'END_OF_FILE'
  1919. X/*-
  1920. X * Copyright (c) 1990, 1993
  1921. X *    The Regents of the University of California.  All rights reserved.
  1922. X *
  1923. X * This code is derived from software contributed to Berkeley by
  1924. X * Mike Olson.
  1925. X *
  1926. X * Redistribution and use in source and binary forms, with or without
  1927. X * modification, are permitted provided that the following conditions
  1928. X * are met:
  1929. X * 1. Redistributions of source code must retain the above copyright
  1930. X *    notice, this list of conditions and the following disclaimer.
  1931. X * 2. Redistributions in binary form must reproduce the above copyright
  1932. X *    notice, this list of conditions and the following disclaimer in the
  1933. X *    documentation and/or other materials provided with the distribution.
  1934. X * 3. All advertising materials mentioning features or use of this software
  1935. X *    must display the following acknowledgement:
  1936. X *    This product includes software developed by the University of
  1937. X *    California, Berkeley and its contributors.
  1938. X * 4. Neither the name of the University nor the names of its contributors
  1939. X *    may be used to endorse or promote products derived from this software
  1940. X *    without specific prior written permission.
  1941. X *
  1942. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1943. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1944. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1945. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1946. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1947. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1948. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1949. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1950. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1951. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1952. X * SUCH DAMAGE.
  1953. X */
  1954. X
  1955. X#if defined(LIBC_SCCS) && !defined(lint)
  1956. Xstatic char sccsid[] = "@(#)main.c    8.1 (Berkeley) 6/4/93";
  1957. X#endif /* LIBC_SCCS and not lint */
  1958. X
  1959. X#include <sys/param.h>
  1960. X#include <fcntl.h>
  1961. X#include <db.h>
  1962. X#include <errno.h>
  1963. X#include <stdio.h>
  1964. X#include <ctype.h>
  1965. X#include <stdlib.h>
  1966. X#include <string.h>
  1967. X#include "btree.h"
  1968. X
  1969. Xtypedef struct cmd_table {
  1970. X    char *cmd;
  1971. X    int nargs;
  1972. X    int rconv;
  1973. X    void (*func) __P((DB *, char **));
  1974. X    char *usage, *descrip;
  1975. X} cmd_table;
  1976. X
  1977. Xint stopstop;
  1978. XDB *globaldb;
  1979. X
  1980. Xvoid append    __P((DB *, char **));
  1981. Xvoid bstat    __P((DB *, char **));
  1982. Xvoid cursor    __P((DB *, char **));
  1983. Xvoid delcur    __P((DB *, char **));
  1984. Xvoid delete    __P((DB *, char **));
  1985. Xvoid dump    __P((DB *, char **));
  1986. Xvoid first    __P((DB *, char **));
  1987. Xvoid get    __P((DB *, char **));
  1988. Xvoid help    __P((DB *, char **));
  1989. Xvoid iafter    __P((DB *, char **));
  1990. Xvoid ibefore    __P((DB *, char **));
  1991. Xvoid icursor    __P((DB *, char **));
  1992. Xvoid insert    __P((DB *, char **));
  1993. Xvoid keydata    __P((DBT *, DBT *));
  1994. Xvoid last    __P((DB *, char **));
  1995. Xvoid list    __P((DB *, char **));
  1996. Xvoid load    __P((DB *, char **));
  1997. Xvoid mstat    __P((DB *, char **));
  1998. Xvoid next    __P((DB *, char **));
  1999. Xint  parse    __P((char *, char **, int));
  2000. Xvoid previous    __P((DB *, char **));
  2001. Xvoid show    __P((DB *, char **));
  2002. Xvoid usage    __P((void));
  2003. Xvoid user    __P((DB *));
  2004. X
  2005. Xcmd_table commands[] = {
  2006. X    "?",    0, 0, help, "help", NULL,
  2007. X    "a",    2, 1, append, "append key def", "append key with data def",
  2008. X    "b",    0, 0, bstat, "bstat", "stat btree",
  2009. X    "c",    1, 1, cursor,  "cursor word", "move cursor to word",
  2010. X    "delc",    0, 0, delcur, "delcur", "delete key the cursor references",
  2011. X    "dele",    1, 1, delete, "delete word", "delete word",
  2012. X    "d",    0, 0, dump, "dump", "dump database",
  2013. X    "f",    0, 0, first, "first", "move cursor to first record",
  2014. X    "g",    1, 1, get, "get key", "locate key",
  2015. X    "h",    0, 0, help, "help", "print command summary",
  2016. X    "ia",    2, 1, iafter, "iafter key data", "insert data after key",
  2017. X    "ib",    2, 1, ibefore, "ibefore key data", "insert data before key",
  2018. X    "ic",    2, 1, icursor, "icursor key data", "replace cursor",
  2019. X    "in",    2, 1, insert, "insert key def", "insert key with data def",
  2020. X    "la",    0, 0, last, "last", "move cursor to last record",
  2021. X    "li",    1, 1, list, "list file", "list to a file",
  2022. X    "loa",    1, 0, load, "load file", NULL,
  2023. X    "loc",    1, 1, get, "get key", NULL,
  2024. X    "m",    0, 0, mstat, "mstat", "stat memory pool",
  2025. X    "n",    0, 0, next, "next", "move cursor forward one record",
  2026. X    "p",    0, 0, previous, "previous", "move cursor back one record",
  2027. X    "q",    0, 0, NULL, "quit", "quit",
  2028. X    "sh",    1, 0, show, "show page", "dump a page",
  2029. X    { NULL },
  2030. X};
  2031. X
  2032. Xint recno;                    /* use record numbers */
  2033. Xchar *dict = "words";                /* default dictionary */
  2034. Xchar *progname;
  2035. X
  2036. Xint
  2037. Xmain(argc, argv)
  2038. X    int argc;
  2039. X    char **argv;
  2040. X{
  2041. X    int c;
  2042. X    DB *db;
  2043. X    BTREEINFO b;
  2044. X
  2045. X    progname = *argv;
  2046. X
  2047. X    b.flags = 0;
  2048. X    b.cachesize = 0;
  2049. X    b.maxkeypage = 0;
  2050. X    b.minkeypage = 0;
  2051. X    b.psize = 0;
  2052. X    b.compare = NULL;
  2053. X    b.prefix = NULL;
  2054. X    b.lorder = 0;
  2055. X
  2056. X    while ((c = getopt(argc, argv, "bc:di:lp:ru")) != EOF) {
  2057. X        switch (c) {
  2058. X        case 'b':
  2059. X            b.lorder = BIG_ENDIAN;
  2060. X            break;
  2061. X        case 'c':
  2062. X            b.cachesize = atoi(optarg);
  2063. X            break;
  2064. X        case 'd':
  2065. X            b.flags |= R_DUP;
  2066. X            break;
  2067. X        case 'i':
  2068. X            dict = optarg;
  2069. X            break;
  2070. X        case 'l':
  2071. X            b.lorder = LITTLE_ENDIAN;
  2072. X            break;
  2073. X        case 'p':
  2074. X            b.psize = atoi(optarg);
  2075. X            break;
  2076. X        case 'r':
  2077. X            recno = 1;
  2078. X            break;
  2079. X        case 'u':
  2080. X            b.flags = 0;
  2081. X            break;
  2082. X        default:
  2083. X            usage();
  2084. X        }
  2085. X    }
  2086. X    argc -= optind;
  2087. X    argv += optind;
  2088. X
  2089. X    if (recno)
  2090. X        db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
  2091. X            0, DB_RECNO, NULL);
  2092. X    else
  2093. X        db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
  2094. X            0600, DB_BTREE, &b);
  2095. X
  2096. X    if (db == NULL) {
  2097. X        (void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
  2098. X        exit(1);
  2099. X    }
  2100. X    globaldb = db;
  2101. X    user(db);
  2102. X    exit(0);
  2103. X    /* NOTREACHED */
  2104. X}
  2105. X
  2106. Xvoid
  2107. Xuser(db)
  2108. X    DB *db;
  2109. X{
  2110. X    FILE *ifp;
  2111. X    int argc, i, last;
  2112. X    char *lbuf, *argv[4], buf[512];
  2113. X
  2114. X    if ((ifp = fopen("/dev/tty", "r")) == NULL) {
  2115. X        (void)fprintf(stderr,
  2116. X            "/dev/tty: %s\n", strerror(errno));
  2117. X        exit(1);
  2118. X    }
  2119. X    for (last = 0;;) {
  2120. X        (void)printf("> ");
  2121. X        (void)fflush(stdout);
  2122. X        if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
  2123. X            break;
  2124. X        if (lbuf[0] == '\n') {
  2125. X            i = last;
  2126. X            goto uselast;
  2127. X        }
  2128. X        lbuf[strlen(lbuf) - 1] = '\0';
  2129. X
  2130. X        if (lbuf[0] == 'q')
  2131. X            break;
  2132. X
  2133. X        argc = parse(lbuf, &argv[0], 3);
  2134. X        if (argc == 0)
  2135. X            continue;
  2136. X
  2137. X        for (i = 0; commands[i].cmd != NULL; i++)
  2138. X            if (strncmp(commands[i].cmd, argv[0],
  2139. X                strlen(commands[i].cmd)) == 0)
  2140. X                break;
  2141. X
  2142. X        if (commands[i].cmd == NULL) {
  2143. X            (void)fprintf(stderr,
  2144. X                "%s: command unknown ('help' for help)\n", lbuf);
  2145. X            continue;
  2146. X        }
  2147. X
  2148. X        if (commands[i].nargs != argc - 1) {
  2149. X            (void)fprintf(stderr, "usage: %s\n", commands[i].usage);
  2150. X            continue;
  2151. X        }
  2152. X
  2153. X        if (recno && commands[i].rconv) {
  2154. X            static recno_t nlong;
  2155. X            nlong = atoi(argv[1]);
  2156. X            argv[1] = (char *)&nlong;
  2157. X        }
  2158. Xuselast:    last = i;
  2159. X        (*commands[i].func)(db, argv);
  2160. X    }
  2161. X    if ((db->sync)(db) == RET_ERROR)
  2162. X        perror("dbsync");
  2163. X    else if ((db->close)(db) == RET_ERROR)
  2164. X        perror("dbclose");
  2165. X}
  2166. X
  2167. Xint
  2168. Xparse(lbuf, argv, maxargc)
  2169. X    char *lbuf, **argv;
  2170. X    int maxargc;
  2171. X{
  2172. X    int argc = 0;
  2173. X    char *c;
  2174. X
  2175. X    c = lbuf;
  2176. X    while (isspace(*c))
  2177. X        c++;
  2178. X    while (*c != '\0' && argc < maxargc) {
  2179. X        *argv++ = c;
  2180. X        argc++;
  2181. X        while (!isspace(*c) && *c != '\0') {
  2182. X            c++;
  2183. X        }
  2184. X        while (isspace(*c))
  2185. X            *c++ = '\0';
  2186. X    }
  2187. X    return (argc);
  2188. X}
  2189. X
  2190. Xvoid
  2191. Xappend(db, argv)
  2192. X    DB *db;
  2193. X    char **argv;
  2194. X{
  2195. X    DBT key, data;
  2196. X    int status;
  2197. X
  2198. X    if (!recno) {
  2199. X        (void)fprintf(stderr,
  2200. X            "append only available for recno db's.\n");
  2201. X        return;
  2202. X    }
  2203. X    key.data = argv[1];
  2204. X    key.size = sizeof(recno_t);
  2205. X    data.data = argv[2];
  2206. X    data.size = strlen(data.data);
  2207. X    status = (db->put)(db, &key, &data, R_APPEND);
  2208. X    switch (status) {
  2209. X    case RET_ERROR:
  2210. X        perror("append/put");
  2211. X        break;
  2212. X    case RET_SPECIAL:
  2213. X        (void)printf("%s (duplicate key)\n", argv[1]);
  2214. X        break;
  2215. X    case RET_SUCCESS:
  2216. X        break;
  2217. X    }
  2218. X}
  2219. X
  2220. Xvoid
  2221. Xcursor(db, argv)
  2222. X    DB *db;
  2223. X    char **argv;
  2224. X{
  2225. X    DBT data, key;
  2226. X    int status;
  2227. X
  2228. X    key.data = argv[1];
  2229. X    if (recno)
  2230. X        key.size = sizeof(recno_t);
  2231. X    else
  2232. X        key.size = strlen(argv[1]) + 1;
  2233. X    status = (*db->seq)(db, &key, &data, R_CURSOR);
  2234. X    switch (status) {
  2235. X    case RET_ERROR:
  2236. X        perror("cursor/seq");
  2237. X        break;
  2238. X    case RET_SPECIAL:
  2239. X        (void)printf("key not found\n");
  2240. X        break;
  2241. X    case RET_SUCCESS:
  2242. X        keydata(&key, &data);
  2243. X        break;
  2244. X    }
  2245. X}
  2246. X
  2247. Xvoid
  2248. Xdelcur(db, argv)
  2249. X    DB *db;
  2250. X    char **argv;
  2251. X{
  2252. X    int status;
  2253. X
  2254. X    status = (*db->del)(db, NULL, R_CURSOR);
  2255. X
  2256. X    if (status == RET_ERROR)
  2257. X        perror("delcur/del");
  2258. X}
  2259. X
  2260. Xvoid
  2261. Xdelete(db, argv)
  2262. X    DB *db;
  2263. X    char **argv;
  2264. X{
  2265. X    DBT key;
  2266. X    int status;
  2267. X
  2268. X    key.data = argv[1];
  2269. X    if (recno)
  2270. X        key.size = sizeof(recno_t);
  2271. X    else
  2272. X        key.size = strlen(argv[1]) + 1;
  2273. X
  2274. X    status = (*db->del)(db, &key, 0);
  2275. X    switch (status) {
  2276. X    case RET_ERROR:
  2277. X        perror("delete/del");
  2278. X        break;
  2279. X    case RET_SPECIAL:
  2280. X        (void)printf("key not found\n");
  2281. X        break;
  2282. X    case RET_SUCCESS:
  2283. X        break;
  2284. X    }
  2285. X}
  2286. X
  2287. Xvoid
  2288. Xdump(db, argv)
  2289. X    DB *db;
  2290. X    char **argv;
  2291. X{
  2292. X    __bt_dump(db);
  2293. X}
  2294. X
  2295. Xvoid
  2296. Xfirst(db, argv)
  2297. X    DB *db;
  2298. X    char **argv;
  2299. X{
  2300. X    DBT data, key;
  2301. X    int status;
  2302. X
  2303. X    status = (*db->seq)(db, &key, &data, R_FIRST);
  2304. X
  2305. X    switch (status) {
  2306. X    case RET_ERROR:
  2307. X        perror("first/seq");
  2308. X        break;
  2309. X    case RET_SPECIAL:
  2310. X        (void)printf("no more keys\n");
  2311. X        break;
  2312. X    case RET_SUCCESS:
  2313. X        keydata(&key, &data);
  2314. X        break;
  2315. X    }
  2316. X}
  2317. X
  2318. Xvoid
  2319. Xget(db, argv)
  2320. X    DB *db;
  2321. X    char **argv;
  2322. X{
  2323. X    DBT data, key;
  2324. X    int status;
  2325. X
  2326. X    key.data = argv[1];
  2327. X    if (recno)
  2328. X        key.size = sizeof(recno_t);
  2329. X    else
  2330. X        key.size = strlen(argv[1]) + 1;
  2331. X
  2332. X    status = (*db->get)(db, &key, &data, 0);
  2333. X
  2334. X    switch (status) {
  2335. X    case RET_ERROR:
  2336. X        perror("get/get");
  2337. X        break;
  2338. X    case RET_SPECIAL:
  2339. X        (void)printf("key not found\n");
  2340. X        break;
  2341. X    case RET_SUCCESS:
  2342. X        keydata(&key, &data);
  2343. X        break;
  2344. X    }
  2345. X}
  2346. X
  2347. Xvoid
  2348. Xhelp(db, argv)
  2349. X    DB *db;
  2350. X    char **argv;
  2351. X{
  2352. X    int i;
  2353. X
  2354. X    for (i = 0; commands[i].cmd; i++)
  2355. X        if (commands[i].descrip)
  2356. X            (void)printf("%s: %s\n",
  2357. X                commands[i].usage, commands[i].descrip);
  2358. X}
  2359. X
  2360. Xvoid
  2361. Xiafter(db, argv)
  2362. X    DB *db;
  2363. X    char **argv;
  2364. X{
  2365. X    DBT key, data;
  2366. X    int status;
  2367. X
  2368. X    if (!recno) {
  2369. X        (void)fprintf(stderr,
  2370. X            "iafter only available for recno db's.\n");
  2371. X        return;
  2372. X    }
  2373. X    key.data = argv[1];
  2374. X    key.size = sizeof(recno_t);
  2375. X    data.data = argv[2];
  2376. X    data.size = strlen(data.data);
  2377. X    status = (db->put)(db, &key, &data, R_IAFTER);
  2378. X    switch (status) {
  2379. X    case RET_ERROR:
  2380. X        perror("iafter/put");
  2381. X        break;
  2382. X    case RET_SPECIAL:
  2383. X        (void)printf("%s (duplicate key)\n", argv[1]);
  2384. X        break;
  2385. X    case RET_SUCCESS:
  2386. X        break;
  2387. X    }
  2388. X}
  2389. X
  2390. Xvoid
  2391. Xibefore(db, argv)
  2392. X    DB *db;
  2393. X    char **argv;
  2394. X{
  2395. X    DBT key, data;
  2396. X    int status;
  2397. X
  2398. X    if (!recno) {
  2399. X        (void)fprintf(stderr,
  2400. X            "ibefore only available for recno db's.\n");
  2401. X        return;
  2402. X    }
  2403. X    key.data = argv[1];
  2404. X    key.size = sizeof(recno_t);
  2405. X    data.data = argv[2];
  2406. X    data.size = strlen(data.data);
  2407. X    status = (db->put)(db, &key, &data, R_IBEFORE);
  2408. X    switch (status) {
  2409. X    case RET_ERROR:
  2410. X        perror("ibefore/put");
  2411. X        break;
  2412. X    case RET_SPECIAL:
  2413. X        (void)printf("%s (duplicate key)\n", argv[1]);
  2414. X        break;
  2415. X    case RET_SUCCESS:
  2416. X        break;
  2417. X    }
  2418. X}
  2419. X
  2420. Xvoid
  2421. Xicursor(db, argv)
  2422. X    DB *db;
  2423. X    char **argv;
  2424. X{
  2425. X    int status;
  2426. X    DBT data, key;
  2427. X
  2428. X    key.data = argv[1];
  2429. X    if (recno)
  2430. X        key.size = sizeof(recno_t);
  2431. X    else
  2432. X        key.size = strlen(argv[1]) + 1;
  2433. X    data.data = argv[2];
  2434. X    data.size = strlen(argv[2]) + 1;
  2435. X
  2436. X    status = (*db->put)(db, &key, &data, R_CURSOR);
  2437. X    switch (status) {
  2438. X    case RET_ERROR:
  2439. X        perror("icursor/put");
  2440. X        break;
  2441. X    case RET_SPECIAL:
  2442. X        (void)printf("%s (duplicate key)\n", argv[1]);
  2443. X        break;
  2444. X    case RET_SUCCESS:
  2445. X        break;
  2446. X    }
  2447. X}
  2448. X
  2449. Xvoid
  2450. Xinsert(db, argv)
  2451. X    DB *db;
  2452. X    char **argv;
  2453. X{
  2454. X    int status;
  2455. X    DBT data, key;
  2456. X
  2457. X    key.data = argv[1];
  2458. X    if (recno)
  2459. X        key.size = sizeof(recno_t);
  2460. X    else
  2461. X        key.size = strlen(argv[1]) + 1;
  2462. X    data.data = argv[2];
  2463. X    data.size = strlen(argv[2]) + 1;
  2464. X
  2465. X    status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
  2466. X    switch (status) {
  2467. X    case RET_ERROR:
  2468. X        perror("insert/put");
  2469. X        break;
  2470. X    case RET_SPECIAL:
  2471. X        (void)printf("%s (duplicate key)\n", argv[1]);
  2472. X        break;
  2473. X    case RET_SUCCESS:
  2474. X        break;
  2475. X    }
  2476. X}
  2477. X
  2478. Xvoid
  2479. Xlast(db, argv)
  2480. X    DB *db;
  2481. X    char **argv;
  2482. X{
  2483. X    DBT data, key;
  2484. X    int status;
  2485. X
  2486. X    status = (*db->seq)(db, &key, &data, R_LAST);
  2487. X
  2488. X    switch (status) {
  2489. X    case RET_ERROR:
  2490. X        perror("last/seq");
  2491. X        break;
  2492. X    case RET_SPECIAL:
  2493. X        (void)printf("no more keys\n");
  2494. X        break;
  2495. X    case RET_SUCCESS:
  2496. X        keydata(&key, &data);
  2497. X        break;
  2498. X    }
  2499. X}
  2500. X
  2501. Xvoid
  2502. Xlist(db, argv)
  2503. X    DB *db;
  2504. X    char **argv;
  2505. X{
  2506. X    DBT data, key;
  2507. X    FILE *fp;
  2508. X    int status;
  2509. X
  2510. X    if ((fp = fopen(argv[1], "w")) == NULL) {
  2511. X        (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
  2512. X        return;
  2513. X    }
  2514. X    status = (*db->seq)(db, &key, &data, R_FIRST);
  2515. X    while (status == RET_SUCCESS) {
  2516. X        (void)fprintf(fp, "%s\n", key.data);
  2517. X        status = (*db->seq)(db, &key, &data, R_NEXT);
  2518. X    }
  2519. X    if (status == RET_ERROR)
  2520. X        perror("list/seq");
  2521. X}
  2522. X
  2523. XDB *BUGdb;
  2524. Xvoid
  2525. Xload(db, argv)
  2526. X    DB *db;
  2527. X    char **argv;
  2528. X{
  2529. X    register char *p, *t;
  2530. X    FILE *fp;
  2531. X    DBT data, key;
  2532. X    recno_t cnt;
  2533. X    size_t len;
  2534. X    int status;
  2535. X    char *lp, buf[16 * 1024];
  2536. X
  2537. X    BUGdb = db;
  2538. X    if ((fp = fopen(argv[1], "r")) == NULL) {
  2539. X        (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
  2540. X        return;
  2541. X    }
  2542. X    (void)printf("loading %s...\n", argv[1]);
  2543. X
  2544. X    for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
  2545. X        if (recno) {
  2546. X            key.data = &cnt;
  2547. X            key.size = sizeof(recno_t);
  2548. X            data.data = lp;
  2549. X            data.size = len + 1;
  2550. X        } else { 
  2551. X            key.data = lp;
  2552. X            key.size = len + 1;
  2553. X            for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
  2554. X            *t = '\0';
  2555. X            data.data = buf;
  2556. X            data.size = len + 1;
  2557. X        }
  2558. X
  2559. X        status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
  2560. X        switch (status) {
  2561. X        case RET_ERROR:
  2562. X            perror("load/put");
  2563. X            exit(1);
  2564. X        case RET_SPECIAL:
  2565. X            if (recno)
  2566. X                (void)fprintf(stderr,
  2567. X                    "duplicate: %ld {%s}\n", cnt, data.data);
  2568. X            else
  2569. X                (void)fprintf(stderr,
  2570. X                    "duplicate: %ld {%s}\n", cnt, key.data);
  2571. X            exit(1);
  2572. X        case RET_SUCCESS:
  2573. X            break;
  2574. X        }
  2575. X    }
  2576. X    (void)fclose(fp);
  2577. X}
  2578. X
  2579. Xvoid
  2580. Xnext(db, argv)
  2581. X    DB *db;
  2582. X    char **argv;
  2583. X{
  2584. X    DBT data, key;
  2585. X    int status;
  2586. X
  2587. X    status = (*db->seq)(db, &key, &data, R_NEXT);
  2588. X
  2589. X    switch (status) {
  2590. X    case RET_ERROR:
  2591. X        perror("next/seq");
  2592. X        break;
  2593. X    case RET_SPECIAL:
  2594. X        (void)printf("no more keys\n");
  2595. X        break;
  2596. X    case RET_SUCCESS:
  2597. X        keydata(&key, &data);
  2598. X        break;
  2599. X    }
  2600. X}
  2601. X
  2602. Xvoid
  2603. Xprevious(db, argv)
  2604. X    DB *db;
  2605. X    char **argv;
  2606. X{
  2607. X    DBT data, key;
  2608. X    int status;
  2609. X
  2610. X    status = (*db->seq)(db, &key, &data, R_PREV);
  2611. X
  2612. X    switch (status) {
  2613. X    case RET_ERROR:
  2614. X        perror("previous/seq");
  2615. X        break;
  2616. X    case RET_SPECIAL:
  2617. X        (void)printf("no more keys\n");
  2618. X        break;
  2619. X    case RET_SUCCESS:
  2620. X        keydata(&key, &data);
  2621. X        break;
  2622. X    }
  2623. X}
  2624. X
  2625. Xvoid
  2626. Xshow(db, argv)
  2627. X    DB *db;
  2628. X    char **argv;
  2629. X{
  2630. X    BTREE *t;
  2631. X    PAGE *h;
  2632. X    pgno_t pg;
  2633. X
  2634. X    pg = atoi(argv[1]);
  2635. X    t = db->internal;
  2636. X    if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
  2637. X        (void)printf("getpage of %ld failed\n", pg);
  2638. X        return;
  2639. X    }
  2640. X    if (pg == 0)
  2641. X        __bt_dmpage(h);
  2642. X    else
  2643. X        __bt_dpage(h);
  2644. X    mpool_put(t->bt_mp, h, 0);
  2645. X}
  2646. X
  2647. Xvoid
  2648. Xbstat(db, argv)
  2649. X    DB *db;
  2650. X    char **argv;
  2651. X{
  2652. X    (void)printf("BTREE\n");
  2653. X    __bt_stat(db);
  2654. X}
  2655. X
  2656. Xvoid
  2657. Xmstat(db, argv)
  2658. X    DB *db;
  2659. X    char **argv;
  2660. X{
  2661. X    (void)printf("MPOOL\n");
  2662. X    mpool_stat(((BTREE *)db->internal)->bt_mp);
  2663. X}
  2664. X
  2665. Xvoid
  2666. Xkeydata(key, data)
  2667. X    DBT *key, *data;
  2668. X{
  2669. X    if (!recno && key->size > 0)
  2670. X        (void)printf("%s/", key->data);
  2671. X    if (data->size > 0)
  2672. X        (void)printf("%s", data->data);
  2673. X    (void)printf("\n");
  2674. X}
  2675. X
  2676. Xvoid
  2677. Xusage()
  2678. X{
  2679. X    (void)fprintf(stderr,
  2680. X        "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
  2681. X        progname);
  2682. X    exit (1);
  2683. X}
  2684. END_OF_FILE
  2685. if test 14829 -ne `wc -c <'test/btree.tests/main.c'`; then
  2686.     echo shar: \"'test/btree.tests/main.c'\" unpacked with wrong size!
  2687. fi
  2688. # end of 'test/btree.tests/main.c'
  2689. fi
  2690. echo shar: End of archive 6 \(of 9\).
  2691. cp /dev/null ark6isdone
  2692. MISSING=""
  2693. for I in 1 2 3 4 5 6 7 8 9 ; do
  2694.     if test ! -f ark${I}isdone ; then
  2695.     MISSING="${MISSING} ${I}"
  2696.     fi
  2697. done
  2698. if test "${MISSING}" = "" ; then
  2699.     echo You have unpacked all 9 archives.
  2700.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2701. else
  2702.     echo You still need to unpack the following archives:
  2703.     echo "        " ${MISSING}
  2704. fi
  2705. ##  End of shell archive.
  2706. exit 0
  2707.