1495ee684SToomas Soome /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 1990, 1993, 1994
37c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
67c478bd9Sstevel@tonic-gate  * Margo Seltzer.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
97c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
107c478bd9Sstevel@tonic-gate  * are met:
117c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
127c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
137c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
147c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
157c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
167c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
177c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
187c478bd9Sstevel@tonic-gate  *	This product includes software developed by the University of
197c478bd9Sstevel@tonic-gate  *	California, Berkeley and its contributors.
207c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
217c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
227c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
237c478bd9Sstevel@tonic-gate  *
247c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
257c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
267c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
277c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
287c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
297c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
307c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
317c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
327c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
337c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
347c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #undef _TS_ERRNO_
387c478bd9Sstevel@tonic-gate #include <sys/param.h>
397c478bd9Sstevel@tonic-gate #include <sys/stat.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate #include <fcntl.h>
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <string.h>
467c478bd9Sstevel@tonic-gate #include <unistd.h>
477c478bd9Sstevel@tonic-gate #include <libintl.h>
4856a424ccSmp #ifdef DEBUG
497c478bd9Sstevel@tonic-gate #include <assert.h>
507c478bd9Sstevel@tonic-gate #endif
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include "db-int.h"
537c478bd9Sstevel@tonic-gate #include "hash.h"
547c478bd9Sstevel@tonic-gate #include "page.h"
557c478bd9Sstevel@tonic-gate #include "extern.h"
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static int32_t flush_meta __P((HTAB *));
5856a424ccSmp static int32_t hash_access __P((HTAB *, ACTION, const DBT *, DBT *));
597c478bd9Sstevel@tonic-gate static int32_t hash_close __P((DB *));
607c478bd9Sstevel@tonic-gate static int32_t hash_delete __P((const DB *, const DBT *, u_int32_t));
617c478bd9Sstevel@tonic-gate static int32_t hash_fd __P((const DB *));
627c478bd9Sstevel@tonic-gate static int32_t hash_get __P((const DB *, const DBT *, DBT *, u_int32_t));
637c478bd9Sstevel@tonic-gate static int32_t hash_put __P((const DB *, DBT *, const DBT *, u_int32_t));
647c478bd9Sstevel@tonic-gate static int32_t hash_seq __P((const DB *, DBT *, DBT *, u_int32_t));
657c478bd9Sstevel@tonic-gate static int32_t hash_sync __P((const DB *, u_int32_t));
667c478bd9Sstevel@tonic-gate static int32_t hdestroy __P((HTAB *));
677c478bd9Sstevel@tonic-gate static int32_t cursor_get __P((const DB *, CURSOR *, DBT *, DBT *, \
687c478bd9Sstevel@tonic-gate 	u_int32_t));
697c478bd9Sstevel@tonic-gate static int32_t cursor_delete __P((const DB *, CURSOR *, u_int32_t));
7056a424ccSmp static HTAB *init_hash __P((HTAB *, const char *, const HASHINFO *));
717c478bd9Sstevel@tonic-gate static int32_t init_htab __P((HTAB *, int32_t));
727c478bd9Sstevel@tonic-gate #if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
737c478bd9Sstevel@tonic-gate static void swap_header __P((HTAB *));
747c478bd9Sstevel@tonic-gate static void swap_header_copy __P((HASHHDR *, HASHHDR *));
757c478bd9Sstevel@tonic-gate #endif
767c478bd9Sstevel@tonic-gate static u_int32_t hget_header __P((HTAB *, u_int32_t));
777c478bd9Sstevel@tonic-gate static void hput_header __P((HTAB *));
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #define RETURN_ERROR(ERR, LOC)	{ save_errno = ERR; goto LOC; }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /* Return values */
827c478bd9Sstevel@tonic-gate #define	SUCCESS	 (0)
837c478bd9Sstevel@tonic-gate #define	ERROR	(-1)
847c478bd9Sstevel@tonic-gate #define	ABNORMAL (1)
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
877c478bd9Sstevel@tonic-gate u_int32_t hash_accesses, hash_collisions, hash_expansions, hash_overflows,
887c478bd9Sstevel@tonic-gate 	hash_bigpages;
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /************************** INTERFACE ROUTINES ***************************/
927c478bd9Sstevel@tonic-gate /* OPEN/CLOSE */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate extern DB *
957c478bd9Sstevel@tonic-gate __kdb2_hash_open(file, flags, mode, info, dflags)
967c478bd9Sstevel@tonic-gate 	const char *file;
977c478bd9Sstevel@tonic-gate 	int32_t flags, mode, dflags;
987c478bd9Sstevel@tonic-gate 	const HASHINFO *info;	/* Special directives for create */
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	struct stat statbuf;
1017c478bd9Sstevel@tonic-gate 	DB *dbp;
1027c478bd9Sstevel@tonic-gate 	DBT mpool_key;
1037c478bd9Sstevel@tonic-gate 	HTAB *hashp;
1047c478bd9Sstevel@tonic-gate 	int32_t bpages, csize, new_table, save_errno, specified_file;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	if ((flags & O_ACCMODE) == O_WRONLY) {
1077c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1087c478bd9Sstevel@tonic-gate 		return (NULL);
1097c478bd9Sstevel@tonic-gate 	}
110159d09a2SMark Phalan 	if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
1117c478bd9Sstevel@tonic-gate 		return (NULL);
1127c478bd9Sstevel@tonic-gate 	hashp->fp = -1;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	/* set this now, before file goes away... */
1157c478bd9Sstevel@tonic-gate 	specified_file = (file != NULL);
1167c478bd9Sstevel@tonic-gate 	if (!file) {
1177c478bd9Sstevel@tonic-gate 		/*
1187c478bd9Sstevel@tonic-gate 		 * If we are root and thus have access to /var/run, then use
1197c478bd9Sstevel@tonic-gate 		 * it, else tempnam(3) will use /var/tmp.
1207c478bd9Sstevel@tonic-gate 		 */
1217c478bd9Sstevel@tonic-gate 		if (!(file = tempnam("/var/run", NULL))) {
1227c478bd9Sstevel@tonic-gate 			/*
1237c478bd9Sstevel@tonic-gate 			 * No memory here is not the only failure
1247c478bd9Sstevel@tonic-gate 			 * possibility, but probably the most likely.
1257c478bd9Sstevel@tonic-gate 			 */
1267c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
1277c478bd9Sstevel@tonic-gate 			free(hashp);
1287c478bd9Sstevel@tonic-gate 			return(NULL);
1297c478bd9Sstevel@tonic-gate 		}
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 		/* store the file name so that we can unlink it later */
13256a424ccSmp 		hashp->fname = file;
13356a424ccSmp #ifdef DEBUG
1347c478bd9Sstevel@tonic-gate 			fprintf(stderr, dgettext(TEXT_DOMAIN,
1357c478bd9Sstevel@tonic-gate 			"Using file name %s.\n"), file);
1367c478bd9Sstevel@tonic-gate #endif
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 	/*
1397c478bd9Sstevel@tonic-gate 	 * Even if user wants write only, we need to be able to read
1407c478bd9Sstevel@tonic-gate 	 * the actual file, so we need to open it read/write. But, the
1417c478bd9Sstevel@tonic-gate 	 * field in the hashp structure needs to be accurate so that
1427c478bd9Sstevel@tonic-gate 	 * we can check accesses.
1437c478bd9Sstevel@tonic-gate 	 */
1447c478bd9Sstevel@tonic-gate 	hashp->flags = flags;
1457c478bd9Sstevel@tonic-gate 	hashp->save_file = specified_file && (hashp->flags & O_RDWR);
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	new_table = 0;
1487c478bd9Sstevel@tonic-gate 	if (!file || (flags & O_TRUNC) ||
1497c478bd9Sstevel@tonic-gate 	    (stat(file, &statbuf) && (errno == ENOENT))) {
1507c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
1517c478bd9Sstevel@tonic-gate 			errno = 0;	/* In case someone looks at errno. */
1527c478bd9Sstevel@tonic-gate 		new_table = 1;
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 	if (file) {
1557c478bd9Sstevel@tonic-gate 		if ((hashp->fp = open(file, flags|O_BINARY, mode)) == -1)
1567c478bd9Sstevel@tonic-gate 			RETURN_ERROR(errno, error0);
1577c478bd9Sstevel@tonic-gate 		(void)fcntl(hashp->fp, F_SETFD, 1);
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	/* Process arguments to set up hash table header. */
1617c478bd9Sstevel@tonic-gate 	if (new_table) {
16256a424ccSmp 		if (!(hashp = init_hash(hashp, file, info)))
1637c478bd9Sstevel@tonic-gate 			RETURN_ERROR(errno, error1);
1647c478bd9Sstevel@tonic-gate 	} else {
1657c478bd9Sstevel@tonic-gate 		/* Table already exists */
1667c478bd9Sstevel@tonic-gate 		if (info && info->hash)
1677c478bd9Sstevel@tonic-gate 			hashp->hash = info->hash;
1687c478bd9Sstevel@tonic-gate 		else
1697c478bd9Sstevel@tonic-gate 			hashp->hash = __default_hash;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		/* copy metadata from page into header */
1727c478bd9Sstevel@tonic-gate 		if (hget_header(hashp,
1737c478bd9Sstevel@tonic-gate 		    (info && info->bsize ? info->bsize : DEF_BUCKET_SIZE)) !=
1747c478bd9Sstevel@tonic-gate 		    sizeof(HASHHDR))
1757c478bd9Sstevel@tonic-gate 			RETURN_ERROR(EFTYPE, error1);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		/* Verify file type, versions and hash function */
1787c478bd9Sstevel@tonic-gate 		if (hashp->hdr.magic != HASHMAGIC)
1797c478bd9Sstevel@tonic-gate 			RETURN_ERROR(EFTYPE, error1);
1807c478bd9Sstevel@tonic-gate #define	OLDHASHVERSION	1
1817c478bd9Sstevel@tonic-gate 		if (hashp->hdr.version != HASHVERSION &&
1827c478bd9Sstevel@tonic-gate 		    hashp->hdr.version != OLDHASHVERSION)
1837c478bd9Sstevel@tonic-gate 			RETURN_ERROR(EFTYPE, error1);
1847c478bd9Sstevel@tonic-gate 		if (hashp->hash(CHARKEY, sizeof(CHARKEY))
1857c478bd9Sstevel@tonic-gate 		    != hashp->hdr.h_charkey)
1867c478bd9Sstevel@tonic-gate 			RETURN_ERROR(EFTYPE, error1);
1877c478bd9Sstevel@tonic-gate 		/*
1887c478bd9Sstevel@tonic-gate 		 * Figure out how many segments we need.  Max_Bucket is the
1897c478bd9Sstevel@tonic-gate 		 * maximum bucket number, so the number of buckets is
1907c478bd9Sstevel@tonic-gate 		 * max_bucket + 1.
1917c478bd9Sstevel@tonic-gate 		 */
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 		/* Read in bitmaps */
1947c478bd9Sstevel@tonic-gate 		bpages = (hashp->hdr.spares[hashp->hdr.ovfl_point] +
1957c478bd9Sstevel@tonic-gate 		    (hashp->hdr.bsize << BYTE_SHIFT) - 1) >>
1967c478bd9Sstevel@tonic-gate 		    (hashp->hdr.bshift + BYTE_SHIFT);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 		hashp->nmaps = bpages;
1997c478bd9Sstevel@tonic-gate 		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/* start up mpool */
2037c478bd9Sstevel@tonic-gate 	mpool_key.data = (u_int8_t *)file;
2047c478bd9Sstevel@tonic-gate 	mpool_key.size = strlen(file);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (info && info->cachesize)
2077c478bd9Sstevel@tonic-gate 		csize = info->cachesize / hashp->hdr.bsize;
2087c478bd9Sstevel@tonic-gate 	else
2097c478bd9Sstevel@tonic-gate 		csize = DEF_CACHESIZE / hashp->hdr.bsize;
2107c478bd9Sstevel@tonic-gate 	hashp->mp = mpool_open(&mpool_key, hashp->fp, hashp->hdr.bsize, csize);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (!hashp->mp)
2137c478bd9Sstevel@tonic-gate 		RETURN_ERROR(errno, error1);
2147c478bd9Sstevel@tonic-gate 	mpool_filter(hashp->mp, __pgin_routine, __pgout_routine, hashp);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * For a new table, set up the bitmaps.
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	if (new_table &&
2207c478bd9Sstevel@tonic-gate 	   init_htab(hashp, info && info->nelem ? info->nelem : 1))
2217c478bd9Sstevel@tonic-gate 		goto error2;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/* initialize the cursor queue */
2247c478bd9Sstevel@tonic-gate 	TAILQ_INIT(&hashp->curs_queue);
2257c478bd9Sstevel@tonic-gate 	hashp->seq_cursor = NULL;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/* get a chunk of memory for our split buffer */
2297c478bd9Sstevel@tonic-gate 	hashp->split_buf = (PAGE16 *)malloc(hashp->hdr.bsize);
2307c478bd9Sstevel@tonic-gate 	if (!hashp->split_buf)
2317c478bd9Sstevel@tonic-gate 		goto error2;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	hashp->new_file = new_table;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if (!(dbp = (DB *)malloc(sizeof(DB))))
2367c478bd9Sstevel@tonic-gate 		goto error2;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	dbp->internal = hashp;
2397c478bd9Sstevel@tonic-gate 	dbp->close = hash_close;
2407c478bd9Sstevel@tonic-gate 	dbp->del = hash_delete;
2417c478bd9Sstevel@tonic-gate 	dbp->fd = hash_fd;
2427c478bd9Sstevel@tonic-gate 	dbp->get = hash_get;
2437c478bd9Sstevel@tonic-gate 	dbp->put = hash_put;
2447c478bd9Sstevel@tonic-gate 	dbp->seq = hash_seq;
2457c478bd9Sstevel@tonic-gate 	dbp->sync = hash_sync;
2467c478bd9Sstevel@tonic-gate 	dbp->type = DB_HASH;
2477c478bd9Sstevel@tonic-gate 
24856a424ccSmp #ifdef DEBUG
2497c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
2507c478bd9Sstevel@tonic-gate 	    "%s\n%s%lx\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
2517c478bd9Sstevel@tonic-gate 	    "init_htab:",
2527c478bd9Sstevel@tonic-gate 	    "TABLE POINTER   ", (void *)hashp,
2537c478bd9Sstevel@tonic-gate 	    "BUCKET SIZE     ", hashp->hdr.bsize,
2547c478bd9Sstevel@tonic-gate 	    "BUCKET SHIFT    ", hashp->hdr.bshift,
2557c478bd9Sstevel@tonic-gate 	    "FILL FACTOR     ", hashp->hdr.ffactor,
2567c478bd9Sstevel@tonic-gate 	    "MAX BUCKET      ", hashp->hdr.max_bucket,
2577c478bd9Sstevel@tonic-gate 	    "OVFL POINT      ", hashp->hdr.ovfl_point,
2587c478bd9Sstevel@tonic-gate 	    "LAST FREED      ", hashp->hdr.last_freed,
2597c478bd9Sstevel@tonic-gate 	    "HIGH MASK       ", hashp->hdr.high_mask,
2607c478bd9Sstevel@tonic-gate 	    "LOW  MASK       ", hashp->hdr.low_mask,
2617c478bd9Sstevel@tonic-gate 	    "NKEYS           ", hashp->hdr.nkeys);
2627c478bd9Sstevel@tonic-gate #endif
2637c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
2647c478bd9Sstevel@tonic-gate 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
2657c478bd9Sstevel@tonic-gate 	hash_bigpages = 0;
2667c478bd9Sstevel@tonic-gate #endif
2677c478bd9Sstevel@tonic-gate 	return (dbp);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate error2:
270159d09a2SMark Phalan 	save_errno = errno;
2717c478bd9Sstevel@tonic-gate 	hdestroy(hashp);
2727c478bd9Sstevel@tonic-gate 	errno = save_errno;
2737c478bd9Sstevel@tonic-gate 	return (NULL);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate error1:
2767c478bd9Sstevel@tonic-gate 	if (hashp != NULL)
2777c478bd9Sstevel@tonic-gate 		(void)close(hashp->fp);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate error0:
2807c478bd9Sstevel@tonic-gate 	if (!specified_file)
28156a424ccSmp 		free((void*)(hashp->fname)); /* SUNW14resync */
2827c478bd9Sstevel@tonic-gate 	free(hashp);
2837c478bd9Sstevel@tonic-gate 	errno = save_errno;
2847c478bd9Sstevel@tonic-gate 	return (NULL);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate static int32_t
hash_close(dbp)2887c478bd9Sstevel@tonic-gate hash_close(dbp)
2897c478bd9Sstevel@tonic-gate 	DB *dbp;
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate 	HTAB *hashp;
2927c478bd9Sstevel@tonic-gate 	int32_t retval;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (!dbp)
2957c478bd9Sstevel@tonic-gate 		return (ERROR);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
2987c478bd9Sstevel@tonic-gate 	retval = hdestroy(hashp);
2997c478bd9Sstevel@tonic-gate 	free(dbp);
3007c478bd9Sstevel@tonic-gate 	return (retval);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate static int32_t
hash_fd(dbp)3047c478bd9Sstevel@tonic-gate hash_fd(dbp)
3057c478bd9Sstevel@tonic-gate 	const DB *dbp;
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	HTAB *hashp;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (!dbp)
3107c478bd9Sstevel@tonic-gate 		return (ERROR);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
3137c478bd9Sstevel@tonic-gate 	if (hashp->fp == -1) {
3147c478bd9Sstevel@tonic-gate 		errno = ENOENT;
3157c478bd9Sstevel@tonic-gate 		return (-1);
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 	return (hashp->fp);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate /************************** LOCAL CREATION ROUTINES **********************/
3217c478bd9Sstevel@tonic-gate static HTAB *
init_hash(hashp,file,info)3227c478bd9Sstevel@tonic-gate init_hash(hashp, file, info)
3237c478bd9Sstevel@tonic-gate 	HTAB *hashp;
3247c478bd9Sstevel@tonic-gate 	const char *file;
32556a424ccSmp 	const HASHINFO *info;
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	struct stat statbuf;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	hashp->hdr.nkeys = 0;
3307c478bd9Sstevel@tonic-gate 	hashp->hdr.lorder = DB_BYTE_ORDER;
3317c478bd9Sstevel@tonic-gate 	hashp->hdr.bsize = DEF_BUCKET_SIZE;
3327c478bd9Sstevel@tonic-gate 	hashp->hdr.bshift = DEF_BUCKET_SHIFT;
3337c478bd9Sstevel@tonic-gate 	hashp->hdr.ffactor = DEF_FFACTOR;
3347c478bd9Sstevel@tonic-gate 	hashp->hash = __default_hash;
3357c478bd9Sstevel@tonic-gate 	memset(hashp->hdr.spares, 0, sizeof(hashp->hdr.spares));
3367c478bd9Sstevel@tonic-gate 	memset(hashp->hdr.bitmaps, 0, sizeof(hashp->hdr.bitmaps));
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	/* Fix bucket size to be optimal for file system */
3397c478bd9Sstevel@tonic-gate 	if (file != NULL) {
3407c478bd9Sstevel@tonic-gate 		if (stat(file, &statbuf))
3417c478bd9Sstevel@tonic-gate 			return (NULL);
3427c478bd9Sstevel@tonic-gate 		hashp->hdr.bsize = statbuf.st_blksize;
3437c478bd9Sstevel@tonic-gate 		hashp->hdr.bshift = __log2(hashp->hdr.bsize);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	if (info) {
3467c478bd9Sstevel@tonic-gate 		if (info->bsize) {
3477c478bd9Sstevel@tonic-gate 			/* Round pagesize up to power of 2 */
3487c478bd9Sstevel@tonic-gate 			hashp->hdr.bshift = __log2(info->bsize);
3497c478bd9Sstevel@tonic-gate 			hashp->hdr.bsize = 1 << hashp->hdr.bshift;
3507c478bd9Sstevel@tonic-gate 			if (hashp->hdr.bsize > MAX_BSIZE) {
3517c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3527c478bd9Sstevel@tonic-gate 				return (NULL);
3537c478bd9Sstevel@tonic-gate 			}
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 		if (info->ffactor)
3567c478bd9Sstevel@tonic-gate 			hashp->hdr.ffactor = info->ffactor;
3577c478bd9Sstevel@tonic-gate 		if (info->hash)
3587c478bd9Sstevel@tonic-gate 			hashp->hash = info->hash;
3597c478bd9Sstevel@tonic-gate 		if (info->lorder) {
3607c478bd9Sstevel@tonic-gate 			if ((info->lorder != DB_BIG_ENDIAN) &&
3617c478bd9Sstevel@tonic-gate 			    (info->lorder != DB_LITTLE_ENDIAN)) {
3627c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3637c478bd9Sstevel@tonic-gate 				return (NULL);
3647c478bd9Sstevel@tonic-gate 			}
3657c478bd9Sstevel@tonic-gate 			hashp->hdr.lorder = info->lorder;
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	return (hashp);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * Returns 0 on No Error
3737c478bd9Sstevel@tonic-gate  */
3747c478bd9Sstevel@tonic-gate static int32_t
init_htab(hashp,nelem)3757c478bd9Sstevel@tonic-gate init_htab(hashp, nelem)
3767c478bd9Sstevel@tonic-gate 	HTAB *hashp;
3777c478bd9Sstevel@tonic-gate 	int32_t nelem;
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	int32_t l2, nbuckets;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	/*
3827c478bd9Sstevel@tonic-gate 	 * Divide number of elements by the fill factor and determine a
3837c478bd9Sstevel@tonic-gate 	 * desired number of buckets.  Allocate space for the next greater
3847c478bd9Sstevel@tonic-gate 	 * power of two number of buckets.
3857c478bd9Sstevel@tonic-gate 	 */
3867c478bd9Sstevel@tonic-gate 	nelem = (nelem - 1) / hashp->hdr.ffactor + 1;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	l2 = __log2(MAX(nelem, 2));
3897c478bd9Sstevel@tonic-gate 	nbuckets = 1 << l2;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	hashp->hdr.spares[l2] = l2 + 1;
3927c478bd9Sstevel@tonic-gate 	hashp->hdr.spares[l2 + 1] = l2 + 1;
3937c478bd9Sstevel@tonic-gate 	hashp->hdr.ovfl_point = l2;
3947c478bd9Sstevel@tonic-gate 	hashp->hdr.last_freed = 2;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	hashp->hdr.max_bucket = hashp->hdr.low_mask = nbuckets - 1;
3977c478bd9Sstevel@tonic-gate 	hashp->hdr.high_mask = (nbuckets << 1) - 1;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * The number of header pages is the size of the header divided by
4017c478bd9Sstevel@tonic-gate 	 * the amount of freespace on header pages (the page size - the
4027c478bd9Sstevel@tonic-gate 	 * size of 1 integer where the length of the header info on that
4037c478bd9Sstevel@tonic-gate 	 * page is stored) plus another page if it didn't divide evenly.
4047c478bd9Sstevel@tonic-gate 	 */
4057c478bd9Sstevel@tonic-gate 	hashp->hdr.hdrpages =
4067c478bd9Sstevel@tonic-gate 	    (sizeof(HASHHDR) / (hashp->hdr.bsize - HEADER_OVERHEAD)) +
4077c478bd9Sstevel@tonic-gate 	    (((sizeof(HASHHDR) % (hashp->hdr.bsize - HEADER_OVERHEAD)) == 0)
4087c478bd9Sstevel@tonic-gate 	    ? 0 : 1);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/* Create pages for these buckets */
4117c478bd9Sstevel@tonic-gate 	/*
4127c478bd9Sstevel@tonic-gate 	for (i = 0; i <= hashp->hdr.max_bucket; i++) {
4137c478bd9Sstevel@tonic-gate 		if (__new_page(hashp, (u_int32_t)i, A_BUCKET) != 0)
4147c478bd9Sstevel@tonic-gate 			return (-1);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	*/
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/* First bitmap page is at: splitpoint l2 page offset 1 */
4197c478bd9Sstevel@tonic-gate 	if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
4207c478bd9Sstevel@tonic-gate 		return (-1);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	return (0);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * Functions to get/put hash header.  We access the file directly.
4277c478bd9Sstevel@tonic-gate  */
4287c478bd9Sstevel@tonic-gate static u_int32_t
hget_header(hashp,page_size)4297c478bd9Sstevel@tonic-gate hget_header(hashp, page_size)
4307c478bd9Sstevel@tonic-gate 	HTAB *hashp;
4317c478bd9Sstevel@tonic-gate 	u_int32_t page_size;
4327c478bd9Sstevel@tonic-gate {
433495ee684SToomas Soome 	u_int32_t num_copied;
4347c478bd9Sstevel@tonic-gate 	u_int8_t *hdr_dest;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	num_copied = 0;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	hdr_dest = (u_int8_t *)&hashp->hdr;
4397c478bd9Sstevel@tonic-gate 
440*55fea89dSDan Cross 	/*
4417c478bd9Sstevel@tonic-gate 	 * XXX
4427c478bd9Sstevel@tonic-gate 	 * This should not be printing to stderr on a "normal" error case.
4437c478bd9Sstevel@tonic-gate 	 */
4447c478bd9Sstevel@tonic-gate 	lseek(hashp->fp, 0, SEEK_SET);
4457c478bd9Sstevel@tonic-gate 	num_copied = read(hashp->fp, hdr_dest, sizeof(HASHHDR));
4467c478bd9Sstevel@tonic-gate 	if (num_copied != sizeof(HASHHDR)) {
4477c64d375Smp 		/* Solaris Kerberos: Make sure to print a newline */
4487c478bd9Sstevel@tonic-gate 		fprintf(stderr, dgettext(TEXT_DOMAIN,
4497c64d375Smp 			"hash: could not retrieve header\n"));
4507c478bd9Sstevel@tonic-gate 		return (0);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate #if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
4537c478bd9Sstevel@tonic-gate 	swap_header(hashp);
4547c478bd9Sstevel@tonic-gate #endif
4557c478bd9Sstevel@tonic-gate 	return (num_copied);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate static void
hput_header(hashp)4597c478bd9Sstevel@tonic-gate hput_header(hashp)
4607c478bd9Sstevel@tonic-gate 	HTAB *hashp;
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	HASHHDR *whdrp;
4637c478bd9Sstevel@tonic-gate #if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
4647c478bd9Sstevel@tonic-gate 	HASHHDR whdr;
4657c478bd9Sstevel@tonic-gate #endif
4667c478bd9Sstevel@tonic-gate 	u_int32_t num_copied, i;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	num_copied = i = 0;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	whdrp = &hashp->hdr;
4717c478bd9Sstevel@tonic-gate #if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
4727c478bd9Sstevel@tonic-gate 	whdrp = &whdr;
4737c478bd9Sstevel@tonic-gate 	swap_header_copy(&hashp->hdr, whdrp);
4747c478bd9Sstevel@tonic-gate #endif
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	lseek(hashp->fp, 0, SEEK_SET);
4777c478bd9Sstevel@tonic-gate 	num_copied = write(hashp->fp, whdrp, sizeof(HASHHDR));
4787c478bd9Sstevel@tonic-gate 	if (num_copied != sizeof(HASHHDR))
4797c64d375Smp 		/* Solaris Kerberos: Make sure to print a newline */
4807c478bd9Sstevel@tonic-gate 		(void)fprintf(stderr, dgettext(TEXT_DOMAIN,
4817c64d375Smp 			"hash: could not write hash header\n"));
4827c478bd9Sstevel@tonic-gate 	return;
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /********************** DESTROY/CLOSE ROUTINES ************************/
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate  * Flushes any changes to the file if necessary and destroys the hashp
4897c478bd9Sstevel@tonic-gate  * structure, freeing all allocated space.
4907c478bd9Sstevel@tonic-gate  */
4917c478bd9Sstevel@tonic-gate static int32_t
hdestroy(hashp)4927c478bd9Sstevel@tonic-gate hdestroy(hashp)
4937c478bd9Sstevel@tonic-gate 	HTAB *hashp;
4947c478bd9Sstevel@tonic-gate {
4957c478bd9Sstevel@tonic-gate 	int32_t save_errno;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	save_errno = 0;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
5007c478bd9Sstevel@tonic-gate 	{ int i;
5017c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr, dgettext(TEXT_DOMAIN,
5027c478bd9Sstevel@tonic-gate 			"hdestroy: accesses %ld collisions %ld\n"),
5037c478bd9Sstevel@tonic-gate 	    hash_accesses, hash_collisions);
5047c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
5057c478bd9Sstevel@tonic-gate 	   dgettext(TEXT_DOMAIN,
5067c478bd9Sstevel@tonic-gate 			 "hdestroy: expansions %ld\n"), hash_expansions);
5077c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
5087c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN,
5097c478bd9Sstevel@tonic-gate 			"hdestroy: overflows %ld\n"), hash_overflows);
5107c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
5117c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN,
5127c478bd9Sstevel@tonic-gate 			"hdestroy: big key/data pages %ld\n"), hash_bigpages);
5137c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
5147c478bd9Sstevel@tonic-gate 	    "keys %ld maxp %d\n", hashp->hdr.nkeys, hashp->hdr.max_bucket);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCACHED; i++)
5177c478bd9Sstevel@tonic-gate 		(void)fprintf(stderr,
5187c478bd9Sstevel@tonic-gate 		    "spares[%d] = %d\n", i, hashp->hdr.spares[i]);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate #endif
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (flush_meta(hashp) && !save_errno)
5237c478bd9Sstevel@tonic-gate 		save_errno = errno;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	/* Free the split page */
5267c478bd9Sstevel@tonic-gate 	if (hashp->split_buf)
5277c478bd9Sstevel@tonic-gate 		free(hashp->split_buf);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/* Free the big key and big data returns */
5307c478bd9Sstevel@tonic-gate 	if (hashp->bigkey_buf)
5317c478bd9Sstevel@tonic-gate 		free(hashp->bigkey_buf);
5327c478bd9Sstevel@tonic-gate 	if (hashp->bigdata_buf)
5337c478bd9Sstevel@tonic-gate 		free(hashp->bigdata_buf);
534*55fea89dSDan Cross 
5357c478bd9Sstevel@tonic-gate 	/* XXX This should really iterate over the cursor queue, but
5367c478bd9Sstevel@tonic-gate 	   it's not clear how to do that, and the only cursor a hash
5377c478bd9Sstevel@tonic-gate 	   table ever creates is the one used by hash_seq().  Passing
5387c478bd9Sstevel@tonic-gate 	   NULL as the first arg is also a kludge, but I know that
5397c478bd9Sstevel@tonic-gate 	   it's never used, so I do it.  The intent is to plug the
5407c478bd9Sstevel@tonic-gate 	   memory leak.  Correctness can come later. */
541*55fea89dSDan Cross 
5427c478bd9Sstevel@tonic-gate 	if (hashp->seq_cursor)
5437c478bd9Sstevel@tonic-gate 		hashp->seq_cursor->delete(NULL, hashp->seq_cursor, 0);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* shut down mpool */
5467c478bd9Sstevel@tonic-gate 	mpool_sync(hashp->mp);
5477c478bd9Sstevel@tonic-gate 	mpool_close(hashp->mp);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if (hashp->fp != -1)
5507c478bd9Sstevel@tonic-gate 		(void)close(hashp->fp);
5517c478bd9Sstevel@tonic-gate 
552*55fea89dSDan Cross 	/*
5537c478bd9Sstevel@tonic-gate 	 * *** This may cause problems if hashp->fname is set in any case
5547c478bd9Sstevel@tonic-gate 	 * other than the case that we are generating a temporary file name.
5557c478bd9Sstevel@tonic-gate 	 * Note that the new version of mpool should support temporary
5567c478bd9Sstevel@tonic-gate 	 * files within mpool itself.
5577c478bd9Sstevel@tonic-gate 	 */
5587c478bd9Sstevel@tonic-gate 	if (hashp->fname && !hashp->save_file) {
55956a424ccSmp #ifdef DEBUG
5607c478bd9Sstevel@tonic-gate 		fprintf(stderr, dgettext(TEXT_DOMAIN,
5617c478bd9Sstevel@tonic-gate 			"Unlinking file %s.\n"), hashp->fname);
5627c478bd9Sstevel@tonic-gate #endif
5637c478bd9Sstevel@tonic-gate 		/* we need to chmod the file to allow it to be deleted... */
5647c478bd9Sstevel@tonic-gate 		chmod(hashp->fname, 0700);
5657c478bd9Sstevel@tonic-gate 		unlink(hashp->fname);
5667c478bd9Sstevel@tonic-gate 		/* destroy the temporary name */
56756a424ccSmp 		free((void *)(hashp->fname)); /* SUNW14resync */
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	free(hashp);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (save_errno) {
5727c478bd9Sstevel@tonic-gate 		errno = save_errno;
5737c478bd9Sstevel@tonic-gate 		return (ERROR);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 	return (SUCCESS);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * Write modified pages to disk
5807c478bd9Sstevel@tonic-gate  *
5817c478bd9Sstevel@tonic-gate  * Returns:
5827c478bd9Sstevel@tonic-gate  *	 0 == OK
5837c478bd9Sstevel@tonic-gate  *	-1 ERROR
5847c478bd9Sstevel@tonic-gate  */
5857c478bd9Sstevel@tonic-gate static int32_t
hash_sync(dbp,flags)5867c478bd9Sstevel@tonic-gate hash_sync(dbp, flags)
5877c478bd9Sstevel@tonic-gate 	const DB *dbp;
5887c478bd9Sstevel@tonic-gate 	u_int32_t flags;
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	HTAB *hashp;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/*
5957c478bd9Sstevel@tonic-gate 	 * XXX
5967c478bd9Sstevel@tonic-gate 	 * Check success/failure conditions.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	return (flush_meta(hashp) || mpool_sync(hashp->mp));
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate  * Returns:
6037c478bd9Sstevel@tonic-gate  *	 0 == OK
6047c478bd9Sstevel@tonic-gate  *	-1 indicates that errno should be set
6057c478bd9Sstevel@tonic-gate  */
6067c478bd9Sstevel@tonic-gate static int32_t
flush_meta(hashp)6077c478bd9Sstevel@tonic-gate flush_meta(hashp)
6087c478bd9Sstevel@tonic-gate 	HTAB *hashp;
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int32_t i;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	if (!hashp->save_file)
6137c478bd9Sstevel@tonic-gate 		return (0);
6147c478bd9Sstevel@tonic-gate 	hashp->hdr.magic = HASHMAGIC;
6157c478bd9Sstevel@tonic-gate 	hashp->hdr.version = HASHVERSION;
6167c478bd9Sstevel@tonic-gate 	hashp->hdr.h_charkey = hashp->hash(CHARKEY, sizeof(CHARKEY));
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	/* write out metadata */
6197c478bd9Sstevel@tonic-gate 	hput_header(hashp);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCACHED; i++)
6227c478bd9Sstevel@tonic-gate 		if (hashp->mapp[i]) {
6237c478bd9Sstevel@tonic-gate 			if (__put_page(hashp,
6247c478bd9Sstevel@tonic-gate 			    (PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
6257c478bd9Sstevel@tonic-gate 				return (-1);
6267c478bd9Sstevel@tonic-gate 			hashp->mapp[i] = NULL;
6277c478bd9Sstevel@tonic-gate 		}
6287c478bd9Sstevel@tonic-gate 	return (0);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate /*******************************SEARCH ROUTINES *****************************/
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate  * All the access routines return
6347c478bd9Sstevel@tonic-gate  *
6357c478bd9Sstevel@tonic-gate  * Returns:
6367c478bd9Sstevel@tonic-gate  *	 0 on SUCCESS
6377c478bd9Sstevel@tonic-gate  *	 1 to indicate an external ERROR (i.e. key not found, etc)
6387c478bd9Sstevel@tonic-gate  *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate /* *** make sure this is true! */
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate static int32_t
hash_get(dbp,key,data,flag)6447c478bd9Sstevel@tonic-gate hash_get(dbp, key, data, flag)
6457c478bd9Sstevel@tonic-gate 	const DB *dbp;
6467c478bd9Sstevel@tonic-gate 	const DBT *key;
6477c478bd9Sstevel@tonic-gate 	DBT *data;
6487c478bd9Sstevel@tonic-gate 	u_int32_t flag;
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate 	HTAB *hashp;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
6537c478bd9Sstevel@tonic-gate 	if (flag) {
6547c478bd9Sstevel@tonic-gate 		hashp->local_errno = errno = EINVAL;
6557c478bd9Sstevel@tonic-gate 		return (ERROR);
6567c478bd9Sstevel@tonic-gate 	}
65756a424ccSmp 	return (hash_access(hashp, HASH_GET, key, data));
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate static int32_t
hash_put(dbp,key,data,flag)6617c478bd9Sstevel@tonic-gate hash_put(dbp, key, data, flag)
6627c478bd9Sstevel@tonic-gate 	const DB *dbp;
6637c478bd9Sstevel@tonic-gate 	DBT *key;
6647c478bd9Sstevel@tonic-gate 	const DBT *data;
6657c478bd9Sstevel@tonic-gate 	u_int32_t flag;
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	HTAB *hashp;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
6707c478bd9Sstevel@tonic-gate 	if (flag && flag != R_NOOVERWRITE) {
6717c478bd9Sstevel@tonic-gate 		hashp->local_errno = errno = EINVAL;
6727c478bd9Sstevel@tonic-gate 		return (ERROR);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
6757c478bd9Sstevel@tonic-gate 		hashp->local_errno = errno = EPERM;
6767c478bd9Sstevel@tonic-gate 		return (ERROR);
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 	return (hash_access(hashp, flag == R_NOOVERWRITE ?
67956a424ccSmp 		HASH_PUTNEW : HASH_PUT, key, (DBT *)data));
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate static int32_t
hash_delete(dbp,key,flag)6837c478bd9Sstevel@tonic-gate hash_delete(dbp, key, flag)
6847c478bd9Sstevel@tonic-gate 	const DB *dbp;
6857c478bd9Sstevel@tonic-gate 	const DBT *key;
6867c478bd9Sstevel@tonic-gate 	u_int32_t flag;		/* Ignored */
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	HTAB *hashp;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
6917c478bd9Sstevel@tonic-gate 	if (flag) {
6927c478bd9Sstevel@tonic-gate 		hashp->local_errno = errno = EINVAL;
6937c478bd9Sstevel@tonic-gate 		return (ERROR);
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
6967c478bd9Sstevel@tonic-gate 		hashp->local_errno = errno = EPERM;
6977c478bd9Sstevel@tonic-gate 		return (ERROR);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
70056a424ccSmp 	return (hash_access(hashp, HASH_DELETE, key, NULL));
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate /*
7047c478bd9Sstevel@tonic-gate  * Assume that hashp has been set in wrapper routine.
7057c478bd9Sstevel@tonic-gate  */
7067c478bd9Sstevel@tonic-gate static int32_t
hash_access(hashp,action,key,val)7077c478bd9Sstevel@tonic-gate hash_access(hashp, action, key, val)
7087c478bd9Sstevel@tonic-gate 	HTAB *hashp;
7097c478bd9Sstevel@tonic-gate 	ACTION action;
71056a424ccSmp 	const DBT *key;
71156a424ccSmp 	DBT *val;
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate 	DBT page_key, page_val;
7147c478bd9Sstevel@tonic-gate 	CURSOR cursor;
7157c478bd9Sstevel@tonic-gate 	ITEM_INFO item_info;
7167c478bd9Sstevel@tonic-gate 	u_int32_t bucket;
7177c478bd9Sstevel@tonic-gate 	u_int32_t num_items;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
7207c478bd9Sstevel@tonic-gate 	hash_accesses++;
7217c478bd9Sstevel@tonic-gate #endif
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	num_items = 0;
7247c478bd9Sstevel@tonic-gate 
725*55fea89dSDan Cross 	/*
7267c478bd9Sstevel@tonic-gate 	 * Set up item_info so that we're looking for space to add an item
7277c478bd9Sstevel@tonic-gate 	 * as we cycle through the pages looking for the key.
7287c478bd9Sstevel@tonic-gate 	 */
7297c478bd9Sstevel@tonic-gate 	if (action == HASH_PUT || action == HASH_PUTNEW) {
7307c478bd9Sstevel@tonic-gate 		if (ISBIG(key->size + val->size, hashp))
7317c478bd9Sstevel@tonic-gate 			item_info.seek_size = PAIR_OVERHEAD;
7327c478bd9Sstevel@tonic-gate 		else
7337c478bd9Sstevel@tonic-gate 			item_info.seek_size = key->size + val->size;
7347c478bd9Sstevel@tonic-gate 	} else
7357c478bd9Sstevel@tonic-gate 		item_info.seek_size = 0;
7367c478bd9Sstevel@tonic-gate 	item_info.seek_found_page = 0;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	bucket = __call_hash(hashp, (int8_t *)key->data, key->size);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	cursor.pagep = NULL;
7417c478bd9Sstevel@tonic-gate 	__get_item_reset(hashp, &cursor);
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	cursor.bucket = bucket;
7447c478bd9Sstevel@tonic-gate 	while (1) {
7457c478bd9Sstevel@tonic-gate 		__get_item_next(hashp, &cursor, &page_key, &page_val, &item_info);
7467c478bd9Sstevel@tonic-gate 		if (item_info.status == ITEM_ERROR)
7477c478bd9Sstevel@tonic-gate 			return (ABNORMAL);
7487c478bd9Sstevel@tonic-gate 		if (item_info.status == ITEM_NO_MORE)
7497c478bd9Sstevel@tonic-gate 			break;
7507c478bd9Sstevel@tonic-gate 		num_items++;
7517c478bd9Sstevel@tonic-gate 		if (item_info.key_off == BIGPAIR) {
7527c478bd9Sstevel@tonic-gate 			/*
7537c478bd9Sstevel@tonic-gate 			 * !!!
7547c478bd9Sstevel@tonic-gate 			 * 0 is a valid index.
7557c478bd9Sstevel@tonic-gate 			 */
7567c478bd9Sstevel@tonic-gate 			if (__find_bigpair(hashp, &cursor, (int8_t *)key->data,
7577c478bd9Sstevel@tonic-gate 			    key->size) > 0)
7587c478bd9Sstevel@tonic-gate 				goto found;
7597c478bd9Sstevel@tonic-gate 		} else if (key->size == page_key.size &&
7607c478bd9Sstevel@tonic-gate 		    !memcmp(key->data, page_key.data, key->size))
7617c478bd9Sstevel@tonic-gate 			goto found;
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
7647c478bd9Sstevel@tonic-gate 	hash_collisions++;
7657c478bd9Sstevel@tonic-gate #endif
7667c478bd9Sstevel@tonic-gate 	__get_item_done(hashp, &cursor);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	/*
7697c478bd9Sstevel@tonic-gate 	 * At this point, item_info will list either the last page in
7707c478bd9Sstevel@tonic-gate 	 * the chain, or the last page in the chain plus a pgno for where
7717c478bd9Sstevel@tonic-gate 	 * to find the first page in the chain with space for the
7727c478bd9Sstevel@tonic-gate 	 * item we wish to add.
7737c478bd9Sstevel@tonic-gate 	 */
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	/* Not found */
7767c478bd9Sstevel@tonic-gate 	switch (action) {
7777c478bd9Sstevel@tonic-gate 	case HASH_PUT:
7787c478bd9Sstevel@tonic-gate 	case HASH_PUTNEW:
7797c478bd9Sstevel@tonic-gate 		if (__addel(hashp, &item_info, key, val, num_items, 0))
7807c478bd9Sstevel@tonic-gate 			return (ERROR);
7817c478bd9Sstevel@tonic-gate 		break;
7827c478bd9Sstevel@tonic-gate 	case HASH_GET:
7837c478bd9Sstevel@tonic-gate 	case HASH_DELETE:
7847c478bd9Sstevel@tonic-gate 	default:
7857c478bd9Sstevel@tonic-gate 		return (ABNORMAL);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (item_info.caused_expand)
7897c478bd9Sstevel@tonic-gate 		__expand_table(hashp);
7907c478bd9Sstevel@tonic-gate 	return (SUCCESS);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate found:	__get_item_done(hashp, &cursor);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	switch (action) {
7957c478bd9Sstevel@tonic-gate 	case HASH_PUTNEW:
7967c478bd9Sstevel@tonic-gate 		/* mpool_put(hashp->mp, pagep, 0); */
7977c478bd9Sstevel@tonic-gate 		return (ABNORMAL);
7987c478bd9Sstevel@tonic-gate 	case HASH_GET:
7997c478bd9Sstevel@tonic-gate 		if (item_info.key_off == BIGPAIR) {
8007c478bd9Sstevel@tonic-gate 			if (__big_return(hashp, &item_info, val, 0))
8017c478bd9Sstevel@tonic-gate 				return (ERROR);
8027c478bd9Sstevel@tonic-gate 		} else {
8037c478bd9Sstevel@tonic-gate 			val->data = page_val.data;
8047c478bd9Sstevel@tonic-gate 			val->size = page_val.size;
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 		/* *** data may not be available! */
8077c478bd9Sstevel@tonic-gate 		break;
8087c478bd9Sstevel@tonic-gate 	case HASH_PUT:
8097c478bd9Sstevel@tonic-gate 		if (__delpair(hashp, &cursor, &item_info) ||
8107c478bd9Sstevel@tonic-gate 		    __addel(hashp, &item_info, key, val, UNKNOWN, 0))
8117c478bd9Sstevel@tonic-gate 			return (ERROR);
8127c478bd9Sstevel@tonic-gate 		__get_item_done(hashp, &cursor);
8137c478bd9Sstevel@tonic-gate 		if (item_info.caused_expand)
8147c478bd9Sstevel@tonic-gate 			__expand_table(hashp);
8157c478bd9Sstevel@tonic-gate 		break;
8167c478bd9Sstevel@tonic-gate 	case HASH_DELETE:
8177c478bd9Sstevel@tonic-gate 		if (__delpair(hashp, &cursor, &item_info))
8187c478bd9Sstevel@tonic-gate 			return (ERROR);
8197c478bd9Sstevel@tonic-gate 		break;
8207c478bd9Sstevel@tonic-gate 	default:
8217c478bd9Sstevel@tonic-gate 		abort();
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate 	return (SUCCESS);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate /* ****************** CURSORS ********************************** */
8277c478bd9Sstevel@tonic-gate CURSOR *
__cursor_creat(dbp)8287c478bd9Sstevel@tonic-gate __cursor_creat(dbp)
8297c478bd9Sstevel@tonic-gate 	const DB *dbp;
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	CURSOR *new_curs;
8327c478bd9Sstevel@tonic-gate 	HTAB *hashp;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	new_curs = (CURSOR *)malloc(sizeof(struct cursor_t));
8357c478bd9Sstevel@tonic-gate 	if (!new_curs)
8367c478bd9Sstevel@tonic-gate 		return NULL;
8377c478bd9Sstevel@tonic-gate 	new_curs->internal =
8387c478bd9Sstevel@tonic-gate 	    (struct item_info *)malloc(sizeof(struct item_info));
8397c478bd9Sstevel@tonic-gate 	if (!new_curs->internal) {
8407c478bd9Sstevel@tonic-gate 		free(new_curs);
8417c478bd9Sstevel@tonic-gate 		return NULL;
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 	new_curs->get = cursor_get;
8447c478bd9Sstevel@tonic-gate 	new_curs->delete = cursor_delete;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	new_curs->bucket = 0;
8477c478bd9Sstevel@tonic-gate 	new_curs->pgno = INVALID_PGNO;
8487c478bd9Sstevel@tonic-gate 	new_curs->ndx = 0;
8497c478bd9Sstevel@tonic-gate 	new_curs->pgndx = 0;
8507c478bd9Sstevel@tonic-gate 	new_curs->pagep = NULL;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/* place onto queue of cursors */
8537c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
8547c478bd9Sstevel@tonic-gate 	TAILQ_INSERT_TAIL(&hashp->curs_queue, new_curs, queue);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	return new_curs;
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate static int32_t
cursor_get(dbp,cursorp,key,val,flags)8607c478bd9Sstevel@tonic-gate cursor_get(dbp, cursorp, key, val, flags)
8617c478bd9Sstevel@tonic-gate 	const DB *dbp;
8627c478bd9Sstevel@tonic-gate 	CURSOR *cursorp;
8637c478bd9Sstevel@tonic-gate 	DBT *key, *val;
8647c478bd9Sstevel@tonic-gate 	u_int32_t flags;
8657c478bd9Sstevel@tonic-gate {
8667c478bd9Sstevel@tonic-gate 	HTAB *hashp;
8677c478bd9Sstevel@tonic-gate 	ITEM_INFO item_info;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	if (flags && flags != R_FIRST && flags != R_NEXT) {
8727c478bd9Sstevel@tonic-gate 		hashp->local_errno = errno = EINVAL;
8737c478bd9Sstevel@tonic-gate 		return (ERROR);
8747c478bd9Sstevel@tonic-gate 	}
8757c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
8767c478bd9Sstevel@tonic-gate 	hash_accesses++;
8777c478bd9Sstevel@tonic-gate #endif
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	item_info.seek_size = 0;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	if (flags == R_FIRST)
8827c478bd9Sstevel@tonic-gate 		__get_item_first(hashp, cursorp, key, val, &item_info);
8837c478bd9Sstevel@tonic-gate 	else
8847c478bd9Sstevel@tonic-gate 		__get_item_next(hashp, cursorp, key, val, &item_info);
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	/*
8877c478bd9Sstevel@tonic-gate 	 * This needs to be changed around.  As is, get_item_next advances
8887c478bd9Sstevel@tonic-gate 	 * the pointers on the page but this function actually advances
889*55fea89dSDan Cross 	 * bucket pointers.  This works, since the only other place we
8907c478bd9Sstevel@tonic-gate 	 * use get_item_next is in hash_access which only deals with one
8917c478bd9Sstevel@tonic-gate 	 * bucket at a time.  However, there is the problem that certain other
8927c478bd9Sstevel@tonic-gate 	 * functions (such as find_bigpair and delpair) depend on the
8937c478bd9Sstevel@tonic-gate 	 * pgndx member of the cursor.  Right now, they are using pngdx - 1
8947c478bd9Sstevel@tonic-gate 	 * since indices refer to the __next__ item that is to be fetched
8957c478bd9Sstevel@tonic-gate 	 * from the page.  This is ugly, as you may have noticed, whoever
8967c478bd9Sstevel@tonic-gate 	 * you are.  The best solution would be to depend on item_infos to
8977c478bd9Sstevel@tonic-gate 	 * deal with _current_ information, and have the cursors only
8987c478bd9Sstevel@tonic-gate 	 * deal with _next_ information.  In that scheme, get_item_next
8997c478bd9Sstevel@tonic-gate 	 * would also advance buckets.  Version 3...
9007c478bd9Sstevel@tonic-gate 	 */
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/*
9047c478bd9Sstevel@tonic-gate 	 * Must always enter this loop to do error handling and
9057c478bd9Sstevel@tonic-gate 	 * check for big key/data pair.
9067c478bd9Sstevel@tonic-gate 	 */
9077c478bd9Sstevel@tonic-gate 	while (1) {
9087c478bd9Sstevel@tonic-gate 		if (item_info.status == ITEM_OK) {
9097c478bd9Sstevel@tonic-gate 			if (item_info.key_off == BIGPAIR &&
9107c478bd9Sstevel@tonic-gate 			    __big_keydata(hashp, cursorp->pagep, key, val,
9117c478bd9Sstevel@tonic-gate 			    item_info.pgndx))
9127c478bd9Sstevel@tonic-gate 				return (ABNORMAL);
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 			break;
9157c478bd9Sstevel@tonic-gate 		} else if (item_info.status != ITEM_NO_MORE)
9167c478bd9Sstevel@tonic-gate 			return (ABNORMAL);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		__put_page(hashp, cursorp->pagep, A_RAW, 0);
9197c478bd9Sstevel@tonic-gate 		cursorp->ndx = cursorp->pgndx = 0;
9207c478bd9Sstevel@tonic-gate 		cursorp->bucket++;
9217c478bd9Sstevel@tonic-gate 		cursorp->pgno = INVALID_PGNO;
9227c478bd9Sstevel@tonic-gate 		cursorp->pagep = NULL;
9237c478bd9Sstevel@tonic-gate 		if (cursorp->bucket > hashp->hdr.max_bucket)
9247c478bd9Sstevel@tonic-gate 			return (ABNORMAL);
9257c478bd9Sstevel@tonic-gate 		__get_item_next(hashp, cursorp, key, val, &item_info);
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	__get_item_done(hashp, cursorp);
9297c478bd9Sstevel@tonic-gate 	return (0);
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate static int32_t
cursor_delete(dbp,cursor,flags)9337c478bd9Sstevel@tonic-gate cursor_delete(dbp, cursor, flags)
9347c478bd9Sstevel@tonic-gate 	const DB *dbp;
9357c478bd9Sstevel@tonic-gate 	CURSOR *cursor;
9367c478bd9Sstevel@tonic-gate 	u_int32_t flags;
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate 	/* XXX this is empirically determined, so it might not be completely
9397c478bd9Sstevel@tonic-gate 	   correct, but it seems to work.  At the very least it fixes
9407c478bd9Sstevel@tonic-gate 	   a memory leak */
941*55fea89dSDan Cross 
9427c478bd9Sstevel@tonic-gate 	free(cursor->internal);
9437c478bd9Sstevel@tonic-gate 	free(cursor);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	return (0);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate static int32_t
hash_seq(dbp,key,val,flag)9497c478bd9Sstevel@tonic-gate hash_seq(dbp, key, val, flag)
9507c478bd9Sstevel@tonic-gate 	const DB *dbp;
9517c478bd9Sstevel@tonic-gate 	DBT *key, *val;
9527c478bd9Sstevel@tonic-gate 	u_int32_t flag;
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	HTAB *hashp;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	/*
9577c478bd9Sstevel@tonic-gate 	 * Seq just uses the default cursor to go sequecing through the
958*55fea89dSDan Cross 	 * database.  Note that the default cursor is the first in the list.
9597c478bd9Sstevel@tonic-gate 	 */
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	hashp = (HTAB *)dbp->internal;
9627c478bd9Sstevel@tonic-gate 	if (!hashp->seq_cursor)
9637c478bd9Sstevel@tonic-gate 		hashp->seq_cursor = __cursor_creat(dbp);
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	return (hashp->seq_cursor->get(dbp, hashp->seq_cursor, key, val, flag));
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate /********************************* UTILITIES ************************/
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate  * Returns:
9727c478bd9Sstevel@tonic-gate  *	 0 ==> OK
9737c478bd9Sstevel@tonic-gate  *	-1 ==> Error
9747c478bd9Sstevel@tonic-gate  */
9757c478bd9Sstevel@tonic-gate int32_t
__expand_table(hashp)9767c478bd9Sstevel@tonic-gate __expand_table(hashp)
9777c478bd9Sstevel@tonic-gate 	HTAB *hashp;
9787c478bd9Sstevel@tonic-gate {
9797c478bd9Sstevel@tonic-gate 	u_int32_t old_bucket, new_bucket;
9807c478bd9Sstevel@tonic-gate 	int32_t spare_ndx;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate #ifdef HASH_STATISTICS
9837c478bd9Sstevel@tonic-gate 	hash_expansions++;
9847c478bd9Sstevel@tonic-gate #endif
9857c478bd9Sstevel@tonic-gate 	new_bucket = ++hashp->hdr.max_bucket;
9867c478bd9Sstevel@tonic-gate 	old_bucket = (hashp->hdr.max_bucket & hashp->hdr.low_mask);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/* Get a page for this new bucket */
9897c478bd9Sstevel@tonic-gate 	if (__new_page(hashp, new_bucket, A_BUCKET) != 0)
9907c478bd9Sstevel@tonic-gate 		return (-1);
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	/*
9937c478bd9Sstevel@tonic-gate 	 * If the split point is increasing (hdr.max_bucket's log base 2
9947c478bd9Sstevel@tonic-gate 	 * increases), we need to copy the current contents of the spare
9957c478bd9Sstevel@tonic-gate 	 * split bucket to the next bucket.
9967c478bd9Sstevel@tonic-gate 	 */
9977c478bd9Sstevel@tonic-gate 	spare_ndx = __log2(hashp->hdr.max_bucket + 1);
9987c478bd9Sstevel@tonic-gate 	if (spare_ndx > hashp->hdr.ovfl_point) {
9997c478bd9Sstevel@tonic-gate 		hashp->hdr.spares[spare_ndx] = hashp->hdr.spares[hashp->hdr.ovfl_point];
10007c478bd9Sstevel@tonic-gate 		hashp->hdr.ovfl_point = spare_ndx;
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 	if (new_bucket > hashp->hdr.high_mask) {
10037c478bd9Sstevel@tonic-gate 		/* Starting a new doubling */
10047c478bd9Sstevel@tonic-gate 		hashp->hdr.low_mask = hashp->hdr.high_mask;
10057c478bd9Sstevel@tonic-gate 		hashp->hdr.high_mask = new_bucket | hashp->hdr.low_mask;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	if (BUCKET_TO_PAGE(new_bucket) > MAX_PAGES(hashp)) {
10087c478bd9Sstevel@tonic-gate 		fprintf(stderr,dgettext(TEXT_DOMAIN,
10097c478bd9Sstevel@tonic-gate 			 "hash: Cannot allocate new bucket.  Pages exhausted.\n"));
10107c478bd9Sstevel@tonic-gate 		return (-1);
10117c478bd9Sstevel@tonic-gate 	}
10127c478bd9Sstevel@tonic-gate 	/* Relocate records to the new bucket */
10137c478bd9Sstevel@tonic-gate 	return (__split_page(hashp, old_bucket, new_bucket));
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate u_int32_t
__call_hash(hashp,k,len)10177c478bd9Sstevel@tonic-gate __call_hash(hashp, k, len)
10187c478bd9Sstevel@tonic-gate 	HTAB *hashp;
10197c478bd9Sstevel@tonic-gate 	int8_t *k;
10207c478bd9Sstevel@tonic-gate 	int32_t len;
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate 	int32_t n, bucket;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	n = hashp->hash(k, len);
10257c478bd9Sstevel@tonic-gate 	bucket = n & hashp->hdr.high_mask;
10267c478bd9Sstevel@tonic-gate 	if (bucket > hashp->hdr.max_bucket)
10277c478bd9Sstevel@tonic-gate 		bucket = bucket & hashp->hdr.low_mask;
10287c478bd9Sstevel@tonic-gate 	return (bucket);
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate #if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
10327c478bd9Sstevel@tonic-gate /*
10337c478bd9Sstevel@tonic-gate  * Hashp->hdr needs to be byteswapped.
10347c478bd9Sstevel@tonic-gate  */
10357c478bd9Sstevel@tonic-gate static void
swap_header_copy(srcp,destp)10367c478bd9Sstevel@tonic-gate swap_header_copy(srcp, destp)
10377c478bd9Sstevel@tonic-gate 	HASHHDR *srcp, *destp;
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	int32_t i;
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->magic, destp->magic);
10427c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->version, destp->version);
10437c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->lorder, destp->lorder);
10447c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->bsize, destp->bsize);
10457c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->bshift, destp->bshift);
10467c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
10477c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->last_freed, destp->last_freed);
10487c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->max_bucket, destp->max_bucket);
10497c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->high_mask, destp->high_mask);
10507c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->low_mask, destp->low_mask);
10517c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->ffactor, destp->ffactor);
10527c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->nkeys, destp->nkeys);
10537c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->hdrpages, destp->hdrpages);
10547c478bd9Sstevel@tonic-gate 	P_32_COPY(srcp->h_charkey, destp->h_charkey);
10557c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCACHED; i++) {
10567c478bd9Sstevel@tonic-gate 		P_32_COPY(srcp->spares[i], destp->spares[i]);
10577c478bd9Sstevel@tonic-gate 		P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
10587c478bd9Sstevel@tonic-gate 	}
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate static void
swap_header(hashp)10627c478bd9Sstevel@tonic-gate swap_header(hashp)
10637c478bd9Sstevel@tonic-gate 	HTAB *hashp;
10647c478bd9Sstevel@tonic-gate {
10657c478bd9Sstevel@tonic-gate 	HASHHDR *hdrp;
10667c478bd9Sstevel@tonic-gate 	int32_t i;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	hdrp = &hashp->hdr;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->magic);
10717c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->version);
10727c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->lorder);
10737c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->bsize);
10747c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->bshift);
10757c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->ovfl_point);
10767c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->last_freed);
10777c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->max_bucket);
10787c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->high_mask);
10797c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->low_mask);
10807c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->ffactor);
10817c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->nkeys);
10827c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->hdrpages);
10837c478bd9Sstevel@tonic-gate 	M_32_SWAP(hdrp->h_charkey);
10847c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCACHED; i++) {
10857c478bd9Sstevel@tonic-gate 		M_32_SWAP(hdrp->spares[i]);
10867c478bd9Sstevel@tonic-gate 		M_16_SWAP(hdrp->bitmaps[i]);
10877c478bd9Sstevel@tonic-gate 	}
10887c478bd9Sstevel@tonic-gate }
10897c478bd9Sstevel@tonic-gate #endif /* DB_BYTE_ORDER == DB_LITTLE_ENDIAN */
1090