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