home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2961 < prev    next >
Encoding:
Internet Message Format  |  1991-03-04  |  42.9 KB

  1. From: lee@sq.sq.com (Liam R. E. Quin)
  2. Newsgroups: alt.sources
  3. Subject: lq-text Full Text Retrieval Database Part 13/13
  4. Message-ID: <1991Mar4.021224.17094@sq.sq.com>
  5. Date: 4 Mar 91 02:12:24 GMT
  6.  
  7. : cut here --- cut here --
  8. : To unbundle, sh this file
  9. #! /bin/sh
  10. : part 13
  11. echo x - lq-text/src/ozmahash/hash.h 1>&2
  12. sed 's/^X//' >lq-text/src/ozmahash/hash.h <<'@@@End of lq-text/src/ozmahash/hash.h'
  13. X/*-
  14. X * Copyright (c) 1990 The Regents of the University of California.
  15. X * All rights reserved.
  16. X *
  17. X * This code is derived from software contributed to Berkeley by
  18. X * Margo Seltzer.
  19. X *
  20. X * %sccs.include.redist.c%
  21. X *
  22. X *    %W% (Berkeley) %G%
  23. X */
  24. X
  25. X/* Operations */
  26. Xtypedef enum { HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, 
  27. X        HASH_FIRST, HASH_NEXT } ACTION;
  28. X
  29. X/* Buffer Management structures */
  30. Xtypedef struct _bufhead BUFHEAD;
  31. X
  32. Xstruct _bufhead {
  33. X    BUFHEAD    *prev;        /* LRU links */
  34. X    BUFHEAD    *next;        /* LRU links */
  35. X    BUFHEAD    *ovfl;        /* Overflow page buffer header */
  36. X    int        addr;        /* Address of this page */
  37. X    char    *page;        /* Actual page data */
  38. X    char    flags;    /* Combination of BUF_MOD, BUF_DISK, BUF_BUCKET */
  39. X};
  40. X
  41. X/* Flag Values */
  42. X#define    BUF_MOD        0x0001
  43. X#define BUF_DISK    0x0002
  44. X#define    BUF_BUCKET    0x0004
  45. X
  46. X#define IS_BUCKET(X)    (X & BUF_BUCKET)
  47. X
  48. Xtypedef BUFHEAD    **SEGMENT;
  49. X
  50. X/* Hash Table Information */
  51. Xtypedef struct hashhdr {    /* Disk resident portion */
  52. X    int magic;    /* Magic NO for hash tables */
  53. X    int version;    /* Version ID */
  54. X    long lorder;    /* Byte Order */
  55. X    int bsize;    /* Bucket/Page Size */
  56. X    int bshift;    /* Bucket shift */
  57. X    int dsize;    /* Directory Size */
  58. X    int ssize;    /* Segment Size */
  59. X    int sshift;    /* Segment shift */
  60. X    int max_bucket;    /* ID of Maximum bucket in use */
  61. X    int high_mask;    /* Mask to modulo into entire table */
  62. X    int low_mask;    /* Mask to modulo into lower half of table */
  63. X    int ffactor;    /* Fill factor */
  64. X    int nkeys;    /* Number of keys in hash table */
  65. X    int hdrpages;    /* Size of table header */
  66. X    int h_charkey;    /* value of hash(CHARKEY) */
  67. X# define NCACHED        32    /* number of bit maps and spare points*/
  68. X    int spares[NCACHED];    /* spare pages for overflow */
  69. X    u_short bitmaps[NCACHED];    /* address of overflow page bitmaps */
  70. X} HASHHDR;
  71. X
  72. Xtypedef struct htab {    /* Memory resident data structure */
  73. X    HASHHDR hdr;    /* Header */
  74. X    int nsegs;    /* Number of allocated segments */
  75. X    int exsegs;    /* Number of extra allocated segments */
  76. X    int (*hash)();    /* Hash Function */
  77. X    int flags;    /* Flag values */
  78. X    int fp;        /* File pointer */
  79. X    char *tmp_buf;    /* Temporary Buffer for BIG data */
  80. X    char *tmp_key;    /* Temporary Buffer for BIG keys */
  81. X    BUFHEAD *cpage;    /* Current page */
  82. X    int cbucket;    /* Current bucket */
  83. X    int cndx;      /* Index of next item on cpage */
  84. X    int errno;    /* Error Number -- for DBM compatability */
  85. X    int new_file;    /* Indicates whether fd is backing store or no */
  86. X    int save_file;    /* Indicates whether we need to flush file at exit */
  87. X    u_long *mapp[NCACHED];    /* Pointers to page maps */
  88. X    int nbufs;    /* Number of buffers left to allocate */
  89. X    BUFHEAD    bufhead; /* Header of buffer lru list */
  90. X    SEGMENT     *dir;    /* Hash Bucket directory */
  91. X} HTAB;
  92. X
  93. X
  94. X/*
  95. X * Constants
  96. X */
  97. X#define    MAX_BSIZE        65536    /* 2^16 */
  98. X#define MIN_BUFFERS        6
  99. X#define MINHDRSIZE        512
  100. X#define DEF_BUFSIZE        65536    /* 64 K */
  101. X#define DEF_BUCKET_SIZE    256
  102. X#define DEF_BUCKET_SHIFT    8    /* log2(BUCKET) */
  103. X#define DEF_SEGSIZE        256
  104. X#define DEF_SEGSIZE_SHIFT        8      /* log2(SEGSIZE)     */
  105. X#define DEF_DIRSIZE        256
  106. X#define DEF_FFACTOR        5
  107. X#define SPLTMAX        8
  108. X#define CHARKEY        "%$sniglet^&"
  109. X#define NUMKEY            1038583
  110. X#define VERSION_NO        3
  111. X#define BYTE_SHIFT        3
  112. X#define INT_TO_BYTE        2
  113. X#define INT_BYTE_SHIFT        5
  114. X#define ALL_SET        ((unsigned)0xFFFFFFFF)
  115. X#define ALL_CLEAR        0
  116. X
  117. X
  118. X#define MAX(A,B)    ( (A>B)?A:B )
  119. X#define PTROF(X)    ((BUFHEAD *)((unsigned)(X)&~0x3))
  120. X#define ISMOD(X)    ((unsigned)(X)&0x1)
  121. X#define DOMOD(X)    (X = (char *)( (unsigned)X | 0x1))
  122. X#define ISDISK(X)    ((unsigned)(X)&0x2)
  123. X#define DODISK(X)    (X = (char *)( (unsigned)X | 0x2))
  124. X
  125. X#define BITS_PER_MAP    32
  126. X
  127. X/* Given the address of the beginning of a big map, clear/set the nth bit */
  128. X
  129. X#define CLRBIT(A,N) ((A)[N/BITS_PER_MAP] &= ~(1<<(N%BITS_PER_MAP)))
  130. X#define SETBIT(A,N) ((A)[N/BITS_PER_MAP] |= (1<<(N%BITS_PER_MAP)))
  131. X#define ISSET(A,N) ((A)[N/BITS_PER_MAP] & (1<<(N%BITS_PER_MAP)))
  132. X
  133. X/* Overflow management */
  134. X/*
  135. X    Overflow page numbers are allocated per split point.
  136. X    At each doubling of the table, we can allocate extra
  137. X    pages.  So, an overflow page number has the top 5 bits
  138. X    indicate which split point and the lower 11 bits indicate
  139. X    which page at that split point is indicated (pages within
  140. X    split points are numberered starting with 1).
  141. X
  142. X
  143. X*/
  144. X
  145. X#define SPLITSHIFT    11
  146. X#define SPLITMASK    0x7FF
  147. X#define SPLITNUM(N)    (((unsigned)N) >> SPLITSHIFT)
  148. X#define OPAGENUM(N)    (N & SPLITMASK)
  149. X#define    OADDR_OF(S,O)    ((S << SPLITSHIFT) + O)
  150. X
  151. X#define BUCKET_TO_PAGE(B) \
  152. X    B + hashp->HDRPAGES + (B ? hashp->SPARES[log2(B+1)-1] : 0)
  153. X#define OADDR_TO_PAGE(B)     \
  154. X    BUCKET_TO_PAGE ( (1 << SPLITNUM(B)) -1 ) + OPAGENUM(B);
  155. X
  156. X/*
  157. X    page.h contains a detailed description of the page format.
  158. X
  159. X    Normally, keys and data are accessed from offset tables in the
  160. X    top of each page which point to the beginning of the key and
  161. X    data.  There are four flag values which may be stored in these
  162. X    offset tables which indicate the following:
  163. X
  164. X    OVFLPAGE    Rather than a key data pair, this pair contains
  165. X            the address of an overflow page.  The format of
  166. X            the pair is:
  167. X                OVERFLOW_PAGE_NUMBER OVFLPAGE
  168. X
  169. X    PARTIAL_KEY    This must be the first key/data pair on a page 
  170. X            and implies that page contains only a partial key.  
  171. X            That is, the key is too big to fit on a single page 
  172. X            so it starts on this page and continues on the next.
  173. X            The format of the page is:
  174. X                KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
  175. X                
  176. X                KEY_OFF -- offset of the beginning of the key
  177. X                PARTIAL_KEY -- 1
  178. X                OVFL_PAGENO - page number of the next overflow page
  179. X                OVFLPAGE -- 0
  180. X    FULL_KEY    This must be the first key/data pair on the page.  It
  181. X            is used in two cases.  
  182. X
  183. X            Case 1:
  184. X                There is a complete key on the page but no data
  185. X                (because it wouldn't fit).  The next page contains
  186. X                the data.
  187. X
  188. X                Page format it:
  189. X                KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
  190. X
  191. X                KEY_OFF -- offset of the beginning of the key
  192. X                FULL_KEY -- 2
  193. X                OVFL_PAGENO - page number of the next overflow page
  194. X                OVFLPAGE -- 0
  195. X
  196. X            Case 2:
  197. X                This page contains no key, but part of a large 
  198. X                data field, which is continued on the next page.
  199. X
  200. X                Page format it:
  201. X                DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
  202. X
  203. X                KEY_OFF -- offset of the beginning of the data on
  204. X                    this page
  205. X                FULL_KEY -- 2
  206. X                OVFL_PAGENO - page number of the next overflow page
  207. X                OVFLPAGE -- 0
  208. X
  209. X    FULL_KEY_DATA    This must be the first key/data pair on the page.
  210. X            There are two cases:
  211. X
  212. X            Case 1:
  213. X                This page contains a key and the beginning of the
  214. X                data field, but the data field is continued on the
  215. X                next page.
  216. X
  217. X                Page format is:
  218. X                KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
  219. X
  220. X                KEY_OFF -- offset of the beginning of the key
  221. X                FULL_KEY_DATA -- 3
  222. X                OVFL_PAGENO - page number of the next overflow page
  223. X                DATA_OFF -- offset of the beginning of the data 
  224. X
  225. X            Case 2:
  226. X                This page contains the last page of a big data pair.
  227. X                There is no key, only the  tail end of the data 
  228. X                on this page.
  229. X
  230. X                Page format is:
  231. X                DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
  232. X
  233. X                DATA_OFF -- offset of the beginning of the data on
  234. X                    this page
  235. X                FULL_KEY_DATA -- 3
  236. X                OVFL_PAGENO - page number of the next overflow page
  237. X                OVFLPAGE -- 0
  238. X
  239. X                OVFL_PAGENO and OVFLPAGE are optional (they are
  240. X                not present if there is no next page).
  241. X*/
  242. X#define OVFLPAGE    0
  243. X#define PARTIAL_KEY    1
  244. X#define FULL_KEY    2
  245. X#define FULL_KEY_DATA    3
  246. X#define    REAL_KEY    4
  247. X
  248. X
  249. X/* Short hands for accessing structure */
  250. X#define BSIZE    hdr.bsize
  251. X#define BSHIFT    hdr.bshift
  252. X#define DSIZE    hdr.dsize
  253. X#define SGSIZE    hdr.ssize
  254. X#define SSHIFT    hdr.sshift
  255. X#define LORDER    hdr.lorder
  256. X#define MAX_BUCKET    hdr.max_bucket
  257. X#define FFACTOR        hdr.ffactor
  258. X#define HIGH_MASK    hdr.high_mask
  259. X#define LOW_MASK    hdr.low_mask
  260. X#define NKEYS        hdr.nkeys
  261. X#define HDRPAGES    hdr.hdrpages
  262. X#define SPARES        hdr.spares
  263. X#define BITMAPS        hdr.bitmaps
  264. X#define VERSION        hdr.version
  265. X#define MAGIC        hdr.magic
  266. X#define NEXT_FREE    hdr.next_free
  267. X#define H_CHARKEY    hdr.h_charkey
  268. @@@End of lq-text/src/ozmahash/hash.h
  269. echo x - lq-text/src/ozmahash/hfunc.c 1>&2
  270. sed 's/^X//' >lq-text/src/ozmahash/hfunc.c <<'@@@End of lq-text/src/ozmahash/hfunc.c'
  271. X/*-
  272. X * Copyright (c) 1990 The Regents of the University of California.
  273. X * All rights reserved.
  274. X *
  275. X * This code is derived from software contributed to Berkeley by
  276. X * Margo Seltzer.
  277. X *
  278. X * %sccs.include.redist.c%
  279. X */
  280. X
  281. X#if defined(LIBC_SCCS) && !defined(lint)
  282. Xstatic char sccsid[] = "%W% (Berkeley) %G%";
  283. X#endif /* LIBC_SCCS and not lint */
  284. X
  285. X/* Global default hash function */
  286. Xstatic    int    hash1();
  287. Xstatic    int    hash2();
  288. Xstatic    int    hash3();
  289. Xstatic    int    hash4();
  290. X
  291. Xint    (*default_hash)() = hash4;
  292. X
  293. X/******************************* HASH FUNCTIONS **************************/
  294. X/*
  295. X    Assume that we've already split the bucket to which this
  296. X    key hashes, calculate that bucket, and check that in fact
  297. X    we did already split it.
  298. X
  299. X    This came from ejb's hsearch.
  300. X*/
  301. X
  302. X# define PRIME1            37
  303. X# define PRIME2            1048583
  304. X
  305. Xstatic int
  306. Xhash1(key,len)
  307. Xchar *key;
  308. Xint len;
  309. X{
  310. X    register int h;
  311. X    register int l = len;
  312. X    register unsigned char *k = (unsigned char *) key;
  313. X
  314. X    h = 0;
  315. X    /*
  316. X     * Convert string to integer
  317. X     */
  318. X    while (l--) h = h * PRIME1 ^ (*k++ - ' ');
  319. X    h %= PRIME2;
  320. X
  321. X    return (h);
  322. X}
  323. X
  324. X/*
  325. X    Phong's linear congruential hash
  326. X*/
  327. X#define dcharhash(h, c)    ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
  328. X
  329. Xstatic int
  330. Xhash2(str, n)
  331. X    register unsigned char *str;
  332. X    int n;
  333. X{
  334. X    register unsigned char *e, c;
  335. X    register int h;
  336. X
  337. X    e = str + n;
  338. X    for (h = 0; str != e;) {
  339. X        c = *str++;
  340. X        if (!c && str > e)
  341. X            break;
  342. X        dcharhash(h,c);
  343. X    }
  344. X    return(h);
  345. X}
  346. X
  347. X/*
  348. X * This is INCREDIBLY ugly, but fast.
  349. X * We break the string up into 8 byte units.  On the first time
  350. X * through the loop we get the "leftover bytes" (strlen % 8).
  351. X * On every other iteration, we perform 8 HASHC's so we handle
  352. X * all 8 bytes.  Essentially, this saves us 7 cmp & branch
  353. X * instructions.  If this routine is heavily used enough, it's
  354. X * worth the ugly coding
  355. X * 
  356. X * OZ's original sdbm hash
  357. X */
  358. Xstatic int
  359. Xhash3(key,nbytes)
  360. Xchar *key;
  361. Xint nbytes;
  362. X{
  363. X        register int n = 0;
  364. X    register char *str = key;
  365. X    register int loop;
  366. X    register int len = nbytes;
  367. X
  368. X#define HASHC   n = *str++ + 65599 * n
  369. X
  370. X        if (len > 0) {
  371. X                loop = (len + 8 - 1) >> 3;
  372. X
  373. X                switch(len & (8 - 1)) {
  374. X            case 0: do {        /* All fall throughs */
  375. X                    HASHC;  
  376. X                case 7: HASHC;
  377. X                case 6: HASHC;  
  378. X                case 5: HASHC;
  379. X                case 4: HASHC;  
  380. X                case 3: HASHC;
  381. X                case 2: HASHC;  
  382. X                case 1: HASHC;
  383. X                        } while (--loop);
  384. X                }
  385. X
  386. X        }
  387. X    return(n);
  388. X}
  389. X
  390. X/* Hash function from Chris Torek */
  391. Xstatic int
  392. Xhash4(key,nbytes)
  393. Xchar    *key;
  394. Xint    nbytes;
  395. X{
  396. X        register int h = 0;
  397. X    register char *p = key;
  398. X    register int loop;
  399. X    register int len = nbytes;
  400. X
  401. X#define HASH4a   h = (h << 5) - h + *p++;
  402. X#define HASH4b   h = (h << 5) + h + *p++;
  403. X#define HASH4 HASH4b
  404. X
  405. X        if (len > 0) {
  406. X                loop = (len + 8 - 1) >> 3;
  407. X
  408. X                switch(len & (8 - 1)) {
  409. X            case 0: do {        /* All fall throughs */
  410. X                    HASH4;  
  411. X                case 7: HASH4;
  412. X                case 6: HASH4;  
  413. X                case 5: HASH4;
  414. X                case 4: HASH4;  
  415. X                case 3: HASH4;
  416. X                case 2: HASH4;  
  417. X                case 1: HASH4;
  418. X                        } while (--loop);
  419. X                }
  420. X
  421. X        }
  422. X    return(h);
  423. X}
  424. @@@End of lq-text/src/ozmahash/hfunc.c
  425. echo x - lq-text/src/ozmahash/hsearch.c 1>&2
  426. sed 's/^X//' >lq-text/src/ozmahash/hsearch.c <<'@@@End of lq-text/src/ozmahash/hsearch.c'
  427. X/*-
  428. X * Copyright (c) 1990 The Regents of the University of California.
  429. X * All rights reserved.
  430. X *
  431. X * This code is derived from software contributed to Berkeley by
  432. X * Margo Seltzer.
  433. X *
  434. X * %sccs.include.redist.c%
  435. X */
  436. X
  437. X#if defined(LIBC_SCCS) && !defined(lint)
  438. Xstatic char sccsid[] = "%W% (Berkeley) %G%";
  439. X#endif /* LIBC_SCCS and not lint */
  440. X#include    <sys/file.h>
  441. X#include    <sys/types.h>
  442. X#include    <stdio.h>
  443. X#include    <db.h>
  444. X#include    <search.h>
  445. X
  446. Xstatic    DB    *dbp = NULL;
  447. Xstatic    ENTRY    retval;
  448. X
  449. Xextern    int
  450. Xhcreate ( nel )
  451. Xunsigned    nel;
  452. X{
  453. X    int    status;
  454. X    HASHINFO    info;
  455. X
  456. X    info.nelem = nel;
  457. X    info.bsize = 256;
  458. X    info.ffactor = 8;
  459. X    info.ncached = NULL;
  460. X    info.hash = NULL;
  461. X    info.lorder = 0;
  462. X    dbp = hash_open ( NULL, O_CREAT|O_RDWR, 0600, &info );
  463. X    return ( (int) dbp );
  464. X}
  465. X
  466. X
  467. Xextern ENTRY    *
  468. Xhsearch ( item, action )
  469. XENTRY    item;
  470. XACTION    action;
  471. X{
  472. X    int    status;
  473. X    DBT    key, val;
  474. X
  475. X    if ( !dbp ) {
  476. X    return(NULL);
  477. X    }
  478. X
  479. X    key.data = item.key;
  480. X    key.size = strlen(item.key) + 1;
  481. X
  482. X    if ( action == ENTER ) {
  483. X    val.data = item.data;
  484. X    val.size = strlen(item.data) + 1;
  485. X    status = (dbp->put) ( dbp, &key, &val, R_NOOVERWRITE );
  486. X    if ( status ) {
  487. X        return(NULL);
  488. X    } 
  489. X    } else {
  490. X    /* FIND */
  491. X    status = (dbp->get) ( dbp, &key, &val );
  492. X    if ( status ) {
  493. X        return ( NULL );
  494. X    } else {
  495. X        item.data = val.data;
  496. X    }
  497. X    }
  498. X    return ( &item );
  499. X}
  500. X
  501. X
  502. Xextern void
  503. Xhdestroy ()
  504. X{
  505. X    if (dbp) {
  506. X    (void)(dbp->close) (dbp);
  507. X    dbp = NULL;
  508. X    }
  509. X    return;
  510. X}
  511. X
  512. X
  513. @@@End of lq-text/src/ozmahash/hsearch.c
  514. echo x - lq-text/src/ozmahash/log2.c 1>&2
  515. sed 's/^X//' >lq-text/src/ozmahash/log2.c <<'@@@End of lq-text/src/ozmahash/log2.c'
  516. X/*-
  517. X * Copyright (c) 1990 The Regents of the University of California.
  518. X * All rights reserved.
  519. X *
  520. X * This code is derived from software contributed to Berkeley by
  521. X * Margo Seltzer.
  522. X *
  523. X * %sccs.include.redist.c%
  524. X */
  525. X
  526. X#if defined(LIBC_SCCS) && !defined(lint)
  527. Xstatic char sccsid[] = "%W% (Berkeley) %G%";
  528. X#endif /* LIBC_SCCS and not lint */
  529. X
  530. Xlog2( num )
  531. Xint    num;
  532. X{
  533. X    register int    i;
  534. X    register int    limit = 1;
  535. X
  536. X    for ( i = 0; limit < num; limit = limit << 1, i++ );
  537. X    return (i);
  538. X}
  539. @@@End of lq-text/src/ozmahash/log2.c
  540. echo x - lq-text/src/ozmahash/mkstemp.c 1>&2
  541. sed 's/^X//' >lq-text/src/ozmahash/mkstemp.c <<'@@@End of lq-text/src/ozmahash/mkstemp.c'
  542. X/*-
  543. X * Copyright (c) 1990 The Regents of the University of California.
  544. X * All rights reserved.
  545. X *
  546. X * This code is derived from software contributed to Berkeley by
  547. X * Margo Seltzer.
  548. X *
  549. X * %sccs.include.redist.c%
  550. X */
  551. X
  552. X#if defined(LIBC_SCCS) && !defined(lint)
  553. Xstatic char sccsid[] = "%W% (Berkeley) %G%";
  554. X#endif /* LIBC_SCCS and not lint */
  555. X
  556. X#include <sys/file.h>
  557. X
  558. Xmkstemp(as)
  559. X    char *as;
  560. X{
  561. X    register char *s;
  562. X    register unsigned int pid;
  563. X    register int fd, i;
  564. X
  565. X    pid = getpid();
  566. X    s = as;
  567. X    while (*s++)
  568. X        /* void */;
  569. X    s--;
  570. X    while (*--s == 'X') {
  571. X        *s = (pid % 10) + '0';
  572. X        pid /= 10;
  573. X    }
  574. X    s++;
  575. X    i = 'a';
  576. X    while ((fd = open(as, O_CREAT|O_EXCL|O_RDWR, 0600)) == -1) {
  577. X        if (i == 'z')
  578. X            return(-1);
  579. X        *s = i++;
  580. X    }
  581. X    return(fd);
  582. X}
  583. @@@End of lq-text/src/ozmahash/mkstemp.c
  584. echo x - lq-text/src/ozmahash/ndbm.c 1>&2
  585. sed 's/^X//' >lq-text/src/ozmahash/ndbm.c <<'@@@End of lq-text/src/ozmahash/ndbm.c'
  586. X/*-
  587. X * Copyright (c) 1990 The Regents of the University of California.
  588. X * All rights reserved.
  589. X *
  590. X * This code is derived from software contributed to Berkeley by
  591. X * Margo Seltzer.
  592. X *
  593. X * %sccs.include.redist.c%
  594. X */
  595. X
  596. X#if defined(LIBC_SCCS) && !defined(lint)
  597. Xstatic char sccsid[] = "%W% (Berkeley) %G%";
  598. X#endif /* LIBC_SCCS and not lint */
  599. X/*
  600. X    This package provides a dbm compatible interface to the new hashing
  601. X    package described in db(3)
  602. X*/
  603. X
  604. X#include <sys/types.h>
  605. X#include <stdio.h>
  606. X#include <ndbm.h>
  607. X#include <hash.h>
  608. X
  609. X/*
  610. X    return     *DBM on success
  611. X        NULL on failure
  612. X*/
  613. Xextern DBM *
  614. Xdbm_open( file, flags, mode )
  615. Xchar     *file;
  616. Xint    flags;
  617. Xint    mode;
  618. X{
  619. X    HASHINFO    info;
  620. X
  621. X    info.bsize = 1024;
  622. X    info.ffactor = 256; /* Liam -- smaller databases? */
  623. X    /** info.ffactor = 5; **/
  624. X    info.nelem = 1;
  625. X    info.ncached = NULL;
  626. X    info.hash = NULL;
  627. X    info.lorder = 0;
  628. X    return( hash_open ( file, flags, mode, &info ) );
  629. X}
  630. X
  631. Xextern void 
  632. Xdbm_close(db)
  633. XDBM    *db;
  634. X{
  635. X    (void)(db->close) (db);
  636. X}
  637. X
  638. X/*
  639. X    Returns     DATUM on success
  640. X        NULL on failure
  641. X*/
  642. Xextern datum 
  643. Xdbm_fetch( db, key )
  644. XDBM     *db;
  645. Xdatum    key;
  646. X{
  647. X    int    status;
  648. X    datum    retval;
  649. X
  650. X    status = (db->get) ( db, (DBT *)&key, (DBT *)&retval );
  651. X    if ( status ) {
  652. X    retval.dptr = NULL;
  653. X    retval.dsize = 0;
  654. X    }
  655. X    return(retval);
  656. X}
  657. X
  658. X/*
  659. X    Returns     DATUM on success
  660. X        NULL on failure
  661. X*/
  662. Xextern datum 
  663. Xdbm_firstkey(db)
  664. XDBM     *db;
  665. X{
  666. X    int    status;
  667. X    datum    retkey;
  668. X    datum    retdata;
  669. X
  670. X    status = (db->seq) ( db, (DBT *)&retkey, (DBT *)&retdata, R_FIRST );
  671. X    if ( status ) {
  672. X    retkey.dptr = NULL;
  673. X    retkey.dsize = 0;
  674. X    }
  675. X    return(retkey);
  676. X}
  677. X/*
  678. X    Returns     DATUM on success
  679. X        NULL on failure
  680. X*/
  681. Xextern datum 
  682. Xdbm_nextkey(db)
  683. XDBM     *db;
  684. X{
  685. X    int    status;
  686. X    datum    retkey;
  687. X    datum    retdata;
  688. X
  689. X    status = (db->seq) ( db, (DBT *)&retkey, (DBT *)&retdata, R_NEXT );
  690. X    if ( status ) {
  691. X    retkey.dptr = NULL;
  692. X    retkey.dsize = 0;
  693. X    }
  694. X    return(retkey);
  695. X}
  696. X
  697. X/*
  698. X    0 on success
  699. X    <0 failure
  700. X*/
  701. Xextern int 
  702. Xdbm_delete(db, key)
  703. XDBM     *db;
  704. Xdatum    key;
  705. X{
  706. X    int    status;
  707. X
  708. X    status = (db->delete)( db, (DBT *)&key );
  709. X    if ( status ) {
  710. X    return(-1);
  711. X    } else {
  712. X    return(0);
  713. X    }
  714. X}
  715. X
  716. X/*
  717. X    0 on success
  718. X    <0 failure
  719. X    1 if DBM_INSERT and entry exists
  720. X*/
  721. Xextern int 
  722. Xdbm_store(db, key, content, flags)
  723. XDBM     *db;
  724. Xdatum    key;
  725. Xdatum    content;
  726. Xint    flags;
  727. X{
  728. X    return ((db->put)( db, (DBT *)&key, (DBT *)&content, 
  729. X            (flags == DBM_INSERT) ? R_NOOVERWRITE : 0 ));
  730. X}
  731. X
  732. Xextern int
  733. Xdbm_error(db)
  734. XDBM    *db;
  735. X{
  736. X    HTAB    *hp;
  737. X
  738. X    hp = (HTAB *)db->internal;
  739. X    return ( hp->errno );
  740. X}
  741. X
  742. Xextern int
  743. Xdbm_clearerr(db)
  744. XDBM    *db;
  745. X{
  746. X    HTAB    *hp;
  747. X
  748. X    hp = (HTAB *)db->internal;
  749. X    hp->errno = 0;
  750. X    return ( 0 );
  751. X}
  752. @@@End of lq-text/src/ozmahash/ndbm.c
  753. echo x - lq-text/src/ozmahash/ndbm.h 1>&2
  754. sed 's/^X//' >lq-text/src/ozmahash/ndbm.h <<'@@@End of lq-text/src/ozmahash/ndbm.h'
  755. X/*
  756. X * Copyright (c) 1989 The Regents of the University of California.
  757. X * All rights reserved.
  758. X *
  759. X * Redistribution and use in source and binary forms are permitted
  760. X * provided that the above copyright notice and this paragraph are
  761. X * duplicated in all such forms and that any documentation,
  762. X * advertising materials, and other materials related to such
  763. X * distribution and use acknowledge that the software was developed
  764. X * by the University of California, Berkeley.  The name of the
  765. X * University may not be used to endorse or promote products derived
  766. X * from this software without specific prior written permission.
  767. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  768. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  769. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  770. X *
  771. X *    %W% (Berkeley) %G%
  772. X */
  773. X#include <db.h>
  774. X
  775. X/* Map dbm interface onto hash(3) */
  776. X#define DBM_RDONLY    O_RDONLY
  777. X
  778. X/* Flags to dbm_store() */
  779. X#define DBM_INSERT      0
  780. X#define DBM_REPLACE     1
  781. X
  782. Xtypedef struct {
  783. X    char     *dptr;
  784. X    int    dsize;
  785. X} datum;
  786. X
  787. Xtypedef DB    DBM;
  788. X
  789. X#ifdef __STDC__ || c_plusplus
  790. Xextern DBM *dbm_open(const char *, int, int);
  791. Xextern void dbm_close(DBM *);
  792. Xextern datum dbm_fetch(DBM *, datum);
  793. Xextern datum dbm_firstkey(DBM *);
  794. Xextern datum dbm_nextkey(DBM *);
  795. Xextern long dbm_forder(DBM *, datum);
  796. Xextern int dbm_delete(DBM *, datum);
  797. Xextern int dbm_store(DBM *, datum, datum, int);
  798. X#else
  799. Xextern DBM *dbm_open();
  800. Xextern void dbm_close();
  801. Xextern datum dbm_fetch();
  802. Xextern datum dbm_firstkey();
  803. Xextern datum dbm_nextkey();
  804. Xextern long dbm_forder();
  805. Xextern int dbm_delete();
  806. Xextern int dbm_store();
  807. X#endif
  808. @@@End of lq-text/src/ozmahash/ndbm.h
  809. echo x - lq-text/src/ozmahash/page.c 1>&2
  810. sed 's/^X//' >lq-text/src/ozmahash/page.c <<'@@@End of lq-text/src/ozmahash/page.c'
  811. X/*-
  812. X * Copyright (c) 1990 The Regents of the University of California.
  813. X * All rights reserved.
  814. X *
  815. X * This code is derived from software contributed to Berkeley by
  816. X * Margo Seltzer.
  817. X *
  818. X * %sccs.include.redist.c%
  819. X */
  820. X
  821. X#if defined(LIBC_SCCS) && !defined(lint)
  822. Xstatic char sccsid[] = "%W% (Berkeley) %G%";
  823. X#endif /* LIBC_SCCS and not lint */
  824. X/******************************************************************************
  825. XPACKAGE:  hashing
  826. X
  827. XDESCRIPTION: 
  828. X    Page manipulation for hashing package.
  829. X
  830. XROUTINES: 
  831. X    External
  832. X    get_page
  833. X    add_ovflpage
  834. X    Internal
  835. X    overflow_page
  836. X    open_temp
  837. X******************************************************************************/
  838. X
  839. X#include <sys/types.h>
  840. X#include <sys/file.h>
  841. X#include <assert.h>
  842. X#include <errno.h>
  843. X#include <db.h>
  844. X#include <hash.h>
  845. X#include <page.h>
  846. X#include <stdio.h>
  847. X#include <endian.h>
  848. X
  849. X/* Externals */
  850. X/* buf.c */
  851. Xextern BUFHEAD    *get_buf();
  852. Xextern void reclaim_buf();
  853. X
  854. X/* big.c */
  855. Xextern int big_split();
  856. Xextern int big_insert();
  857. Xextern int big_delete();
  858. Xextern int find_bigpair();
  859. X
  860. X/* dynahash.c */
  861. Xextern    int    call_hash();
  862. Xextern    int    expand_table();
  863. X
  864. X/* my externals */
  865. Xextern int get_page();
  866. Xextern BUFHEAD *add_ovflpage();
  867. Xextern int split_page();
  868. Xextern int  addel();
  869. X
  870. X/* my internals */
  871. Xstatic u_short overflow_page();
  872. Xstatic int open_temp();
  873. Xstatic void squeeze_key();
  874. Xstatic void putpair();
  875. X
  876. X#ifdef HASH_STATISTICS
  877. Xextern long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
  878. X#endif
  879. X#define    PAGE_INIT(P)                    \
  880. X{                            \
  881. X    ((u_short *)P)[0] = 0;                \
  882. X    ((u_short *)P)[1] = hashp->BSIZE - 3 * sizeof(u_short);    \
  883. X    ((u_short *)P)[2] = hashp->BSIZE;            \
  884. X}
  885. X
  886. X/*
  887. X    This is called AFTER we have verified that there is room on the
  888. X    page for the pair (PAIRFITS has returned true) so we go right
  889. X    ahead and start moving stuff on.
  890. X*/
  891. Xstatic void
  892. Xputpair(p, key, val)
  893. Xchar *p;
  894. XDBT *key;
  895. XDBT *val;
  896. X{
  897. X    register u_short n;
  898. X    register u_short off;
  899. X    register u_short *bp = (u_short *) p;
  900. X
  901. X/* enter the key first */
  902. X    n = bp[0];
  903. X
  904. X    off = OFFSET(bp) - key->size;
  905. X    bcopy( key->data, p+off, key->size );
  906. X    bp[++n] = off;
  907. X
  908. X/* now the data */
  909. X    off -= val->size;
  910. X    bcopy(val->data,  p + off, val->size);
  911. X    bp[++n] = off;
  912. X
  913. X/* adjust page info */
  914. X    bp[0] = n;
  915. X    bp[n+1] = off - ((n+3)*sizeof(u_short));
  916. X    bp[n+2] = off;
  917. X    return;
  918. X}
  919. X/*
  920. X    0 OK
  921. X    -1 error
  922. X*/
  923. Xextern int
  924. Xdelpair(bufp, ndx)
  925. XBUFHEAD *bufp;
  926. Xregister int ndx;
  927. X{
  928. X    register u_short *bp = (u_short *) bufp->page;
  929. X    register int n = bp[0];
  930. X    register u_short newoff;
  931. X    u_short pairlen;
  932. X
  933. X    if ( bp[ndx+1] < REAL_KEY ) return ( big_delete ( bufp, ndx ) );
  934. X    if ( ndx != 1 ) newoff = bp[ndx-1];
  935. X    else newoff = hashp->BSIZE;
  936. X    pairlen = newoff - bp[ndx+1];
  937. X
  938. X    if ( ndx != (n-1) ) {
  939. X        /* Hard Case -- need to shuffle keys */
  940. X        register int i;
  941. X        register char *src = bufp->page + (int)OFFSET(bp);
  942. X        register char *dst = src + (int)pairlen;
  943. X        bcopy ( src, dst, bp[ndx+1] - OFFSET(bp) );
  944. X
  945. X        /* Now adjust the pointers */
  946. X        for ( i = ndx+2; i <= n; i += 2 ) {
  947. X            if ( bp[i+1]  == OVFLPAGE ) {
  948. X            bp[i-2] = bp[i];
  949. X            bp[i-1] = bp[i+1];
  950. X            } else {
  951. X            bp[i-2] = bp[i] + pairlen;
  952. X            bp[i-1] = bp[i+1] + pairlen;
  953. X            }
  954. X        }
  955. X    }
  956. X
  957. X    /* Finally adjust the page data */
  958. X    bp[n] = OFFSET(bp) + pairlen;
  959. X    bp[n-1] = bp[n+1] + pairlen + 2 * sizeof(u_short);
  960. X    bp[0] = n-2;
  961. X    hashp->NKEYS--;
  962. X
  963. X    bufp->flags |= BUF_MOD;
  964. X    return (0);
  965. X}
  966. X/*
  967. X    -1 ==> Error
  968. X    0 ==> OK
  969. X*/
  970. Xextern int
  971. Xsplit_page(obucket, nbucket)
  972. Xint obucket;
  973. Xint nbucket;
  974. X{
  975. X    DBT key;
  976. X    DBT val;
  977. X
  978. X    register BUFHEAD *new_bufp;
  979. X    register BUFHEAD *old_bufp;
  980. X    register u_short *ino;
  981. X    register char    *np;
  982. X    char    *op;
  983. X
  984. X    u_short copyto = (u_short)hashp->BSIZE;
  985. X    u_short off = (u_short)hashp->BSIZE;
  986. X    int n;
  987. X    u_short diff;
  988. X    u_short moved;
  989. X    int ndx;
  990. X
  991. X    old_bufp = get_buf ( obucket, NULL, 0 );
  992. X    new_bufp = get_buf ( nbucket, NULL, 0 );
  993. X
  994. X    old_bufp->flags |= BUF_MOD;
  995. X    new_bufp->flags |= BUF_MOD;
  996. X
  997. X    ino = (u_short *)(op = old_bufp->page);
  998. X    np = new_bufp->page;
  999. X
  1000. X    moved = 0;
  1001. X
  1002. X    for (n = 1, ndx = 1; n < ino[0]; n+=2) {
  1003. X        if ( ino[n+1] < REAL_KEY ) {
  1004. X            return ( ugly_split( obucket, old_bufp, new_bufp, 
  1005. X                     copyto, moved ) );
  1006. X        }
  1007. X        key.data = op + ino[n]; 
  1008. X        key.size = off - ino[n];
  1009. X
  1010. X        if ( call_hash ( key.data, key.size ) == obucket ) {
  1011. X            /* Don't switch page */
  1012. X            diff = copyto - off;
  1013. X            if ( diff ) {
  1014. X            copyto = ino[n+1] + diff;
  1015. X            bcopy ( op + ino[n+1], op + copyto,  off-ino[n+1]);
  1016. X            ino[ndx] = copyto + ino[n] - ino[n+1];
  1017. X            ino[ndx+1] = copyto;
  1018. X            } else copyto = ino[n+1];
  1019. X            ndx += 2;
  1020. X        } else {
  1021. X            /* Switch page */
  1022. X            val.data = op + ino[n+1];
  1023. X            val.size = ino[n] - ino[n+1];
  1024. X            putpair( np, &key, &val);
  1025. X            moved +=2;
  1026. X        }
  1027. X
  1028. X        off = ino[n+1];
  1029. X    }
  1030. X
  1031. X    /* Now clean up the page */
  1032. X    ino[0] -= moved;
  1033. X    FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3);
  1034. X    OFFSET(ino) = copyto;
  1035. X
  1036. X#ifdef DEBUG3
  1037. X    fprintf(stderr, "split %d/%d\n", 
  1038. X           ((u_short *) np)[0] / 2,
  1039. X           ((u_short *) op)[0] / 2);
  1040. X#endif
  1041. X    return(0);
  1042. X}
  1043. X/*
  1044. X    0 ==> success
  1045. X    -1 ==> failure
  1046. X
  1047. X    Called when we encounter an overflow page during split handling.
  1048. X    this is special cased since we have to begin checking whether
  1049. X    the key/data pairs fit on their respective pages and because
  1050. X    we may need overflow pages for both the old and new pages
  1051. X*/
  1052. Xstatic int
  1053. Xugly_split( obucket, old_bufp, new_bufp, copyto, moved )
  1054. Xint    obucket;    /* Same as split_page */
  1055. XBUFHEAD    *old_bufp;        
  1056. XBUFHEAD    *new_bufp;
  1057. Xu_short    copyto;        /* First byte on page which contains key/data values */
  1058. Xint    moved;        /* number of pairs moved to new page */
  1059. X{
  1060. X    register BUFHEAD *bufp = old_bufp;        /* Buffer header for ino */
  1061. X    register u_short    *ino = (u_short *)old_bufp->page;    
  1062. X                        /* Page keys come off of */
  1063. X    register u_short    *np = (u_short *)new_bufp->page;    /* New page */
  1064. X    register u_short    *op = (u_short *)old_bufp->page;    
  1065. X                        /* Page keys go on to if they
  1066. X                           aren't moving */
  1067. X
  1068. X    char    *cino;                /* Character value of ino */
  1069. X    BUFHEAD    *last_bfp = NULL;        /* Last buffer header OVFL which
  1070. X                           needs to be freed */
  1071. X    u_short    ov_addr, last_addr = 0;
  1072. X    u_short    n;
  1073. X    u_short    off;
  1074. X
  1075. X    DBT    key, val;
  1076. X    SPLIT_RETURN    ret;
  1077. X
  1078. X    n = ino[0]-1;
  1079. X    while ( n < ino[0] ) {
  1080. X    if ( ino[n+1] == OVFLPAGE ) {
  1081. X        ov_addr = ino[n];
  1082. X        /* 
  1083. X        Fix up the old page -- the extra 2 are the fields which
  1084. X        contained the overflow information 
  1085. X        */
  1086. X        ino[0] -= (moved + 2);
  1087. X        FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3);
  1088. X        OFFSET(ino) = copyto;
  1089. X
  1090. X        bufp = get_buf ( ov_addr, bufp, 0 );
  1091. X        if ( !bufp ) return(-1);
  1092. X
  1093. X        ino = (u_short *)bufp->page;
  1094. X        n = 1;
  1095. X        off = copyto = hashp->BSIZE;
  1096. X        moved = 0;
  1097. X
  1098. X        if ( last_bfp ) {
  1099. X        free_ovflpage( last_bfp);
  1100. X        }
  1101. X        last_bfp = bufp;
  1102. X    } 
  1103. X
  1104. X    if ( (ino[2] < REAL_KEY) && (ino[2] != OVFLPAGE) ) {
  1105. X        if (big_split (old_bufp, new_bufp, bufp, ov_addr, obucket, &ret)) {
  1106. X        return(-1);
  1107. X        }
  1108. X        old_bufp = ret.oldp;
  1109. X        if ( !old_bufp ) return(-1);
  1110. X        op = (u_short *)old_bufp->page;
  1111. X        new_bufp = ret.newp;
  1112. X        if ( !new_bufp ) return(-1);
  1113. X        np = (u_short *)new_bufp->page;
  1114. X        bufp = ret.nextp;
  1115. X        if ( !bufp ) return(0);
  1116. X        cino = (char *)bufp->page;
  1117. X        ino = (u_short *)cino;
  1118. X        last_bfp = ret.nextp;
  1119. X    }
  1120. X    
  1121. X
  1122. X    for ( n = 1; (n < ino[0]) && (ino[n+1] >= REAL_KEY); n += 2 ) {
  1123. X        cino = (char *)ino;
  1124. X        key.data = cino + ino[n]; 
  1125. X        key.size = off - ino[n];
  1126. X        val.data = cino + ino[n+1];
  1127. X        val.size = ino[n] - ino[n+1];
  1128. X        off = ino[n+1];
  1129. X
  1130. X        if ( call_hash ( key.data, key.size ) == obucket ) {
  1131. X        /* Keep on old page */
  1132. X        if (PAIRFITS(op,(&key),(&val))) putpair((char *)op, &key, &val);
  1133. X        else {
  1134. X            old_bufp = add_ovflpage ( old_bufp );
  1135. X            if ( !old_bufp ) return(-1);
  1136. X            op = (u_short *)old_bufp->page;
  1137. X            putpair ((char *)op, &key, &val);
  1138. X        }
  1139. X        old_bufp->flags |= BUF_MOD;
  1140. X        } else {
  1141. X        /* Move to new page */
  1142. X        if (PAIRFITS(np,(&key),(&val))) putpair((char *)np, &key, &val);
  1143. X        else {
  1144. X            new_bufp = add_ovflpage ( new_bufp );
  1145. X            if ( !new_bufp )return(-1);
  1146. X            np = (u_short *)new_bufp->page;
  1147. X            putpair ((char *)np, &key, &val);
  1148. X        } 
  1149. X        new_bufp->flags |= BUF_MOD;
  1150. X        }
  1151. X    }
  1152. X    }
  1153. X    if ( last_bfp ) {
  1154. X    free_ovflpage(last_bfp);
  1155. X    }
  1156. X
  1157. X    return (0);
  1158. X}
  1159. X/*
  1160. X    Add the given pair to the page
  1161. X    1 ==> failure
  1162. X    0 ==> OK
  1163. X*/
  1164. Xextern int
  1165. Xaddel(bufp, key, val)
  1166. XBUFHEAD    *bufp;
  1167. XDBT    *key;
  1168. XDBT    *val;
  1169. X{
  1170. X    register u_short *bp = (u_short *)bufp->page;
  1171. X    register u_short *sop;
  1172. X    int    do_expand;
  1173. X
  1174. X    do_expand = 0;
  1175. X    while ( bp[0] &&  (bp[bp[0]] < REAL_KEY) ) {
  1176. X    /* Exception case */
  1177. X    if ( bp[2] < REAL_KEY ) {
  1178. X        /* This is a big-keydata pair */
  1179. X        bufp = add_ovflpage(bufp);
  1180. X        if ( !bufp ) {
  1181. X        return(-1);
  1182. X        }
  1183. X        bp = (u_short *)bufp->page;
  1184. X    } else {
  1185. X        /* Try to squeeze key on this page */
  1186. X        if ( FREESPACE(bp) > PAIRSIZE(key,val) ) {
  1187. X        squeeze_key ( bp, key, val );
  1188. X        return(0);
  1189. X        } else {
  1190. X        bufp = get_buf ( bp[bp[0]-1], bufp, 0 );
  1191. X        if (!bufp) {
  1192. X            return(-1);
  1193. X        }
  1194. X        bp = (u_short *)bufp->page;
  1195. X        }
  1196. X    }
  1197. X    }
  1198. X
  1199. X    if ( PAIRFITS(bp,key,val) ) putpair (bufp->page, key, val);
  1200. X    else {
  1201. X    do_expand = 1;
  1202. X    bufp = add_ovflpage ( bufp );
  1203. X    if (!bufp)return(-1);
  1204. X    sop = (u_short *) bufp->page;
  1205. X
  1206. X    if ( PAIRFITS(sop, key, val) ) putpair ( (char *)sop, key, val );
  1207. X    else if ( big_insert ( bufp, key, val ) ) {
  1208. X        return(-1);
  1209. X    }
  1210. X    }
  1211. X    bufp->flags |= BUF_MOD;
  1212. X    /* 
  1213. X    If the average number of keys per bucket exceeds the fill factor,
  1214. X    expand the table
  1215. X    */
  1216. X    hashp->NKEYS++;
  1217. X    if (do_expand || 
  1218. X    (hashp->NKEYS / (hashp->MAX_BUCKET+1) > hashp->FFACTOR) ) {
  1219. X     return(expand_table());
  1220. X    }
  1221. X    return(0);
  1222. X}
  1223. X
  1224. X/*
  1225. X    returns a pointer, NULL on error
  1226. X*/
  1227. Xextern BUFHEAD *
  1228. Xadd_ovflpage ( bufp )
  1229. XBUFHEAD    *bufp;
  1230. X{
  1231. X    register    u_short    *sp = (u_short *)bufp->page;
  1232. X
  1233. X    u_short    ovfl_num;
  1234. X    u_short    ndx, newoff;
  1235. X    char    *op;
  1236. X    DBT    okey, oval;
  1237. X#ifdef DEBUG1
  1238. X    int    tmp1, tmp2;
  1239. X#endif
  1240. X
  1241. X    bufp->flags |= BUF_MOD;
  1242. X    ovfl_num = overflow_page ();
  1243. X#ifdef DEBUG1
  1244. X    tmp1 = bufp->addr;
  1245. X    tmp2 = bufp->ovfl?bufp->ovfl->addr:0;
  1246. X#endif
  1247. X    if (!ovfl_num || !(bufp->ovfl = get_buf ( ovfl_num, bufp, 1 ))) {
  1248. X    return(NULL);
  1249. X    }
  1250. X    bufp->ovfl->flags |= BUF_MOD;
  1251. X#ifdef DEBUG1
  1252. X    fprintf ( stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n", tmp1, tmp2, 
  1253. X        bufp->ovfl->addr );
  1254. X#endif
  1255. X    ndx = sp[0];
  1256. X    /* 
  1257. X    Since a pair is allocated on a page only if there's room
  1258. X    to add an overflow page, we know that the OVFL information
  1259. X    will fit on the page
  1260. X    */
  1261. X    sp[ndx+4] = OFFSET(sp);
  1262. X    sp[ndx+3] = FREESPACE(sp) - OVFLSIZE;
  1263. X    sp[ndx+1] = ovfl_num;
  1264. X    sp[ndx+2] = OVFLPAGE;
  1265. X    sp[0] = ndx+2;
  1266. X#ifdef HASH_STATISTICS
  1267. X        hash_overflows++;
  1268. X#endif
  1269. X    return(bufp->ovfl);
  1270. X}
  1271. X
  1272. X/*
  1273. X    0 indicates SUCCESS
  1274. X    -1 indicates FAILURE
  1275. X*/
  1276. Xextern    int
  1277. Xget_page ( p, bucket, is_bucket, is_disk, is_bitmap )
  1278. Xchar    *p;
  1279. Xint    bucket;
  1280. Xint    is_bucket;
  1281. Xint    is_disk;
  1282. Xint    is_bitmap;
  1283. X{
  1284. X    register int size;
  1285. X    register int fd;
  1286. X    register int page;
  1287. X    u_short    *bp;
  1288. X    int        rsize;
  1289. X
  1290. X    fd = hashp->fp;
  1291. X    size = hashp->BSIZE;
  1292. X
  1293. X    if ( !fd || (hashp->new_file && !is_disk) ) {
  1294. X    PAGE_INIT(p);
  1295. X    return(0);
  1296. X    }
  1297. X
  1298. X    if ( is_bucket) page = BUCKET_TO_PAGE (bucket);
  1299. X    else page = OADDR_TO_PAGE (bucket);
  1300. X    if ((lseek ( fd, page << hashp->BSHIFT, L_SET ) == -1) || 
  1301. X    ((rsize = read ( fd, p, size )) == -1 )) {
  1302. X    return(-1);
  1303. X    } 
  1304. X    if ( rsize != size ) {
  1305. X    errno = EFTYPE;        
  1306. X    return(-1);
  1307. X    }
  1308. X    bp = (u_short *)p;
  1309. X    if (!bp[0]) {
  1310. X    PAGE_INIT(p);
  1311. X    } else if ( hashp->LORDER != BYTE_ORDER ) {
  1312. X    register int i;
  1313. X    register int max;
  1314. X
  1315. X    if ( is_bitmap ) {
  1316. X        max = hashp->BSIZE >> 2;    /* divide by 4 */
  1317. X        for ( i=0; i < max; i++ ) {
  1318. X        BLSWAP(((long *)p)[i]);
  1319. X        }
  1320. X    } else {
  1321. X        BSSWAP(bp[0]);
  1322. X        max = bp[0] + 2;
  1323. X        for ( i=1; i <= max; i++ ) {
  1324. X        BSSWAP(bp[i]);
  1325. X        }
  1326. X    }
  1327. X    }
  1328. X    return (0);
  1329. X}
  1330. X
  1331. X/* 
  1332. X    Write page p to disk
  1333. X    -1==>failure
  1334. X    0==> OK
  1335. X*/
  1336. Xextern int
  1337. Xput_page ( p, bucket, is_bucket, is_bitmap )
  1338. Xchar    *p;
  1339. Xint    bucket;
  1340. Xint    is_bucket;
  1341. Xint    is_bitmap;
  1342. X{
  1343. X    register int size;
  1344. X    register int fd;
  1345. X    register int page;
  1346. X    int    wsize;
  1347. X
  1348. X    size = hashp->BSIZE;
  1349. X    if ( !hashp->fp && open_temp() ) return (1);
  1350. X    fd = hashp->fp;
  1351. X
  1352. X    if ( hashp->LORDER != BYTE_ORDER ) {
  1353. X    register int i;
  1354. X    register int max;
  1355. X
  1356. X    if ( is_bitmap ) {
  1357. X        max = hashp->BSIZE >> 2;    /* divide by 4 */
  1358. X        for ( i=0; i < max; i++ ) {
  1359. X        BLSWAP(((long *)p)[i]);
  1360. X        }
  1361. X    } else {
  1362. X        max = ((u_short *)p)[0] + 2;
  1363. X        for ( i=0; i <= max; i++ ) {
  1364. X        BSSWAP(((u_short *)p)[i]);
  1365. X        }
  1366. X    }
  1367. X    }
  1368. X    if (is_bucket ) page = BUCKET_TO_PAGE (bucket);
  1369. X    else page = OADDR_TO_PAGE ( bucket );
  1370. X    if ((lseek ( fd, page << hashp->BSHIFT, L_SET ) == -1) || 
  1371. X    ((wsize = write ( fd, p, size )) == -1 )) {
  1372. X    /* Errno is set */
  1373. X    return(-1);
  1374. X    }
  1375. X    if ( wsize != size ) {
  1376. X    errno = EFTYPE;    
  1377. X    return(-1);
  1378. X    }
  1379. X    return(0);
  1380. X}
  1381. X#define BYTE_MASK    ((1 << INT_BYTE_SHIFT) -1)
  1382. X/*
  1383. X    Initialize a new bitmap page.  Bitmap pages are left in memory
  1384. X    once they are read in.
  1385. X*/
  1386. Xextern u_long *
  1387. Xinit_bitmap(pnum, nbits, ndx)
  1388. Xu_short    pnum;
  1389. Xint    nbits;
  1390. Xint    ndx;
  1391. X{
  1392. X    u_long    *ip;
  1393. X    int        clearints;
  1394. X    int        clearbytes;
  1395. X
  1396. X    if ( !(ip = (u_long *)malloc (hashp->BSIZE)) ) return (NULL);
  1397. X    clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
  1398. X    clearbytes = clearints << INT_TO_BYTE;
  1399. X    memset ((char *)ip, 0, clearbytes );
  1400. X    memset ( ((char *) ip) + clearbytes, 0xFF, 
  1401. X        hashp->BSIZE-clearbytes );
  1402. X    ip[clearints-1] = ALL_SET << (nbits & BYTE_MASK);
  1403. X    SETBIT(ip, 0);
  1404. X    hashp->BITMAPS[ndx] = pnum;
  1405. X    hashp->mapp[ndx] = ip;
  1406. X    return(ip);
  1407. X}
  1408. Xstatic int
  1409. Xfirst_free ( map )
  1410. Xu_long map;
  1411. X{
  1412. X    register u_long      mask;
  1413. X    register u_long      i;
  1414. X
  1415. X    mask = 0x1;
  1416. X    for ( i=0; i < BITS_PER_MAP; i++ ) {
  1417. X    if ( !(mask & map) ) return(i);
  1418. X    mask = mask << 1;
  1419. X    }
  1420. X    return ( i );
  1421. X}
  1422. X
  1423. Xstatic u_short
  1424. Xoverflow_page ( )
  1425. X{
  1426. X    register    int max_free;
  1427. X    register    int splitnum;
  1428. X    register    u_long *freep;
  1429. X    register    int offset;
  1430. X    u_short    addr;
  1431. X    int        in_use_bits;
  1432. X    int        free_page, free_bit;
  1433. X    int        i, j, bit;
  1434. X#ifdef DEBUG2
  1435. X    int    tmp1, tmp2;
  1436. X#endif
  1437. X
  1438. X    splitnum = log2(hashp->MAX_BUCKET);
  1439. X    max_free = hashp->SPARES[splitnum];
  1440. X
  1441. X    free_page = (max_free-1) >> (hashp->BSHIFT + BYTE_SHIFT);
  1442. X    free_bit  = (max_free-1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
  1443. X
  1444. X    /* Look through all the free maps to find the first free block */
  1445. X    for ( i = 0; i <= free_page; i++ ) {
  1446. X    if (!(freep = (u_long *)hashp->mapp[i]) ) return(NULL);
  1447. X    if ( i == free_page ) in_use_bits = free_bit;
  1448. X    else in_use_bits = (hashp->BSIZE << BYTE_SHIFT) -1;
  1449. X
  1450. X    for (j = 0, bit = 0; bit <= in_use_bits; j++, bit += BITS_PER_MAP ) {
  1451. X         if ( freep[j] != ALL_SET ) goto found;
  1452. X    }
  1453. X    }
  1454. X    /* No Free Page Found */
  1455. X    hashp->SPARES[splitnum]++;
  1456. X    offset = hashp->SPARES[splitnum] - 
  1457. X         (splitnum ? hashp->SPARES[splitnum-1] : 0);
  1458. X
  1459. X    /* Check if we need to allocate a new bitmap page */
  1460. X    if ( free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1 ) {
  1461. X    free_page++;
  1462. X    if ( free_page >= NCACHED ) {
  1463. X        fprintf ( stderr, 
  1464. X        "HASH: Out of overflow pages.  Increase page size\n" );
  1465. X        return(NULL);
  1466. X    }
  1467. X    /* 
  1468. X        This is tricky.  The 1 indicates that you want the
  1469. X        new page allocated with 1 clear bit.  Actually, you
  1470. X        are going to allocate 2 pages from this map.  The first
  1471. X        is going to be the map page, the second is the overflow
  1472. X        page we were looking for.  The init_bitmap routine
  1473. X        automatically, sets the first bit of itself to indicate
  1474. X        that the bitmap itself is in use.  We would explicitly
  1475. X        set the second bit, but don't have to if we tell init_bitmap
  1476. X        not to leave it clear in the first place.
  1477. X    */
  1478. X    init_bitmap ( OADDR_OF(splitnum, offset), 1, free_page );
  1479. X    hashp->SPARES[splitnum]++;
  1480. X#ifdef DEBUG2
  1481. X    free_bit = 2;
  1482. X#endif
  1483. X    offset++;
  1484. X    } else {
  1485. X    /* 
  1486. X        Free_bit addresses the last used bit.  Bump it to
  1487. X        address the first available bit.
  1488. X    */    
  1489. X    free_bit++;
  1490. X    SETBIT ( freep, free_bit );
  1491. X    }
  1492. X
  1493. X    /* Calculate address of the new overflow page */
  1494. X    if ( offset > SPLITMASK ) {
  1495. X    fprintf ( stderr, 
  1496. X        "HASH: Out of overflow pages.  Increase page size\n" );
  1497. X    return(NULL);
  1498. X    }
  1499. X    addr = OADDR_OF(splitnum, offset);
  1500. X#ifdef DEBUG2
  1501. X    fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
  1502. X        addr, free_bit, free_page );
  1503. X#endif
  1504. X    return(addr);
  1505. X
  1506. Xfound:
  1507. X    bit = bit + first_free(freep[j]);
  1508. X    SETBIT(freep,bit);
  1509. X#ifdef DEBUG2
  1510. X    tmp1 = bit;
  1511. X    tmp2 = i;
  1512. X#endif
  1513. X    /* 
  1514. X    Bits are addressed starting with 0, but overflow pages are
  1515. X    addressed beginning at 1. Bit is a bit addressnumber, so we 
  1516. X    need to increment it to convert it to a page number.
  1517. X    */
  1518. X    bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
  1519. X
  1520. X    /* Calculate the split number for this page */
  1521. X    for ( i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++ );
  1522. X    offset =(i ? bit - hashp->SPARES[i-1] : bit );
  1523. X    if ( offset >= SPLITMASK ) return(NULL);/* Out of overflow pages */
  1524. X    addr = OADDR_OF(i, offset);
  1525. X#ifdef DEBUG2
  1526. X    fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
  1527. X        addr, tmp1, tmp2 );
  1528. X#endif
  1529. X
  1530. X    /* Allocate and return the overflow page */
  1531. X    return (addr);
  1532. X}
  1533. X
  1534. X/*
  1535. X    Mark this overflow page as free.
  1536. X*/
  1537. Xfree_ovflpage ( obufp )
  1538. XBUFHEAD    *obufp;
  1539. X{
  1540. X    register u_short addr = obufp->addr;
  1541. X    int    free_page, free_bit;
  1542. X    int bit_address;
  1543. X    u_short ndx;
  1544. X    u_long *freep;
  1545. X    int j;
  1546. X
  1547. X#ifdef DEBUG1
  1548. X    fprintf ( stderr, "Freeing %d\n", addr );
  1549. X#endif
  1550. X    ndx = (((u_short)addr) >> SPLITSHIFT);
  1551. X    bit_address = (ndx ? hashp->SPARES[ndx-1] : 0) + (addr & SPLITMASK) - 1;
  1552. X    free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
  1553. X    free_bit  = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
  1554. X
  1555. X    freep = hashp->mapp[free_page];
  1556. X    assert(freep);
  1557. X    CLRBIT(freep, free_bit);
  1558. X#ifdef DEBUG2
  1559. X    fprintf ( stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
  1560. X        obufp->addr, free_bit, free_page );
  1561. X#endif
  1562. X    reclaim_buf ( obufp );
  1563. X    return;
  1564. X}
  1565. X
  1566. X/*
  1567. X0 success
  1568. X-1 failure
  1569. X*/
  1570. Xstatic int
  1571. Xopen_temp()
  1572. X{
  1573. X    char        *namestr = "_hashXXXXXX";
  1574. X
  1575. X    if ((hashp->fp = mkstemp ( namestr )) == -1){
  1576. X    return (-1);
  1577. X    }
  1578. X    unlink(namestr);    /* Make sure file goes away at process exit*/
  1579. X    return(0);
  1580. X}
  1581. X
  1582. X/* 
  1583. X    We have to know that the key will fit, but the
  1584. X    last entry on the page is an overflow pair, so we
  1585. X    need to shift things.
  1586. X*/
  1587. Xstatic void
  1588. Xsqueeze_key ( sp, key, val )
  1589. Xu_short    *sp;
  1590. XDBT    *key;
  1591. XDBT    *val;
  1592. X{
  1593. X    register    char    *p = (char *)sp;
  1594. X    u_short    free_space, off;
  1595. X    u_short    pageno, n;
  1596. X
  1597. X    n = sp[0];
  1598. X    free_space = FREESPACE(sp);
  1599. X    off = OFFSET(sp);
  1600. X
  1601. X    pageno = sp[n-1];
  1602. X    off -= key->size;
  1603. X    sp[n-1] = off;
  1604. X    bcopy ( key->data, p + off, key->size );
  1605. X    off -= val->size;
  1606. X    sp[n] = off;
  1607. X    bcopy ( val->data, p + off, val->size );
  1608. X    sp[0] = n+2;
  1609. X    sp[n+1] = pageno;
  1610. X    sp[n+2] = OVFLPAGE;
  1611. X    FREESPACE(sp) = free_space - PAIRSIZE(key,val);
  1612. X    OFFSET(sp) = off;
  1613. X}
  1614. X
  1615. X#ifdef DEBUG4
  1616. Xprint_chain ( addr )
  1617. Xshort    addr;
  1618. X{
  1619. X    BUFHEAD    *bufp;
  1620. X    short    *bp;
  1621. X    short    oaddr;
  1622. X
  1623. X    fprintf ( stderr, "%d ", addr );
  1624. X    bufp = get_buf ( (int)addr, NULL, 0 );
  1625. X    bp = (short *)bufp->page;
  1626. X    while ( bp[0] && 
  1627. X        ((bp[bp[0]] == OVFLPAGE) ||
  1628. X         ((bp[0] > 2) && bp[2] < REAL_KEY))) {
  1629. X        oaddr = bp[bp[0]-1];
  1630. X        fprintf ( stderr, "%d ", (int)oaddr );
  1631. X        bufp = get_buf ( (int)oaddr, bufp, 0 );
  1632. X        bp = (short *)bufp->page;
  1633. X    }
  1634. X    fprintf ( stderr, "\n" );
  1635. X}
  1636. X#endif
  1637. @@@End of lq-text/src/ozmahash/page.c
  1638. echo x - lq-text/src/ozmahash/page.h 1>&2
  1639. sed 's/^X//' >lq-text/src/ozmahash/page.h <<'@@@End of lq-text/src/ozmahash/page.h'
  1640. X/*
  1641. X * Copyright (c) 1989 The Regents of the University of California.
  1642. X * All rights reserved.
  1643. X *
  1644. X * Redistribution and use in source and binary forms are permitted
  1645. X * provided that the above copyright notice and this paragraph are
  1646. X * duplicated in all such forms and that any documentation,
  1647. X * advertising materials, and other materials related to such
  1648. X * distribution and use acknowledge that the software was developed
  1649. X * by the University of California, Berkeley.  The name of the
  1650. X * University may not be used to endorse or promote products derived
  1651. X * from this software without specific prior written permission.
  1652. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1653. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1654. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1655. X *
  1656. X *    %W% (Berkeley) %G%
  1657. X */
  1658. X/*
  1659. X    RCS INFO
  1660. X    $header$
  1661. X
  1662. X    Definitions for hashing page file format.
  1663. X*/
  1664. Xextern    HTAB    *hashp;
  1665. X/*
  1666. X * routines dealing with a data page
  1667. X *
  1668. X * page format:
  1669. X *    +------------------------------+
  1670. X * p    | n | keyoff | datoff | keyoff |
  1671. X *     +------------+--------+--------+
  1672. X *    | datoff | free  |  ptr  | --> |
  1673. X *    +--------+---------------------+
  1674. X *    |     F R E E A R E A       |
  1675. X *    +--------------+---------------+
  1676. X *    |  <---- - - - | data          |
  1677. X *    +--------+-----+----+----------+
  1678. X *    |  key   | data     | key      |
  1679. X *    +--------+----------+----------+
  1680. X *
  1681. X * Pointer to the free space is always:  p[p[0] + 2]
  1682. X * Amount of free space on the page is:  p[p[0] + 1]
  1683. X */
  1684. X
  1685. X/*
  1686. X    How many bytes required for this pair?
  1687. X    2 shorts in the table at the top of the page +
  1688. X    room for the key and room for the data
  1689. X
  1690. X    We prohibit entering a pair on a page unless there is also
  1691. X    room to append an overflow page. The reason for this it that
  1692. X    you can get in a situation where a single key/data pair fits
  1693. X    on a page, but you can't append an overflow page and later
  1694. X    you'd have to split the key/data and handle like a big pair.
  1695. X    You might as well do this up front.
  1696. X
  1697. X*/
  1698. X#define    PAIRSIZE(K,D)    (2*sizeof(u_short) + K->size + D->size)
  1699. X#define BIGOVERHEAD    (4*sizeof(u_short))
  1700. X#define KEYSIZE(K)    (4*sizeof(u_short) + K->size);
  1701. X#define OVFLSIZE    (2*sizeof(u_short))
  1702. X#define FREESPACE(P)    (P[P[0]+1])
  1703. X#define    OFFSET(P)    (P[P[0]+2])
  1704. X#define PAIRFITS(P,K,D)    ((P[1] >= REAL_KEY) && \
  1705. X             (PAIRSIZE(K,D) + OVFLSIZE) <= FREESPACE(P))
  1706. X#define PAGE_META(N)    ((N+3) * sizeof(u_short))
  1707. X
  1708. X#define    MIN(A,B)    (A<=B?A:B)
  1709. X
  1710. Xtypedef struct {
  1711. X    BUFHEAD    *newp;
  1712. X    BUFHEAD    *oldp;
  1713. X    BUFHEAD    *nextp;
  1714. X    u_short    next_addr;
  1715. X} SPLIT_RETURN;
  1716. X
  1717. @@@End of lq-text/src/ozmahash/page.h
  1718. echo x - lq-text/src/ozmahash/search.h 1>&2
  1719. sed 's/^X//' >lq-text/src/ozmahash/search.h <<'@@@End of lq-text/src/ozmahash/search.h'
  1720. X/*-
  1721. X * Copyright (c) 1990 The Regents of the University of California.
  1722. X * All rights reserved.
  1723. X *
  1724. X * This code is derived from software contributed to Berkeley by
  1725. X * Margo Seltzer.
  1726. X *
  1727. X * %sccs.include.redist.c%
  1728. X *
  1729. X *    %W% (Berkeley) %G%
  1730. X */
  1731. X
  1732. X/* Backward Compatibility to hsearch interface */
  1733. Xtypedef struct entry { 
  1734. X    char    *key; 
  1735. X    char    *data; 
  1736. X} ENTRY;
  1737. X
  1738. Xtypedef enum { FIND, ENTER } ACTION;
  1739. @@@End of lq-text/src/ozmahash/search.h
  1740. if ! test -d lq-text/src/sdbm
  1741. then
  1742.     cd lq-text/src
  1743.     sh UseHash
  1744. fi
  1745. echo End of the last part
  1746. exit 0
  1747. -- 
  1748. Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337
  1749.