xref: /csrg-svn/lib/libc/db/btree/bt_open.c (revision 46570)
145876Sbostic /*-
245876Sbostic  * Copyright (c) 1990 The Regents of the University of California.
345876Sbostic  * All rights reserved.
445876Sbostic  *
545876Sbostic  * This code is derived from software contributed to Berkeley by
645876Sbostic  * Mike Olson.
745876Sbostic  *
845876Sbostic  * %sccs.include.redist.c%
945876Sbostic  */
1045876Sbostic 
1145876Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*46570Sbostic static char sccsid[] = "@(#)bt_open.c	5.6 (Berkeley) 02/23/91";
1345876Sbostic #endif /* LIBC_SCCS and not lint */
1445876Sbostic 
1545876Sbostic /*
1645876Sbostic  *  btree.c -- implementation of btree access method for 4.4BSD.
1745876Sbostic  *
1845876Sbostic  *	The design here is based on that of the btree access method used
1945876Sbostic  *	in the Postgres database system at UC Berkeley.  The implementation
2045876Sbostic  *	is wholly independent of the Postgres code.
2145876Sbostic  *
2245876Sbostic  *	This implementation supports btrees on disk (supply a filename) or
2345876Sbostic  *	in memory (don't).  Public interfaces defined here are:
2445876Sbostic  *
2545876Sbostic  *		btree_open()	-- wrapper; returns a filled DB struct for
2645876Sbostic  *				   a btree.
2745876Sbostic  *
2845876Sbostic  *		bt_open()	-- open a new or existing btree.
2945876Sbostic  *		bt_get()	-- fetch data from a tree by key.
3045876Sbostic  *		bt_seq()	-- do a sequential scan on a tree.
3145876Sbostic  *		bt_put()	-- add data to a tree by key.
3245876Sbostic  *		bt_delete()	-- remove data from a tree by key.
3345876Sbostic  *		bt_close()	-- close a btree.
3445876Sbostic  *		bt_sync()	-- force btree pages to disk (disk trees only).
3545876Sbostic  */
3645876Sbostic 
3745876Sbostic #include <sys/param.h>
3845876Sbostic #include <sys/stat.h>
3946561Sbostic #include <signal.h>
4046561Sbostic #include <errno.h>
4146561Sbostic #include <fcntl.h>
4245876Sbostic #include <db.h>
4346561Sbostic #include <stdlib.h>
4446561Sbostic #include <string.h>
4546561Sbostic #include <unistd.h>
4646127Smao #include "btree.h"
4745876Sbostic 
4846127Smao BTREEINFO _DefaultBTInfo = {
4945876Sbostic 	0,	/* flags */
5045876Sbostic 	0,	/* cachesize */
5145876Sbostic 	0,	/* psize */
5245876Sbostic 	strcmp,	/* compare */
5345876Sbostic 	0
5445876Sbostic };
5545876Sbostic 
5645876Sbostic /*
5745876Sbostic  *  BTREE_OPEN -- Wrapper routine to open a btree.
5845876Sbostic  *
5945876Sbostic  *	Creates and fills a DB struct, and calls the routine that actually
6045876Sbostic  *	opens the btree.
6145876Sbostic  *
6245876Sbostic  *	Parameters:
6345876Sbostic  *		f:  filename to open
6445876Sbostic  *		flags:  flag bits passed to open
6545876Sbostic  *		mode:  permission bits, used if O_CREAT specified
6645876Sbostic  *		b:  BTREEINFO pointer
6745876Sbostic  *
6845876Sbostic  *	Returns:
6945876Sbostic  *		Filled-in DBT on success; NULL on failure, with errno
7045876Sbostic  *		set as appropriate.
7145876Sbostic  *
7245876Sbostic  *	Side Effects:
7345876Sbostic  *		Allocates memory for the DB struct.
7445876Sbostic  */
7545876Sbostic 
7645876Sbostic DB *
7745876Sbostic btree_open(f, flags, mode, b)
7846561Sbostic 	const char *f;
7945876Sbostic 	int flags;
8045876Sbostic 	int mode;
8146561Sbostic 	const BTREEINFO *b;
8245876Sbostic {
8345876Sbostic 	DB *db;
8445876Sbostic 	BTREE t;
8545876Sbostic 
8645876Sbostic 	if ((db = (DB *) malloc((unsigned) sizeof(DB))) == (DB *) NULL)
8745876Sbostic 		return ((DB *) NULL);
8845876Sbostic 
8945876Sbostic 	if ((t = bt_open(f, flags, mode, b)) == (BTREE) NULL) {
9045876Sbostic 		(void) free ((char *) db);
9145876Sbostic 		return ((DB *) NULL);
9245876Sbostic 	}
9345876Sbostic 
9445876Sbostic 	db->internal = (char *) t;
9545876Sbostic 	db->close = bt_close;
9646561Sbostic 	db->del = bt_delete;
9745876Sbostic 	db->get = bt_get;
9845876Sbostic 	db->put = bt_put;
9945876Sbostic 	db->seq = bt_seq;
10045876Sbostic 	db->sync = bt_sync;
10145876Sbostic 
10245876Sbostic 	return (db);
10345876Sbostic }
10445876Sbostic 
10545876Sbostic /*
10645876Sbostic  *  BT_OPEN -- Open a btree.
10745876Sbostic  *
10845876Sbostic  *	This routine creates the correct kind (disk or in-memory) of
10945876Sbostic  *	btree and initializes it as required.
11045876Sbostic  *
11145876Sbostic  *	Parameters:
11245876Sbostic  *		f -- name of btree (NULL for in-memory btrees)
11345876Sbostic  *		flags -- flags passed to open()
11445876Sbostic  *		mode -- mode passed to open ()
11545876Sbostic  *		b -- BTREEINFO structure, describing btree
11645876Sbostic  *
11745876Sbostic  *	Returns:
11845876Sbostic  *		(Opaque) pointer to the btree.  On failure, returns NULL
11945876Sbostic  *		with errno set as appropriate.
12045876Sbostic  *
12145876Sbostic  *	Side Effects:
12245876Sbostic  *		Allocates memory, opens files.
12345876Sbostic  */
12445876Sbostic 
12545876Sbostic BTREE
12645876Sbostic bt_open(f, flags, mode, b)
12745876Sbostic 	char *f;
12845876Sbostic 	int flags;
12945876Sbostic 	int mode;
13045876Sbostic 	BTREEINFO *b;
13145876Sbostic {
13245876Sbostic 	BTREE_P t;
13345876Sbostic 	HTABLE ht;
13445876Sbostic 	int nbytes;
13545876Sbostic 	int fd;
13645876Sbostic 	CURSOR *c;
13745876Sbostic 	BTMETA m;
13845876Sbostic 	struct stat buf;
13945876Sbostic 
14045876Sbostic 	/* use the default info if none was provided */
14145876Sbostic 	if (b == (BTREEINFO *) NULL)
14245876Sbostic 		b = &_DefaultBTInfo;
14345876Sbostic 
14445876Sbostic 	if ((t = (BTREE_P) malloc((unsigned) sizeof *t)) == (BTREE_P) NULL)
14545876Sbostic 		return ((BTREE) NULL);
14645876Sbostic 
14745876Sbostic 	if (b->compare)
14845876Sbostic 		t->bt_compare = b->compare;
14945876Sbostic 	else
15045876Sbostic 		t->bt_compare = strcmp;
15145876Sbostic 
15245876Sbostic 	t->bt_fname = f;
15345876Sbostic 	t->bt_curpage = (BTHEADER *) NULL;
15445876Sbostic 	t->bt_free = P_NONE;
15545876Sbostic 	c = &(t->bt_cursor);
15645876Sbostic 	c->c_pgno = P_NONE;
15745876Sbostic 	c->c_index = 0;
15845876Sbostic 	c->c_flags = (u_char) NULL;
15945876Sbostic 	c->c_key = (char *) NULL;
16045876Sbostic 	t->bt_stack = (BTSTACK *) NULL;
16145876Sbostic 	t->bt_flags = 0;
16245876Sbostic 
16345876Sbostic 	/*
16445876Sbostic 	 *  If no file name was supplied, this is an in-memory btree.
16545876Sbostic 	 *  Otherwise, it's a disk-based btree.
16645876Sbostic 	 */
16745876Sbostic 	if (f == (char *) NULL) {
16845876Sbostic 		/* in memory */
16945876Sbostic 		if ((t->bt_psize = b->psize) < MINPSIZE) {
17045876Sbostic 			if (t->bt_psize != 0) {
17145876Sbostic 				(void) free ((char *) t);
17245876Sbostic 				errno = EINVAL;
17345876Sbostic 				return ((BTREE) NULL);
17445876Sbostic 			}
17545876Sbostic 			t->bt_psize = getpagesize();
17645876Sbostic 		}
17745876Sbostic 
17845876Sbostic 		nbytes = HTSIZE * sizeof(HTBUCKET *);
17945876Sbostic 		if ((ht = (HTABLE) malloc((unsigned) nbytes))
18045876Sbostic 		    == (HTABLE) NULL) {
18145876Sbostic 			(void) free((char *) t);
18245876Sbostic 			return ((BTREE) NULL);
18345876Sbostic 		}
18445876Sbostic 		(void) bzero((char *) ht, nbytes);
18545876Sbostic 		t->bt_s.bt_ht = ht;
18645876Sbostic 		t->bt_npages = 0;
18745876Sbostic 		t->bt_lorder = BYTE_ORDER;
18845876Sbostic 		if (!(b->flags & R_DUP))
18945876Sbostic 			t->bt_flags |= BTF_NODUPS;
19045876Sbostic 	} else {
19145876Sbostic 		/* on disk */
19245876Sbostic 		if ((fd = open(f, O_RDONLY, 0)) < 0) {
19345876Sbostic 			/* doesn't exist yet, be sure page is big enough */
19445876Sbostic 			if ((t->bt_psize = b->psize) < sizeof(BTHEADER)
19545876Sbostic 			    && b->psize != 0) {
19645876Sbostic 				(void) free((char *) t);
19745876Sbostic 				errno = EINVAL;
19845876Sbostic 				return ((BTREE) NULL);
19945876Sbostic 			}
20045876Sbostic 			if (b->lorder == 0)
20145876Sbostic 				b->lorder = BYTE_ORDER;
20245876Sbostic 
20345876Sbostic 			if (b->lorder != BIG_ENDIAN
20445876Sbostic 			    && b->lorder != LITTLE_ENDIAN) {
20545876Sbostic 				(void) free((char *) t);
20645876Sbostic 				errno = EINVAL;
20745876Sbostic 				return ((BTREE) NULL);
20845876Sbostic 			}
20945876Sbostic 			t->bt_lorder = b->lorder;
21045876Sbostic 			if (!(b->flags & R_DUP))
21145876Sbostic 				t->bt_flags |= BTF_NODUPS;
21245876Sbostic 		} else {
21345876Sbostic 			/* exists, get page size from file */
21445876Sbostic 			if (read(fd, &m, sizeof(m)) < sizeof(m)) {
21545876Sbostic 				(void) close(fd);
21645876Sbostic 				(void) free((char *) t);
21745876Sbostic 				errno = EINVAL;
21845876Sbostic 				return ((BTREE) NULL);
21945876Sbostic 			}
22045876Sbostic 
22145876Sbostic 			/* lorder always stored in host-independent format */
22245876Sbostic 			NTOHL(m.m_lorder);
22345876Sbostic 			if (m.m_lorder != BIG_ENDIAN
22445876Sbostic 			    && m.m_lorder != LITTLE_ENDIAN) {
22545876Sbostic 				(void) free((char *) t);
22645876Sbostic 				errno = EINVAL;
22745876Sbostic 				return ((BTREE) NULL);
22845876Sbostic 			}
22945876Sbostic 			t->bt_lorder = m.m_lorder;
23045876Sbostic 
23145876Sbostic 			if (t->bt_lorder != BYTE_ORDER) {
23245876Sbostic 				BLSWAP(m.m_magic);
23345876Sbostic 				BLSWAP(m.m_version);
23445876Sbostic 				BLSWAP(m.m_psize);
23545876Sbostic 				BLSWAP(m.m_free);
23645876Sbostic 				BLSWAP(m.m_flags);
23745876Sbostic 			}
23845876Sbostic 
23945876Sbostic 			if (m.m_magic != BTREEMAGIC
24045876Sbostic 			    || m.m_version != BTREEVERSION
24145876Sbostic 			    || m.m_psize < MINPSIZE) {
24245876Sbostic 				(void) close(fd);
24345876Sbostic 				(void) free((char *) t);
24445876Sbostic #ifndef EFTYPE
24545876Sbostic #define EFTYPE	-100
24645876Sbostic #endif
24745876Sbostic 				errno = EFTYPE;
24845876Sbostic 				return ((BTREE) NULL);
24945876Sbostic 			}
25045876Sbostic 			t->bt_psize = m.m_psize;
25145876Sbostic 			t->bt_free = m.m_free;
25245876Sbostic 			t->bt_flags |= (m.m_flags & BTF_NODUPS) | BTF_METAOK;
25345876Sbostic 			(void) close(fd);
25445876Sbostic 		}
25545876Sbostic 
25645876Sbostic 		/* now open the file the way the user wanted it */
25745876Sbostic 		if ((t->bt_s.bt_d.d_fd = open(f, flags, mode)) < 0) {
25845876Sbostic 			(void) free ((char *) t);
25945876Sbostic 			return ((BTREE) NULL);
26045876Sbostic 		}
26145876Sbostic 
26246453Smao 		/* access method files are always close-on-exec */
26346453Smao 		if (fcntl(t->bt_s.bt_d.d_fd, F_SETFL, 1) == -1) {
26446453Smao 			(void) close(t->bt_s.bt_d.d_fd);
26546453Smao 			(void) free ((char *) t);
26646453Smao 			return ((BTREE) NULL);
26746453Smao 		}
26846453Smao 
26945876Sbostic 		/* get number of pages, page size if necessary */
27045876Sbostic 		(void) fstat(t->bt_s.bt_d.d_fd, &buf);
27145876Sbostic 		if (t->bt_psize == 0)
27245876Sbostic 			t->bt_psize = buf.st_blksize;
27345876Sbostic 		t->bt_npages = (pgno_t) (buf.st_size / t->bt_psize);
27445876Sbostic 
27545876Sbostic 		/* page zero is metadata, doesn't count */
27645876Sbostic 		if (t->bt_npages > 0)
27745876Sbostic 			--(t->bt_npages);
27845876Sbostic 
27945876Sbostic 		if (b->cachesize == 0)
28045876Sbostic 			b->cachesize = DEFCACHE;
28145876Sbostic 
28245876Sbostic 		/* get an lru buffer cache, if the user asked for one */
28345876Sbostic 		if ((b->cachesize / t->bt_psize) > 0) {
28445876Sbostic 			BTDISK *d = &(t->bt_s.bt_d);
28545876Sbostic 
28645876Sbostic 			d->d_cache = lruinit(d->d_fd,
28746127Smao 					     (int) (b->cachesize / t->bt_psize),
28846127Smao 					     (int) t->bt_psize,
28945876Sbostic 					     (char *) t->bt_lorder,
29045876Sbostic 					     _bt_pgin, _bt_pgout);
29145876Sbostic 
29245876Sbostic 			if (d->d_cache == (char *) NULL) {
29345876Sbostic 				(void) free((char *) t);
29445876Sbostic 				return ((BTREE) NULL);
29545876Sbostic 			}
29645876Sbostic 		}
29745876Sbostic 	}
29845876Sbostic 
29945876Sbostic 	/* remember if tree was opened for write */
30045876Sbostic 	if (((flags & O_WRONLY) == O_WRONLY)
30145876Sbostic 	    || ((flags & O_RDWR) == O_RDWR))
30245876Sbostic 		t->bt_flags |= BTF_ISWRITE;
30345876Sbostic 
30445876Sbostic 	return ((BTREE) t);
30545876Sbostic }
30645876Sbostic 
30745876Sbostic /*
30845876Sbostic  *  BT_GET -- Get an entry from a btree.
30945876Sbostic  *
31045876Sbostic  *	Does a key lookup in the tree to find the specified key, and returns
31145876Sbostic  *	the key/data pair found.
31245876Sbostic  *
31345876Sbostic  *	Parameters:
31445876Sbostic  *		tree -- btree in which to do lookup
31545876Sbostic  *		key -- key to find
31645876Sbostic  *		data -- pointer to DBT in which to return data
31745876Sbostic  *		flag -- ignored
31845876Sbostic  *
31945876Sbostic  *	Returns:
32045876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the key is not
32145876Sbostic  *		found.  If key is not found, nothing is stored in the
32245876Sbostic  *		return DBT 'data'.
32345876Sbostic  *
32445876Sbostic  *	Side Effects:
32545876Sbostic  *		None.
32645876Sbostic  *
32745876Sbostic  *	Warnings:
32845876Sbostic  *		Return data is statically allocated, and will be overwritten
32945876Sbostic  *		at the next call.
33045876Sbostic  */
33145876Sbostic 
33245876Sbostic int
33345876Sbostic bt_get(tree, key, data, flag)
33445876Sbostic 	BTREE tree;
33545876Sbostic 	DBT *key;
33645876Sbostic 	DBT *data;
337*46570Sbostic 	u_long flag;
33845876Sbostic {
33945876Sbostic 	BTREE_P t = (BTREE_P) tree;
34045876Sbostic 	BTHEADER *h;
34145876Sbostic 	DATUM *d;
34245876Sbostic 	BTITEM *item;
34345876Sbostic 
34446127Smao #ifdef lint
34546127Smao 	flag = flag;
34646127Smao #endif /* lint */
34746127Smao 
34845876Sbostic 	/* lookup */
34945876Sbostic 	item = _bt_search(t, key);
35045876Sbostic 
35145876Sbostic 	/* clear parent pointer stack */
35245876Sbostic 	while (_bt_pop(t) != P_NONE)
35345876Sbostic 		continue;
35445876Sbostic 
35546453Smao 	if (item == (BTITEM *) NULL)
35646453Smao 		return (RET_ERROR);
35746453Smao 
35845876Sbostic 	h = (BTHEADER *) t->bt_curpage;
35945876Sbostic 	data->size = 0;
36045876Sbostic 	data->data = (char *) NULL;
36145876Sbostic 
36245876Sbostic 	/* match? */
36345876Sbostic 	if (VALIDITEM(t, item)
36445876Sbostic 	    && _bt_cmp(t, key->data, item->bti_index) == 0) {
36545876Sbostic 		d = (DATUM *) GETDATUM(h, item->bti_index);
36645876Sbostic 		return (_bt_buildret(t, d, data, key));
36745876Sbostic 	}
36845876Sbostic 
36945876Sbostic 	/* nope */
37045876Sbostic 	return (RET_SPECIAL);
37145876Sbostic }
37245876Sbostic 
37345876Sbostic /*
37445876Sbostic  *  BT_PUT -- Add an entry to a btree.
37545876Sbostic  *
37645876Sbostic  *	The specified (key, data) pair is added to the tree.  If the tree
37745876Sbostic  *	was created for unique keys only, then duplicates will not be
37845876Sbostic  *	entered.  If the requested key exists in the tree, it will be over-
37945876Sbostic  *	written unless the flags parameter is R_NOOVERWRITE, in which case
38045876Sbostic  *	the update will not be done.  If duplicate keys are permitted in the
38145876Sbostic  *	tree, duplicates will be inserted and will not overwrite existing
38245876Sbostic  *	keys.  Nodes are split as required.
38345876Sbostic  *
38445876Sbostic  *	Parameters:
38545876Sbostic  *		tree -- btree in which to put the new entry
38645876Sbostic  *		key -- key component to add
38745876Sbostic  *		data -- data corresponding to key
38845876Sbostic  *		flag -- R_NOOVERWRITE or zero.
38945876Sbostic  *
39045876Sbostic  *	Returns:
39145876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the
39245876Sbostic  *		NOOVERWRITE flag was set and the specified key exists
39345876Sbostic  *		in the database.
39445876Sbostic  *
39545876Sbostic  *	Side Effects:
39645876Sbostic  *		None.
39745876Sbostic  */
39845876Sbostic 
39945876Sbostic int
40045876Sbostic bt_put(tree, key, data, flag)
40145876Sbostic 	BTREE tree;
40245876Sbostic 	DBT *key;
40345876Sbostic 	DBT *data;
404*46570Sbostic 	u_long flag;
40545876Sbostic {
40645876Sbostic 	BTREE_P t = (BTREE_P) tree;
40745876Sbostic 	BTITEM *item;
40845876Sbostic 
40945876Sbostic 	/* look for this key in the tree */
41045876Sbostic 	item = _bt_search(t, key);
41145876Sbostic 
41245876Sbostic 	/*
41345876Sbostic 	 *  If this tree was originally created without R_DUP, then duplicate
41445876Sbostic 	 *  keys are not allowed.  We need to check this at insertion time.
41545876Sbostic 	 */
41645876Sbostic 
41745876Sbostic 	if (VALIDITEM(t, item) && _bt_cmp(t, key->data, item->bti_index) == 0) {
41845876Sbostic 		if ((t->bt_flags & BTF_NODUPS) && flag == R_NOOVERWRITE) {
41946453Smao 			if (_bt_delone(t, item->bti_index) == RET_ERROR) {
42046453Smao 				while (_bt_pop(t) != P_NONE)
42146453Smao 					continue;
42245876Sbostic 				return (RET_ERROR);
42346453Smao 			}
42445876Sbostic 		}
42545876Sbostic 	}
42645876Sbostic 
42745876Sbostic 	return (_bt_insert(t, item, key, data, flag));
42845876Sbostic }
42945876Sbostic 
43045876Sbostic /*
43145876Sbostic  *  BT_DELETE -- delete a key from the tree.
43245876Sbostic  *
43345876Sbostic  *	Deletes all keys (and their associated data items) matching the
43445876Sbostic  *	supplied key from the tree.  If the flags entry is R_CURSOR, then
43545876Sbostic  *	the current item in the active scan is deleted.
43645876Sbostic  *
43745876Sbostic  *	Parameters:
43845876Sbostic  *		tree -- btree from which to delete key
43945876Sbostic  *		key -- key to delete
44045876Sbostic  *		flags -- R_CURSOR or zero
44145876Sbostic  *
44245876Sbostic  *	Returns:
44345876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the specified
44445876Sbostic  *		key was not in the tree.
44545876Sbostic  *
44645876Sbostic  *	Side Effects:
44745876Sbostic  *		None.
44845876Sbostic  */
44945876Sbostic 
45045876Sbostic int
45145876Sbostic bt_delete(tree, key, flags)
45245876Sbostic 	BTREE tree;
45345876Sbostic 	DBT *key;
454*46570Sbostic 	u_long flags;
45545876Sbostic {
45645876Sbostic 	BTREE_P t = (BTREE_P) tree;
45745876Sbostic 	BTHEADER *h;
45845876Sbostic 	BTITEM *item;
45945876Sbostic 	int ndel = 0;
46045876Sbostic 
46145876Sbostic 	if (flags == R_CURSOR)
46245876Sbostic 		return (_bt_crsrdel(t));
46345876Sbostic 
46445876Sbostic 	/* find the first matching key in the tree */
46545876Sbostic 	item = _bt_first(t, key);
46645876Sbostic 	h = t->bt_curpage;
46745876Sbostic 
46846453Smao 	/* don't need the descent stack for deletes */
46946453Smao 	while (_bt_pop(t) != P_NONE)
47046453Smao 		continue;
47146453Smao 
47245876Sbostic 	/* delete all matching keys */
47345876Sbostic 	for (;;) {
47445876Sbostic 		while (VALIDITEM(t, item)
47545876Sbostic 		       && (_bt_cmp(t, key->data, item->bti_index) == 0)) {
47645876Sbostic 			if (_bt_delone(t, item->bti_index) == RET_ERROR)
47745876Sbostic 				return (RET_ERROR);
47845876Sbostic 			ndel++;
47945876Sbostic 		}
48045876Sbostic 
48145876Sbostic 		if (VALIDITEM(t, item) || h->h_nextpg == P_NONE)
48245876Sbostic 			break;
48345876Sbostic 
48445876Sbostic 		/* next page, if necessary */
48545876Sbostic 		do {
48645876Sbostic 			if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
48745876Sbostic 				return (RET_ERROR);
48845876Sbostic 			h = t->bt_curpage;
48945876Sbostic 		} while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE);
49045876Sbostic 
49145876Sbostic 		item->bti_pgno = h->h_pgno;
49245876Sbostic 		item->bti_index = 0;
49345876Sbostic 
49445876Sbostic 		if (!VALIDITEM(t, item)
49545876Sbostic 		    || _bt_cmp(t, key->data, item->bti_index) != 0)
49645876Sbostic 			break;
49745876Sbostic 	}
49845876Sbostic 
49945876Sbostic 	/* flush changes to disk */
50045876Sbostic 	if (ISDISK(t)) {
50145876Sbostic 		if (h->h_flags & F_DIRTY) {
50245876Sbostic 			if (_bt_write(t, t->bt_curpage, NORELEASE) == RET_ERROR)
50345876Sbostic 				return (RET_ERROR);
50445876Sbostic 		}
50545876Sbostic 	}
50645876Sbostic 
50745876Sbostic 	if (ndel == 0)
50845876Sbostic 		return (RET_SPECIAL);
50945876Sbostic 
51045876Sbostic 	return (RET_SUCCESS);
51145876Sbostic }
51245876Sbostic 
51345876Sbostic /*
51445876Sbostic  *  BT_SYNC -- sync the btree to disk.
51545876Sbostic  *
51645876Sbostic  *	Parameters:
51745876Sbostic  *		tree -- btree to sync.
51845876Sbostic  *
51945876Sbostic  *	Returns:
52045876Sbostic  *		RET_SUCCESS, RET_ERROR.
52145876Sbostic  */
52245876Sbostic 
52345876Sbostic bt_sync(tree)
52445876Sbostic 	BTREE tree;
52545876Sbostic {
52645876Sbostic 	BTREE_P t = (BTREE_P) tree;
52745876Sbostic 	BTHEADER *h;
52845876Sbostic 	pgno_t pgno;
52945876Sbostic 
53045876Sbostic 	/* if this is an in-memory btree, syncing is a no-op */
53145876Sbostic 	if (!ISDISK(t))
53245876Sbostic 		return (RET_SUCCESS);
53345876Sbostic 
53445876Sbostic 	h = (BTHEADER *) t->bt_curpage;
53545876Sbostic 	h->h_flags &= ~F_DIRTY;
53645876Sbostic 
53745876Sbostic 	if (ISCACHE(t)) {
53845876Sbostic 		pgno = t->bt_curpage->h_pgno;
53945876Sbostic 		if (_bt_write(t, h, RELEASE) == RET_ERROR)
54045876Sbostic 			return(RET_ERROR);
54145876Sbostic 		if (lrusync(t->bt_s.bt_d.d_cache) < RET_ERROR)
54245876Sbostic 			return (RET_ERROR);
54345876Sbostic 		if (_bt_getpage(t, pgno) == RET_ERROR)
54445876Sbostic 			return (RET_ERROR);
54545876Sbostic 	} else {
54645876Sbostic 		if (_bt_write(t, h, NORELEASE) == RET_ERROR)
54745876Sbostic 			return (RET_ERROR);
54845876Sbostic 	}
54945876Sbostic 
55045876Sbostic 	return (fsync(t->bt_s.bt_d.d_fd));
55145876Sbostic }
55245876Sbostic 
55345876Sbostic /*
55445876Sbostic  *  BT_SEQ -- Sequential scan interface.
55545876Sbostic  *
55645876Sbostic  *	This routine supports sequential scans on the btree.  If called with
55745876Sbostic  *	flags set to R_CURSOR, or if no seq scan has been initialized in the
55845876Sbostic  *	current tree, we initialize the scan.  Otherwise, we advance the scan
55945876Sbostic  *	and return the next item.
56045876Sbostic  *
56145876Sbostic  *	Scans can be either keyed or non-keyed.  Keyed scans basically have
56245876Sbostic  *	a starting point somewhere in the middle of the tree.  Non-keyed
56345876Sbostic  *	scans start at an endpoint.  Also, scans can be backward (descending
56445876Sbostic  *	order), forward (ascending order), or no movement (keep returning
56545876Sbostic  *	the same item).
56645876Sbostic  *
56745876Sbostic  *	Flags is checked every time we enter the routine, so the user can
56845876Sbostic  *	change directions on an active scan if desired.  The key argument
56945876Sbostic  *	is examined only when we initialize the scan, in order to position
57045876Sbostic  *	it properly.
57145876Sbostic  *
57245876Sbostic  *	Items are returned via the key and data arguments passed in.
57345876Sbostic  *
57445876Sbostic  *	Parameters:
57545876Sbostic  *		tree -- btree in which to do scan
57645876Sbostic  *		key -- key, used to position scan on initialization, and
57745876Sbostic  *		       used to return key components to the user.
57845876Sbostic  *		data -- used to return data components to the user.
57945876Sbostic  *		flags -- specify R_CURSOR, R_FIRST, R_LAST, R_NEXT, or
58045876Sbostic  *			 R_PREV.
58145876Sbostic  *
58245876Sbostic  *	Returns:
58345876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if no more data
58445876Sbostic  *		exists in the tree in the specified direction.
58545876Sbostic  *
58645876Sbostic  *	Side Effects:
58745876Sbostic  *		Changes the btree's notion of the current position in the
58845876Sbostic  *		scan.
58945876Sbostic  *
59045876Sbostic  *	Warnings:
59145876Sbostic  *		The key and data items returned are static and will be
59245876Sbostic  *		overwritten by the next bt_get or bt_seq.
59345876Sbostic  */
59445876Sbostic 
59546127Smao int
59645876Sbostic bt_seq(tree, key, data, flags)
59745876Sbostic 	BTREE tree;
59845876Sbostic 	DBT *key;
59945876Sbostic 	DBT *data;
600*46570Sbostic 	u_long flags;
60145876Sbostic {
60245876Sbostic 	BTREE_P t = (BTREE_P) tree;
60345876Sbostic 	BTHEADER *h;
60445876Sbostic 	DATUM *d;
60545876Sbostic 	int status;
60645876Sbostic 
60745876Sbostic 	/* do we need to initialize the scan? */
60845876Sbostic 	if (flags == R_CURSOR || flags == R_LAST || flags == R_FIRST
60945876Sbostic 	    || !(t->bt_flags & BTF_SEQINIT)) {
61045876Sbostic 
61145876Sbostic 		/* initialize it */
61245876Sbostic 		status = _bt_seqinit(t, key, flags);
61345876Sbostic 	} else {
61445876Sbostic 		/* just advance the current scan pointer */
61545876Sbostic 		status = _bt_seqadvance(t, flags);
61645876Sbostic 	}
61745876Sbostic 
61845876Sbostic 	key->size = data->size = 0;
61945876Sbostic 	key->data = data->data = (char *) NULL;
62045876Sbostic 
62145876Sbostic 	h = t->bt_curpage;
62245876Sbostic 
62345876Sbostic 	/* is there a valid item at the current scan location? */
62445876Sbostic 	if (status == RET_SPECIAL) {
62545876Sbostic 		if (flags == R_NEXT) {
62645876Sbostic 			if (t->bt_cursor.c_index >= NEXTINDEX(h)) {
62745876Sbostic 				if (NEXTINDEX(h) > 0)
62845876Sbostic 					t->bt_cursor.c_index = NEXTINDEX(h) - 1;
62945876Sbostic 				else
63045876Sbostic 					t->bt_cursor.c_index = 0;
63145876Sbostic 			}
63245876Sbostic 		} else {
63345876Sbostic 			t->bt_cursor.c_index = 0;
63445876Sbostic 		}
63545876Sbostic 		return (RET_SPECIAL);
63645876Sbostic 	} else if (status == RET_ERROR)
63745876Sbostic 		return (RET_ERROR);
63845876Sbostic 
63945876Sbostic 	/* okay, return the data */
64045876Sbostic 	d = (DATUM *) GETDATUM(h, t->bt_cursor.c_index);
64145876Sbostic 
64245876Sbostic 	return (_bt_buildret(t, d, data, key));
64345876Sbostic }
64445876Sbostic 
64545876Sbostic /*
64645876Sbostic  *  BT_CLOSE -- Close a btree
64745876Sbostic  *
64845876Sbostic  *	Parameters:
64945876Sbostic  *		tree -- tree to close
65045876Sbostic  *
65145876Sbostic  *	Returns:
65245876Sbostic  *		RET_SUCCESS, RET_ERROR.
65345876Sbostic  *
65445876Sbostic  *	Side Effects:
65545876Sbostic  *		Frees space occupied by the tree.
65645876Sbostic  */
65745876Sbostic 
65845876Sbostic int
65945876Sbostic bt_close(tree)
66045876Sbostic 	BTREE tree;
66145876Sbostic {
66245876Sbostic 	BTREE_P t = (BTREE_P) tree;
66345876Sbostic 	int i;
66445876Sbostic 	BTHEADER *h;
66545876Sbostic 	char *cache;
66645876Sbostic 	struct HTBUCKET *b, *sb;
66745876Sbostic 	HTABLE ht;
66845876Sbostic 	int fd;
66945876Sbostic 
67045876Sbostic 	if (t->bt_cursor.c_key != (char *) NULL)
67145876Sbostic 		(void) free(t->bt_cursor.c_key);
67245876Sbostic 
67345876Sbostic 	if (!ISDISK(t)) {
67445876Sbostic 		/* in-memory tree, release hash table memory */
67545876Sbostic 		ht = t->bt_s.bt_ht;
67645876Sbostic 		for (i = 0; i < HTSIZE; i++) {
67745876Sbostic 			if ((b = ht[i]) == (struct HTBUCKET *) NULL)
67845876Sbostic 				break;
67945876Sbostic 			do {
68045876Sbostic 				sb = b;
68145876Sbostic 				(void) free((char *) b->ht_page);
68245876Sbostic 				b = b->ht_next;
68345876Sbostic 				(void) free((char *) sb);
68445876Sbostic 			} while (b != (struct HTBUCKET *) NULL);
68545876Sbostic 		}
68645876Sbostic 		(void) free ((char *) ht);
68745876Sbostic 		(void) free ((char *) t);
68845876Sbostic 		return (RET_SUCCESS);
68945876Sbostic 	}
69045876Sbostic 
69145876Sbostic 	if ((t->bt_flags & BTF_ISWRITE) && !(t->bt_flags & BTF_METAOK)) {
69245876Sbostic 		if (_bt_wrtmeta(t) == RET_ERROR)
69345876Sbostic 			return (RET_ERROR);
69445876Sbostic 	}
69545876Sbostic 
69645876Sbostic 	if (t->bt_curpage != (BTHEADER *) NULL) {
69745876Sbostic 		h = t->bt_curpage;
69845876Sbostic 		if (h->h_flags & F_DIRTY) {
69945876Sbostic 			if (_bt_write(t, h, RELEASE) == RET_ERROR)
70045876Sbostic 				return (RET_ERROR);
70145876Sbostic 		} else {
70245876Sbostic 			if (_bt_release(t, h) == RET_ERROR)
70345876Sbostic 				return (RET_ERROR);
70445876Sbostic 		}
70545876Sbostic 
70645876Sbostic 		/* flush and free the cache, if there is one */
70745876Sbostic 		if (ISCACHE(t)) {
70845876Sbostic 			cache = t->bt_s.bt_d.d_cache;
70946127Smao 			if (lrusync(cache) == RET_ERROR)
71046127Smao 				return (RET_ERROR);
71145876Sbostic 			lrufree(cache);
71245876Sbostic 		}
71345876Sbostic 		(void) free ((char *) h);
71445876Sbostic 	}
71545876Sbostic 
71645876Sbostic 	fd = t->bt_s.bt_d.d_fd;
71745876Sbostic 	(void) free ((char *) t);
71845876Sbostic 	return (close(fd));
71945876Sbostic }
720