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