xref: /csrg-svn/lib/libc/db/btree/bt_open.c (revision 49322)
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*49322Sbostic static char sccsid[] = "@(#)bt_open.c	5.9 (Berkeley) 05/07/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;
10147729Sbostic 	db->type = DB_BTREE;
10245876Sbostic 
10345876Sbostic 	return (db);
10445876Sbostic }
10545876Sbostic 
10645876Sbostic /*
10745876Sbostic  *  BT_OPEN -- Open a btree.
10845876Sbostic  *
10945876Sbostic  *	This routine creates the correct kind (disk or in-memory) of
11045876Sbostic  *	btree and initializes it as required.
11145876Sbostic  *
11245876Sbostic  *	Parameters:
11345876Sbostic  *		f -- name of btree (NULL for in-memory btrees)
11445876Sbostic  *		flags -- flags passed to open()
11545876Sbostic  *		mode -- mode passed to open ()
11645876Sbostic  *		b -- BTREEINFO structure, describing btree
11745876Sbostic  *
11845876Sbostic  *	Returns:
11945876Sbostic  *		(Opaque) pointer to the btree.  On failure, returns NULL
12045876Sbostic  *		with errno set as appropriate.
12145876Sbostic  *
12245876Sbostic  *	Side Effects:
12345876Sbostic  *		Allocates memory, opens files.
12445876Sbostic  */
12545876Sbostic 
12645876Sbostic BTREE
12745876Sbostic bt_open(f, flags, mode, b)
12845876Sbostic 	char *f;
12945876Sbostic 	int flags;
13045876Sbostic 	int mode;
13145876Sbostic 	BTREEINFO *b;
13245876Sbostic {
13345876Sbostic 	BTREE_P t;
13445876Sbostic 	HTABLE ht;
13545876Sbostic 	int nbytes;
13645876Sbostic 	int fd;
13745876Sbostic 	CURSOR *c;
13845876Sbostic 	BTMETA m;
13945876Sbostic 	struct stat buf;
14045876Sbostic 
14145876Sbostic 	/* use the default info if none was provided */
14245876Sbostic 	if (b == (BTREEINFO *) NULL)
14345876Sbostic 		b = &_DefaultBTInfo;
14445876Sbostic 
14545876Sbostic 	if ((t = (BTREE_P) malloc((unsigned) sizeof *t)) == (BTREE_P) NULL)
14645876Sbostic 		return ((BTREE) NULL);
14745876Sbostic 
14845876Sbostic 	if (b->compare)
14945876Sbostic 		t->bt_compare = b->compare;
15045876Sbostic 	else
15145876Sbostic 		t->bt_compare = strcmp;
15245876Sbostic 
15345876Sbostic 	t->bt_fname = f;
15445876Sbostic 	t->bt_curpage = (BTHEADER *) NULL;
15545876Sbostic 	t->bt_free = P_NONE;
15645876Sbostic 	c = &(t->bt_cursor);
15745876Sbostic 	c->c_pgno = P_NONE;
15845876Sbostic 	c->c_index = 0;
15945876Sbostic 	c->c_flags = (u_char) NULL;
16045876Sbostic 	c->c_key = (char *) NULL;
16145876Sbostic 	t->bt_stack = (BTSTACK *) NULL;
16245876Sbostic 	t->bt_flags = 0;
16345876Sbostic 
16445876Sbostic 	/*
16545876Sbostic 	 *  If no file name was supplied, this is an in-memory btree.
16645876Sbostic 	 *  Otherwise, it's a disk-based btree.
16745876Sbostic 	 */
16845876Sbostic 	if (f == (char *) NULL) {
16945876Sbostic 		/* in memory */
17045876Sbostic 		if ((t->bt_psize = b->psize) < MINPSIZE) {
17145876Sbostic 			if (t->bt_psize != 0) {
17245876Sbostic 				(void) free ((char *) t);
17345876Sbostic 				errno = EINVAL;
17445876Sbostic 				return ((BTREE) NULL);
17545876Sbostic 			}
17645876Sbostic 			t->bt_psize = getpagesize();
17745876Sbostic 		}
17845876Sbostic 
17945876Sbostic 		nbytes = HTSIZE * sizeof(HTBUCKET *);
18045876Sbostic 		if ((ht = (HTABLE) malloc((unsigned) nbytes))
18145876Sbostic 		    == (HTABLE) NULL) {
18245876Sbostic 			(void) free((char *) t);
18345876Sbostic 			return ((BTREE) NULL);
18445876Sbostic 		}
18545876Sbostic 		(void) bzero((char *) ht, nbytes);
18645876Sbostic 		t->bt_s.bt_ht = ht;
18745876Sbostic 		t->bt_npages = 0;
18845876Sbostic 		t->bt_lorder = BYTE_ORDER;
18945876Sbostic 		if (!(b->flags & R_DUP))
19045876Sbostic 			t->bt_flags |= BTF_NODUPS;
19145876Sbostic 	} else {
19245876Sbostic 		/* on disk */
19345876Sbostic 		if ((fd = open(f, O_RDONLY, 0)) < 0) {
19445876Sbostic 			/* doesn't exist yet, be sure page is big enough */
19545876Sbostic 			if ((t->bt_psize = b->psize) < sizeof(BTHEADER)
19645876Sbostic 			    && b->psize != 0) {
19745876Sbostic 				(void) free((char *) t);
19845876Sbostic 				errno = EINVAL;
19945876Sbostic 				return ((BTREE) NULL);
20045876Sbostic 			}
20145876Sbostic 			if (b->lorder == 0)
20245876Sbostic 				b->lorder = BYTE_ORDER;
20345876Sbostic 
20445876Sbostic 			if (b->lorder != BIG_ENDIAN
20545876Sbostic 			    && b->lorder != LITTLE_ENDIAN) {
20645876Sbostic 				(void) free((char *) t);
20745876Sbostic 				errno = EINVAL;
20845876Sbostic 				return ((BTREE) NULL);
20945876Sbostic 			}
21045876Sbostic 			t->bt_lorder = b->lorder;
21145876Sbostic 			if (!(b->flags & R_DUP))
21245876Sbostic 				t->bt_flags |= BTF_NODUPS;
21345876Sbostic 		} else {
21445876Sbostic 			/* exists, get page size from file */
21545876Sbostic 			if (read(fd, &m, sizeof(m)) < sizeof(m)) {
21645876Sbostic 				(void) close(fd);
21745876Sbostic 				(void) free((char *) t);
21845876Sbostic 				errno = EINVAL;
21945876Sbostic 				return ((BTREE) NULL);
22045876Sbostic 			}
22145876Sbostic 
22245876Sbostic 			/* lorder always stored in host-independent format */
22345876Sbostic 			NTOHL(m.m_lorder);
22445876Sbostic 			if (m.m_lorder != BIG_ENDIAN
22545876Sbostic 			    && m.m_lorder != LITTLE_ENDIAN) {
22645876Sbostic 				(void) free((char *) t);
22745876Sbostic 				errno = EINVAL;
22845876Sbostic 				return ((BTREE) NULL);
22945876Sbostic 			}
23045876Sbostic 			t->bt_lorder = m.m_lorder;
23145876Sbostic 
23245876Sbostic 			if (t->bt_lorder != BYTE_ORDER) {
23345876Sbostic 				BLSWAP(m.m_magic);
23445876Sbostic 				BLSWAP(m.m_version);
23545876Sbostic 				BLSWAP(m.m_psize);
23645876Sbostic 				BLSWAP(m.m_free);
23745876Sbostic 				BLSWAP(m.m_flags);
23845876Sbostic 			}
23945876Sbostic 
24045876Sbostic 			if (m.m_magic != BTREEMAGIC
24145876Sbostic 			    || m.m_version != BTREEVERSION
24245876Sbostic 			    || m.m_psize < MINPSIZE) {
24345876Sbostic 				(void) close(fd);
24445876Sbostic 				(void) free((char *) t);
24545876Sbostic #ifndef EFTYPE
24645876Sbostic #define EFTYPE	-100
24745876Sbostic #endif
24845876Sbostic 				errno = EFTYPE;
24945876Sbostic 				return ((BTREE) NULL);
25045876Sbostic 			}
25145876Sbostic 			t->bt_psize = m.m_psize;
25245876Sbostic 			t->bt_free = m.m_free;
25345876Sbostic 			t->bt_flags |= (m.m_flags & BTF_NODUPS) | BTF_METAOK;
25445876Sbostic 			(void) close(fd);
25545876Sbostic 		}
25645876Sbostic 
25745876Sbostic 		/* now open the file the way the user wanted it */
25845876Sbostic 		if ((t->bt_s.bt_d.d_fd = open(f, flags, mode)) < 0) {
25945876Sbostic 			(void) free ((char *) t);
26045876Sbostic 			return ((BTREE) NULL);
26145876Sbostic 		}
26245876Sbostic 
26346453Smao 		/* access method files are always close-on-exec */
26446453Smao 		if (fcntl(t->bt_s.bt_d.d_fd, F_SETFL, 1) == -1) {
26546453Smao 			(void) close(t->bt_s.bt_d.d_fd);
26646453Smao 			(void) free ((char *) t);
26746453Smao 			return ((BTREE) NULL);
26846453Smao 		}
26946453Smao 
27045876Sbostic 		/* get number of pages, page size if necessary */
27145876Sbostic 		(void) fstat(t->bt_s.bt_d.d_fd, &buf);
27245876Sbostic 		if (t->bt_psize == 0)
27345876Sbostic 			t->bt_psize = buf.st_blksize;
27445876Sbostic 		t->bt_npages = (pgno_t) (buf.st_size / t->bt_psize);
27545876Sbostic 
27645876Sbostic 		/* page zero is metadata, doesn't count */
27745876Sbostic 		if (t->bt_npages > 0)
27845876Sbostic 			--(t->bt_npages);
27945876Sbostic 
28045876Sbostic 		if (b->cachesize == 0)
28145876Sbostic 			b->cachesize = DEFCACHE;
28245876Sbostic 
28345876Sbostic 		/* get an lru buffer cache, if the user asked for one */
28445876Sbostic 		if ((b->cachesize / t->bt_psize) > 0) {
28545876Sbostic 			BTDISK *d = &(t->bt_s.bt_d);
28645876Sbostic 
28745876Sbostic 			d->d_cache = lruinit(d->d_fd,
28846127Smao 					     (int) (b->cachesize / t->bt_psize),
28946127Smao 					     (int) t->bt_psize,
29045876Sbostic 					     (char *) t->bt_lorder,
29145876Sbostic 					     _bt_pgin, _bt_pgout);
29245876Sbostic 
29345876Sbostic 			if (d->d_cache == (char *) NULL) {
29445876Sbostic 				(void) free((char *) t);
29545876Sbostic 				return ((BTREE) NULL);
29645876Sbostic 			}
29745876Sbostic 		}
29845876Sbostic 	}
29945876Sbostic 
30045876Sbostic 	/* remember if tree was opened for write */
30145876Sbostic 	if (((flags & O_WRONLY) == O_WRONLY)
30245876Sbostic 	    || ((flags & O_RDWR) == O_RDWR))
30345876Sbostic 		t->bt_flags |= BTF_ISWRITE;
30445876Sbostic 
30545876Sbostic 	return ((BTREE) t);
30645876Sbostic }
30745876Sbostic 
30845876Sbostic /*
30945876Sbostic  *  BT_GET -- Get an entry from a btree.
31045876Sbostic  *
31145876Sbostic  *	Does a key lookup in the tree to find the specified key, and returns
31245876Sbostic  *	the key/data pair found.
31345876Sbostic  *
31445876Sbostic  *	Parameters:
31545876Sbostic  *		tree -- btree in which to do lookup
31645876Sbostic  *		key -- key to find
31745876Sbostic  *		data -- pointer to DBT in which to return data
31845876Sbostic  *		flag -- ignored
31945876Sbostic  *
32045876Sbostic  *	Returns:
32145876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the key is not
32245876Sbostic  *		found.  If key is not found, nothing is stored in the
32345876Sbostic  *		return DBT 'data'.
32445876Sbostic  *
32545876Sbostic  *	Side Effects:
32645876Sbostic  *		None.
32745876Sbostic  *
32845876Sbostic  *	Warnings:
32945876Sbostic  *		Return data is statically allocated, and will be overwritten
33045876Sbostic  *		at the next call.
33145876Sbostic  */
33245876Sbostic 
33345876Sbostic int
334*49322Sbostic bt_get(dbp, key, data, flag)
335*49322Sbostic 	DB *dbp;
336*49322Sbostic 	DBT *key, *data;
33746570Sbostic 	u_long flag;
33845876Sbostic {
339*49322Sbostic 	BTREE_P t = (BTREE_P) (dbp->internal);
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;
36046951Sbostic 	data->data = (u_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
400*49322Sbostic bt_put(dbp, key, data, flag)
401*49322Sbostic 	DB *dbp;
402*49322Sbostic 	DBT *key, *data;
40346570Sbostic 	u_long flag;
40445876Sbostic {
405*49322Sbostic 	BTREE_P t;
40645876Sbostic 	BTITEM *item;
40745876Sbostic 
408*49322Sbostic 	t = (BTREE_P)dbp->internal;
409*49322Sbostic 
41045876Sbostic 	/* look for this key in the tree */
41145876Sbostic 	item = _bt_search(t, key);
41245876Sbostic 
41345876Sbostic 	/*
41445876Sbostic 	 *  If this tree was originally created without R_DUP, then duplicate
41545876Sbostic 	 *  keys are not allowed.  We need to check this at insertion time.
41645876Sbostic 	 */
41745876Sbostic 
41845876Sbostic 	if (VALIDITEM(t, item) && _bt_cmp(t, key->data, item->bti_index) == 0) {
41945876Sbostic 		if ((t->bt_flags & BTF_NODUPS) && flag == R_NOOVERWRITE) {
42046453Smao 			if (_bt_delone(t, item->bti_index) == RET_ERROR) {
42146453Smao 				while (_bt_pop(t) != P_NONE)
42246453Smao 					continue;
42345876Sbostic 				return (RET_ERROR);
42446453Smao 			}
42545876Sbostic 		}
42645876Sbostic 	}
42745876Sbostic 
42845876Sbostic 	return (_bt_insert(t, item, key, data, flag));
42945876Sbostic }
43045876Sbostic 
43145876Sbostic /*
43245876Sbostic  *  BT_DELETE -- delete a key from the tree.
43345876Sbostic  *
43445876Sbostic  *	Deletes all keys (and their associated data items) matching the
43545876Sbostic  *	supplied key from the tree.  If the flags entry is R_CURSOR, then
43645876Sbostic  *	the current item in the active scan is deleted.
43745876Sbostic  *
43845876Sbostic  *	Parameters:
43945876Sbostic  *		tree -- btree from which to delete key
44045876Sbostic  *		key -- key to delete
44145876Sbostic  *		flags -- R_CURSOR or zero
44245876Sbostic  *
44345876Sbostic  *	Returns:
44445876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the specified
44545876Sbostic  *		key was not in the tree.
44645876Sbostic  *
44745876Sbostic  *	Side Effects:
44845876Sbostic  *		None.
44945876Sbostic  */
45045876Sbostic 
45145876Sbostic int
452*49322Sbostic bt_delete(dbp, key, flags)
453*49322Sbostic 	DB *dbp;
45445876Sbostic 	DBT *key;
45546570Sbostic 	u_long flags;
45645876Sbostic {
457*49322Sbostic 	BTREE_P t;
45845876Sbostic 	BTHEADER *h;
45945876Sbostic 	BTITEM *item;
46045876Sbostic 	int ndel = 0;
46145876Sbostic 
462*49322Sbostic 	t = (BTREE_P)dbp->internal;
463*49322Sbostic 
46445876Sbostic 	if (flags == R_CURSOR)
46545876Sbostic 		return (_bt_crsrdel(t));
46645876Sbostic 
46745876Sbostic 	/* find the first matching key in the tree */
46845876Sbostic 	item = _bt_first(t, key);
46945876Sbostic 	h = t->bt_curpage;
47045876Sbostic 
47146453Smao 	/* don't need the descent stack for deletes */
47246453Smao 	while (_bt_pop(t) != P_NONE)
47346453Smao 		continue;
47446453Smao 
47545876Sbostic 	/* delete all matching keys */
47645876Sbostic 	for (;;) {
47745876Sbostic 		while (VALIDITEM(t, item)
47845876Sbostic 		       && (_bt_cmp(t, key->data, item->bti_index) == 0)) {
47945876Sbostic 			if (_bt_delone(t, item->bti_index) == RET_ERROR)
48045876Sbostic 				return (RET_ERROR);
48145876Sbostic 			ndel++;
48245876Sbostic 		}
48345876Sbostic 
48445876Sbostic 		if (VALIDITEM(t, item) || h->h_nextpg == P_NONE)
48545876Sbostic 			break;
48645876Sbostic 
48745876Sbostic 		/* next page, if necessary */
48845876Sbostic 		do {
48945876Sbostic 			if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
49045876Sbostic 				return (RET_ERROR);
49145876Sbostic 			h = t->bt_curpage;
49245876Sbostic 		} while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE);
49345876Sbostic 
49445876Sbostic 		item->bti_pgno = h->h_pgno;
49545876Sbostic 		item->bti_index = 0;
49645876Sbostic 
49745876Sbostic 		if (!VALIDITEM(t, item)
49845876Sbostic 		    || _bt_cmp(t, key->data, item->bti_index) != 0)
49945876Sbostic 			break;
50045876Sbostic 	}
50145876Sbostic 
50245876Sbostic 	/* flush changes to disk */
50345876Sbostic 	if (ISDISK(t)) {
50445876Sbostic 		if (h->h_flags & F_DIRTY) {
50545876Sbostic 			if (_bt_write(t, t->bt_curpage, NORELEASE) == RET_ERROR)
50645876Sbostic 				return (RET_ERROR);
50745876Sbostic 		}
50845876Sbostic 	}
50945876Sbostic 
51045876Sbostic 	if (ndel == 0)
51145876Sbostic 		return (RET_SPECIAL);
51245876Sbostic 
51345876Sbostic 	return (RET_SUCCESS);
51445876Sbostic }
51545876Sbostic 
51645876Sbostic /*
51745876Sbostic  *  BT_SYNC -- sync the btree to disk.
51845876Sbostic  *
51945876Sbostic  *	Parameters:
52045876Sbostic  *		tree -- btree to sync.
52145876Sbostic  *
52245876Sbostic  *	Returns:
52345876Sbostic  *		RET_SUCCESS, RET_ERROR.
52445876Sbostic  */
52545876Sbostic 
526*49322Sbostic bt_sync(dbp)
527*49322Sbostic 	DB *dbp;
52845876Sbostic {
529*49322Sbostic 	BTREE_P t;
53045876Sbostic 	BTHEADER *h;
53145876Sbostic 	pgno_t pgno;
53245876Sbostic 
533*49322Sbostic 	t = (BTREE_P)dbp->internal;
534*49322Sbostic 
53545876Sbostic 	/* if this is an in-memory btree, syncing is a no-op */
53645876Sbostic 	if (!ISDISK(t))
53745876Sbostic 		return (RET_SUCCESS);
53845876Sbostic 
53945876Sbostic 	h = (BTHEADER *) t->bt_curpage;
54045876Sbostic 	h->h_flags &= ~F_DIRTY;
54145876Sbostic 
54245876Sbostic 	if (ISCACHE(t)) {
54345876Sbostic 		pgno = t->bt_curpage->h_pgno;
54445876Sbostic 		if (_bt_write(t, h, RELEASE) == RET_ERROR)
54545876Sbostic 			return(RET_ERROR);
54645876Sbostic 		if (lrusync(t->bt_s.bt_d.d_cache) < RET_ERROR)
54745876Sbostic 			return (RET_ERROR);
54845876Sbostic 		if (_bt_getpage(t, pgno) == RET_ERROR)
54945876Sbostic 			return (RET_ERROR);
55045876Sbostic 	} else {
55145876Sbostic 		if (_bt_write(t, h, NORELEASE) == RET_ERROR)
55245876Sbostic 			return (RET_ERROR);
55345876Sbostic 	}
55445876Sbostic 
55545876Sbostic 	return (fsync(t->bt_s.bt_d.d_fd));
55645876Sbostic }
55745876Sbostic 
55845876Sbostic /*
55945876Sbostic  *  BT_SEQ -- Sequential scan interface.
56045876Sbostic  *
56145876Sbostic  *	This routine supports sequential scans on the btree.  If called with
56245876Sbostic  *	flags set to R_CURSOR, or if no seq scan has been initialized in the
56345876Sbostic  *	current tree, we initialize the scan.  Otherwise, we advance the scan
56445876Sbostic  *	and return the next item.
56545876Sbostic  *
56645876Sbostic  *	Scans can be either keyed or non-keyed.  Keyed scans basically have
56745876Sbostic  *	a starting point somewhere in the middle of the tree.  Non-keyed
56845876Sbostic  *	scans start at an endpoint.  Also, scans can be backward (descending
56945876Sbostic  *	order), forward (ascending order), or no movement (keep returning
57045876Sbostic  *	the same item).
57145876Sbostic  *
57245876Sbostic  *	Flags is checked every time we enter the routine, so the user can
57345876Sbostic  *	change directions on an active scan if desired.  The key argument
57445876Sbostic  *	is examined only when we initialize the scan, in order to position
57545876Sbostic  *	it properly.
57645876Sbostic  *
57745876Sbostic  *	Items are returned via the key and data arguments passed in.
57845876Sbostic  *
57945876Sbostic  *	Parameters:
58045876Sbostic  *		tree -- btree in which to do scan
58145876Sbostic  *		key -- key, used to position scan on initialization, and
58245876Sbostic  *		       used to return key components to the user.
58345876Sbostic  *		data -- used to return data components to the user.
58445876Sbostic  *		flags -- specify R_CURSOR, R_FIRST, R_LAST, R_NEXT, or
58545876Sbostic  *			 R_PREV.
58645876Sbostic  *
58745876Sbostic  *	Returns:
58845876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if no more data
58945876Sbostic  *		exists in the tree in the specified direction.
59045876Sbostic  *
59145876Sbostic  *	Side Effects:
59245876Sbostic  *		Changes the btree's notion of the current position in the
59345876Sbostic  *		scan.
59445876Sbostic  *
59545876Sbostic  *	Warnings:
59645876Sbostic  *		The key and data items returned are static and will be
59745876Sbostic  *		overwritten by the next bt_get or bt_seq.
59845876Sbostic  */
59945876Sbostic 
60046127Smao int
601*49322Sbostic bt_seq(dbp, key, data, flags)
602*49322Sbostic 	DB *dbp;
603*49322Sbostic 	DBT *key, *data;
60446570Sbostic 	u_long flags;
60545876Sbostic {
606*49322Sbostic 	BTREE_P t;
60745876Sbostic 	BTHEADER *h;
60845876Sbostic 	DATUM *d;
60945876Sbostic 	int status;
61045876Sbostic 
611*49322Sbostic 	t = (BTREE_P)dbp->internal;
612*49322Sbostic 
61345876Sbostic 	/* do we need to initialize the scan? */
61445876Sbostic 	if (flags == R_CURSOR || flags == R_LAST || flags == R_FIRST
61545876Sbostic 	    || !(t->bt_flags & BTF_SEQINIT)) {
61645876Sbostic 
61745876Sbostic 		/* initialize it */
61845876Sbostic 		status = _bt_seqinit(t, key, flags);
61945876Sbostic 	} else {
62045876Sbostic 		/* just advance the current scan pointer */
62145876Sbostic 		status = _bt_seqadvance(t, flags);
62245876Sbostic 	}
62345876Sbostic 
62445876Sbostic 	key->size = data->size = 0;
62546951Sbostic 	key->data = data->data = (u_char *) NULL;
62645876Sbostic 
62745876Sbostic 	h = t->bt_curpage;
62845876Sbostic 
62945876Sbostic 	/* is there a valid item at the current scan location? */
63045876Sbostic 	if (status == RET_SPECIAL) {
63145876Sbostic 		if (flags == R_NEXT) {
63245876Sbostic 			if (t->bt_cursor.c_index >= NEXTINDEX(h)) {
63345876Sbostic 				if (NEXTINDEX(h) > 0)
63445876Sbostic 					t->bt_cursor.c_index = NEXTINDEX(h) - 1;
63545876Sbostic 				else
63645876Sbostic 					t->bt_cursor.c_index = 0;
63745876Sbostic 			}
63845876Sbostic 		} else {
63945876Sbostic 			t->bt_cursor.c_index = 0;
64045876Sbostic 		}
64145876Sbostic 		return (RET_SPECIAL);
64245876Sbostic 	} else if (status == RET_ERROR)
64345876Sbostic 		return (RET_ERROR);
64445876Sbostic 
64545876Sbostic 	/* okay, return the data */
64645876Sbostic 	d = (DATUM *) GETDATUM(h, t->bt_cursor.c_index);
64745876Sbostic 
64845876Sbostic 	return (_bt_buildret(t, d, data, key));
64945876Sbostic }
65045876Sbostic 
65145876Sbostic /*
65245876Sbostic  *  BT_CLOSE -- Close a btree
65345876Sbostic  *
65445876Sbostic  *	Parameters:
65545876Sbostic  *		tree -- tree to close
65645876Sbostic  *
65745876Sbostic  *	Returns:
65845876Sbostic  *		RET_SUCCESS, RET_ERROR.
65945876Sbostic  *
66045876Sbostic  *	Side Effects:
66145876Sbostic  *		Frees space occupied by the tree.
66245876Sbostic  */
66345876Sbostic 
66445876Sbostic int
665*49322Sbostic bt_close(dbp)
666*49322Sbostic 	DB *dbp;
66745876Sbostic {
668*49322Sbostic 	struct HTBUCKET *b, *sb;
669*49322Sbostic 	BTREE_P t;
67045876Sbostic 	BTHEADER *h;
671*49322Sbostic 	HTABLE ht;
672*49322Sbostic 	int fd, i;
67345876Sbostic 	char *cache;
67445876Sbostic 
675*49322Sbostic 	t = (BTREE_P)dbp->internal;
676*49322Sbostic 
67745876Sbostic 	if (t->bt_cursor.c_key != (char *) NULL)
67845876Sbostic 		(void) free(t->bt_cursor.c_key);
67945876Sbostic 
68045876Sbostic 	if (!ISDISK(t)) {
68145876Sbostic 		/* in-memory tree, release hash table memory */
68245876Sbostic 		ht = t->bt_s.bt_ht;
68345876Sbostic 		for (i = 0; i < HTSIZE; i++) {
68445876Sbostic 			if ((b = ht[i]) == (struct HTBUCKET *) NULL)
68545876Sbostic 				break;
68645876Sbostic 			do {
68745876Sbostic 				sb = b;
68845876Sbostic 				(void) free((char *) b->ht_page);
68945876Sbostic 				b = b->ht_next;
69045876Sbostic 				(void) free((char *) sb);
69145876Sbostic 			} while (b != (struct HTBUCKET *) NULL);
69245876Sbostic 		}
69345876Sbostic 		(void) free ((char *) ht);
69445876Sbostic 		(void) free ((char *) t);
69545876Sbostic 		return (RET_SUCCESS);
69645876Sbostic 	}
69745876Sbostic 
69845876Sbostic 	if ((t->bt_flags & BTF_ISWRITE) && !(t->bt_flags & BTF_METAOK)) {
69945876Sbostic 		if (_bt_wrtmeta(t) == RET_ERROR)
70045876Sbostic 			return (RET_ERROR);
70145876Sbostic 	}
70245876Sbostic 
70345876Sbostic 	if (t->bt_curpage != (BTHEADER *) NULL) {
70445876Sbostic 		h = t->bt_curpage;
70545876Sbostic 		if (h->h_flags & F_DIRTY) {
70645876Sbostic 			if (_bt_write(t, h, RELEASE) == RET_ERROR)
70745876Sbostic 				return (RET_ERROR);
70845876Sbostic 		} else {
70945876Sbostic 			if (_bt_release(t, h) == RET_ERROR)
71045876Sbostic 				return (RET_ERROR);
71145876Sbostic 		}
71245876Sbostic 
71345876Sbostic 		/* flush and free the cache, if there is one */
71445876Sbostic 		if (ISCACHE(t)) {
71545876Sbostic 			cache = t->bt_s.bt_d.d_cache;
71646127Smao 			if (lrusync(cache) == RET_ERROR)
71746127Smao 				return (RET_ERROR);
71845876Sbostic 			lrufree(cache);
71945876Sbostic 		}
72045876Sbostic 		(void) free ((char *) h);
72145876Sbostic 	}
72245876Sbostic 
72345876Sbostic 	fd = t->bt_s.bt_d.d_fd;
72445876Sbostic 	(void) free ((char *) t);
72545876Sbostic 	return (close(fd));
72645876Sbostic }
727