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