xref: /csrg-svn/lib/libc/db/btree/bt_open.c (revision 47729)
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*47729Sbostic static char sccsid[] = "@(#)bt_open.c	5.8 (Berkeley) 04/02/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;
101*47729Sbostic 	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
33445876Sbostic bt_get(tree, key, data, flag)
33545876Sbostic 	BTREE tree;
33645876Sbostic 	DBT *key;
33745876Sbostic 	DBT *data;
33846570Sbostic 	u_long flag;
33945876Sbostic {
34045876Sbostic 	BTREE_P t = (BTREE_P) tree;
34145876Sbostic 	BTHEADER *h;
34245876Sbostic 	DATUM *d;
34345876Sbostic 	BTITEM *item;
34445876Sbostic 
34546127Smao #ifdef lint
34646127Smao 	flag = flag;
34746127Smao #endif /* lint */
34846127Smao 
34945876Sbostic 	/* lookup */
35045876Sbostic 	item = _bt_search(t, key);
35145876Sbostic 
35245876Sbostic 	/* clear parent pointer stack */
35345876Sbostic 	while (_bt_pop(t) != P_NONE)
35445876Sbostic 		continue;
35545876Sbostic 
35646453Smao 	if (item == (BTITEM *) NULL)
35746453Smao 		return (RET_ERROR);
35846453Smao 
35945876Sbostic 	h = (BTHEADER *) t->bt_curpage;
36045876Sbostic 	data->size = 0;
36146951Sbostic 	data->data = (u_char *) NULL;
36245876Sbostic 
36345876Sbostic 	/* match? */
36445876Sbostic 	if (VALIDITEM(t, item)
36545876Sbostic 	    && _bt_cmp(t, key->data, item->bti_index) == 0) {
36645876Sbostic 		d = (DATUM *) GETDATUM(h, item->bti_index);
36745876Sbostic 		return (_bt_buildret(t, d, data, key));
36845876Sbostic 	}
36945876Sbostic 
37045876Sbostic 	/* nope */
37145876Sbostic 	return (RET_SPECIAL);
37245876Sbostic }
37345876Sbostic 
37445876Sbostic /*
37545876Sbostic  *  BT_PUT -- Add an entry to a btree.
37645876Sbostic  *
37745876Sbostic  *	The specified (key, data) pair is added to the tree.  If the tree
37845876Sbostic  *	was created for unique keys only, then duplicates will not be
37945876Sbostic  *	entered.  If the requested key exists in the tree, it will be over-
38045876Sbostic  *	written unless the flags parameter is R_NOOVERWRITE, in which case
38145876Sbostic  *	the update will not be done.  If duplicate keys are permitted in the
38245876Sbostic  *	tree, duplicates will be inserted and will not overwrite existing
38345876Sbostic  *	keys.  Nodes are split as required.
38445876Sbostic  *
38545876Sbostic  *	Parameters:
38645876Sbostic  *		tree -- btree in which to put the new entry
38745876Sbostic  *		key -- key component to add
38845876Sbostic  *		data -- data corresponding to key
38945876Sbostic  *		flag -- R_NOOVERWRITE or zero.
39045876Sbostic  *
39145876Sbostic  *	Returns:
39245876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the
39345876Sbostic  *		NOOVERWRITE flag was set and the specified key exists
39445876Sbostic  *		in the database.
39545876Sbostic  *
39645876Sbostic  *	Side Effects:
39745876Sbostic  *		None.
39845876Sbostic  */
39945876Sbostic 
40045876Sbostic int
40145876Sbostic bt_put(tree, key, data, flag)
40245876Sbostic 	BTREE tree;
40345876Sbostic 	DBT *key;
40445876Sbostic 	DBT *data;
40546570Sbostic 	u_long flag;
40645876Sbostic {
40745876Sbostic 	BTREE_P t = (BTREE_P) tree;
40845876Sbostic 	BTITEM *item;
40945876Sbostic 
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
45245876Sbostic bt_delete(tree, key, flags)
45345876Sbostic 	BTREE tree;
45445876Sbostic 	DBT *key;
45546570Sbostic 	u_long flags;
45645876Sbostic {
45745876Sbostic 	BTREE_P t = (BTREE_P) tree;
45845876Sbostic 	BTHEADER *h;
45945876Sbostic 	BTITEM *item;
46045876Sbostic 	int ndel = 0;
46145876Sbostic 
46245876Sbostic 	if (flags == R_CURSOR)
46345876Sbostic 		return (_bt_crsrdel(t));
46445876Sbostic 
46545876Sbostic 	/* find the first matching key in the tree */
46645876Sbostic 	item = _bt_first(t, key);
46745876Sbostic 	h = t->bt_curpage;
46845876Sbostic 
46946453Smao 	/* don't need the descent stack for deletes */
47046453Smao 	while (_bt_pop(t) != P_NONE)
47146453Smao 		continue;
47246453Smao 
47345876Sbostic 	/* delete all matching keys */
47445876Sbostic 	for (;;) {
47545876Sbostic 		while (VALIDITEM(t, item)
47645876Sbostic 		       && (_bt_cmp(t, key->data, item->bti_index) == 0)) {
47745876Sbostic 			if (_bt_delone(t, item->bti_index) == RET_ERROR)
47845876Sbostic 				return (RET_ERROR);
47945876Sbostic 			ndel++;
48045876Sbostic 		}
48145876Sbostic 
48245876Sbostic 		if (VALIDITEM(t, item) || h->h_nextpg == P_NONE)
48345876Sbostic 			break;
48445876Sbostic 
48545876Sbostic 		/* next page, if necessary */
48645876Sbostic 		do {
48745876Sbostic 			if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
48845876Sbostic 				return (RET_ERROR);
48945876Sbostic 			h = t->bt_curpage;
49045876Sbostic 		} while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE);
49145876Sbostic 
49245876Sbostic 		item->bti_pgno = h->h_pgno;
49345876Sbostic 		item->bti_index = 0;
49445876Sbostic 
49545876Sbostic 		if (!VALIDITEM(t, item)
49645876Sbostic 		    || _bt_cmp(t, key->data, item->bti_index) != 0)
49745876Sbostic 			break;
49845876Sbostic 	}
49945876Sbostic 
50045876Sbostic 	/* flush changes to disk */
50145876Sbostic 	if (ISDISK(t)) {
50245876Sbostic 		if (h->h_flags & F_DIRTY) {
50345876Sbostic 			if (_bt_write(t, t->bt_curpage, NORELEASE) == RET_ERROR)
50445876Sbostic 				return (RET_ERROR);
50545876Sbostic 		}
50645876Sbostic 	}
50745876Sbostic 
50845876Sbostic 	if (ndel == 0)
50945876Sbostic 		return (RET_SPECIAL);
51045876Sbostic 
51145876Sbostic 	return (RET_SUCCESS);
51245876Sbostic }
51345876Sbostic 
51445876Sbostic /*
51545876Sbostic  *  BT_SYNC -- sync the btree to disk.
51645876Sbostic  *
51745876Sbostic  *	Parameters:
51845876Sbostic  *		tree -- btree to sync.
51945876Sbostic  *
52045876Sbostic  *	Returns:
52145876Sbostic  *		RET_SUCCESS, RET_ERROR.
52245876Sbostic  */
52345876Sbostic 
52445876Sbostic bt_sync(tree)
52545876Sbostic 	BTREE tree;
52645876Sbostic {
52745876Sbostic 	BTREE_P t = (BTREE_P) tree;
52845876Sbostic 	BTHEADER *h;
52945876Sbostic 	pgno_t pgno;
53045876Sbostic 
53145876Sbostic 	/* if this is an in-memory btree, syncing is a no-op */
53245876Sbostic 	if (!ISDISK(t))
53345876Sbostic 		return (RET_SUCCESS);
53445876Sbostic 
53545876Sbostic 	h = (BTHEADER *) t->bt_curpage;
53645876Sbostic 	h->h_flags &= ~F_DIRTY;
53745876Sbostic 
53845876Sbostic 	if (ISCACHE(t)) {
53945876Sbostic 		pgno = t->bt_curpage->h_pgno;
54045876Sbostic 		if (_bt_write(t, h, RELEASE) == RET_ERROR)
54145876Sbostic 			return(RET_ERROR);
54245876Sbostic 		if (lrusync(t->bt_s.bt_d.d_cache) < RET_ERROR)
54345876Sbostic 			return (RET_ERROR);
54445876Sbostic 		if (_bt_getpage(t, pgno) == RET_ERROR)
54545876Sbostic 			return (RET_ERROR);
54645876Sbostic 	} else {
54745876Sbostic 		if (_bt_write(t, h, NORELEASE) == RET_ERROR)
54845876Sbostic 			return (RET_ERROR);
54945876Sbostic 	}
55045876Sbostic 
55145876Sbostic 	return (fsync(t->bt_s.bt_d.d_fd));
55245876Sbostic }
55345876Sbostic 
55445876Sbostic /*
55545876Sbostic  *  BT_SEQ -- Sequential scan interface.
55645876Sbostic  *
55745876Sbostic  *	This routine supports sequential scans on the btree.  If called with
55845876Sbostic  *	flags set to R_CURSOR, or if no seq scan has been initialized in the
55945876Sbostic  *	current tree, we initialize the scan.  Otherwise, we advance the scan
56045876Sbostic  *	and return the next item.
56145876Sbostic  *
56245876Sbostic  *	Scans can be either keyed or non-keyed.  Keyed scans basically have
56345876Sbostic  *	a starting point somewhere in the middle of the tree.  Non-keyed
56445876Sbostic  *	scans start at an endpoint.  Also, scans can be backward (descending
56545876Sbostic  *	order), forward (ascending order), or no movement (keep returning
56645876Sbostic  *	the same item).
56745876Sbostic  *
56845876Sbostic  *	Flags is checked every time we enter the routine, so the user can
56945876Sbostic  *	change directions on an active scan if desired.  The key argument
57045876Sbostic  *	is examined only when we initialize the scan, in order to position
57145876Sbostic  *	it properly.
57245876Sbostic  *
57345876Sbostic  *	Items are returned via the key and data arguments passed in.
57445876Sbostic  *
57545876Sbostic  *	Parameters:
57645876Sbostic  *		tree -- btree in which to do scan
57745876Sbostic  *		key -- key, used to position scan on initialization, and
57845876Sbostic  *		       used to return key components to the user.
57945876Sbostic  *		data -- used to return data components to the user.
58045876Sbostic  *		flags -- specify R_CURSOR, R_FIRST, R_LAST, R_NEXT, or
58145876Sbostic  *			 R_PREV.
58245876Sbostic  *
58345876Sbostic  *	Returns:
58445876Sbostic  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if no more data
58545876Sbostic  *		exists in the tree in the specified direction.
58645876Sbostic  *
58745876Sbostic  *	Side Effects:
58845876Sbostic  *		Changes the btree's notion of the current position in the
58945876Sbostic  *		scan.
59045876Sbostic  *
59145876Sbostic  *	Warnings:
59245876Sbostic  *		The key and data items returned are static and will be
59345876Sbostic  *		overwritten by the next bt_get or bt_seq.
59445876Sbostic  */
59545876Sbostic 
59646127Smao int
59745876Sbostic bt_seq(tree, key, data, flags)
59845876Sbostic 	BTREE tree;
59945876Sbostic 	DBT *key;
60045876Sbostic 	DBT *data;
60146570Sbostic 	u_long flags;
60245876Sbostic {
60345876Sbostic 	BTREE_P t = (BTREE_P) tree;
60445876Sbostic 	BTHEADER *h;
60545876Sbostic 	DATUM *d;
60645876Sbostic 	int status;
60745876Sbostic 
60845876Sbostic 	/* do we need to initialize the scan? */
60945876Sbostic 	if (flags == R_CURSOR || flags == R_LAST || flags == R_FIRST
61045876Sbostic 	    || !(t->bt_flags & BTF_SEQINIT)) {
61145876Sbostic 
61245876Sbostic 		/* initialize it */
61345876Sbostic 		status = _bt_seqinit(t, key, flags);
61445876Sbostic 	} else {
61545876Sbostic 		/* just advance the current scan pointer */
61645876Sbostic 		status = _bt_seqadvance(t, flags);
61745876Sbostic 	}
61845876Sbostic 
61945876Sbostic 	key->size = data->size = 0;
62046951Sbostic 	key->data = data->data = (u_char *) NULL;
62145876Sbostic 
62245876Sbostic 	h = t->bt_curpage;
62345876Sbostic 
62445876Sbostic 	/* is there a valid item at the current scan location? */
62545876Sbostic 	if (status == RET_SPECIAL) {
62645876Sbostic 		if (flags == R_NEXT) {
62745876Sbostic 			if (t->bt_cursor.c_index >= NEXTINDEX(h)) {
62845876Sbostic 				if (NEXTINDEX(h) > 0)
62945876Sbostic 					t->bt_cursor.c_index = NEXTINDEX(h) - 1;
63045876Sbostic 				else
63145876Sbostic 					t->bt_cursor.c_index = 0;
63245876Sbostic 			}
63345876Sbostic 		} else {
63445876Sbostic 			t->bt_cursor.c_index = 0;
63545876Sbostic 		}
63645876Sbostic 		return (RET_SPECIAL);
63745876Sbostic 	} else if (status == RET_ERROR)
63845876Sbostic 		return (RET_ERROR);
63945876Sbostic 
64045876Sbostic 	/* okay, return the data */
64145876Sbostic 	d = (DATUM *) GETDATUM(h, t->bt_cursor.c_index);
64245876Sbostic 
64345876Sbostic 	return (_bt_buildret(t, d, data, key));
64445876Sbostic }
64545876Sbostic 
64645876Sbostic /*
64745876Sbostic  *  BT_CLOSE -- Close a btree
64845876Sbostic  *
64945876Sbostic  *	Parameters:
65045876Sbostic  *		tree -- tree to close
65145876Sbostic  *
65245876Sbostic  *	Returns:
65345876Sbostic  *		RET_SUCCESS, RET_ERROR.
65445876Sbostic  *
65545876Sbostic  *	Side Effects:
65645876Sbostic  *		Frees space occupied by the tree.
65745876Sbostic  */
65845876Sbostic 
65945876Sbostic int
66045876Sbostic bt_close(tree)
66145876Sbostic 	BTREE tree;
66245876Sbostic {
66345876Sbostic 	BTREE_P t = (BTREE_P) tree;
66445876Sbostic 	int i;
66545876Sbostic 	BTHEADER *h;
66645876Sbostic 	char *cache;
66745876Sbostic 	struct HTBUCKET *b, *sb;
66845876Sbostic 	HTABLE ht;
66945876Sbostic 	int fd;
67045876Sbostic 
67145876Sbostic 	if (t->bt_cursor.c_key != (char *) NULL)
67245876Sbostic 		(void) free(t->bt_cursor.c_key);
67345876Sbostic 
67445876Sbostic 	if (!ISDISK(t)) {
67545876Sbostic 		/* in-memory tree, release hash table memory */
67645876Sbostic 		ht = t->bt_s.bt_ht;
67745876Sbostic 		for (i = 0; i < HTSIZE; i++) {
67845876Sbostic 			if ((b = ht[i]) == (struct HTBUCKET *) NULL)
67945876Sbostic 				break;
68045876Sbostic 			do {
68145876Sbostic 				sb = b;
68245876Sbostic 				(void) free((char *) b->ht_page);
68345876Sbostic 				b = b->ht_next;
68445876Sbostic 				(void) free((char *) sb);
68545876Sbostic 			} while (b != (struct HTBUCKET *) NULL);
68645876Sbostic 		}
68745876Sbostic 		(void) free ((char *) ht);
68845876Sbostic 		(void) free ((char *) t);
68945876Sbostic 		return (RET_SUCCESS);
69045876Sbostic 	}
69145876Sbostic 
69245876Sbostic 	if ((t->bt_flags & BTF_ISWRITE) && !(t->bt_flags & BTF_METAOK)) {
69345876Sbostic 		if (_bt_wrtmeta(t) == RET_ERROR)
69445876Sbostic 			return (RET_ERROR);
69545876Sbostic 	}
69645876Sbostic 
69745876Sbostic 	if (t->bt_curpage != (BTHEADER *) NULL) {
69845876Sbostic 		h = t->bt_curpage;
69945876Sbostic 		if (h->h_flags & F_DIRTY) {
70045876Sbostic 			if (_bt_write(t, h, RELEASE) == RET_ERROR)
70145876Sbostic 				return (RET_ERROR);
70245876Sbostic 		} else {
70345876Sbostic 			if (_bt_release(t, h) == RET_ERROR)
70445876Sbostic 				return (RET_ERROR);
70545876Sbostic 		}
70645876Sbostic 
70745876Sbostic 		/* flush and free the cache, if there is one */
70845876Sbostic 		if (ISCACHE(t)) {
70945876Sbostic 			cache = t->bt_s.bt_d.d_cache;
71046127Smao 			if (lrusync(cache) == RET_ERROR)
71146127Smao 				return (RET_ERROR);
71245876Sbostic 			lrufree(cache);
71345876Sbostic 		}
71445876Sbostic 		(void) free ((char *) h);
71545876Sbostic 	}
71645876Sbostic 
71745876Sbostic 	fd = t->bt_s.bt_d.d_fd;
71845876Sbostic 	(void) free ((char *) t);
71945876Sbostic 	return (close(fd));
72045876Sbostic }
721