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