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

  1. Newsgroups: comp.sources.unix
  2. From: bostic@cs.berkeley.edu (Keith Bostic)
  3. Subject: v26i283: db-1.6 - A New Hashing Package for UNIX(tm) (updates dbm/ndbm), Part04/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 283
  9. Archive-Name: db-1.6/part04
  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 4 (of 9)."
  18. # Contents:  btree/bt_debug.c btree/bt_delete.c btree/bt_open.c
  19. #   btree/bt_put.c btree/bt_seq.c doc/hash.3.ps hash/hash.h
  20. #   hash/hash_buf.c mpool/mpool.c
  21. # Wrapped by vixie@gw.home.vix.com on Mon Jul  5 15:27:24 1993
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'btree/bt_debug.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'btree/bt_debug.c'\"
  25. else
  26. echo shar: Extracting \"'btree/bt_debug.c'\" \(8734 characters\)
  27. sed "s/^X//" >'btree/bt_debug.c' <<'END_OF_FILE'
  28. X/*-
  29. X * Copyright (c) 1990, 1993
  30. X *    The Regents of the University of California.  All rights reserved.
  31. X *
  32. X * This code is derived from software contributed to Berkeley by
  33. X * Mike Olson.
  34. X *
  35. X * Redistribution and use in source and binary forms, with or without
  36. X * modification, are permitted provided that the following conditions
  37. X * are met:
  38. X * 1. Redistributions of source code must retain the above copyright
  39. X *    notice, this list of conditions and the following disclaimer.
  40. X * 2. Redistributions in binary form must reproduce the above copyright
  41. X *    notice, this list of conditions and the following disclaimer in the
  42. X *    documentation and/or other materials provided with the distribution.
  43. X * 3. All advertising materials mentioning features or use of this software
  44. X *    must display the following acknowledgement:
  45. X *    This product includes software developed by the University of
  46. X *    California, Berkeley and its contributors.
  47. X * 4. Neither the name of the University nor the names of its contributors
  48. X *    may be used to endorse or promote products derived from this software
  49. X *    without specific prior written permission.
  50. X *
  51. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  52. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  53. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  54. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  55. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  56. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  57. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  58. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  59. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  60. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  61. X * SUCH DAMAGE.
  62. X */
  63. X
  64. X#if defined(LIBC_SCCS) && !defined(lint)
  65. Xstatic char sccsid[] = "@(#)bt_debug.c    8.1 (Berkeley) 6/4/93";
  66. X#endif /* LIBC_SCCS and not lint */
  67. X
  68. X#include <sys/param.h>
  69. X
  70. X#include <stdio.h>
  71. X#include <stdlib.h>
  72. X#include <string.h>
  73. X
  74. X#include <db.h>
  75. X#include "btree.h"
  76. X
  77. X#ifdef DEBUG
  78. X/*
  79. X * BT_DUMP -- Dump the tree
  80. X *
  81. X * Parameters:
  82. X *    dbp:    pointer to the DB
  83. X */
  84. Xvoid
  85. X__bt_dump(dbp)
  86. X    DB *dbp;
  87. X{
  88. X    BTREE *t;
  89. X    PAGE *h;
  90. X    pgno_t i;
  91. X    char *sep;
  92. X
  93. X    t = dbp->internal;
  94. X    (void)fprintf(stderr, "%s: pgsz %d",
  95. X        ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
  96. X    if (ISSET(t, R_RECNO))
  97. X        (void)fprintf(stderr, " keys %lu", t->bt_nrecs);
  98. X#undef X
  99. X#define    X(flag, name) \
  100. X    if (ISSET(t, flag)) { \
  101. X        (void)fprintf(stderr, "%s%s", sep, name); \
  102. X        sep = ", "; \
  103. X    }
  104. X    if (t->bt_flags) {
  105. X        sep = " flags (";
  106. X        X(B_DELCRSR,    "DELCRSR");
  107. X        X(R_FIXLEN,    "FIXLEN");
  108. X        X(B_INMEM,    "INMEM");
  109. X        X(B_NODUPS,    "NODUPS");
  110. X        X(B_RDONLY,    "RDONLY");
  111. X        X(R_RECNO,    "RECNO");
  112. X        X(B_SEQINIT,    "SEQINIT");
  113. X        X(B_METADIRTY,"METADIRTY");
  114. X        (void)fprintf(stderr, ")\n");
  115. X    }
  116. X#undef X
  117. X
  118. X    for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) {
  119. X        __bt_dpage(h);
  120. X        (void)mpool_put(t->bt_mp, h, 0);
  121. X    }
  122. X}
  123. X
  124. X/*
  125. X * BT_DMPAGE -- Dump the meta page
  126. X *
  127. X * Parameters:
  128. X *    h:    pointer to the PAGE
  129. X */
  130. Xvoid
  131. X__bt_dmpage(h)
  132. X    PAGE *h;
  133. X{
  134. X    BTMETA *m;
  135. X    char *sep;
  136. X
  137. X    m = (BTMETA *)h;
  138. X    (void)fprintf(stderr, "magic %lx\n", m->m_magic);
  139. X    (void)fprintf(stderr, "version %lu\n", m->m_version);
  140. X    (void)fprintf(stderr, "psize %lu\n", m->m_psize);
  141. X    (void)fprintf(stderr, "free %lu\n", m->m_free);
  142. X    (void)fprintf(stderr, "nrecs %lu\n", m->m_nrecs);
  143. X    (void)fprintf(stderr, "flags %lu", m->m_flags);
  144. X#undef X
  145. X#define    X(flag, name) \
  146. X    if (m->m_flags & flag) { \
  147. X        (void)fprintf(stderr, "%s%s", sep, name); \
  148. X        sep = ", "; \
  149. X    }
  150. X    if (m->m_flags) {
  151. X        sep = " (";
  152. X        X(B_NODUPS,    "NODUPS");
  153. X        X(R_RECNO,    "RECNO");
  154. X        (void)fprintf(stderr, ")");
  155. X    }
  156. X}
  157. X
  158. X/*
  159. X * BT_DNPAGE -- Dump the page
  160. X *
  161. X * Parameters:
  162. X *    n:    page number to dump.
  163. X */
  164. Xvoid
  165. X__bt_dnpage(dbp, pgno)
  166. X    DB *dbp;
  167. X    pgno_t pgno;
  168. X{
  169. X    BTREE *t;
  170. X    PAGE *h;
  171. X
  172. X    t = dbp->internal;
  173. X    if ((h = mpool_get(t->bt_mp, pgno, 0)) != NULL) {
  174. X        __bt_dpage(h);
  175. X        (void)mpool_put(t->bt_mp, h, 0);
  176. X    }
  177. X}
  178. X
  179. X/*
  180. X * BT_DPAGE -- Dump the page
  181. X *
  182. X * Parameters:
  183. X *    h:    pointer to the PAGE
  184. X */
  185. Xvoid
  186. X__bt_dpage(h)
  187. X    PAGE *h;
  188. X{
  189. X    BINTERNAL *bi;
  190. X    BLEAF *bl;
  191. X    RINTERNAL *ri;
  192. X    RLEAF *rl;
  193. X    indx_t cur, top;
  194. X    char *sep;
  195. X
  196. X    (void)fprintf(stderr, "    page %d: (", h->pgno);
  197. X#undef X
  198. X#define    X(flag, name) \
  199. X    if (h->flags & flag) { \
  200. X        (void)fprintf(stderr, "%s%s", sep, name); \
  201. X        sep = ", "; \
  202. X    }
  203. X    sep = "";
  204. X    X(P_BINTERNAL,    "BINTERNAL")        /* types */
  205. X    X(P_BLEAF,    "BLEAF")
  206. X    X(P_RINTERNAL,    "RINTERNAL")        /* types */
  207. X    X(P_RLEAF,    "RLEAF")
  208. X    X(P_OVERFLOW,    "OVERFLOW")
  209. X    X(P_PRESERVE,    "PRESERVE");
  210. X    (void)fprintf(stderr, ")\n");
  211. X#undef X
  212. X
  213. X    (void)fprintf(stderr, "\tprev %2d next %2d", h->prevpg, h->nextpg);
  214. X    if (h->flags & P_OVERFLOW)
  215. X        return;
  216. X
  217. X    top = NEXTINDEX(h);
  218. X    (void)fprintf(stderr, " lower %3d upper %3d nextind %d\n",
  219. X        h->lower, h->upper, top);
  220. X    for (cur = 0; cur < top; cur++) {
  221. X        (void)fprintf(stderr, "\t[%03d] %4d ", cur, h->linp[cur]);
  222. X        switch(h->flags & P_TYPE) {
  223. X        case P_BINTERNAL:
  224. X            bi = GETBINTERNAL(h, cur);
  225. X            (void)fprintf(stderr,
  226. X                "size %03d pgno %03d", bi->ksize, bi->pgno);
  227. X            if (bi->flags & P_BIGKEY)
  228. X                (void)fprintf(stderr, " (indirect)");
  229. X            else if (bi->ksize)
  230. X                (void)fprintf(stderr,
  231. X                    " {%.*s}", (int)bi->ksize, bi->bytes);
  232. X            break;
  233. X        case P_RINTERNAL:
  234. X            ri = GETRINTERNAL(h, cur);
  235. X            (void)fprintf(stderr, "entries %03d pgno %03d",
  236. X                ri->nrecs, ri->pgno);
  237. X            break;
  238. X        case P_BLEAF:
  239. X            bl = GETBLEAF(h, cur);
  240. X            if (bl->flags & P_BIGKEY)
  241. X                (void)fprintf(stderr,
  242. X                    "big key page %lu size %u/",
  243. X                    *(pgno_t *)bl->bytes,
  244. X                    *(size_t *)(bl->bytes + sizeof(pgno_t)));
  245. X            else if (bl->ksize)
  246. X                (void)fprintf(stderr, "%s/", bl->bytes);
  247. X            if (bl->flags & P_BIGDATA)
  248. X                (void)fprintf(stderr,
  249. X                    "big data page %lu size %u",
  250. X                    *(pgno_t *)(bl->bytes + bl->ksize),
  251. X                    *(size_t *)(bl->bytes + bl->ksize +
  252. X                    sizeof(pgno_t)));
  253. X            else if (bl->dsize)
  254. X                (void)fprintf(stderr, "%.*s",
  255. X                    (int)bl->dsize, bl->bytes + bl->ksize);
  256. X            break;
  257. X        case P_RLEAF:
  258. X            rl = GETRLEAF(h, cur);
  259. X            if (rl->flags & P_BIGDATA)
  260. X                (void)fprintf(stderr,
  261. X                    "big data page %lu size %u",
  262. X                    *(pgno_t *)rl->bytes,
  263. X                    *(size_t *)(rl->bytes + sizeof(pgno_t)));
  264. X            else if (rl->dsize)
  265. X                (void)fprintf(stderr,
  266. X                    "%.*s", (int)rl->dsize, rl->bytes);
  267. X            break;
  268. X        }
  269. X        (void)fprintf(stderr, "\n");
  270. X    }
  271. X}
  272. X#endif
  273. X
  274. X#ifdef STATISTICS
  275. X/*
  276. X * BT_STAT -- Gather/print the tree statistics
  277. X *
  278. X * Parameters:
  279. X *    dbp:    pointer to the DB
  280. X */
  281. Xvoid
  282. X__bt_stat(dbp)
  283. X    DB *dbp;
  284. X{
  285. X    extern u_long bt_cache_hit, bt_cache_miss;
  286. X    extern u_long bt_rootsplit, bt_split, bt_sortsplit;
  287. X    extern u_long bt_pfxsaved;
  288. X    BTREE *t;
  289. X    PAGE *h;
  290. X    pgno_t i, pcont, pinternal, pleaf;
  291. X    u_long ifree, lfree, nkeys;
  292. X    int levels;
  293. X
  294. X    t = dbp->internal;
  295. X    pcont = pinternal = pleaf = 0;
  296. X    nkeys = ifree = lfree = 0;
  297. X    for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) {
  298. X        switch(h->flags & P_TYPE) {
  299. X        case P_BINTERNAL:
  300. X        case P_RINTERNAL:
  301. X            ++pinternal;
  302. X            ifree += h->upper - h->lower;
  303. X            break;
  304. X        case P_BLEAF:
  305. X        case P_RLEAF:
  306. X            ++pleaf;
  307. X            lfree += h->upper - h->lower;
  308. X            nkeys += NEXTINDEX(h);
  309. X            break;
  310. X        case P_OVERFLOW:
  311. X            ++pcont;
  312. X            break;
  313. X        }
  314. X        (void)mpool_put(t->bt_mp, h, 0);
  315. X    }
  316. X
  317. X    /* Count the levels of the tree. */
  318. X    for (i = P_ROOT, levels = 0 ;; ++levels) {
  319. X        h = mpool_get(t->bt_mp, i, 0);
  320. X        if (h->flags & (P_BLEAF|P_RLEAF)) {
  321. X            if (levels == 0)
  322. X                levels = 1;
  323. X            (void)mpool_put(t->bt_mp, h, 0);
  324. X            break;
  325. X        }
  326. X        i = ISSET(t, R_RECNO) ?
  327. X            GETRINTERNAL(h, 0)->pgno :
  328. X            GETBINTERNAL(h, 0)->pgno;
  329. X        (void)mpool_put(t->bt_mp, h, 0);
  330. X    }
  331. X
  332. X    (void)fprintf(stderr, "%d level%s with %ld keys",
  333. X        levels, levels == 1 ? "" : "s", nkeys);
  334. X    if (ISSET(t, R_RECNO))
  335. X        (void)fprintf(stderr, " (%ld header count)", t->bt_nrecs);
  336. X    (void)fprintf(stderr,
  337. X        "\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n",
  338. X        pinternal + pleaf + pcont, pleaf, pinternal, pcont);
  339. X    (void)fprintf(stderr, "%ld cache hits, %ld cache misses\n",
  340. X        bt_cache_hit, bt_cache_miss);
  341. X    (void)fprintf(stderr, "%ld splits (%ld root splits, %ld sort splits)\n",
  342. X        bt_split, bt_rootsplit, bt_sortsplit);
  343. X    pleaf *= t->bt_psize - BTDATAOFF;
  344. X    if (pleaf)
  345. X        (void)fprintf(stderr,
  346. X            "%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n",
  347. X            ((double)(pleaf - lfree) / pleaf) * 100,
  348. X            pleaf - lfree, lfree);
  349. X    pinternal *= t->bt_psize - BTDATAOFF;
  350. X    if (pinternal)
  351. X        (void)fprintf(stderr,
  352. X            "%.0f%% internal fill (%ld bytes used, %ld bytes free\n",
  353. X            ((double)(pinternal - ifree) / pinternal) * 100,
  354. X            pinternal - ifree, ifree);
  355. X    if (bt_pfxsaved)
  356. X        (void)fprintf(stderr, "prefix checking removed %lu bytes.\n",
  357. X            bt_pfxsaved);
  358. X}
  359. X#endif
  360. END_OF_FILE
  361. if test 8734 -ne `wc -c <'btree/bt_debug.c'`; then
  362.     echo shar: \"'btree/bt_debug.c'\" unpacked with wrong size!
  363. fi
  364. # end of 'btree/bt_debug.c'
  365. fi
  366. if test -f 'btree/bt_delete.c' -a "${1}" != "-c" ; then 
  367.   echo shar: Will not clobber existing file \"'btree/bt_delete.c'\"
  368. else
  369. echo shar: Extracting \"'btree/bt_delete.c'\" \(9222 characters\)
  370. sed "s/^X//" >'btree/bt_delete.c' <<'END_OF_FILE'
  371. X/*-
  372. X * Copyright (c) 1990, 1993
  373. X *    The Regents of the University of California.  All rights reserved.
  374. X *
  375. X * This code is derived from software contributed to Berkeley by
  376. X * Mike Olson.
  377. X *
  378. X * Redistribution and use in source and binary forms, with or without
  379. X * modification, are permitted provided that the following conditions
  380. X * are met:
  381. X * 1. Redistributions of source code must retain the above copyright
  382. X *    notice, this list of conditions and the following disclaimer.
  383. X * 2. Redistributions in binary form must reproduce the above copyright
  384. X *    notice, this list of conditions and the following disclaimer in the
  385. X *    documentation and/or other materials provided with the distribution.
  386. X * 3. All advertising materials mentioning features or use of this software
  387. X *    must display the following acknowledgement:
  388. X *    This product includes software developed by the University of
  389. X *    California, Berkeley and its contributors.
  390. X * 4. Neither the name of the University nor the names of its contributors
  391. X *    may be used to endorse or promote products derived from this software
  392. X *    without specific prior written permission.
  393. X *
  394. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  395. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  396. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  397. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  398. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  399. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  400. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  401. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  402. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  403. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  404. X * SUCH DAMAGE.
  405. X */
  406. X
  407. X#if defined(LIBC_SCCS) && !defined(lint)
  408. Xstatic char sccsid[] = "@(#)bt_delete.c    8.1 (Berkeley) 6/4/93";
  409. X#endif /* LIBC_SCCS and not lint */
  410. X
  411. X#include <sys/types.h>
  412. X
  413. X#include <errno.h>
  414. X#include <stdio.h>
  415. X#include <string.h>
  416. X
  417. X#include <db.h>
  418. X#include "btree.h"
  419. X
  420. Xstatic int bt_bdelete __P((BTREE *, const DBT *));
  421. X
  422. X/*
  423. X * __BT_DELETE -- Delete the item(s) referenced by a key.
  424. X *
  425. X * Parameters:
  426. X *    dbp:    pointer to access method
  427. X *    key:    key to delete
  428. X *    flags:    R_CURSOR if deleting what the cursor references
  429. X *
  430. X * Returns:
  431. X *    RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
  432. X */
  433. Xint
  434. X__bt_delete(dbp, key, flags)
  435. X    const DB *dbp;
  436. X    const DBT *key;
  437. X    u_int flags;
  438. X{
  439. X    BTREE *t;
  440. X    int status;
  441. X
  442. X    t = dbp->internal;
  443. X    if (ISSET(t, B_RDONLY)) {
  444. X        errno = EPERM;
  445. X        return (RET_ERROR);
  446. X    }
  447. X    switch(flags) {
  448. X    case 0:
  449. X        status = bt_bdelete(t, key);
  450. X        break;
  451. X    case R_CURSOR:
  452. X        /*
  453. X         * If flags is R_CURSOR, delete the cursor; must already have
  454. X         * started a scan and not have already deleted the record.  For
  455. X         * the delete cursor bit to have been set requires that the
  456. X         * scan be initialized, so no reason to check.
  457. X         */
  458. X        if (!ISSET(t, B_SEQINIT))
  459. X                        goto einval;
  460. X        status = ISSET(t, B_DELCRSR) ?
  461. X            RET_SPECIAL : __bt_crsrdel(t, &t->bt_bcursor);
  462. X        break;
  463. X    default:
  464. Xeinval:        errno = EINVAL;
  465. X        return (RET_ERROR);
  466. X    }
  467. X    if (status == RET_SUCCESS)
  468. X        SET(t, B_MODIFIED);
  469. X    return (status);
  470. X}
  471. X
  472. X/*
  473. X * BT_BDELETE -- Delete all key/data pairs matching the specified key.
  474. X *
  475. X * Parameters:
  476. X *    tree:    tree
  477. X *    key:    key to delete
  478. X *
  479. X * Returns:
  480. X *    RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
  481. X */
  482. Xstatic int
  483. Xbt_bdelete(t, key)
  484. X    BTREE *t;
  485. X    const DBT *key;
  486. X{
  487. X    EPG *e, save;
  488. X    PAGE *h;
  489. X    pgno_t cpgno, pg;
  490. X    indx_t cindex;
  491. X    int deleted, dirty1, dirty2, exact;
  492. X
  493. X    /* Find any matching record; __bt_search pins the page. */
  494. X    if ((e = __bt_search(t, key, &exact)) == NULL)
  495. X        return (RET_ERROR);
  496. X    if (!exact) {
  497. X        mpool_put(t->bt_mp, e->page, 0);
  498. X        return (RET_SPECIAL);
  499. X    }
  500. X
  501. X    /*
  502. X     * Delete forward, then delete backward, from the found key.  The
  503. X     * ordering is so that the deletions don't mess up the page refs.
  504. X     * The first loop deletes the key from the original page, the second
  505. X     * unpins the original page.  In the first loop, dirty1 is set if
  506. X     * the original page is modified, and dirty2 is set if any subsequent
  507. X     * pages are modified.  In the second loop, dirty1 starts off set if
  508. X     * the original page has been modified, and is set if any subsequent
  509. X     * pages are modified.
  510. X     *
  511. X     * If find the key referenced by the cursor, don't delete it, just
  512. X     * flag it for future deletion.  The cursor page number is P_INVALID
  513. X     * unless the sequential scan is initialized, so no reason to check.
  514. X     * A special case is when the already deleted cursor record was the
  515. X     * only record found.  If so, then the delete opertion fails as no
  516. X     * records were deleted.
  517. X     *
  518. X     * Cycle in place in the current page until the current record doesn't
  519. X     * match the key or the page is empty.  If the latter, walk forward,
  520. X     * skipping empty pages and repeating until a record doesn't match
  521. X     * the key or the end of the tree is reached.
  522. X     */
  523. X    cpgno = t->bt_bcursor.pgno;
  524. X    cindex = t->bt_bcursor.index;
  525. X    save = *e;
  526. X    dirty1 = 0;
  527. X    for (h = e->page, deleted = 0;;) {
  528. X        dirty2 = 0;
  529. X        do {
  530. X            if (h->pgno == cpgno && e->index == cindex) {
  531. X                if (!ISSET(t, B_DELCRSR)) {
  532. X                    SET(t, B_DELCRSR);
  533. X                    deleted = 1;
  534. X                }
  535. X                ++e->index;
  536. X            } else {
  537. X                if (__bt_dleaf(t, h, e->index)) {
  538. X                    if (h->pgno != save.page->pgno)
  539. X                        mpool_put(t->bt_mp, h, dirty2);
  540. X                    mpool_put(t->bt_mp, save.page, dirty1);
  541. X                    return (RET_ERROR);
  542. X                }
  543. X                if (h->pgno == save.page->pgno)
  544. X                    dirty1 = MPOOL_DIRTY;
  545. X                else
  546. X                    dirty2 = MPOOL_DIRTY;
  547. X                deleted = 1;
  548. X            }
  549. X        } while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
  550. X
  551. X        /*
  552. X         * Quit if didn't find a match, no next page, or first key on
  553. X         * the next page doesn't match.  Don't unpin the original page
  554. X         * unless an error occurs.
  555. X         */
  556. X        if (e->index < NEXTINDEX(h))
  557. X            break;
  558. X        for (;;) {
  559. X            if ((pg = h->nextpg) == P_INVALID)
  560. X                goto done1;
  561. X            if (h->pgno != save.page->pgno)
  562. X                mpool_put(t->bt_mp, h, dirty2);
  563. X            if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
  564. X                mpool_put(t->bt_mp, save.page, dirty1);
  565. X                return (RET_ERROR);
  566. X            }
  567. X            if (NEXTINDEX(h) != 0) {
  568. X                e->page = h;
  569. X                e->index = 0;
  570. X                break;
  571. X            }
  572. X        }
  573. X
  574. X        if (__bt_cmp(t, key, e) != 0)
  575. X            break;
  576. X    }
  577. X
  578. X    /*
  579. X     * Reach here with the original page and the last page referenced
  580. X     * pinned (they may be the same).  Release it if not the original.
  581. X     */
  582. Xdone1:    if (h->pgno != save.page->pgno)
  583. X        mpool_put(t->bt_mp, h, dirty2);
  584. X
  585. X    /*
  586. X     * Walk backwards from the record previous to the record returned by
  587. X     * __bt_search, skipping empty pages, until a record doesn't match
  588. X     * the key or reach the beginning of the tree.
  589. X     */
  590. X    *e = save;
  591. X    for (;;) {
  592. X        if (e->index)
  593. X            --e->index;
  594. X        for (h = e->page; e->index; --e->index) {
  595. X            if (__bt_cmp(t, key, e) != 0)
  596. X                goto done2;
  597. X            if (h->pgno == cpgno && e->index == cindex) {
  598. X                if (!ISSET(t, B_DELCRSR)) {
  599. X                    SET(t, B_DELCRSR);
  600. X                    deleted = 1;
  601. X                }
  602. X            } else {
  603. X                if (__bt_dleaf(t, h, e->index) == RET_ERROR) {
  604. X                    mpool_put(t->bt_mp, h, dirty1);
  605. X                    return (RET_ERROR);
  606. X                }
  607. X                if (h->pgno == save.page->pgno)
  608. X                    dirty1 = MPOOL_DIRTY;
  609. X                deleted = 1;
  610. X            }
  611. X        }
  612. X
  613. X        if ((pg = h->prevpg) == P_INVALID)
  614. X            goto done2;
  615. X        mpool_put(t->bt_mp, h, dirty1);
  616. X        dirty1 = 0;
  617. X        if ((e->page = mpool_get(t->bt_mp, pg, 0)) == NULL)
  618. X            return (RET_ERROR);
  619. X        e->index = NEXTINDEX(e->page);
  620. X    }
  621. X
  622. X    /*
  623. X     * Reach here with the last page that was looked at pinned.  Release
  624. X     * it.
  625. X     */
  626. Xdone2:    mpool_put(t->bt_mp, h, dirty1);
  627. X    return (deleted ? RET_SUCCESS : RET_SPECIAL);
  628. X}
  629. X
  630. X/*
  631. X * __BT_DLEAF -- Delete a single record from a leaf page.
  632. X *
  633. X * Parameters:
  634. X *    t:    tree
  635. X *    index:    index on current page to delete
  636. X *
  637. X * Returns:
  638. X *    RET_SUCCESS, RET_ERROR.
  639. X */
  640. Xint
  641. X__bt_dleaf(t, h, index)
  642. X    BTREE *t;
  643. X    PAGE *h;
  644. X    int index;
  645. X{
  646. X    register BLEAF *bl;
  647. X    register indx_t *ip, offset;
  648. X    register size_t nbytes;
  649. X    register int cnt;
  650. X    char *from;
  651. X    void *to;
  652. X
  653. X    /*
  654. X     * Delete a record from a btree leaf page.  Internal records are never
  655. X     * deleted from internal pages, regardless of the records that caused
  656. X     * them to be added being deleted.  Pages made empty by deletion are
  657. X     * not reclaimed.  They are, however, made available for reuse.
  658. X     *
  659. X     * Pack the remaining entries at the end of the page, shift the indices
  660. X     * down, overwriting the deleted record and its index.  If the record
  661. X     * uses overflow pages, make them available for reuse.
  662. X     */
  663. X    to = bl = GETBLEAF(h, index);
  664. X    if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
  665. X        return (RET_ERROR);
  666. X    if (bl->flags & P_BIGDATA &&
  667. X        __ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
  668. X        return (RET_ERROR);
  669. X    nbytes = NBLEAF(bl);
  670. X
  671. X    /*
  672. X     * Compress the key/data pairs.  Compress and adjust the [BR]LEAF
  673. X     * offsets.  Reset the headers.
  674. X     */
  675. X    from = (char *)h + h->upper;
  676. X    memmove(from + nbytes, from, (char *)to - from);
  677. X    h->upper += nbytes;
  678. X
  679. X    offset = h->linp[index];
  680. X    for (cnt = index, ip = &h->linp[0]; cnt--; ++ip)
  681. X        if (ip[0] < offset)
  682. X            ip[0] += nbytes;
  683. X    for (cnt = NEXTINDEX(h) - index; --cnt; ++ip)
  684. X        ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
  685. X    h->lower -= sizeof(indx_t);
  686. X    return (RET_SUCCESS);
  687. X}
  688. END_OF_FILE
  689. if test 9222 -ne `wc -c <'btree/bt_delete.c'`; then
  690.     echo shar: \"'btree/bt_delete.c'\" unpacked with wrong size!
  691. fi
  692. # end of 'btree/bt_delete.c'
  693. fi
  694. if test -f 'btree/bt_open.c' -a "${1}" != "-c" ; then 
  695.   echo shar: Will not clobber existing file \"'btree/bt_open.c'\"
  696. else
  697. echo shar: Extracting \"'btree/bt_open.c'\" \(10894 characters\)
  698. sed "s/^X//" >'btree/bt_open.c' <<'END_OF_FILE'
  699. X/*-
  700. X * Copyright (c) 1990, 1993
  701. X *    The Regents of the University of California.  All rights reserved.
  702. X *
  703. X * This code is derived from software contributed to Berkeley by
  704. X * Mike Olson.
  705. X *
  706. X * Redistribution and use in source and binary forms, with or without
  707. X * modification, are permitted provided that the following conditions
  708. X * are met:
  709. X * 1. Redistributions of source code must retain the above copyright
  710. X *    notice, this list of conditions and the following disclaimer.
  711. X * 2. Redistributions in binary form must reproduce the above copyright
  712. X *    notice, this list of conditions and the following disclaimer in the
  713. X *    documentation and/or other materials provided with the distribution.
  714. X * 3. All advertising materials mentioning features or use of this software
  715. X *    must display the following acknowledgement:
  716. X *    This product includes software developed by the University of
  717. X *    California, Berkeley and its contributors.
  718. X * 4. Neither the name of the University nor the names of its contributors
  719. X *    may be used to endorse or promote products derived from this software
  720. X *    without specific prior written permission.
  721. X *
  722. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  723. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  724. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  725. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  726. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  727. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  728. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  729. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  730. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  731. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  732. X * SUCH DAMAGE.
  733. X */
  734. X
  735. X#if defined(LIBC_SCCS) && !defined(lint)
  736. Xstatic char sccsid[] = "@(#)bt_open.c    8.1 (Berkeley) 6/4/93";
  737. X#endif /* LIBC_SCCS and not lint */
  738. X
  739. X/*
  740. X * Implementation of btree access method for 4.4BSD.
  741. X *
  742. X * The design here was originally based on that of the btree access method
  743. X * used in the Postgres database system at UC Berkeley.  This implementation
  744. X * is wholly independent of the Postgres code.
  745. X */
  746. X
  747. X#include <sys/param.h>
  748. X#include <sys/stat.h>
  749. X
  750. X#include <errno.h>
  751. X#include <fcntl.h>
  752. X#include <limits.h>
  753. X#include <signal.h>
  754. X#include <stdio.h>
  755. X#include <stdlib.h>
  756. X#include <string.h>
  757. X#include <unistd.h>
  758. X
  759. X#define    __DBINTERFACE_PRIVATE
  760. X#include <db.h>
  761. X#include "btree.h"
  762. X
  763. Xstatic int byteorder __P((void));
  764. Xstatic int nroot __P((BTREE *));
  765. Xstatic int tmp __P((void));
  766. X
  767. X/*
  768. X * __BT_OPEN -- Open a btree.
  769. X *
  770. X * Creates and fills a DB struct, and calls the routine that actually
  771. X * opens the btree.
  772. X *
  773. X * Parameters:
  774. X *    fname:    filename (NULL for in-memory trees)
  775. X *    flags:    open flag bits
  776. X *    mode:    open permission bits
  777. X *    b:    BTREEINFO pointer
  778. X *
  779. X * Returns:
  780. X *    NULL on failure, pointer to DB on success.
  781. X *
  782. X */
  783. XDB *
  784. X__bt_open(fname, flags, mode, openinfo)
  785. X    const char *fname;
  786. X    int flags, mode;
  787. X    const BTREEINFO *openinfo;
  788. X{
  789. X    BTMETA m;
  790. X    BTREE *t;
  791. X    BTREEINFO b;
  792. X    DB *dbp;
  793. X    pgno_t ncache;
  794. X    struct stat sb;
  795. X    int machine_lorder, nr;
  796. X
  797. X    t = NULL;
  798. X
  799. X    /*
  800. X     * Intention is to make sure all of the user's selections are okay
  801. X     * here and then use them without checking.  Can't be complete, since
  802. X     * we don't know the right page size, lorder or flags until the backing
  803. X     * file is opened.  Also, the file's page size can cause the cachesize
  804. X     * to change.
  805. X     */
  806. X    machine_lorder = byteorder();
  807. X    if (openinfo) {
  808. X        b = *openinfo;
  809. X
  810. X        /* Flags: R_DUP. */
  811. X        if (b.flags & ~(R_DUP))
  812. X            goto einval;
  813. X
  814. X        /*
  815. X         * Page size must be indx_t aligned and >= MINPSIZE.  Default
  816. X         * page size is set farther on, based on the underlying file
  817. X         * transfer size.
  818. X         */
  819. X        if (b.psize &&
  820. X            (b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 ||
  821. X            b.psize & sizeof(indx_t) - 1))
  822. X            goto einval;
  823. X
  824. X        /* Minimum number of keys per page; absolute minimum is 2. */
  825. X        if (b.minkeypage) {
  826. X            if (b.minkeypage < 2)
  827. X                goto einval;
  828. X        } else
  829. X            b.minkeypage = DEFMINKEYPAGE;
  830. X
  831. X        /* If no comparison, use default comparison and prefix. */
  832. X        if (b.compare == NULL) {
  833. X            b.compare = __bt_defcmp;
  834. X            if (b.prefix == NULL)
  835. X                b.prefix = __bt_defpfx;
  836. X        }
  837. X
  838. X        if (b.lorder == 0)
  839. X            b.lorder = machine_lorder;
  840. X    } else {
  841. X        b.compare = __bt_defcmp;
  842. X        b.cachesize = 0;
  843. X        b.flags = 0;
  844. X        b.lorder = machine_lorder;
  845. X        b.minkeypage = DEFMINKEYPAGE;
  846. X        b.prefix = __bt_defpfx;
  847. X        b.psize = 0;
  848. X    }
  849. X
  850. X    /* Check for the ubiquitous PDP-11. */
  851. X    if (b.lorder != BIG_ENDIAN && b.lorder != LITTLE_ENDIAN)
  852. X        goto einval;
  853. X
  854. X    /* Allocate and initialize DB and BTREE structures. */
  855. X    if ((t = malloc(sizeof(BTREE))) == NULL)
  856. X        goto err;
  857. X    t->bt_fd = -1;            /* Don't close unopened fd on error. */
  858. X    if ((t->bt_dbp = dbp = malloc(sizeof(DB))) == NULL)
  859. X        goto err;
  860. X    t->bt_bcursor.pgno = P_INVALID;
  861. X    t->bt_bcursor.index = 0;
  862. X    t->bt_stack = NULL;
  863. X    t->bt_sp = t->bt_maxstack = 0;
  864. X    t->bt_kbuf = t->bt_dbuf = NULL;
  865. X    t->bt_kbufsz = t->bt_dbufsz = 0;
  866. X    t->bt_lorder = b.lorder;
  867. X    t->bt_order = NOT;
  868. X    t->bt_cmp = b.compare;
  869. X    t->bt_pfx = b.prefix;
  870. X    t->bt_flags = 0;
  871. X    if (t->bt_lorder != machine_lorder)
  872. X        SET(t, B_NEEDSWAP);
  873. X
  874. X    dbp->type = DB_BTREE;
  875. X    dbp->internal = t;
  876. X    dbp->close = __bt_close;
  877. X    dbp->del = __bt_delete;
  878. X    dbp->fd = __bt_fd;
  879. X    dbp->get = __bt_get;
  880. X    dbp->put = __bt_put;
  881. X    dbp->seq = __bt_seq;
  882. X    dbp->sync = __bt_sync;
  883. X
  884. X    /*
  885. X     * If no file name was supplied, this is an in-memory btree and we
  886. X     * open a backing temporary file.  Otherwise, it's a disk-based tree.
  887. X     */
  888. X    if (fname) {
  889. X        switch(flags & O_ACCMODE) {
  890. X        case O_RDONLY:
  891. X            SET(t, B_RDONLY);
  892. X            break;
  893. X        case O_RDWR:
  894. X            break;
  895. X        case O_WRONLY:
  896. X        default:
  897. X            goto einval;
  898. X        }
  899. X        
  900. X        if ((t->bt_fd =
  901. X            open(fname, flags & __USE_OPEN_FLAGS, mode)) < 0)
  902. X            goto err;
  903. X
  904. X    } else {
  905. X        if ((flags & O_ACCMODE) != O_RDWR)
  906. X            goto einval;
  907. X        if ((t->bt_fd = tmp()) == -1)
  908. X            goto err;
  909. X        SET(t, B_INMEM);
  910. X    }
  911. X
  912. X    if (fcntl(t->bt_fd, F_SETFD, 1) == -1)
  913. X        goto err;
  914. X
  915. X    if (fstat(t->bt_fd, &sb))
  916. X        goto err;
  917. X    if (sb.st_size) {
  918. X        nr = read(t->bt_fd, &m, sizeof(BTMETA));
  919. X        if (nr < 0)
  920. X            goto err;
  921. X        if (nr != sizeof(BTMETA))
  922. X            goto eftype;
  923. X
  924. X        /*
  925. X         * Read in the meta-data.  This can change the notion of what
  926. X         * the lorder, page size and flags are, and, when the page size
  927. X         * changes, the cachesize value can change too.  If the user
  928. X         * specified the wrong byte order for an existing database, we
  929. X         * don't bother to return an error, we just clear the NEEDSWAP
  930. X         * bit.
  931. X         */
  932. X        if (m.m_magic == BTREEMAGIC)
  933. X            CLR(t, B_NEEDSWAP);
  934. X        else {
  935. X            SET(t, B_NEEDSWAP);
  936. X            BLSWAP(m.m_magic);
  937. X            BLSWAP(m.m_version);
  938. X            BLSWAP(m.m_psize);
  939. X            BLSWAP(m.m_free);
  940. X            BLSWAP(m.m_nrecs);
  941. X            BLSWAP(m.m_flags);
  942. X        }
  943. X        if (m.m_magic != BTREEMAGIC || m.m_version != BTREEVERSION)
  944. X            goto eftype;
  945. X        if (m.m_psize < MINPSIZE || m.m_psize > MAX_PAGE_OFFSET + 1 ||
  946. X            m.m_psize & sizeof(indx_t) - 1)
  947. X            goto eftype;
  948. X        if (m.m_flags & ~SAVEMETA)
  949. X            goto eftype;
  950. X        b.psize = m.m_psize;
  951. X        t->bt_flags |= m.m_flags;
  952. X        t->bt_free = m.m_free;
  953. X        t->bt_nrecs = m.m_nrecs;
  954. X    } else {
  955. X        /*
  956. X         * Set the page size to the best value for I/O to this file.
  957. X         * Don't overflow the page offset type.
  958. X         */
  959. X        if (b.psize == 0) {
  960. X            b.psize = sb.st_blksize;
  961. X            if (b.psize < MINPSIZE)
  962. X                b.psize = MINPSIZE;
  963. X            if (b.psize > MAX_PAGE_OFFSET + 1)
  964. X                b.psize = MAX_PAGE_OFFSET + 1;
  965. X        }
  966. X
  967. X        /* Set flag if duplicates permitted. */
  968. X        if (!(b.flags & R_DUP))
  969. X            SET(t, B_NODUPS);
  970. X
  971. X        t->bt_free = P_INVALID;
  972. X        t->bt_nrecs = 0;
  973. X        SET(t, B_METADIRTY);
  974. X    }
  975. X
  976. X    t->bt_psize = b.psize;
  977. X
  978. X    /* Set the cache size; must be a multiple of the page size. */
  979. X    if (b.cachesize && b.cachesize & b.psize - 1)
  980. X        b.cachesize += (~b.cachesize & b.psize - 1) + 1;
  981. X    if (b.cachesize < b.psize * MINCACHE)
  982. X        b.cachesize = b.psize * MINCACHE;
  983. X
  984. X    /* Calculate number of pages to cache. */
  985. X    ncache = (b.cachesize + t->bt_psize - 1) / t->bt_psize;
  986. X
  987. X    /*
  988. X     * The btree data structure requires that at least two keys can fit on
  989. X     * a page, but other than that there's no fixed requirement.  The user
  990. X     * specified a minimum number per page, and we translated that into the
  991. X     * number of bytes a key/data pair can use before being placed on an
  992. X     * overflow page.  This calculation includes the page header, the size
  993. X     * of the index referencing the leaf item and the size of the leaf item
  994. X     * structure.  Also, don't let the user specify a minkeypage such that
  995. X     * a key/data pair won't fit even if both key and data are on overflow
  996. X     * pages.
  997. X     */
  998. X    t->bt_ovflsize = (t->bt_psize - BTDATAOFF) / b.minkeypage -
  999. X        (sizeof(indx_t) + NBLEAFDBT(0, 0));
  1000. X    if (t->bt_ovflsize < NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t))
  1001. X        t->bt_ovflsize =
  1002. X            NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t);
  1003. X
  1004. X    /* Initialize the buffer pool. */
  1005. X    if ((t->bt_mp =
  1006. X        mpool_open(NULL, t->bt_fd, t->bt_psize, ncache)) == NULL)
  1007. X        goto err;
  1008. X    if (!ISSET(t, B_INMEM))
  1009. X        mpool_filter(t->bt_mp, __bt_pgin, __bt_pgout, t);
  1010. X
  1011. X    /* Create a root page if new tree. */
  1012. X    if (nroot(t) == RET_ERROR)
  1013. X        goto err;
  1014. X
  1015. X    return (dbp);
  1016. X
  1017. Xeinval:    errno = EINVAL;
  1018. X    goto err;
  1019. X
  1020. Xeftype:    errno = EFTYPE;
  1021. X    goto err;
  1022. X
  1023. Xerr:    if (t) {
  1024. X        if (t->bt_dbp)
  1025. X            free(t->bt_dbp);
  1026. X        if (t->bt_fd != -1)
  1027. X            (void)close(t->bt_fd);
  1028. X        free(t);
  1029. X    }
  1030. X    return (NULL);
  1031. X}
  1032. X
  1033. X/*
  1034. X * NROOT -- Create the root of a new tree.
  1035. X *
  1036. X * Parameters:
  1037. X *    t:    tree
  1038. X *
  1039. X * Returns:
  1040. X *    RET_ERROR, RET_SUCCESS
  1041. X */
  1042. Xstatic int
  1043. Xnroot(t)
  1044. X    BTREE *t;
  1045. X{
  1046. X    PAGE *meta, *root;
  1047. X    pgno_t npg;
  1048. X
  1049. X    if ((meta = mpool_get(t->bt_mp, 0, 0)) != NULL) {
  1050. X        mpool_put(t->bt_mp, meta, 0);
  1051. X        return (RET_SUCCESS);
  1052. X    }
  1053. X    if (errno != EINVAL)
  1054. X        return (RET_ERROR);
  1055. X
  1056. X    if ((meta = mpool_new(t->bt_mp, &npg)) == NULL)
  1057. X        return (RET_ERROR);
  1058. X
  1059. X    if ((root = mpool_new(t->bt_mp, &npg)) == NULL)
  1060. X        return (RET_ERROR);
  1061. X
  1062. X    if (npg != P_ROOT)
  1063. X        return (RET_ERROR);
  1064. X    root->pgno = npg;
  1065. X    root->prevpg = root->nextpg = P_INVALID;
  1066. X    root->lower = BTDATAOFF;
  1067. X    root->upper = t->bt_psize;
  1068. X    root->flags = P_BLEAF;
  1069. X    memset(meta, 0, t->bt_psize);
  1070. X    mpool_put(t->bt_mp, meta, MPOOL_DIRTY);
  1071. X    mpool_put(t->bt_mp, root, MPOOL_DIRTY);
  1072. X    return (RET_SUCCESS);
  1073. X}
  1074. X
  1075. Xstatic int
  1076. Xtmp()
  1077. X{
  1078. X    sigset_t set, oset;
  1079. X    int fd;
  1080. X    char *envtmp;
  1081. X    char path[MAXPATHLEN];
  1082. X
  1083. X    envtmp = getenv("TMPDIR");
  1084. X    (void)snprintf(path,
  1085. X        sizeof(path), "%s/bt.XXXXXX", envtmp ? envtmp : "/tmp");
  1086. X
  1087. X    (void)sigfillset(&set);
  1088. X    (void)sigprocmask(SIG_BLOCK, &set, &oset);
  1089. X    if ((fd = mkstemp(path)) != -1)
  1090. X        (void)unlink(path);
  1091. X    (void)sigprocmask(SIG_SETMASK, &oset, NULL);
  1092. X    return(fd);
  1093. X}
  1094. X
  1095. Xstatic int
  1096. Xbyteorder()
  1097. X{
  1098. X    u_long x;            /* XXX: 32-bit assumption. */
  1099. X    u_char *p;
  1100. X
  1101. X    x = 0x01020304;
  1102. X    p = (u_char *)&x;
  1103. X    switch (*p) {
  1104. X    case 1:
  1105. X        return (BIG_ENDIAN);
  1106. X    case 4:
  1107. X        return (LITTLE_ENDIAN);
  1108. X    default:
  1109. X        return (0);
  1110. X    }
  1111. X}
  1112. X
  1113. Xint
  1114. X__bt_fd(dbp)
  1115. X        const DB *dbp;
  1116. X{
  1117. X    BTREE *t;
  1118. X
  1119. X    t = dbp->internal;
  1120. X
  1121. X    if (ISSET(t, B_INMEM)) {
  1122. X        errno = ENOENT;
  1123. X        return (-1);
  1124. X    }
  1125. X    return (t->bt_fd);
  1126. X}
  1127. END_OF_FILE
  1128. if test 10894 -ne `wc -c <'btree/bt_open.c'`; then
  1129.     echo shar: \"'btree/bt_open.c'\" unpacked with wrong size!
  1130. fi
  1131. # end of 'btree/bt_open.c'
  1132. fi
  1133. if test -f 'btree/bt_put.c' -a "${1}" != "-c" ; then 
  1134.   echo shar: Will not clobber existing file \"'btree/bt_put.c'\"
  1135. else
  1136. echo shar: Extracting \"'btree/bt_put.c'\" \(8268 characters\)
  1137. sed "s/^X//" >'btree/bt_put.c' <<'END_OF_FILE'
  1138. X/*-
  1139. X * Copyright (c) 1990, 1993
  1140. X *    The Regents of the University of California.  All rights reserved.
  1141. X *
  1142. X * This code is derived from software contributed to Berkeley by
  1143. X * Mike Olson.
  1144. X *
  1145. X * Redistribution and use in source and binary forms, with or without
  1146. X * modification, are permitted provided that the following conditions
  1147. X * are met:
  1148. X * 1. Redistributions of source code must retain the above copyright
  1149. X *    notice, this list of conditions and the following disclaimer.
  1150. X * 2. Redistributions in binary form must reproduce the above copyright
  1151. X *    notice, this list of conditions and the following disclaimer in the
  1152. X *    documentation and/or other materials provided with the distribution.
  1153. X * 3. All advertising materials mentioning features or use of this software
  1154. X *    must display the following acknowledgement:
  1155. X *    This product includes software developed by the University of
  1156. X *    California, Berkeley and its contributors.
  1157. X * 4. Neither the name of the University nor the names of its contributors
  1158. X *    may be used to endorse or promote products derived from this software
  1159. X *    without specific prior written permission.
  1160. X *
  1161. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1162. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1163. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1164. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1165. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1166. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1167. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1168. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1169. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1170. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1171. X * SUCH DAMAGE.
  1172. X */
  1173. X
  1174. X#if defined(LIBC_SCCS) && !defined(lint)
  1175. Xstatic char sccsid[] = "@(#)bt_put.c    8.1 (Berkeley) 6/4/93";
  1176. X#endif /* LIBC_SCCS and not lint */
  1177. X
  1178. X#include <sys/types.h>
  1179. X
  1180. X#include <errno.h>
  1181. X#include <stdio.h>
  1182. X#include <stdlib.h>
  1183. X#include <string.h>
  1184. X
  1185. X#include <db.h>
  1186. X#include "btree.h"
  1187. X
  1188. Xstatic EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
  1189. X
  1190. X/*
  1191. X * __BT_PUT -- Add a btree item to the tree.
  1192. X *
  1193. X * Parameters:
  1194. X *    dbp:    pointer to access method
  1195. X *    key:    key
  1196. X *    data:    data
  1197. X *    flag:    R_NOOVERWRITE
  1198. X *
  1199. X * Returns:
  1200. X *    RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
  1201. X *    tree and R_NOOVERWRITE specified.
  1202. X */
  1203. Xint
  1204. X__bt_put(dbp, key, data, flags)
  1205. X    const DB *dbp;
  1206. X    DBT *key;
  1207. X    const DBT *data;
  1208. X    u_int flags;
  1209. X{
  1210. X    BTREE *t;
  1211. X    DBT tkey, tdata;
  1212. X    EPG *e;
  1213. X    PAGE *h;
  1214. X    indx_t index, nxtindex;
  1215. X    pgno_t pg;
  1216. X    size_t nbytes;
  1217. X    int dflags, exact, status;
  1218. X    char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
  1219. X
  1220. X    t = dbp->internal;
  1221. X
  1222. X    switch (flags) {
  1223. X    case R_CURSOR:
  1224. X        if (!ISSET(t, B_SEQINIT))
  1225. X            goto einval;
  1226. X        if (ISSET(t, B_DELCRSR))
  1227. X            goto einval;
  1228. X        break;
  1229. X    case 0:
  1230. X    case R_NOOVERWRITE:
  1231. X        break;
  1232. X    default:
  1233. Xeinval:        errno = EINVAL;
  1234. X        return (RET_ERROR);
  1235. X    }
  1236. X
  1237. X    if (ISSET(t, B_RDONLY)) {
  1238. X        errno = EPERM;
  1239. X        return (RET_ERROR);
  1240. X    }
  1241. X
  1242. X    /*
  1243. X     * If the key/data won't fit on a page, store it on indirect pages.
  1244. X     * Only store the key on the overflow page if it's too big after the
  1245. X     * data is on an overflow page.
  1246. X     *
  1247. X     * XXX
  1248. X     * If the insert fails later on, these pages aren't recovered.
  1249. X     */
  1250. X    dflags = 0;
  1251. X    if (key->size + data->size > t->bt_ovflsize) {
  1252. X        if (key->size > t->bt_ovflsize) {
  1253. Xstorekey:        if (__ovfl_put(t, key, &pg) == RET_ERROR)
  1254. X                return (RET_ERROR);
  1255. X            tkey.data = kb;
  1256. X            tkey.size = NOVFLSIZE;
  1257. X            memmove(kb, &pg, sizeof(pgno_t));
  1258. X            memmove(kb + sizeof(pgno_t),
  1259. X                &key->size, sizeof(size_t));
  1260. X            dflags |= P_BIGKEY;
  1261. X            key = &tkey;
  1262. X        }
  1263. X        if (key->size + data->size > t->bt_ovflsize) {
  1264. X            if (__ovfl_put(t, data, &pg) == RET_ERROR)
  1265. X                return (RET_ERROR);
  1266. X            tdata.data = db;
  1267. X            tdata.size = NOVFLSIZE;
  1268. X            memmove(db, &pg, sizeof(pgno_t));
  1269. X            memmove(db + sizeof(pgno_t),
  1270. X                &data->size, sizeof(size_t));
  1271. X            dflags |= P_BIGDATA;
  1272. X            data = &tdata;
  1273. X        }
  1274. X        if (key->size + data->size > t->bt_ovflsize)
  1275. X            goto storekey;
  1276. X    }
  1277. X
  1278. X    /* Replace the cursor. */
  1279. X    if (flags == R_CURSOR) {
  1280. X        if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL)
  1281. X            return (RET_ERROR);
  1282. X        index = t->bt_bcursor.index;
  1283. X        goto delete;
  1284. X    }
  1285. X
  1286. X    /*
  1287. X     * Find the key to delete, or, the location at which to insert.  Bt_fast
  1288. X     * and __bt_search pin the returned page.
  1289. X     */
  1290. X    if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
  1291. X        if ((e = __bt_search(t, key, &exact)) == NULL)
  1292. X            return (RET_ERROR);
  1293. X    h = e->page;
  1294. X    index = e->index;
  1295. X
  1296. X    /*
  1297. X     * Add the specified key/data pair to the tree.  If an identical key
  1298. X     * is already in the tree, and R_NOOVERWRITE is set, an error is
  1299. X     * returned.  If R_NOOVERWRITE is not set, the key is either added (if
  1300. X     * duplicates are permitted) or an error is returned.
  1301. X     *
  1302. X     * Pages are split as required.
  1303. X     */
  1304. X    switch (flags) {
  1305. X    case R_NOOVERWRITE:
  1306. X        if (!exact)
  1307. X            break;
  1308. X        /*
  1309. X         * One special case is if the cursor references the record and
  1310. X         * it's been flagged for deletion.  Then, we delete the record,
  1311. X         * leaving the cursor there -- this means that the inserted
  1312. X         * record will not be seen in a cursor scan.
  1313. X         */
  1314. X        if (ISSET(t, B_DELCRSR) && t->bt_bcursor.pgno == h->pgno &&
  1315. X            t->bt_bcursor.index == index) {
  1316. X            CLR(t, B_DELCRSR);
  1317. X            goto delete;
  1318. X        }
  1319. X        mpool_put(t->bt_mp, h, 0);
  1320. X        return (RET_SPECIAL);
  1321. X    default:
  1322. X        if (!exact || !ISSET(t, B_NODUPS))
  1323. X            break;
  1324. Xdelete:        if (__bt_dleaf(t, h, index) == RET_ERROR) {
  1325. X            mpool_put(t->bt_mp, h, 0);
  1326. X            return (RET_ERROR);
  1327. X        }
  1328. X        break;
  1329. X    }
  1330. X
  1331. X    /*
  1332. X     * If not enough room, or the user has put a ceiling on the number of
  1333. X     * keys permitted in the page, split the page.  The split code will
  1334. X     * insert the key and data and unpin the current page.  If inserting
  1335. X     * into the offset array, shift the pointers up.
  1336. X     */
  1337. X    nbytes = NBLEAFDBT(key->size, data->size);
  1338. X    if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
  1339. X        if ((status = __bt_split(t, h, key,
  1340. X            data, dflags, nbytes, index)) != RET_SUCCESS)
  1341. X            return (status);
  1342. X        goto success;
  1343. X    }
  1344. X
  1345. X    if (index < (nxtindex = NEXTINDEX(h)))
  1346. X        memmove(h->linp + index + 1, h->linp + index,
  1347. X            (nxtindex - index) * sizeof(indx_t));
  1348. X    h->lower += sizeof(indx_t);
  1349. X
  1350. X    h->linp[index] = h->upper -= nbytes;
  1351. X    dest = (char *)h + h->upper;
  1352. X    WR_BLEAF(dest, key, data, dflags);
  1353. X
  1354. X    if (t->bt_order == NOT)
  1355. X        if (h->nextpg == P_INVALID) {
  1356. X            if (index == NEXTINDEX(h) - 1) {
  1357. X                t->bt_order = FORWARD;
  1358. X                t->bt_last.index = index;
  1359. X                t->bt_last.pgno = h->pgno;
  1360. X            }
  1361. X        } else if (h->prevpg == P_INVALID) {
  1362. X            if (index == 0) {
  1363. X                t->bt_order = BACK;
  1364. X                t->bt_last.index = 0;
  1365. X                t->bt_last.pgno = h->pgno;
  1366. X            }
  1367. X        }
  1368. X
  1369. X    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  1370. X
  1371. Xsuccess:
  1372. X    if (flags == R_SETCURSOR) {
  1373. X        t->bt_bcursor.pgno = e->page->pgno;
  1374. X        t->bt_bcursor.index = e->index;
  1375. X    }
  1376. X    SET(t, B_MODIFIED);
  1377. X    return (RET_SUCCESS);
  1378. X}
  1379. X
  1380. X#ifdef STATISTICS
  1381. Xu_long bt_cache_hit, bt_cache_miss;
  1382. X#endif
  1383. X
  1384. X/*
  1385. X * BT_FAST -- Do a quick check for sorted data.
  1386. X *
  1387. X * Parameters:
  1388. X *    t:    tree
  1389. X *    key:    key to insert
  1390. X *
  1391. X * Returns:
  1392. X *     EPG for new record or NULL if not found.
  1393. X */
  1394. Xstatic EPG *
  1395. Xbt_fast(t, key, data, exactp)
  1396. X    BTREE *t;
  1397. X    const DBT *key, *data;
  1398. X    int *exactp;
  1399. X{
  1400. X    EPG e;
  1401. X    PAGE *h;
  1402. X    size_t nbytes;
  1403. X    int cmp;
  1404. X
  1405. X    if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
  1406. X        t->bt_order = NOT;
  1407. X        return (NULL);
  1408. X    }
  1409. X    e.page = h;
  1410. X    e.index = t->bt_last.index;
  1411. X
  1412. X    /*
  1413. X     * If won't fit in this page or have too many keys in this page, have
  1414. X     * to search to get split stack.
  1415. X     */
  1416. X    nbytes = NBLEAFDBT(key->size, data->size);
  1417. X    if (h->upper - h->lower < nbytes + sizeof(indx_t))
  1418. X        goto miss;
  1419. X
  1420. X    if (t->bt_order == FORWARD) {
  1421. X        if (e.page->nextpg != P_INVALID)
  1422. X            goto miss;
  1423. X        if (e.index != NEXTINDEX(h) - 1)
  1424. X            goto miss;
  1425. X        if ((cmp = __bt_cmp(t, key, &e)) < 0)
  1426. X            goto miss;
  1427. X        t->bt_last.index = cmp ? ++e.index : e.index;
  1428. X    } else {
  1429. X        if (e.page->prevpg != P_INVALID)
  1430. X            goto miss;
  1431. X        if (e.index != 0)
  1432. X            goto miss;
  1433. X        if ((cmp = __bt_cmp(t, key, &e)) > 0)
  1434. X            goto miss;
  1435. X        t->bt_last.index = 0;
  1436. X    }
  1437. X    *exactp = cmp == 0;
  1438. X#ifdef STATISTICS
  1439. X    ++bt_cache_hit;
  1440. X#endif
  1441. X    return (&e);
  1442. X
  1443. Xmiss:
  1444. X#ifdef STATISTICS
  1445. X    ++bt_cache_miss;
  1446. X#endif
  1447. X    t->bt_order = NOT;
  1448. X    mpool_put(t->bt_mp, h, 0);
  1449. X    return (NULL);
  1450. X}
  1451. END_OF_FILE
  1452. if test 8268 -ne `wc -c <'btree/bt_put.c'`; then
  1453.     echo shar: \"'btree/bt_put.c'\" unpacked with wrong size!
  1454. fi
  1455. # end of 'btree/bt_put.c'
  1456. fi
  1457. if test -f 'btree/bt_seq.c' -a "${1}" != "-c" ; then 
  1458.   echo shar: Will not clobber existing file \"'btree/bt_seq.c'\"
  1459. else
  1460. echo shar: Extracting \"'btree/bt_seq.c'\" \(9520 characters\)
  1461. sed "s/^X//" >'btree/bt_seq.c' <<'END_OF_FILE'
  1462. X/*-
  1463. X * Copyright (c) 1990, 1993
  1464. X *    The Regents of the University of California.  All rights reserved.
  1465. X *
  1466. X * This code is derived from software contributed to Berkeley by
  1467. X * Mike Olson.
  1468. X *
  1469. X * Redistribution and use in source and binary forms, with or without
  1470. X * modification, are permitted provided that the following conditions
  1471. X * are met:
  1472. X * 1. Redistributions of source code must retain the above copyright
  1473. X *    notice, this list of conditions and the following disclaimer.
  1474. X * 2. Redistributions in binary form must reproduce the above copyright
  1475. X *    notice, this list of conditions and the following disclaimer in the
  1476. X *    documentation and/or other materials provided with the distribution.
  1477. X * 3. All advertising materials mentioning features or use of this software
  1478. X *    must display the following acknowledgement:
  1479. X *    This product includes software developed by the University of
  1480. X *    California, Berkeley and its contributors.
  1481. X * 4. Neither the name of the University nor the names of its contributors
  1482. X *    may be used to endorse or promote products derived from this software
  1483. X *    without specific prior written permission.
  1484. X *
  1485. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1486. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1487. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1488. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1489. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1490. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1491. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1492. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1493. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1494. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1495. X * SUCH DAMAGE.
  1496. X */
  1497. X
  1498. X#if defined(LIBC_SCCS) && !defined(lint)
  1499. Xstatic char sccsid[] = "@(#)bt_seq.c    8.1 (Berkeley) 6/4/93";
  1500. X#endif /* LIBC_SCCS and not lint */
  1501. X
  1502. X#include <sys/types.h>
  1503. X
  1504. X#include <errno.h>
  1505. X#include <stddef.h>
  1506. X#include <stdio.h>
  1507. X#include <stdlib.h>
  1508. X
  1509. X#include <db.h>
  1510. X#include "btree.h"
  1511. X
  1512. Xstatic int     bt_seqadv __P((BTREE *, EPG *, int));
  1513. Xstatic int     bt_seqset __P((BTREE *, EPG *, DBT *, int));
  1514. X
  1515. X/*
  1516. X * Sequential scan support.
  1517. X *
  1518. X * The tree can be scanned sequentially, starting from either end of the tree
  1519. X * or from any specific key.  A scan request before any scanning is done is
  1520. X * initialized as starting from the least node.
  1521. X *
  1522. X * Each tree has an EPGNO which has the current position of the cursor.  The
  1523. X * cursor has to survive deletions/insertions in the tree without losing its
  1524. X * position.  This is done by noting deletions without doing them, and then
  1525. X * doing them when the cursor moves (or the tree is closed).
  1526. X */
  1527. X
  1528. X/*
  1529. X * __BT_SEQ -- Btree sequential scan interface.
  1530. X *
  1531. X * Parameters:
  1532. X *    dbp:    pointer to access method
  1533. X *    key:    key for positioning and return value
  1534. X *    data:    data return value
  1535. X *    flags:    R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
  1536. X *
  1537. X * Returns:
  1538. X *    RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
  1539. X */
  1540. Xint
  1541. X__bt_seq(dbp, key, data, flags)
  1542. X    const DB *dbp;
  1543. X    DBT *key, *data;
  1544. X    u_int flags;
  1545. X{
  1546. X    BTREE *t;
  1547. X    EPG e;
  1548. X    int status;
  1549. X
  1550. X    /*
  1551. X     * If scan unitialized as yet, or starting at a specific record, set
  1552. X     * the scan to a specific key.  Both bt_seqset and bt_seqadv pin the
  1553. X     * page the cursor references if they're successful.
  1554. X     */
  1555. X    t = dbp->internal;
  1556. X    switch(flags) {
  1557. X    case R_NEXT:
  1558. X    case R_PREV:
  1559. X        if (ISSET(t, B_SEQINIT)) {
  1560. X            status = bt_seqadv(t, &e, flags);
  1561. X            break;
  1562. X        }
  1563. X        /* FALLTHROUGH */
  1564. X    case R_CURSOR:
  1565. X    case R_FIRST:
  1566. X    case R_LAST:
  1567. X        status = bt_seqset(t, &e, key, flags);
  1568. X        break;
  1569. X    default:
  1570. X        errno = EINVAL;
  1571. X        return (RET_ERROR);
  1572. X    }
  1573. X
  1574. X    if (status == RET_SUCCESS) {
  1575. X        status = __bt_ret(t, &e, key, data);
  1576. X
  1577. X        /* Update the actual cursor. */
  1578. X        t->bt_bcursor.pgno = e.page->pgno;
  1579. X        t->bt_bcursor.index = e.index;
  1580. X        mpool_put(t->bt_mp, e.page, 0);
  1581. X        SET(t, B_SEQINIT);
  1582. X    }
  1583. X    return (status);
  1584. X}
  1585. X
  1586. X/*
  1587. X * BT_SEQSET -- Set the sequential scan to a specific key.
  1588. X *
  1589. X * Parameters:
  1590. X *    t:    tree
  1591. X *    ep:    storage for returned key
  1592. X *    key:    key for initial scan position
  1593. X *    flags:    R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
  1594. X *
  1595. X * Side effects:
  1596. X *    Pins the page the cursor references.
  1597. X *
  1598. X * Returns:
  1599. X *    RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
  1600. X */
  1601. Xstatic int
  1602. Xbt_seqset(t, ep, key, flags)
  1603. X    BTREE *t;
  1604. X    EPG *ep;
  1605. X    DBT *key;
  1606. X    int flags;
  1607. X{
  1608. X    EPG *e;
  1609. X    PAGE *h;
  1610. X    pgno_t pg;
  1611. X    int exact;
  1612. X
  1613. X    /*
  1614. X     * Delete any already deleted record that we've been saving because
  1615. X     * the cursor pointed to it.  Since going to a specific key, should
  1616. X     * delete any logically deleted records so they aren't found.
  1617. X     */
  1618. X    if (ISSET(t, B_DELCRSR) && __bt_crsrdel(t, &t->bt_bcursor))
  1619. X        return (RET_ERROR);
  1620. X
  1621. X    /*
  1622. X     * Find the first, last or specific key in the tree and point the cursor
  1623. X     * at it.  The cursor may not be moved until a new key has been found.
  1624. X     */
  1625. X    switch(flags) {
  1626. X    case R_CURSOR:                /* Keyed scan. */
  1627. X        /*
  1628. X         * Find the first instance of the key or the smallest key which
  1629. X         * is greater than or equal to the specified key.  If run out
  1630. X         * of keys, return RET_SPECIAL.
  1631. X         */
  1632. X        if (key->data == NULL || key->size == 0) {
  1633. X            errno = EINVAL;
  1634. X            return (RET_ERROR);
  1635. X        }
  1636. X        e = __bt_first(t, key, &exact);    /* Returns pinned page. */
  1637. X        if (e == NULL)
  1638. X            return (RET_ERROR);
  1639. X        /*
  1640. X         * If at the end of a page, skip any empty pages and find the
  1641. X         * next entry.
  1642. X         */
  1643. X        if (e->index == NEXTINDEX(e->page)) {
  1644. X            h = e->page;
  1645. X            do {
  1646. X                pg = h->nextpg;
  1647. X                mpool_put(t->bt_mp, h, 0);
  1648. X                if (pg == P_INVALID)
  1649. X                    return (RET_SPECIAL);
  1650. X                if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1651. X                    return (RET_ERROR);
  1652. X            } while (NEXTINDEX(h) == 0);
  1653. X            e->index = 0;
  1654. X            e->page = h;
  1655. X        }
  1656. X        *ep = *e;
  1657. X        break;
  1658. X    case R_FIRST:                /* First record. */
  1659. X    case R_NEXT:
  1660. X        /* Walk down the left-hand side of the tree. */
  1661. X        for (pg = P_ROOT;;) {
  1662. X            if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1663. X                return (RET_ERROR);
  1664. X            if (h->flags & (P_BLEAF | P_RLEAF))
  1665. X                break;
  1666. X            pg = GETBINTERNAL(h, 0)->pgno;
  1667. X            mpool_put(t->bt_mp, h, 0);
  1668. X        }
  1669. X
  1670. X        /* Skip any empty pages. */
  1671. X        while (NEXTINDEX(h) == 0 && h->nextpg != P_INVALID) {
  1672. X            pg = h->nextpg;
  1673. X            mpool_put(t->bt_mp, h, 0);
  1674. X            if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1675. X                return (RET_ERROR);
  1676. X        }
  1677. X
  1678. X        if (NEXTINDEX(h) == 0) {
  1679. X            mpool_put(t->bt_mp, h, 0);
  1680. X            return (RET_SPECIAL);
  1681. X        }
  1682. X
  1683. X        ep->page = h;
  1684. X        ep->index = 0;
  1685. X        break;
  1686. X    case R_LAST:                /* Last record. */
  1687. X    case R_PREV:
  1688. X        /* Walk down the right-hand side of the tree. */
  1689. X        for (pg = P_ROOT;;) {
  1690. X            if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1691. X                return (RET_ERROR);
  1692. X            if (h->flags & (P_BLEAF | P_RLEAF))
  1693. X                break;
  1694. X            pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
  1695. X            mpool_put(t->bt_mp, h, 0);
  1696. X        }
  1697. X
  1698. X        /* Skip any empty pages. */
  1699. X        while (NEXTINDEX(h) == 0 && h->prevpg != P_INVALID) {
  1700. X            pg = h->prevpg;
  1701. X            mpool_put(t->bt_mp, h, 0);
  1702. X            if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1703. X                return (RET_ERROR);
  1704. X        }
  1705. X
  1706. X        if (NEXTINDEX(h) == 0) {
  1707. X            mpool_put(t->bt_mp, h, 0);
  1708. X            return (RET_SPECIAL);
  1709. X        }
  1710. X
  1711. X        ep->page = h;
  1712. X        ep->index = NEXTINDEX(h) - 1;
  1713. X        break;
  1714. X    }
  1715. X    return (RET_SUCCESS);
  1716. X}
  1717. X
  1718. X/*
  1719. X * BT_SEQADVANCE -- Advance the sequential scan.
  1720. X *
  1721. X * Parameters:
  1722. X *    t:    tree
  1723. X *    flags:    R_NEXT, R_PREV
  1724. X *
  1725. X * Side effects:
  1726. X *    Pins the page the new key/data record is on.
  1727. X *
  1728. X * Returns:
  1729. X *    RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
  1730. X */
  1731. Xstatic int
  1732. Xbt_seqadv(t, e, flags)
  1733. X    BTREE *t;
  1734. X    EPG *e;
  1735. X    int flags;
  1736. X{
  1737. X    EPGNO *c, delc;
  1738. X    PAGE *h;
  1739. X    indx_t index;
  1740. X    pgno_t pg;
  1741. X
  1742. X    /* Save the current cursor if going to delete it. */
  1743. X    c = &t->bt_bcursor;
  1744. X    if (ISSET(t, B_DELCRSR))
  1745. X        delc = *c;
  1746. X
  1747. X    if ((h = mpool_get(t->bt_mp, c->pgno, 0)) == NULL)
  1748. X        return (RET_ERROR);
  1749. X
  1750. X    /*
  1751. X      * Find the next/previous record in the tree and point the cursor at it.
  1752. X     * The cursor may not be moved until a new key has been found.
  1753. X     */
  1754. X    index = c->index;
  1755. X    switch(flags) {
  1756. X    case R_NEXT:            /* Next record. */
  1757. X        if (++index == NEXTINDEX(h)) {
  1758. X            do {
  1759. X                pg = h->nextpg;
  1760. X                mpool_put(t->bt_mp, h, 0);
  1761. X                if (pg == P_INVALID)
  1762. X                    return (RET_SPECIAL);
  1763. X                if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1764. X                    return (RET_ERROR);
  1765. X            } while (NEXTINDEX(h) == 0);
  1766. X            index = 0;
  1767. X        }
  1768. X        break;
  1769. X    case R_PREV:            /* Previous record. */
  1770. X        if (index-- == 0) {
  1771. X            do {
  1772. X                pg = h->prevpg;
  1773. X                mpool_put(t->bt_mp, h, 0);
  1774. X                if (pg == P_INVALID)
  1775. X                    return (RET_SPECIAL);
  1776. X                if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
  1777. X                    return (RET_ERROR);
  1778. X            } while (NEXTINDEX(h) == 0);
  1779. X            index = NEXTINDEX(h) - 1;
  1780. X        }
  1781. X        break;
  1782. X    }
  1783. X
  1784. X    e->page = h;
  1785. X    e->index = index;
  1786. X
  1787. X    /*
  1788. X     * Delete any already deleted record that we've been saving because the
  1789. X     * cursor pointed to it.  This could cause the new index to be shifted
  1790. X     * down by one if the record we're deleting is on the same page and has
  1791. X     * a larger index.
  1792. X     */
  1793. X    if (ISSET(t, B_DELCRSR)) {
  1794. X        CLR(t, B_DELCRSR);            /* Don't try twice. */
  1795. X        if (c->pgno == delc.pgno && c->index > delc.index)
  1796. X            --c->index;
  1797. X        if (__bt_crsrdel(t, &delc))
  1798. X            return (RET_ERROR);
  1799. X    }
  1800. X    return (RET_SUCCESS);
  1801. X}
  1802. X
  1803. X/*
  1804. X * __BT_CRSRDEL -- Delete the record referenced by the cursor.
  1805. X *
  1806. X * Parameters:
  1807. X *    t:    tree
  1808. X *
  1809. X * Returns:
  1810. X *    RET_ERROR, RET_SUCCESS
  1811. X */
  1812. Xint
  1813. X__bt_crsrdel(t, c)
  1814. X    BTREE *t;
  1815. X    EPGNO *c;
  1816. X{
  1817. X    PAGE *h;
  1818. X    int status;
  1819. X
  1820. X    CLR(t, B_DELCRSR);            /* Don't try twice. */
  1821. X    if ((h = mpool_get(t->bt_mp, c->pgno, 0)) == NULL)
  1822. X        return (RET_ERROR);
  1823. X    status = __bt_dleaf(t, h, c->index);
  1824. X    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  1825. X    return (status);
  1826. X}
  1827. END_OF_FILE
  1828. if test 9520 -ne `wc -c <'btree/bt_seq.c'`; then
  1829.     echo shar: \"'btree/bt_seq.c'\" unpacked with wrong size!
  1830. fi
  1831. # end of 'btree/bt_seq.c'
  1832. fi
  1833. if test -f 'doc/hash.3.ps' -a "${1}" != "-c" ; then 
  1834.   echo shar: Will not clobber existing file \"'doc/hash.3.ps'\"
  1835. else
  1836. echo shar: Extracting \"'doc/hash.3.ps'\" \(11062 characters\)
  1837. sed "s/^X//" >'doc/hash.3.ps' <<'END_OF_FILE'
  1838. X%!PS-Adobe-3.0
  1839. X%%Creator: groff version 1.08
  1840. X%%DocumentNeededResources: font Times-Roman
  1841. X%%+ font Times-Bold
  1842. X%%+ font Times-Italic
  1843. X%%DocumentSuppliedResources: procset grops 1.08 0
  1844. X%%Pages: 2
  1845. X%%PageOrder: Ascend
  1846. X%%Orientation: Portrait
  1847. X%%EndComments
  1848. X%%BeginProlog
  1849. X%%BeginResource: procset grops 1.08 0
  1850. X/setpacking where{
  1851. Xpop
  1852. Xcurrentpacking
  1853. Xtrue setpacking
  1854. X}if
  1855. X/grops 120 dict dup begin
  1856. X/SC 32 def
  1857. X/A/show load def
  1858. X/B{0 SC 3 -1 roll widthshow}bind def
  1859. X/C{0 exch ashow}bind def
  1860. X/D{0 exch 0 SC 5 2 roll awidthshow}bind def
  1861. X/E{0 rmoveto show}bind def
  1862. X/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
  1863. X/G{0 rmoveto 0 exch ashow}bind def
  1864. X/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  1865. X/I{0 exch rmoveto show}bind def
  1866. X/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
  1867. X/K{0 exch rmoveto 0 exch ashow}bind def
  1868. X/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  1869. X/M{rmoveto show}bind def
  1870. X/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
  1871. X/O{rmoveto 0 exch ashow}bind def
  1872. X/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  1873. X/Q{moveto show}bind def
  1874. X/R{moveto 0 SC 3 -1 roll widthshow}bind def
  1875. X/S{moveto 0 exch ashow}bind def
  1876. X/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
  1877. X/SF{
  1878. Xfindfont exch
  1879. X[exch dup 0 exch 0 exch neg 0 0]makefont
  1880. Xdup setfont
  1881. X[exch/setfont cvx]cvx bind def
  1882. X}bind def
  1883. X/MF{
  1884. Xfindfont
  1885. X[5 2 roll
  1886. X0 3 1 roll 
  1887. Xneg 0 0]makefont
  1888. Xdup setfont
  1889. X[exch/setfont cvx]cvx bind def
  1890. X}bind def
  1891. X/level0 0 def
  1892. X/RES 0 def
  1893. X/PL 0 def
  1894. X/LS 0 def
  1895. X/PLG{
  1896. Xgsave newpath clippath pathbbox grestore
  1897. Xexch pop add exch pop
  1898. X}bind def
  1899. X/BP{
  1900. X/level0 save def
  1901. X1 setlinecap
  1902. X1 setlinejoin
  1903. X72 RES div dup scale
  1904. XLS{
  1905. X90 rotate
  1906. X}{
  1907. X0 PL translate
  1908. X}ifelse
  1909. X1 -1 scale
  1910. X}bind def
  1911. X/EP{
  1912. Xlevel0 restore
  1913. Xshowpage
  1914. X}bind def
  1915. X/DA{
  1916. Xnewpath arcn stroke
  1917. X}bind def
  1918. X/SN{
  1919. Xtransform
  1920. X.25 sub exch .25 sub exch
  1921. Xround .25 add exch round .25 add exch
  1922. Xitransform
  1923. X}bind def
  1924. X/DL{
  1925. XSN
  1926. Xmoveto
  1927. XSN
  1928. Xlineto stroke
  1929. X}bind def
  1930. X/DC{
  1931. Xnewpath 0 360 arc closepath
  1932. X}bind def
  1933. X/TM matrix def
  1934. X/DE{
  1935. XTM currentmatrix pop
  1936. Xtranslate scale newpath 0 0 .5 0 360 arc closepath
  1937. XTM setmatrix
  1938. X}bind def
  1939. X/RC/rcurveto load def
  1940. X/RL/rlineto load def
  1941. X/ST/stroke load def
  1942. X/MT/moveto load def
  1943. X/CL/closepath load def
  1944. X/FL{
  1945. Xcurrentgray exch setgray fill setgray
  1946. X}bind def
  1947. X/BL/fill load def
  1948. X/LW/setlinewidth load def
  1949. X/RE{
  1950. Xfindfont
  1951. Xdup maxlength 1 index/FontName known not{1 add}if dict begin
  1952. X{
  1953. X1 index/FID ne{def}{pop pop}ifelse
  1954. X}forall
  1955. X/Encoding exch def
  1956. Xdup/FontName exch def
  1957. Xcurrentdict end definefont pop
  1958. X}bind def
  1959. X/DEFS 0 def
  1960. X/EBEGIN{
  1961. Xmoveto
  1962. XDEFS begin
  1963. X}bind def
  1964. X/EEND/end load def
  1965. X/CNT 0 def
  1966. X/level1 0 def
  1967. X/PBEGIN{
  1968. X/level1 save def
  1969. Xtranslate
  1970. Xdiv 3 1 roll div exch scale
  1971. Xneg exch neg exch translate
  1972. X0 setgray
  1973. X0 setlinecap
  1974. X1 setlinewidth
  1975. X0 setlinejoin
  1976. X10 setmiterlimit
  1977. X[]0 setdash
  1978. X/setstrokeadjust where{
  1979. Xpop
  1980. Xfalse setstrokeadjust
  1981. X}if
  1982. X/setoverprint where{
  1983. Xpop
  1984. Xfalse setoverprint
  1985. X}if
  1986. Xnewpath
  1987. X/CNT countdictstack def
  1988. Xuserdict begin
  1989. X/showpage{}def
  1990. X}bind def
  1991. X/PEND{
  1992. Xclear
  1993. Xcountdictstack CNT sub{end}repeat
  1994. Xlevel1 restore
  1995. X}bind def
  1996. Xend def
  1997. X/setpacking where{
  1998. Xpop
  1999. Xsetpacking
  2000. X}if
  2001. X%%EndResource
  2002. X%%IncludeResource: font Times-Roman
  2003. X%%IncludeResource: font Times-Bold
  2004. X%%IncludeResource: font Times-Italic
  2005. Xgrops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
  2006. X792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
  2007. X/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
  2008. X/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
  2009. X/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
  2010. X/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
  2011. X/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
  2012. X/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
  2013. 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
  2014. X/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
  2015. X/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
  2016. X/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
  2017. X/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
  2018. X/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
  2019. X/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
  2020. X/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
  2021. X/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
  2022. X/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
  2023. X/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
  2024. X/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
  2025. X/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
  2026. X/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
  2027. X/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
  2028. X/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
  2029. X/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
  2030. X/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
  2031. X/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
  2032. X%%EndProlog
  2033. X%%Page: 1 1
  2034. X%%BeginPageSetup
  2035. XBP
  2036. X%%EndPageSetup
  2037. X/F0 10/Times-Roman@0 SF 182.62(HASH\(3\) 1993 HASH\(3\))72 48 R/F1 9
  2038. X/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0
  2039. X(hash \255 hash database access method)108 96 Q F1(SYNOPSIS)72 112.8 Q/F2 10
  2040. X/Times-Bold@0 SF(#include <sys/types.h>)108 124.8 Q(#include <db)108 136.8 Q
  2041. X(.h>)-.4 E F1(DESCRIPTION)72 153.6 Q F0 .29(The routine)108 165.6 R/F3 10
  2042. X/Times-Italic@0 SF(dbopen)2.79 E F0 .29(is the library interf)2.79 F .29
  2043. X(ace to database \214les.)-.1 F .29
  2044. X(One of the supported \214le formats is hash \214les.)5.29 F .974
  2045. X(The general description of the database access methods is in)108 177.6 R F3
  2046. X(dbopen)3.475 E F0 .975(\(3\), this manual page describes only).24 F
  2047. X(the hash speci\214c information.)108 189.6 Q(The hash data structure is an e)
  2048. X108 206.4 Q(xtensible, dynamic hashing scheme.)-.15 E .83
  2049. X(The access method speci\214c data structure pro)108 223.2 R .83(vided to)-.15
  2050. XF F3(dbopen)3.33 E F0 .83(is de\214ned in the <db)3.33 F .83
  2051. X(.h> include \214le as fol-)-.4 F(lo)108 235.2 Q(ws:)-.25 E(typedef struct {)
  2052. X108 259.2 Q(int bsize;)144 271.2 Q(int cachesize;)144 283.2 Q(int f)144 295.2 Q
  2053. X-.1(fa)-.25 G(ctor;).1 E(u_long \(*hash\)\(const v)144 307.2 Q
  2054. X(oid *, size_t\);)-.2 E(int lorder;)144 319.2 Q(int nelem;)144 331.2 Q 2.5(}H)
  2055. X108 343.2 S(ASHINFO;)122.52 343.2 Q
  2056. X(The elements of this structure are as follo)108 360 Q(ws:)-.25 E(bsize)108
  2057. X376.8 Q F3(Bsize)144 376.8 Q F0 1.393(de\214nes the hash table b)3.893 F(uck)
  2058. X-.2 E 1.393(et size, and is, by def)-.1 F 1.394(ault, 256 bytes.)-.1 F 1.394
  2059. X(It may be preferable to)6.394 F
  2060. X(increase the page size for disk-resident tables and tables with lar)144 388.8
  2061. XQ(ge data items.)-.18 E(cachesize)108 405.6 Q 3.16(As)144 417.6 S .66
  2062. X(uggested maximum size, in bytes, of the memory cache.)158.27 417.6 R .659
  2063. X(This v)5.659 F .659(alue is)-.25 F F2(only)3.159 E F0(advisory)3.159 E 3.159
  2064. X(,a)-.65 G .659(nd the)514.621 417.6 R
  2065. X(access method will allocate more memory rather than f)144 429.6 Q(ail.)-.1 E
  2066. X-2.1 -.25(ff a)108 446.4 T(ctor).25 E F3(Ffactor)9.7 E F0 .482
  2067. X(indicates a desired density within the hash table.)2.981 F .482
  2068. X(It is an approximation of the number of)5.482 F -.1(ke)144 458.4 S .429
  2069. X(ys allo)-.05 F .429(wed to accumulate in an)-.25 F 2.929(yo)-.15 G .429(ne b)
  2070. X291.454 458.4 R(uck)-.2 E .429(et, determining when the hash table gro)-.1 F
  2071. X.428(ws or shrinks.)-.25 F(The def)144 470.4 Q(ault v)-.1 E(alue is 8.)-.25 E
  2072. X(hash)108 487.2 Q F3(Hash)144 487.2 Q F0 .1(is a user de\214ned hash function.)
  2073. X2.6 F .1(Since no hash function performs equally well on all possible)5.1 F
  2074. X.924(data, the user may \214nd that the b)144 499.2 R .923
  2075. X(uilt-in hash function does poorly on a particular data set.)-.2 F(User)5.923 E
  2076. X1.408(speci\214ed hash functions must tak)144 511.2 R 3.909(et)-.1 G 1.609 -.1
  2077. X(wo a)293.431 511.2 T -.18(rg).1 G 1.409
  2078. X(uments \(a pointer to a byte string and a length\) and).18 F
  2079. X(return an u_long to be used as the hash v)144 523.2 Q(alue.)-.25 E 9.62
  2080. X(lorder The)108 540 R 1.597(byte order for inte)4.097 F 1.596
  2081. X(gers in the stored database metadata.)-.15 F 1.596
  2082. X(The number should represent the)6.596 F .688(order as an inte)144 552 R .689
  2083. X(ger; for e)-.15 F .689(xample, big endian order w)-.15 F .689
  2084. X(ould be the number 4,321.)-.1 F(If)5.689 E F3(lor)3.189 E(der)-.37 E F0 .689
  2085. X(is 0 \(no)3.189 F .822(order is speci\214ed\) the current host order is used.)
  2086. X144 564 R .822(If the)5.822 F .822(\214le already e)5.822 F .821
  2087. X(xists, the speci\214ed v)-.15 F .821(alue is)-.25 F(ignored and the v)144 576
  2088. XQ(alue speci\214ed when the tree w)-.25 E(as created is used.)-.1 E(nelem)108
  2089. X592.8 Q F3(Nelem)144 592.8 Q F0 .701
  2090. X(is an estimate of the \214nal size of the hash table.)3.2 F .701
  2091. X(If not set or set too lo)5.701 F 2.001 -.65(w, h)-.25 H .701(ash tables will)
  2092. X.65 F -.15(ex)144 604.8 S .448(pand gracefully as k).15 F -.15(ey)-.1 G 2.948
  2093. X(sa).15 G .448(re entered, although a slight performance de)255.912 604.8 R
  2094. X.447(gradation may be noticed.)-.15 F(The def)144 616.8 Q(ault v)-.1 E
  2095. X(alue is 1.)-.25 E .79(If the \214le already e)108 633.6 R .79
  2096. X(xists \(and the O_TR)-.15 F .79(UNC \215ag is not speci\214ed\), the v)-.4 F
  2097. X.79(alues speci\214ed for the parameters)-.25 F(bsize, f)108 645.6 Q -.1(fa)
  2098. X-.25 G(ctor).1 E 2.5(,l)-.4 G(order and nelem are ignored and the v)167.23
  2099. X645.6 Q(alues speci\214ed when the tree w)-.25 E(as created are used.)-.1 E
  2100. X1.232(If a hash function is speci\214ed,)108 662.4 R F3(hash_open)3.731 E F0
  2101. X1.231(will attempt to determine if the hash function speci\214ed is the)3.731 F
  2102. X(same as the one with which the database w)108 674.4 Q(as created, and will f)
  2103. X-.1 E(ail if it is not.)-.1 E(Backw)108 691.2 Q .861(ard compatible interf)-.1
  2104. XF .861(aces to the routines described in)-.1 F F3(dbm)3.362 E F0 .862
  2105. X(\(3\), and).32 F F3(ndbm)3.362 E F0 .862(\(3\) are pro).32 F .862(vided, ho)
  2106. X-.15 F(we)-.25 E -.15(ve)-.25 G -.4(r,).15 G(these interf)108 703.2 Q
  2107. X(aces are not compatible with pre)-.1 E(vious \214le formats.)-.25 E 214.835
  2108. X(6, June)72 768 R(1)535 768 Q EP
  2109. X%%Page: 2 2
  2110. X%%BeginPageSetup
  2111. XBP
  2112. X%%EndPageSetup
  2113. X/F0 10/Times-Roman@0 SF 182.62(HASH\(3\) 1993 HASH\(3\))72 48 R/F1 9
  2114. X/Times-Bold@0 SF(SEE ALSO)72 84 Q/F2 10/Times-Italic@0 SF(btr)108 96 Q(ee)-.37
  2115. XE F0(\(3\),).18 E F2(dbopen)2.5 E F0(\(3\),).24 E F2(mpool)2.5 E F0(\(3\),).51
  2116. XE F2 -.37(re)2.5 G(cno).37 E F0(\(3\)).18 E F2(Dynamic Hash T)108 108 Q(ables)
  2117. X-.92 E F0 2.5(,P).27 G(er)206.79 108 Q(-Ak)-.2 E 2.5(eL)-.1 G
  2118. X(arson, Communications of the A)242.86 108 Q(CM, April 1988.)-.4 E F2 2.5(AN)
  2119. X108 120 S .3 -.15(ew H)123.28 120 T(ash P).15 E(ac)-.8 E(ka)-.2 E .2 -.1(ge f)
  2120. X-.1 H(or UNIX).1 E F0 2.5(,M).94 G(ar)248.41 120 Q(go Seltzer)-.18 E 2.5(,U)-.4
  2121. XG(SENIX Proceedings, W)308.09 120 Q(inter 1991.)-.4 E F1 -.09(BU)72 136.8 S(GS)
  2122. X.09 E F0(Only big and little endian byte order is supported.)108 148.8 Q
  2123. X214.835(6, June)72 768 R(2)535 768 Q EP
  2124. X%%Trailer
  2125. Xend
  2126. X%%EOF
  2127. END_OF_FILE
  2128. if test 11062 -ne `wc -c <'doc/hash.3.ps'`; then
  2129.     echo shar: \"'doc/hash.3.ps'\" unpacked with wrong size!
  2130. fi
  2131. # end of 'doc/hash.3.ps'
  2132. fi
  2133. if test -f 'hash/hash.h' -a "${1}" != "-c" ; then 
  2134.   echo shar: Will not clobber existing file \"'hash/hash.h'\"
  2135. else
  2136. echo shar: Extracting \"'hash/hash.h'\" \(9978 characters\)
  2137. sed "s/^X//" >'hash/hash.h' <<'END_OF_FILE'
  2138. X/*-
  2139. X * Copyright (c) 1990, 1993
  2140. X *    The Regents of the University of California.  All rights reserved.
  2141. X *
  2142. X * This code is derived from software contributed to Berkeley by
  2143. X * Margo Seltzer.
  2144. X *
  2145. X * Redistribution and use in source and binary forms, with or without
  2146. X * modification, are permitted provided that the following conditions
  2147. X * are met:
  2148. X * 1. Redistributions of source code must retain the above copyright
  2149. X *    notice, this list of conditions and the following disclaimer.
  2150. X * 2. Redistributions in binary form must reproduce the above copyright
  2151. X *    notice, this list of conditions and the following disclaimer in the
  2152. X *    documentation and/or other materials provided with the distribution.
  2153. X * 3. All advertising materials mentioning features or use of this software
  2154. X *    must display the following acknowledgement:
  2155. X *    This product includes software developed by the University of
  2156. X *    California, Berkeley and its contributors.
  2157. X * 4. Neither the name of the University nor the names of its contributors
  2158. X *    may be used to endorse or promote products derived from this software
  2159. X *    without specific prior written permission.
  2160. X *
  2161. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  2162. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2163. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2164. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  2165. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  2166. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  2167. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  2168. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  2169. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  2170. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  2171. X * SUCH DAMAGE.
  2172. X *
  2173. X *    @(#)hash.h    8.1 (Berkeley) 6/4/93
  2174. X */
  2175. X
  2176. X/* Operations */
  2177. Xtypedef enum {
  2178. X    HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
  2179. X} ACTION;
  2180. X
  2181. X/* Buffer Management structures */
  2182. Xtypedef struct _bufhead BUFHEAD;
  2183. X
  2184. Xstruct _bufhead {
  2185. X    BUFHEAD    *prev;        /* LRU links */
  2186. X    BUFHEAD    *next;        /* LRU links */
  2187. X    BUFHEAD    *ovfl;        /* Overflow page buffer header */
  2188. X    u_int     addr;        /* Address of this page */
  2189. X    char    *page;        /* Actual page data */
  2190. X    char     flags;
  2191. X#define    BUF_MOD        0x0001
  2192. X#define BUF_DISK    0x0002
  2193. X#define    BUF_BUCKET    0x0004
  2194. X#define    BUF_PIN        0x0008
  2195. X};
  2196. X
  2197. X#define IS_BUCKET(X)    ((X) & BUF_BUCKET)
  2198. X
  2199. Xtypedef BUFHEAD **SEGMENT;
  2200. X
  2201. X/* Hash Table Information */
  2202. Xtypedef struct hashhdr {    /* Disk resident portion */
  2203. X    int    magic;        /* Magic NO for hash tables */
  2204. X    int    version;    /* Version ID */
  2205. X    long    lorder;        /* Byte Order */
  2206. X    int    bsize;        /* Bucket/Page Size */
  2207. X    int    bshift;        /* Bucket shift */
  2208. X    int    dsize;        /* Directory Size */
  2209. X    int    ssize;        /* Segment Size */
  2210. X    int    sshift;        /* Segment shift */
  2211. X    int    ovfl_point;    /* Where overflow pages are being allocated */
  2212. X    int    last_freed;    /* Last overflow page freed */
  2213. X    int    max_bucket;    /* ID of Maximum bucket in use */
  2214. X    int    high_mask;    /* Mask to modulo into entire table */
  2215. X    int    low_mask;    /* Mask to modulo into lower half of table */
  2216. X    int    ffactor;    /* Fill factor */
  2217. X    int    nkeys;        /* Number of keys in hash table */
  2218. X    int    hdrpages;    /* Size of table header */
  2219. X    int    h_charkey;    /* value of hash(CHARKEY) */
  2220. X#define NCACHED    32        /* number of bit maps and spare points */
  2221. X    int    spares[NCACHED];/* spare pages for overflow */
  2222. X    u_short    bitmaps[NCACHED];    /* address of overflow page bitmaps */
  2223. X} HASHHDR;
  2224. X
  2225. Xtypedef struct htab {        /* Memory resident data structure */
  2226. X    HASHHDR hdr;        /* Header */
  2227. X    int    nsegs;        /* Number of allocated segments */
  2228. X    int    exsegs;        /* Number of extra allocated segments */
  2229. X    int    (*hash) ();    /* Hash Function */
  2230. X    int    flags;        /* Flag values */
  2231. X    int    fp;        /* File pointer */
  2232. X    char    *tmp_buf;    /* Temporary Buffer for BIG data */
  2233. X    char    *tmp_key;    /* Temporary Buffer for BIG keys */
  2234. X    BUFHEAD *cpage;        /* Current page */
  2235. X    int    cbucket;    /* Current bucket */
  2236. X    int    cndx;        /* Index of next item on cpage */
  2237. X    int    errno;        /* Error Number -- for DBM compatability */
  2238. X    int    new_file;    /* Indicates if fd is backing store or no */
  2239. X    int    save_file;    /* Indicates whether we need to flush file at
  2240. X                 * exit */
  2241. X    u_long *mapp[NCACHED];    /* Pointers to page maps */
  2242. X    int    nmaps;        /* Initial number of bitmaps */
  2243. X    int    nbufs;        /* Number of buffers left to allocate */
  2244. X    BUFHEAD bufhead;    /* Header of buffer lru list */
  2245. X    SEGMENT *dir;        /* Hash Bucket directory */
  2246. X} HTAB;
  2247. X
  2248. X/*
  2249. X * Constants
  2250. X */
  2251. X#define    MAX_BSIZE        65536        /* 2^16 */
  2252. X#define MIN_BUFFERS        6
  2253. X#define MINHDRSIZE        512
  2254. X#define DEF_BUFSIZE        65536        /* 64 K */
  2255. X#define DEF_BUCKET_SIZE        4096
  2256. X#define DEF_BUCKET_SHIFT    12        /* log2(BUCKET) */
  2257. X#define DEF_SEGSIZE        256
  2258. X#define DEF_SEGSIZE_SHIFT    8        /* log2(SEGSIZE)     */
  2259. X#define DEF_DIRSIZE        256
  2260. X#define DEF_FFACTOR        65536
  2261. X#define MIN_FFACTOR        4
  2262. X#define SPLTMAX            8
  2263. X#define CHARKEY            "%$sniglet^&"
  2264. X#define NUMKEY            1038583
  2265. X#define BYTE_SHIFT        3
  2266. X#define INT_TO_BYTE        2
  2267. X#define INT_BYTE_SHIFT        5
  2268. X#define ALL_SET            ((u_int)0xFFFFFFFF)
  2269. X#define ALL_CLEAR        0
  2270. X
  2271. X#define PTROF(X)    ((BUFHEAD *)((u_int)(X)&~0x3))
  2272. X#define ISMOD(X)    ((u_int)(X)&0x1)
  2273. X#define DOMOD(X)    ((X) = (char *)((u_int)(X)|0x1))
  2274. X#define ISDISK(X)    ((u_int)(X)&0x2)
  2275. X#define DODISK(X)    ((X) = (char *)((u_int)(X)|0x2))
  2276. X
  2277. X#define BITS_PER_MAP    32
  2278. X
  2279. X/* Given the address of the beginning of a big map, clear/set the nth bit */
  2280. X#define CLRBIT(A, N)    ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
  2281. X#define SETBIT(A, N)    ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
  2282. X#define ISSET(A, N)    ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
  2283. X
  2284. X/* Overflow management */
  2285. X/*
  2286. X * Overflow page numbers are allocated per split point.  At each doubling of
  2287. X * the table, we can allocate extra pages.  So, an overflow page number has
  2288. X * the top 5 bits indicate which split point and the lower 11 bits indicate
  2289. X * which page at that split point is indicated (pages within split points are
  2290. X * numberered starting with 1).
  2291. X */
  2292. X
  2293. X#define SPLITSHIFT    11
  2294. X#define SPLITMASK    0x7FF
  2295. X#define SPLITNUM(N)    (((u_int)(N)) >> SPLITSHIFT)
  2296. X#define OPAGENUM(N)    ((N) & SPLITMASK)
  2297. X#define    OADDR_OF(S,O)    ((u_int)((u_int)(S) << SPLITSHIFT) + (O))
  2298. X
  2299. X#define BUCKET_TO_PAGE(B) \
  2300. X    (B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__log2((B)+1)-1] : 0)
  2301. X#define OADDR_TO_PAGE(B)     \
  2302. X    BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
  2303. X
  2304. X/*
  2305. X * page.h contains a detailed description of the page format.
  2306. X *
  2307. X * Normally, keys and data are accessed from offset tables in the top of
  2308. X * each page which point to the beginning of the key and data.  There are
  2309. X * four flag values which may be stored in these offset tables which indicate
  2310. X * the following:
  2311. X *
  2312. X *
  2313. X * OVFLPAGE    Rather than a key data pair, this pair contains
  2314. X *        the address of an overflow page.  The format of
  2315. X *        the pair is:
  2316. X *            OVERFLOW_PAGE_NUMBER OVFLPAGE
  2317. X *
  2318. X * PARTIAL_KEY    This must be the first key/data pair on a page
  2319. X *        and implies that page contains only a partial key.
  2320. X *        That is, the key is too big to fit on a single page
  2321. X *        so it starts on this page and continues on the next.
  2322. X *        The format of the page is:
  2323. X *            KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
  2324. X *        
  2325. X *            KEY_OFF -- offset of the beginning of the key
  2326. X *            PARTIAL_KEY -- 1
  2327. X *            OVFL_PAGENO - page number of the next overflow page
  2328. X *            OVFLPAGE -- 0
  2329. X *
  2330. X * FULL_KEY    This must be the first key/data pair on the page.  It
  2331. X *        is used in two cases.
  2332. X *
  2333. X *        Case 1:
  2334. X *            There is a complete key on the page but no data
  2335. X *            (because it wouldn't fit).  The next page contains
  2336. X *            the data.
  2337. X *
  2338. X *            Page format it:
  2339. X *            KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
  2340. X *
  2341. X *            KEY_OFF -- offset of the beginning of the key
  2342. X *            FULL_KEY -- 2
  2343. X *            OVFL_PAGENO - page number of the next overflow page
  2344. X *            OVFLPAGE -- 0
  2345. X *
  2346. X *        Case 2:
  2347. X *            This page contains no key, but part of a large
  2348. X *            data field, which is continued on the next page.
  2349. X *
  2350. X *            Page format it:
  2351. X *            DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
  2352. X *
  2353. X *            KEY_OFF -- offset of the beginning of the data on
  2354. X *                this page
  2355. X *            FULL_KEY -- 2
  2356. X *            OVFL_PAGENO - page number of the next overflow page
  2357. X *            OVFLPAGE -- 0
  2358. X *
  2359. X * FULL_KEY_DATA 
  2360. X *        This must be the first key/data pair on the page.
  2361. X *        There are two cases:
  2362. X *
  2363. X *        Case 1:
  2364. X *            This page contains a key and the beginning of the
  2365. X *            data field, but the data field is continued on the
  2366. X *            next page.
  2367. X *
  2368. X *            Page format is:
  2369. X *            KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
  2370. X *
  2371. X *            KEY_OFF -- offset of the beginning of the key
  2372. X *            FULL_KEY_DATA -- 3
  2373. X *            OVFL_PAGENO - page number of the next overflow page
  2374. X *            DATA_OFF -- offset of the beginning of the data
  2375. X *
  2376. X *        Case 2:
  2377. X *            This page contains the last page of a big data pair.
  2378. X *            There is no key, only the  tail end of the data
  2379. X *            on this page.
  2380. X *
  2381. X *            Page format is:
  2382. X *            DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
  2383. X *
  2384. X *            DATA_OFF -- offset of the beginning of the data on
  2385. X *                this page
  2386. X *            FULL_KEY_DATA -- 3
  2387. X *            OVFL_PAGENO - page number of the next overflow page
  2388. X *            OVFLPAGE -- 0
  2389. X *
  2390. X *            OVFL_PAGENO and OVFLPAGE are optional (they are
  2391. X *            not present if there is no next page).
  2392. X */
  2393. X
  2394. X#define OVFLPAGE    0
  2395. X#define PARTIAL_KEY    1
  2396. X#define FULL_KEY    2
  2397. X#define FULL_KEY_DATA    3
  2398. X#define    REAL_KEY    4
  2399. X
  2400. X/* Short hands for accessing structure */
  2401. X#define BSIZE        hdr.bsize
  2402. X#define BSHIFT        hdr.bshift
  2403. X#define DSIZE        hdr.dsize
  2404. X#define SGSIZE        hdr.ssize
  2405. X#define SSHIFT        hdr.sshift
  2406. X#define LORDER        hdr.lorder
  2407. X#define OVFL_POINT    hdr.ovfl_point
  2408. X#define    LAST_FREED    hdr.last_freed
  2409. X#define MAX_BUCKET    hdr.max_bucket
  2410. X#define FFACTOR        hdr.ffactor
  2411. X#define HIGH_MASK    hdr.high_mask
  2412. X#define LOW_MASK    hdr.low_mask
  2413. X#define NKEYS        hdr.nkeys
  2414. X#define HDRPAGES    hdr.hdrpages
  2415. X#define SPARES        hdr.spares
  2416. X#define BITMAPS        hdr.bitmaps
  2417. X#define VERSION        hdr.version
  2418. X#define MAGIC        hdr.magic
  2419. X#define NEXT_FREE    hdr.next_free
  2420. X#define H_CHARKEY    hdr.h_charkey
  2421. END_OF_FILE
  2422. if test 9978 -ne `wc -c <'hash/hash.h'`; then
  2423.     echo shar: \"'hash/hash.h'\" unpacked with wrong size!
  2424. fi
  2425. # end of 'hash/hash.h'
  2426. fi
  2427. if test -f 'hash/hash_buf.c' -a "${1}" != "-c" ; then 
  2428.   echo shar: Will not clobber existing file \"'hash/hash_buf.c'\"
  2429. else
  2430. echo shar: Extracting \"'hash/hash_buf.c'\" \(9015 characters\)
  2431. sed "s/^X//" >'hash/hash_buf.c' <<'END_OF_FILE'
  2432. X/*-
  2433. X * Copyright (c) 1990, 1993
  2434. X *    The Regents of the University of California.  All rights reserved.
  2435. X *
  2436. X * This code is derived from software contributed to Berkeley by
  2437. X * Margo Seltzer.
  2438. X *
  2439. X * Redistribution and use in source and binary forms, with or without
  2440. X * modification, are permitted provided that the following conditions
  2441. X * are met:
  2442. X * 1. Redistributions of source code must retain the above copyright
  2443. X *    notice, this list of conditions and the following disclaimer.
  2444. X * 2. Redistributions in binary form must reproduce the above copyright
  2445. X *    notice, this list of conditions and the following disclaimer in the
  2446. X *    documentation and/or other materials provided with the distribution.
  2447. X * 3. All advertising materials mentioning features or use of this software
  2448. X *    must display the following acknowledgement:
  2449. X *    This product includes software developed by the University of
  2450. X *    California, Berkeley and its contributors.
  2451. X * 4. Neither the name of the University nor the names of its contributors
  2452. X *    may be used to endorse or promote products derived from this software
  2453. X *    without specific prior written permission.
  2454. X *
  2455. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  2456. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2457. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2458. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  2459. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  2460. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  2461. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  2462. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  2463. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  2464. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  2465. X * SUCH DAMAGE.
  2466. X */
  2467. X
  2468. X#if defined(LIBC_SCCS) && !defined(lint)
  2469. Xstatic char sccsid[] = "@(#)hash_buf.c    8.1 (Berkeley) 6/4/93";
  2470. X#endif /* LIBC_SCCS and not lint */
  2471. X
  2472. X/*
  2473. X * PACKAGE: hash
  2474. X *
  2475. X * DESCRIPTION:
  2476. X *    Contains buffer management
  2477. X *
  2478. X * ROUTINES:
  2479. X * External
  2480. X *    __buf_init
  2481. X *    __get_buf
  2482. X *    __buf_free
  2483. X *    __reclaim_buf
  2484. X * Internal
  2485. X *    newbuf
  2486. X */
  2487. X
  2488. X#include <sys/param.h>
  2489. X
  2490. X#include <errno.h>
  2491. X#include <stdio.h>
  2492. X#include <stdlib.h>
  2493. X#ifdef DEBUG
  2494. X#include <assert.h>
  2495. X#endif
  2496. X
  2497. X#include <db.h>
  2498. X#include "hash.h"
  2499. X#include "page.h"
  2500. X#include "extern.h"
  2501. X
  2502. Xstatic BUFHEAD *newbuf __P((HTAB *, u_int, BUFHEAD *));
  2503. X
  2504. X/* Unlink B from its place in the lru */
  2505. X#define BUF_REMOVE(B) { \
  2506. X    (B)->prev->next = (B)->next; \
  2507. X    (B)->next->prev = (B)->prev; \
  2508. X}
  2509. X
  2510. X/* Insert B after P */
  2511. X#define BUF_INSERT(B, P) { \
  2512. X    (B)->next = (P)->next; \
  2513. X    (B)->prev = (P); \
  2514. X    (P)->next = (B); \
  2515. X    (B)->next->prev = (B); \
  2516. X}
  2517. X
  2518. X#define    MRU    hashp->bufhead.next
  2519. X#define    LRU    hashp->bufhead.prev
  2520. X
  2521. X#define MRU_INSERT(B)    BUF_INSERT((B), &hashp->bufhead)
  2522. X#define LRU_INSERT(B)    BUF_INSERT((B), LRU)
  2523. X
  2524. X/*
  2525. X * We are looking for a buffer with address "addr".  If prev_bp is NULL, then
  2526. X * address is a bucket index.  If prev_bp is not NULL, then it points to the
  2527. X * page previous to an overflow page that we are trying to find.
  2528. X *
  2529. X * CAVEAT:  The buffer header accessed via prev_bp's ovfl field may no longer
  2530. X * be valid.  Therefore, you must always verify that its address matches the
  2531. X * address you are seeking.
  2532. X */
  2533. Xextern BUFHEAD *
  2534. X__get_buf(hashp, addr, prev_bp, newpage)
  2535. X    HTAB *hashp;
  2536. X    u_int addr;
  2537. X    BUFHEAD *prev_bp;
  2538. X    int newpage;    /* If prev_bp set, indicates a new overflow page. */
  2539. X{
  2540. X    register BUFHEAD *bp;
  2541. X    register u_int is_disk_mask;
  2542. X    register int is_disk, segment_ndx;
  2543. X    SEGMENT segp;
  2544. X
  2545. X    is_disk = 0;
  2546. X    is_disk_mask = 0;
  2547. X    if (prev_bp) {
  2548. X        bp = prev_bp->ovfl;
  2549. X        if (!bp || (bp->addr != addr))
  2550. X            bp = NULL;
  2551. X        if (!newpage)
  2552. X            is_disk = BUF_DISK;
  2553. X    } else {
  2554. X        /* Grab buffer out of directory */
  2555. X        segment_ndx = addr & (hashp->SGSIZE - 1);
  2556. X
  2557. X        /* valid segment ensured by __call_hash() */
  2558. X        segp = hashp->dir[addr >> hashp->SSHIFT];
  2559. X#ifdef DEBUG
  2560. X        assert(segp != NULL);
  2561. X#endif
  2562. X        bp = PTROF(segp[segment_ndx]);
  2563. X        is_disk_mask = ISDISK(segp[segment_ndx]);
  2564. X        is_disk = is_disk_mask || !hashp->new_file;
  2565. X    }
  2566. X
  2567. X    if (!bp) {
  2568. X        bp = newbuf(hashp, addr, prev_bp);
  2569. X        if (!bp ||
  2570. X            __get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
  2571. X            return (NULL);
  2572. X        if (!prev_bp)
  2573. X            segp[segment_ndx] =
  2574. X                (BUFHEAD *)((u_int)bp | is_disk_mask);
  2575. X    } else {
  2576. X        BUF_REMOVE(bp);
  2577. X        MRU_INSERT(bp);
  2578. X    }
  2579. X    return (bp);
  2580. X}
  2581. X
  2582. X/*
  2583. X * We need a buffer for this page. Either allocate one, or evict a resident
  2584. X * one (if we have as many buffers as we're allowed) and put this one in.
  2585. X *
  2586. X * If newbuf finds an error (returning NULL), it also sets errno.
  2587. X */
  2588. Xstatic BUFHEAD *
  2589. Xnewbuf(hashp, addr, prev_bp)
  2590. X    HTAB *hashp;
  2591. X    u_int addr;
  2592. X    BUFHEAD *prev_bp;
  2593. X{
  2594. X    register BUFHEAD *bp;        /* The buffer we're going to use */
  2595. X    register BUFHEAD *xbp;        /* Temp pointer */
  2596. X    register BUFHEAD *next_xbp;
  2597. X    SEGMENT segp;
  2598. X    int segment_ndx;
  2599. X    u_short oaddr, *shortp;
  2600. X
  2601. X    oaddr = 0;
  2602. X    bp = LRU;
  2603. X    /*
  2604. X     * If LRU buffer is pinned, the buffer pool is too small. We need to
  2605. X     * allocate more buffers.
  2606. X     */
  2607. X    if (hashp->nbufs || (bp->flags & BUF_PIN)) {
  2608. X        /* Allocate a new one */
  2609. X        bp = malloc(sizeof(struct _bufhead));
  2610. X        if (!bp || !(bp->page = malloc(hashp->BSIZE)))
  2611. X            return (NULL);
  2612. X        if (hashp->nbufs)
  2613. X            hashp->nbufs--;
  2614. X    } else {
  2615. X        /* Kick someone out */
  2616. X        BUF_REMOVE(bp);
  2617. X        /*
  2618. X         * If this is an overflow page with addr 0, it's already been
  2619. X         * flushed back in an overflow chain and initialized.
  2620. X         */
  2621. X        if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
  2622. X            /*
  2623. X             * Set oaddr before __put_page so that you get it
  2624. X             * before bytes are swapped.
  2625. X             */
  2626. X            shortp = (u_short *)bp->page;
  2627. X            if (shortp[0])
  2628. X                oaddr = shortp[shortp[0] - 1];
  2629. X            if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
  2630. X                bp->addr, (int)IS_BUCKET(bp->flags), 0))
  2631. X                return (NULL);
  2632. X            /*
  2633. X             * Update the pointer to this page (i.e. invalidate it).
  2634. X             *
  2635. X             * If this is a new file (i.e. we created it at open
  2636. X             * time), make sure that we mark pages which have been
  2637. X             * written to disk so we retrieve them from disk later,
  2638. X             * rather than allocating new pages.
  2639. X             */
  2640. X            if (IS_BUCKET(bp->flags)) {
  2641. X                segment_ndx = bp->addr & (hashp->SGSIZE - 1);
  2642. X                segp = hashp->dir[bp->addr >> hashp->SSHIFT];
  2643. X#ifdef DEBUG
  2644. X                assert(segp != NULL);
  2645. X#endif
  2646. X
  2647. X                if (hashp->new_file &&
  2648. X                    ((bp->flags & BUF_MOD) ||
  2649. X                    ISDISK(segp[segment_ndx])))
  2650. X                    segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
  2651. X                else
  2652. X                    segp[segment_ndx] = NULL;
  2653. X            }
  2654. X            /*
  2655. X             * Since overflow pages can only be access by means of
  2656. X             * their bucket, free overflow pages associated with
  2657. X             * this bucket.
  2658. X             */
  2659. X            for (xbp = bp; xbp->ovfl;) {
  2660. X                next_xbp = xbp->ovfl;
  2661. X                xbp->ovfl = 0;
  2662. X                xbp = next_xbp;
  2663. X
  2664. X                /* Check that ovfl pointer is up date. */
  2665. X                if (IS_BUCKET(xbp->flags) ||
  2666. X                    (oaddr != xbp->addr))
  2667. X                    break;
  2668. X
  2669. X                shortp = (u_short *)xbp->page;
  2670. X                if (shortp[0])
  2671. X                    /* set before __put_page */
  2672. X                    oaddr = shortp[shortp[0] - 1];
  2673. X                if ((xbp->flags & BUF_MOD) && __put_page(hashp,
  2674. X                    xbp->page, xbp->addr, 0, 0))
  2675. X                    return (NULL);
  2676. X                xbp->addr = 0;
  2677. X                xbp->flags = 0;
  2678. X                BUF_REMOVE(xbp);
  2679. X                LRU_INSERT(xbp);
  2680. X            }
  2681. X        }
  2682. X    }
  2683. X
  2684. X    /* Now assign this buffer */
  2685. X    bp->addr = addr;
  2686. X#ifdef DEBUG1
  2687. X    (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
  2688. X        bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
  2689. X#endif
  2690. X    bp->ovfl = NULL;
  2691. X    if (prev_bp) {
  2692. X        /*
  2693. X         * If prev_bp is set, this is an overflow page, hook it in to
  2694. X         * the buffer overflow links.
  2695. X         */
  2696. X#ifdef DEBUG1
  2697. X        (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
  2698. X            prev_bp->addr, (prev_bp->ovfl ? bp->ovfl->addr : 0),
  2699. X            (bp ? bp->addr : 0));
  2700. X#endif
  2701. X        prev_bp->ovfl = bp;
  2702. X        bp->flags = 0;
  2703. X    } else
  2704. X        bp->flags = BUF_BUCKET;
  2705. X    MRU_INSERT(bp);
  2706. X    return (bp);
  2707. X}
  2708. X
  2709. Xextern void
  2710. X__buf_init(hashp, nbytes)
  2711. X    HTAB *hashp;
  2712. X    int nbytes;
  2713. X{
  2714. X    BUFHEAD *bfp;
  2715. X    int npages;
  2716. X
  2717. X    bfp = &(hashp->bufhead);
  2718. X    npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
  2719. X    npages = MAX(npages, MIN_BUFFERS);
  2720. X
  2721. X    hashp->nbufs = npages;
  2722. X    bfp->next = bfp;
  2723. X    bfp->prev = bfp;
  2724. X    /*
  2725. X     * This space is calloc'd so these are already null.
  2726. X     *
  2727. X     * bfp->ovfl = NULL;
  2728. X     * bfp->flags = 0;
  2729. X     * bfp->page = NULL;
  2730. X     * bfp->addr = 0;
  2731. X     */
  2732. X}
  2733. X
  2734. Xextern int
  2735. X__buf_free(hashp, do_free, to_disk)
  2736. X    HTAB *hashp;
  2737. X    int do_free, to_disk;
  2738. X{
  2739. X    BUFHEAD *bp;
  2740. X
  2741. X    /* Need to make sure that buffer manager has been initialized */
  2742. X    if (!LRU)
  2743. X        return (0);
  2744. X    for (bp = LRU; bp != &hashp->bufhead;) {
  2745. X        /* Check that the buffer is valid */
  2746. X        if (bp->addr || IS_BUCKET(bp->flags)) {
  2747. X            if (to_disk && (bp->flags & BUF_MOD) &&
  2748. X                __put_page(hashp, bp->page,
  2749. X                bp->addr, IS_BUCKET(bp->flags), 0))
  2750. X                return (-1);
  2751. X        }
  2752. X        /* Check if we are freeing stuff */
  2753. X        if (do_free) {
  2754. X            if (bp->page)
  2755. X                free(bp->page);
  2756. X            BUF_REMOVE(bp);
  2757. X            free(bp);
  2758. X            bp = LRU;
  2759. X        } else
  2760. X            bp = bp->prev;
  2761. X    }
  2762. X    return (0);
  2763. X}
  2764. X
  2765. Xextern void
  2766. X__reclaim_buf(hashp, bp)
  2767. X    HTAB *hashp;
  2768. X    BUFHEAD *bp;
  2769. X{
  2770. X    bp->ovfl = 0;
  2771. X    bp->addr = 0;
  2772. X    bp->flags = 0;
  2773. X    BUF_REMOVE(bp);
  2774. X    LRU_INSERT(bp);
  2775. X}
  2776. END_OF_FILE
  2777. if test 9015 -ne `wc -c <'hash/hash_buf.c'`; then
  2778.     echo shar: \"'hash/hash_buf.c'\" unpacked with wrong size!
  2779. fi
  2780. # end of 'hash/hash_buf.c'
  2781. fi
  2782. if test -f 'mpool/mpool.c' -a "${1}" != "-c" ; then 
  2783.   echo shar: Will not clobber existing file \"'mpool/mpool.c'\"
  2784. else
  2785. echo shar: Extracting \"'mpool/mpool.c'\" \(11661 characters\)
  2786. sed "s/^X//" >'mpool/mpool.c' <<'END_OF_FILE'
  2787. X/*-
  2788. X * Copyright (c) 1990, 1993
  2789. X *    The Regents of the University of California.  All rights reserved.
  2790. X *
  2791. X * Redistribution and use in source and binary forms, with or without
  2792. X * modification, are permitted provided that the following conditions
  2793. X * are met:
  2794. X * 1. Redistributions of source code must retain the above copyright
  2795. X *    notice, this list of conditions and the following disclaimer.
  2796. X * 2. Redistributions in binary form must reproduce the above copyright
  2797. X *    notice, this list of conditions and the following disclaimer in the
  2798. X *    documentation and/or other materials provided with the distribution.
  2799. X * 3. All advertising materials mentioning features or use of this software
  2800. X *    must display the following acknowledgement:
  2801. X *    This product includes software developed by the University of
  2802. X *    California, Berkeley and its contributors.
  2803. X * 4. Neither the name of the University nor the names of its contributors
  2804. X *    may be used to endorse or promote products derived from this software
  2805. X *    without specific prior written permission.
  2806. X *
  2807. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  2808. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2809. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2810. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  2811. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  2812. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  2813. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  2814. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  2815. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  2816. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  2817. X * SUCH DAMAGE.
  2818. X */
  2819. X
  2820. X#if defined(LIBC_SCCS) && !defined(lint)
  2821. Xstatic char sccsid[] = "@(#)mpool.c    8.1 (Berkeley) 6/6/93";
  2822. X#endif /* LIBC_SCCS and not lint */
  2823. X
  2824. X#include <sys/param.h>
  2825. X#include <sys/stat.h>
  2826. X
  2827. X#include <errno.h>
  2828. X#include <stdio.h>
  2829. X#include <stdlib.h>
  2830. X#include <string.h>
  2831. X#include <unistd.h>
  2832. X
  2833. X#include <db.h>
  2834. X#define    __MPOOLINTERFACE_PRIVATE
  2835. X#include "mpool.h"
  2836. X
  2837. Xstatic BKT *mpool_bkt __P((MPOOL *));
  2838. Xstatic BKT *mpool_look __P((MPOOL *, pgno_t));
  2839. Xstatic int  mpool_write __P((MPOOL *, BKT *));
  2840. X#ifdef DEBUG
  2841. Xstatic void __mpoolerr __P((const char *fmt, ...));
  2842. X#endif
  2843. X
  2844. X/*
  2845. X * MPOOL_OPEN -- initialize a memory pool.
  2846. X *
  2847. X * Parameters:
  2848. X *    key:        Shared buffer key.
  2849. X *    fd:        File descriptor.
  2850. X *    pagesize:    File page size.
  2851. X *    maxcache:    Max number of cached pages.
  2852. X *
  2853. X * Returns:
  2854. X *    MPOOL pointer, NULL on error.
  2855. X */
  2856. XMPOOL *
  2857. Xmpool_open(key, fd, pagesize, maxcache)
  2858. X    DBT *key;
  2859. X    int fd;
  2860. X    pgno_t pagesize, maxcache;
  2861. X{
  2862. X    struct stat sb;
  2863. X    MPOOL *mp;
  2864. X    int entry;
  2865. X
  2866. X    if (fstat(fd, &sb))
  2867. X        return (NULL);
  2868. X    /* XXX
  2869. X     * We should only set st_size to 0 for pipes -- 4.4BSD has the fix so
  2870. X     * that stat(2) returns true for ISSOCK on pipes.  Until then, this is
  2871. X     * fairly close.
  2872. X     */
  2873. X    if (!S_ISREG(sb.st_mode)) {
  2874. X        errno = ESPIPE;
  2875. X        return (NULL);
  2876. X    }
  2877. X
  2878. X    if ((mp = malloc(sizeof(MPOOL))) == NULL)
  2879. X        return (NULL);
  2880. X    mp->free.cnext = mp->free.cprev = (BKT *)&mp->free;
  2881. X    mp->lru.cnext = mp->lru.cprev = (BKT *)&mp->lru;
  2882. X    for (entry = 0; entry < HASHSIZE; ++entry)
  2883. X        mp->hashtable[entry].hnext = mp->hashtable[entry].hprev = 
  2884. X            mp->hashtable[entry].cnext = mp->hashtable[entry].cprev =
  2885. X            (BKT *)&mp->hashtable[entry];
  2886. X    mp->curcache = 0;
  2887. X    mp->maxcache = maxcache;
  2888. X    mp->pagesize = pagesize;
  2889. X    mp->npages = sb.st_size / pagesize;
  2890. X    mp->fd = fd;
  2891. X    mp->pgcookie = NULL;
  2892. X    mp->pgin = mp->pgout = NULL;
  2893. X
  2894. X#ifdef STATISTICS
  2895. X    mp->cachehit = mp->cachemiss = mp->pagealloc = mp->pageflush = 
  2896. X        mp->pageget = mp->pagenew = mp->pageput = mp->pageread = 
  2897. X        mp->pagewrite = 0;
  2898. X#endif
  2899. X    return (mp);
  2900. X}
  2901. X
  2902. X/*
  2903. X * MPOOL_FILTER -- initialize input/output filters.
  2904. X *
  2905. X * Parameters:
  2906. X *    pgin:        Page in conversion routine.
  2907. X *    pgout:        Page out conversion routine.
  2908. X *    pgcookie:    Cookie for page in/out routines.
  2909. X */
  2910. Xvoid
  2911. Xmpool_filter(mp, pgin, pgout, pgcookie)
  2912. X    MPOOL *mp;
  2913. X    void (*pgin) __P((void *, pgno_t, void *));
  2914. X    void (*pgout) __P((void *, pgno_t, void *));
  2915. X    void *pgcookie;
  2916. X{
  2917. X    mp->pgin = pgin;
  2918. X    mp->pgout = pgout;
  2919. X    mp->pgcookie = pgcookie;
  2920. X}
  2921. X    
  2922. X/*
  2923. X * MPOOL_NEW -- get a new page
  2924. X *
  2925. X * Parameters:
  2926. X *    mp:        mpool cookie
  2927. X *    pgnoadddr:    place to store new page number
  2928. X * Returns:
  2929. X *    RET_ERROR, RET_SUCCESS
  2930. X */
  2931. Xvoid *
  2932. Xmpool_new(mp, pgnoaddr)
  2933. X    MPOOL *mp;
  2934. X    pgno_t *pgnoaddr;
  2935. X{
  2936. X    BKT *b;
  2937. X    BKTHDR *hp;
  2938. X
  2939. X#ifdef STATISTICS
  2940. X    ++mp->pagenew;
  2941. X#endif
  2942. X    /*
  2943. X     * Get a BKT from the cache.  Assign a new page number, attach it to
  2944. X     * the hash and lru chains and return.
  2945. X     */
  2946. X    if ((b = mpool_bkt(mp)) == NULL)
  2947. X        return (NULL);
  2948. X    *pgnoaddr = b->pgno = mp->npages++;
  2949. X    b->flags = MPOOL_PINNED;
  2950. X    inshash(b, b->pgno);
  2951. X    inschain(b, &mp->lru);
  2952. X    return (b->page);
  2953. X}
  2954. X
  2955. X/*
  2956. X * MPOOL_GET -- get a page from the pool
  2957. X *
  2958. X * Parameters:
  2959. X *    mp:    mpool cookie
  2960. X *    pgno:    page number
  2961. X *    flags:    not used
  2962. X *
  2963. X * Returns:
  2964. X *    RET_ERROR, RET_SUCCESS
  2965. X */
  2966. Xvoid *
  2967. Xmpool_get(mp, pgno, flags)
  2968. X    MPOOL *mp;
  2969. X    pgno_t pgno;
  2970. X    u_int flags;        /* XXX not used? */
  2971. X{
  2972. X    BKT *b;
  2973. X    BKTHDR *hp;
  2974. X    off_t off;
  2975. X    int nr;
  2976. X
  2977. X    /*
  2978. X     * If asking for a specific page that is already in the cache, find
  2979. X     * it and return it.
  2980. X     */
  2981. X    if (b = mpool_look(mp, pgno)) {
  2982. X#ifdef STATISTICS
  2983. X        ++mp->pageget;
  2984. X#endif
  2985. X#ifdef DEBUG
  2986. X        if (b->flags & MPOOL_PINNED)
  2987. X            __mpoolerr("mpool_get: page %d already pinned",
  2988. X                b->pgno);
  2989. X#endif
  2990. X        rmchain(b);
  2991. X        inschain(b, &mp->lru);
  2992. X        b->flags |= MPOOL_PINNED;
  2993. X        return (b->page);
  2994. X    }
  2995. X
  2996. X    /* Not allowed to retrieve a non-existent page. */
  2997. X    if (pgno >= mp->npages) {
  2998. X        errno = EINVAL;
  2999. X        return (NULL);
  3000. X    }
  3001. X
  3002. X    /* Get a page from the cache. */
  3003. X    if ((b = mpool_bkt(mp)) == NULL)
  3004. X        return (NULL);
  3005. X    b->pgno = pgno;
  3006. X    b->flags = MPOOL_PINNED;
  3007. X
  3008. X#ifdef STATISTICS
  3009. X    ++mp->pageread;
  3010. X#endif
  3011. X    /* Read in the contents. */
  3012. X    off = mp->pagesize * pgno;
  3013. X    if (lseek(mp->fd, off, SEEK_SET) != off)
  3014. X        return (NULL);
  3015. X    if ((nr = read(mp->fd, b->page, mp->pagesize)) != mp->pagesize) {
  3016. X        if (nr >= 0)
  3017. X            errno = EFTYPE;
  3018. X        return (NULL);
  3019. X    }
  3020. X    if (mp->pgin)
  3021. X        (mp->pgin)(mp->pgcookie, b->pgno, b->page);
  3022. X
  3023. X    inshash(b, b->pgno);
  3024. X    inschain(b, &mp->lru);
  3025. X#ifdef STATISTICS
  3026. X    ++mp->pageget;
  3027. X#endif
  3028. X    return (b->page);
  3029. X}
  3030. X
  3031. X/*
  3032. X * MPOOL_PUT -- return a page to the pool
  3033. X *
  3034. X * Parameters:
  3035. X *    mp:    mpool cookie
  3036. X *    page:    page pointer
  3037. X *    pgno:    page number
  3038. X *
  3039. X * Returns:
  3040. X *    RET_ERROR, RET_SUCCESS
  3041. X */
  3042. Xint
  3043. Xmpool_put(mp, page, flags)
  3044. X    MPOOL *mp;
  3045. X    void *page;
  3046. X    u_int flags;
  3047. X{
  3048. X    BKT *baddr;
  3049. X#ifdef DEBUG
  3050. X    BKT *b;
  3051. X#endif
  3052. X
  3053. X#ifdef STATISTICS
  3054. X    ++mp->pageput;
  3055. X#endif
  3056. X    baddr = (BKT *)((char *)page - sizeof(BKT));
  3057. X#ifdef DEBUG
  3058. X    if (!(baddr->flags & MPOOL_PINNED))
  3059. X        __mpoolerr("mpool_put: page %d not pinned", b->pgno);
  3060. X    for (b = mp->lru.cnext; b != (BKT *)&mp->lru; b = b->cnext) {
  3061. X        if (b == (BKT *)&mp->lru)
  3062. X            __mpoolerr("mpool_put: %0x: bad address", baddr);
  3063. X        if (b == baddr)
  3064. X            break;
  3065. X    }
  3066. X#endif
  3067. X    baddr->flags &= ~MPOOL_PINNED;
  3068. X    baddr->flags |= flags & MPOOL_DIRTY;
  3069. X    return (RET_SUCCESS);
  3070. X}
  3071. X
  3072. X/*
  3073. X * MPOOL_CLOSE -- close the buffer pool
  3074. X *
  3075. X * Parameters:
  3076. X *    mp:    mpool cookie
  3077. X *
  3078. X * Returns:
  3079. X *    RET_ERROR, RET_SUCCESS
  3080. X */
  3081. Xint
  3082. Xmpool_close(mp)
  3083. X    MPOOL *mp;
  3084. X{
  3085. X    BKT *b, *next;
  3086. X
  3087. X    /* Free up any space allocated to the lru pages. */
  3088. X    for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = next) {
  3089. X        next = b->cprev;
  3090. X        free(b);
  3091. X    }
  3092. X    free(mp);
  3093. X    return (RET_SUCCESS);
  3094. X}
  3095. X
  3096. X/*
  3097. X * MPOOL_SYNC -- sync the file to disk.
  3098. X *
  3099. X * Parameters:
  3100. X *    mp:    mpool cookie
  3101. X *
  3102. X * Returns:
  3103. X *    RET_ERROR, RET_SUCCESS
  3104. X */
  3105. Xint
  3106. Xmpool_sync(mp)
  3107. X    MPOOL *mp;
  3108. X{
  3109. X    BKT *b;
  3110. X
  3111. X    for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = b->cprev)
  3112. X        if (b->flags & MPOOL_DIRTY && mpool_write(mp, b) == RET_ERROR)
  3113. X            return (RET_ERROR);
  3114. X    return (fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
  3115. X}
  3116. X
  3117. X/*
  3118. X * MPOOL_BKT -- get/create a BKT from the cache
  3119. X *
  3120. X * Parameters:
  3121. X *    mp:    mpool cookie
  3122. X *
  3123. X * Returns:
  3124. X *    NULL on failure and a pointer to the BKT on success    
  3125. X */
  3126. Xstatic BKT *
  3127. Xmpool_bkt(mp)
  3128. X    MPOOL *mp;
  3129. X{
  3130. X    BKT *b;
  3131. X
  3132. X    if (mp->curcache < mp->maxcache)
  3133. X        goto new;
  3134. X
  3135. X    /*
  3136. X     * If the cache is maxxed out, search the lru list for a buffer we
  3137. X     * can flush.  If we find one, write it if necessary and take it off
  3138. X     * any lists.  If we don't find anything we grow the cache anyway.
  3139. X     * The cache never shrinks.
  3140. X     */
  3141. X    for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = b->cprev)
  3142. X        if (!(b->flags & MPOOL_PINNED)) {
  3143. X            if (b->flags & MPOOL_DIRTY &&
  3144. X                mpool_write(mp, b) == RET_ERROR)
  3145. X                return (NULL);
  3146. X            rmhash(b);
  3147. X            rmchain(b);
  3148. X#ifdef STATISTICS
  3149. X            ++mp->pageflush;
  3150. X#endif
  3151. X#ifdef DEBUG
  3152. X            {
  3153. X                void *spage;
  3154. X                spage = b->page;
  3155. X                memset(b, 0xff, sizeof(BKT) + mp->pagesize);
  3156. X                b->page = spage;
  3157. X            }
  3158. X#endif
  3159. X            return (b);
  3160. X        }
  3161. X
  3162. Xnew:    if ((b = malloc(sizeof(BKT) + mp->pagesize)) == NULL)
  3163. X        return (NULL);
  3164. X#ifdef STATISTICS
  3165. X    ++mp->pagealloc;
  3166. X#endif
  3167. X#ifdef DEBUG
  3168. X    memset(b, 0xff, sizeof(BKT) + mp->pagesize);
  3169. X#endif
  3170. X    b->page = (char *)b + sizeof(BKT);
  3171. X    ++mp->curcache;
  3172. X    return (b);
  3173. X}
  3174. X
  3175. X/*
  3176. X * MPOOL_WRITE -- sync a page to disk
  3177. X *
  3178. X * Parameters:
  3179. X *    mp:    mpool cookie
  3180. X *
  3181. X * Returns:
  3182. X *    RET_ERROR, RET_SUCCESS
  3183. X */
  3184. Xstatic int
  3185. Xmpool_write(mp, b)
  3186. X    MPOOL *mp;
  3187. X    BKT *b;
  3188. X{
  3189. X    off_t off;
  3190. X
  3191. X    if (mp->pgout)
  3192. X        (mp->pgout)(mp->pgcookie, b->pgno, b->page);
  3193. X
  3194. X#ifdef STATISTICS
  3195. X    ++mp->pagewrite;
  3196. X#endif
  3197. X    off = mp->pagesize * b->pgno;
  3198. X    if (lseek(mp->fd, off, SEEK_SET) != off)
  3199. X        return (RET_ERROR);
  3200. X    if (write(mp->fd, b->page, mp->pagesize) != mp->pagesize)
  3201. X        return (RET_ERROR);
  3202. X    b->flags &= ~MPOOL_DIRTY;
  3203. X    return (RET_SUCCESS);
  3204. X}
  3205. X
  3206. X/*
  3207. X * MPOOL_LOOK -- lookup a page
  3208. X *
  3209. X * Parameters:
  3210. X *    mp:    mpool cookie
  3211. X *    pgno:    page number
  3212. X *
  3213. X * Returns:
  3214. X *    NULL on failure and a pointer to the BKT on success
  3215. X */
  3216. Xstatic BKT *
  3217. Xmpool_look(mp, pgno)
  3218. X    MPOOL *mp;
  3219. X    pgno_t pgno;
  3220. X{
  3221. X    register BKT *b;
  3222. X    register BKTHDR *tb;
  3223. X
  3224. X    /* XXX
  3225. X     * If find the buffer, put it first on the hash chain so can
  3226. X     * find it again quickly.
  3227. X     */
  3228. X    tb = &mp->hashtable[HASHKEY(pgno)];
  3229. X    for (b = tb->hnext; b != (BKT *)tb; b = b->hnext)
  3230. X        if (b->pgno == pgno) {
  3231. X#ifdef STATISTICS
  3232. X            ++mp->cachehit;
  3233. X#endif
  3234. X            return (b);
  3235. X        }
  3236. X#ifdef STATISTICS
  3237. X    ++mp->cachemiss;
  3238. X#endif
  3239. X    return (NULL);
  3240. X}
  3241. X
  3242. X#ifdef STATISTICS
  3243. X/*
  3244. X * MPOOL_STAT -- cache statistics
  3245. X *
  3246. X * Parameters:
  3247. X *    mp:    mpool cookie
  3248. X */
  3249. Xvoid
  3250. Xmpool_stat(mp)
  3251. X    MPOOL *mp;
  3252. X{
  3253. X    BKT *b;
  3254. X    int cnt;
  3255. X    char *sep;
  3256. X
  3257. X    (void)fprintf(stderr, "%lu pages in the file\n", mp->npages);
  3258. X    (void)fprintf(stderr,
  3259. X        "page size %lu, cacheing %lu pages of %lu page max cache\n",
  3260. X        mp->pagesize, mp->curcache, mp->maxcache);
  3261. X    (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
  3262. X        mp->pageput, mp->pageget, mp->pagenew);
  3263. X    (void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
  3264. X        mp->pagealloc, mp->pageflush);
  3265. X    if (mp->cachehit + mp->cachemiss)
  3266. X        (void)fprintf(stderr,
  3267. X            "%.0f%% cache hit rate (%lu hits, %lu misses)\n", 
  3268. X            ((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
  3269. X            * 100, mp->cachehit, mp->cachemiss);
  3270. X    (void)fprintf(stderr, "%lu page reads, %lu page writes\n",
  3271. X        mp->pageread, mp->pagewrite);
  3272. X
  3273. X    sep = "";
  3274. X    cnt = 0;
  3275. X    for (b = mp->lru.cnext; b != (BKT *)&mp->lru; b = b->cnext) {
  3276. X        (void)fprintf(stderr, "%s%d", sep, b->pgno);
  3277. X        if (b->flags & MPOOL_DIRTY)
  3278. X            (void)fprintf(stderr, "d");
  3279. X        if (b->flags & MPOOL_PINNED)
  3280. X            (void)fprintf(stderr, "P");
  3281. X        if (++cnt == 10) {
  3282. X            sep = "\n";
  3283. X            cnt = 0;
  3284. X        } else
  3285. X            sep = ", ";
  3286. X            
  3287. X    }
  3288. X    (void)fprintf(stderr, "\n");
  3289. X}
  3290. X#endif
  3291. X
  3292. X#ifdef DEBUG
  3293. X#if __STDC__
  3294. X#include <stdarg.h>
  3295. X#else
  3296. X#include <varargs.h>
  3297. X#endif
  3298. X
  3299. Xstatic void
  3300. X#if __STDC__
  3301. X__mpoolerr(const char *fmt, ...)
  3302. X#else
  3303. X__mpoolerr(fmt, va_alist)
  3304. X    char *fmt;
  3305. X    va_dcl
  3306. X#endif
  3307. X{
  3308. X    va_list ap;
  3309. X#if __STDC__
  3310. X    va_start(ap, fmt);
  3311. X#else
  3312. X    va_start(ap);
  3313. X#endif
  3314. X    (void)vfprintf(stderr, fmt, ap);
  3315. X    va_end(ap);
  3316. X    (void)fprintf(stderr, "\n");
  3317. X    abort();
  3318. X    /* NOTREACHED */
  3319. X}
  3320. X#endif
  3321. END_OF_FILE
  3322. if test 11661 -ne `wc -c <'mpool/mpool.c'`; then
  3323.     echo shar: \"'mpool/mpool.c'\" unpacked with wrong size!
  3324. fi
  3325. # end of 'mpool/mpool.c'
  3326. fi
  3327. echo shar: End of archive 4 \(of 9\).
  3328. cp /dev/null ark4isdone
  3329. MISSING=""
  3330. for I in 1 2 3 4 5 6 7 8 9 ; do
  3331.     if test ! -f ark${I}isdone ; then
  3332.     MISSING="${MISSING} ${I}"
  3333.     fi
  3334. done
  3335. if test "${MISSING}" = "" ; then
  3336.     echo You have unpacked all 9 archives.
  3337.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  3338. else
  3339.     echo You still need to unpack the following archives:
  3340.     echo "        " ${MISSING}
  3341. fi
  3342. ##  End of shell archive.
  3343. exit 0
  3344.