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*46453Smao static char sccsid[] = "@(#)bt_open.c 5.4 (Berkeley) 02/18/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> 4246127Smao #include <sys/types.h> 4345876Sbostic #include <db.h> 4446127Smao #include "btree.h" 4545876Sbostic 4646127Smao 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 260*46453Smao /* access method files are always close-on-exec */ 261*46453Smao if (fcntl(t->bt_s.bt_d.d_fd, F_SETFL, 1) == -1) { 262*46453Smao (void) close(t->bt_s.bt_d.d_fd); 263*46453Smao (void) free ((char *) t); 264*46453Smao return ((BTREE) NULL); 265*46453Smao } 266*46453Smao 26745876Sbostic /* get number of pages, page size if necessary */ 26845876Sbostic (void) fstat(t->bt_s.bt_d.d_fd, &buf); 26945876Sbostic if (t->bt_psize == 0) 27045876Sbostic t->bt_psize = buf.st_blksize; 27145876Sbostic t->bt_npages = (pgno_t) (buf.st_size / t->bt_psize); 27245876Sbostic 27345876Sbostic /* page zero is metadata, doesn't count */ 27445876Sbostic if (t->bt_npages > 0) 27545876Sbostic --(t->bt_npages); 27645876Sbostic 27745876Sbostic if (b->cachesize == 0) 27845876Sbostic b->cachesize = DEFCACHE; 27945876Sbostic 28045876Sbostic /* get an lru buffer cache, if the user asked for one */ 28145876Sbostic if ((b->cachesize / t->bt_psize) > 0) { 28245876Sbostic BTDISK *d = &(t->bt_s.bt_d); 28345876Sbostic 28445876Sbostic d->d_cache = lruinit(d->d_fd, 28546127Smao (int) (b->cachesize / t->bt_psize), 28646127Smao (int) t->bt_psize, 28745876Sbostic (char *) t->bt_lorder, 28845876Sbostic _bt_pgin, _bt_pgout); 28945876Sbostic 29045876Sbostic if (d->d_cache == (char *) NULL) { 29145876Sbostic (void) free((char *) t); 29245876Sbostic return ((BTREE) NULL); 29345876Sbostic } 29445876Sbostic } 29545876Sbostic } 29645876Sbostic 29745876Sbostic /* remember if tree was opened for write */ 29845876Sbostic if (((flags & O_WRONLY) == O_WRONLY) 29945876Sbostic || ((flags & O_RDWR) == O_RDWR)) 30045876Sbostic t->bt_flags |= BTF_ISWRITE; 30145876Sbostic 30245876Sbostic return ((BTREE) t); 30345876Sbostic } 30445876Sbostic 30545876Sbostic /* 30645876Sbostic * BT_GET -- Get an entry from a btree. 30745876Sbostic * 30845876Sbostic * Does a key lookup in the tree to find the specified key, and returns 30945876Sbostic * the key/data pair found. 31045876Sbostic * 31145876Sbostic * Parameters: 31245876Sbostic * tree -- btree in which to do lookup 31345876Sbostic * key -- key to find 31445876Sbostic * data -- pointer to DBT in which to return data 31545876Sbostic * flag -- ignored 31645876Sbostic * 31745876Sbostic * Returns: 31845876Sbostic * RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the key is not 31945876Sbostic * found. If key is not found, nothing is stored in the 32045876Sbostic * return DBT 'data'. 32145876Sbostic * 32245876Sbostic * Side Effects: 32345876Sbostic * None. 32445876Sbostic * 32545876Sbostic * Warnings: 32645876Sbostic * Return data is statically allocated, and will be overwritten 32745876Sbostic * at the next call. 32845876Sbostic */ 32945876Sbostic 33045876Sbostic int 33145876Sbostic bt_get(tree, key, data, flag) 33245876Sbostic BTREE tree; 33345876Sbostic DBT *key; 33445876Sbostic DBT *data; 33545876Sbostic int flag; 33645876Sbostic { 33745876Sbostic BTREE_P t = (BTREE_P) tree; 33845876Sbostic BTHEADER *h; 33945876Sbostic DATUM *d; 34045876Sbostic BTITEM *item; 34145876Sbostic 34246127Smao #ifdef lint 34346127Smao flag = flag; 34446127Smao #endif /* lint */ 34546127Smao 34645876Sbostic /* lookup */ 34745876Sbostic item = _bt_search(t, key); 34845876Sbostic 34945876Sbostic /* clear parent pointer stack */ 35045876Sbostic while (_bt_pop(t) != P_NONE) 35145876Sbostic continue; 35245876Sbostic 353*46453Smao if (item == (BTITEM *) NULL) 354*46453Smao return (RET_ERROR); 355*46453Smao 35645876Sbostic h = (BTHEADER *) t->bt_curpage; 35745876Sbostic data->size = 0; 35845876Sbostic data->data = (char *) NULL; 35945876Sbostic 36045876Sbostic /* match? */ 36145876Sbostic if (VALIDITEM(t, item) 36245876Sbostic && _bt_cmp(t, key->data, item->bti_index) == 0) { 36345876Sbostic d = (DATUM *) GETDATUM(h, item->bti_index); 36445876Sbostic return (_bt_buildret(t, d, data, key)); 36545876Sbostic } 36645876Sbostic 36745876Sbostic /* nope */ 36845876Sbostic return (RET_SPECIAL); 36945876Sbostic } 37045876Sbostic 37145876Sbostic /* 37245876Sbostic * BT_PUT -- Add an entry to a btree. 37345876Sbostic * 37445876Sbostic * The specified (key, data) pair is added to the tree. If the tree 37545876Sbostic * was created for unique keys only, then duplicates will not be 37645876Sbostic * entered. If the requested key exists in the tree, it will be over- 37745876Sbostic * written unless the flags parameter is R_NOOVERWRITE, in which case 37845876Sbostic * the update will not be done. If duplicate keys are permitted in the 37945876Sbostic * tree, duplicates will be inserted and will not overwrite existing 38045876Sbostic * keys. Nodes are split as required. 38145876Sbostic * 38245876Sbostic * Parameters: 38345876Sbostic * tree -- btree in which to put the new entry 38445876Sbostic * key -- key component to add 38545876Sbostic * data -- data corresponding to key 38645876Sbostic * flag -- R_NOOVERWRITE or zero. 38745876Sbostic * 38845876Sbostic * Returns: 38945876Sbostic * RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the 39045876Sbostic * NOOVERWRITE flag was set and the specified key exists 39145876Sbostic * in the database. 39245876Sbostic * 39345876Sbostic * Side Effects: 39445876Sbostic * None. 39545876Sbostic */ 39645876Sbostic 39745876Sbostic int 39845876Sbostic bt_put(tree, key, data, flag) 39945876Sbostic BTREE tree; 40045876Sbostic DBT *key; 40145876Sbostic DBT *data; 40245876Sbostic int flag; 40345876Sbostic { 40445876Sbostic BTREE_P t = (BTREE_P) tree; 40545876Sbostic BTITEM *item; 40645876Sbostic 40745876Sbostic /* look for this key in the tree */ 40845876Sbostic item = _bt_search(t, key); 40945876Sbostic 41045876Sbostic /* 41145876Sbostic * If this tree was originally created without R_DUP, then duplicate 41245876Sbostic * keys are not allowed. We need to check this at insertion time. 41345876Sbostic */ 41445876Sbostic 41545876Sbostic if (VALIDITEM(t, item) && _bt_cmp(t, key->data, item->bti_index) == 0) { 41645876Sbostic if ((t->bt_flags & BTF_NODUPS) && flag == R_NOOVERWRITE) { 417*46453Smao if (_bt_delone(t, item->bti_index) == RET_ERROR) { 418*46453Smao while (_bt_pop(t) != P_NONE) 419*46453Smao continue; 42045876Sbostic return (RET_ERROR); 421*46453Smao } 42245876Sbostic } 42345876Sbostic } 42445876Sbostic 42545876Sbostic return (_bt_insert(t, item, key, data, flag)); 42645876Sbostic } 42745876Sbostic 42845876Sbostic /* 42945876Sbostic * BT_DELETE -- delete a key from the tree. 43045876Sbostic * 43145876Sbostic * Deletes all keys (and their associated data items) matching the 43245876Sbostic * supplied key from the tree. If the flags entry is R_CURSOR, then 43345876Sbostic * the current item in the active scan is deleted. 43445876Sbostic * 43545876Sbostic * Parameters: 43645876Sbostic * tree -- btree from which to delete key 43745876Sbostic * key -- key to delete 43845876Sbostic * flags -- R_CURSOR or zero 43945876Sbostic * 44045876Sbostic * Returns: 44145876Sbostic * RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the specified 44245876Sbostic * key was not in the tree. 44345876Sbostic * 44445876Sbostic * Side Effects: 44545876Sbostic * None. 44645876Sbostic */ 44745876Sbostic 44845876Sbostic int 44945876Sbostic bt_delete(tree, key, flags) 45045876Sbostic BTREE tree; 45145876Sbostic DBT *key; 45245876Sbostic int flags; 45345876Sbostic { 45445876Sbostic BTREE_P t = (BTREE_P) tree; 45545876Sbostic BTHEADER *h; 45645876Sbostic BTITEM *item; 45745876Sbostic int ndel = 0; 45845876Sbostic 45945876Sbostic if (flags == R_CURSOR) 46045876Sbostic return (_bt_crsrdel(t)); 46145876Sbostic 46245876Sbostic /* find the first matching key in the tree */ 46345876Sbostic item = _bt_first(t, key); 46445876Sbostic h = t->bt_curpage; 46545876Sbostic 466*46453Smao /* don't need the descent stack for deletes */ 467*46453Smao while (_bt_pop(t) != P_NONE) 468*46453Smao continue; 469*46453Smao 47045876Sbostic /* delete all matching keys */ 47145876Sbostic for (;;) { 47245876Sbostic while (VALIDITEM(t, item) 47345876Sbostic && (_bt_cmp(t, key->data, item->bti_index) == 0)) { 47445876Sbostic if (_bt_delone(t, item->bti_index) == RET_ERROR) 47545876Sbostic return (RET_ERROR); 47645876Sbostic ndel++; 47745876Sbostic } 47845876Sbostic 47945876Sbostic if (VALIDITEM(t, item) || h->h_nextpg == P_NONE) 48045876Sbostic break; 48145876Sbostic 48245876Sbostic /* next page, if necessary */ 48345876Sbostic do { 48445876Sbostic if (_bt_getpage(t, h->h_nextpg) == RET_ERROR) 48545876Sbostic return (RET_ERROR); 48645876Sbostic h = t->bt_curpage; 48745876Sbostic } while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE); 48845876Sbostic 48945876Sbostic item->bti_pgno = h->h_pgno; 49045876Sbostic item->bti_index = 0; 49145876Sbostic 49245876Sbostic if (!VALIDITEM(t, item) 49345876Sbostic || _bt_cmp(t, key->data, item->bti_index) != 0) 49445876Sbostic break; 49545876Sbostic } 49645876Sbostic 49745876Sbostic /* flush changes to disk */ 49845876Sbostic if (ISDISK(t)) { 49945876Sbostic if (h->h_flags & F_DIRTY) { 50045876Sbostic if (_bt_write(t, t->bt_curpage, NORELEASE) == RET_ERROR) 50145876Sbostic return (RET_ERROR); 50245876Sbostic } 50345876Sbostic } 50445876Sbostic 50545876Sbostic if (ndel == 0) 50645876Sbostic return (RET_SPECIAL); 50745876Sbostic 50845876Sbostic return (RET_SUCCESS); 50945876Sbostic } 51045876Sbostic 51145876Sbostic /* 51245876Sbostic * BT_SYNC -- sync the btree to disk. 51345876Sbostic * 51445876Sbostic * Parameters: 51545876Sbostic * tree -- btree to sync. 51645876Sbostic * 51745876Sbostic * Returns: 51845876Sbostic * RET_SUCCESS, RET_ERROR. 51945876Sbostic */ 52045876Sbostic 52145876Sbostic bt_sync(tree) 52245876Sbostic BTREE tree; 52345876Sbostic { 52445876Sbostic BTREE_P t = (BTREE_P) tree; 52545876Sbostic BTHEADER *h; 52645876Sbostic pgno_t pgno; 52745876Sbostic 52845876Sbostic /* if this is an in-memory btree, syncing is a no-op */ 52945876Sbostic if (!ISDISK(t)) 53045876Sbostic return (RET_SUCCESS); 53145876Sbostic 53245876Sbostic h = (BTHEADER *) t->bt_curpage; 53345876Sbostic h->h_flags &= ~F_DIRTY; 53445876Sbostic 53545876Sbostic if (ISCACHE(t)) { 53645876Sbostic pgno = t->bt_curpage->h_pgno; 53745876Sbostic if (_bt_write(t, h, RELEASE) == RET_ERROR) 53845876Sbostic return(RET_ERROR); 53945876Sbostic if (lrusync(t->bt_s.bt_d.d_cache) < RET_ERROR) 54045876Sbostic return (RET_ERROR); 54145876Sbostic if (_bt_getpage(t, pgno) == RET_ERROR) 54245876Sbostic return (RET_ERROR); 54345876Sbostic } else { 54445876Sbostic if (_bt_write(t, h, NORELEASE) == RET_ERROR) 54545876Sbostic return (RET_ERROR); 54645876Sbostic } 54745876Sbostic 54845876Sbostic return (fsync(t->bt_s.bt_d.d_fd)); 54945876Sbostic } 55045876Sbostic 55145876Sbostic /* 55245876Sbostic * BT_SEQ -- Sequential scan interface. 55345876Sbostic * 55445876Sbostic * This routine supports sequential scans on the btree. If called with 55545876Sbostic * flags set to R_CURSOR, or if no seq scan has been initialized in the 55645876Sbostic * current tree, we initialize the scan. Otherwise, we advance the scan 55745876Sbostic * and return the next item. 55845876Sbostic * 55945876Sbostic * Scans can be either keyed or non-keyed. Keyed scans basically have 56045876Sbostic * a starting point somewhere in the middle of the tree. Non-keyed 56145876Sbostic * scans start at an endpoint. Also, scans can be backward (descending 56245876Sbostic * order), forward (ascending order), or no movement (keep returning 56345876Sbostic * the same item). 56445876Sbostic * 56545876Sbostic * Flags is checked every time we enter the routine, so the user can 56645876Sbostic * change directions on an active scan if desired. The key argument 56745876Sbostic * is examined only when we initialize the scan, in order to position 56845876Sbostic * it properly. 56945876Sbostic * 57045876Sbostic * Items are returned via the key and data arguments passed in. 57145876Sbostic * 57245876Sbostic * Parameters: 57345876Sbostic * tree -- btree in which to do scan 57445876Sbostic * key -- key, used to position scan on initialization, and 57545876Sbostic * used to return key components to the user. 57645876Sbostic * data -- used to return data components to the user. 57745876Sbostic * flags -- specify R_CURSOR, R_FIRST, R_LAST, R_NEXT, or 57845876Sbostic * R_PREV. 57945876Sbostic * 58045876Sbostic * Returns: 58145876Sbostic * RET_SUCCESS, RET_ERROR, or RET_SPECIAL if no more data 58245876Sbostic * exists in the tree in the specified direction. 58345876Sbostic * 58445876Sbostic * Side Effects: 58545876Sbostic * Changes the btree's notion of the current position in the 58645876Sbostic * scan. 58745876Sbostic * 58845876Sbostic * Warnings: 58945876Sbostic * The key and data items returned are static and will be 59045876Sbostic * overwritten by the next bt_get or bt_seq. 59145876Sbostic */ 59245876Sbostic 59346127Smao int 59445876Sbostic bt_seq(tree, key, data, flags) 59545876Sbostic BTREE tree; 59645876Sbostic DBT *key; 59745876Sbostic DBT *data; 59845876Sbostic int flags; 59945876Sbostic { 60045876Sbostic BTREE_P t = (BTREE_P) tree; 60145876Sbostic BTHEADER *h; 60245876Sbostic DATUM *d; 60345876Sbostic int status; 60445876Sbostic 60545876Sbostic /* do we need to initialize the scan? */ 60645876Sbostic if (flags == R_CURSOR || flags == R_LAST || flags == R_FIRST 60745876Sbostic || !(t->bt_flags & BTF_SEQINIT)) { 60845876Sbostic 60945876Sbostic /* initialize it */ 61045876Sbostic status = _bt_seqinit(t, key, flags); 61145876Sbostic } else { 61245876Sbostic /* just advance the current scan pointer */ 61345876Sbostic status = _bt_seqadvance(t, flags); 61445876Sbostic } 61545876Sbostic 61645876Sbostic key->size = data->size = 0; 61745876Sbostic key->data = data->data = (char *) NULL; 61845876Sbostic 61945876Sbostic h = t->bt_curpage; 62045876Sbostic 62145876Sbostic /* is there a valid item at the current scan location? */ 62245876Sbostic if (status == RET_SPECIAL) { 62345876Sbostic if (flags == R_NEXT) { 62445876Sbostic if (t->bt_cursor.c_index >= NEXTINDEX(h)) { 62545876Sbostic if (NEXTINDEX(h) > 0) 62645876Sbostic t->bt_cursor.c_index = NEXTINDEX(h) - 1; 62745876Sbostic else 62845876Sbostic t->bt_cursor.c_index = 0; 62945876Sbostic } 63045876Sbostic } else { 63145876Sbostic t->bt_cursor.c_index = 0; 63245876Sbostic } 63345876Sbostic return (RET_SPECIAL); 63445876Sbostic } else if (status == RET_ERROR) 63545876Sbostic return (RET_ERROR); 63645876Sbostic 63745876Sbostic /* okay, return the data */ 63845876Sbostic d = (DATUM *) GETDATUM(h, t->bt_cursor.c_index); 63945876Sbostic 64045876Sbostic return (_bt_buildret(t, d, data, key)); 64145876Sbostic } 64245876Sbostic 64345876Sbostic /* 64445876Sbostic * BT_CLOSE -- Close a btree 64545876Sbostic * 64645876Sbostic * Parameters: 64745876Sbostic * tree -- tree to close 64845876Sbostic * 64945876Sbostic * Returns: 65045876Sbostic * RET_SUCCESS, RET_ERROR. 65145876Sbostic * 65245876Sbostic * Side Effects: 65345876Sbostic * Frees space occupied by the tree. 65445876Sbostic */ 65545876Sbostic 65645876Sbostic int 65745876Sbostic bt_close(tree) 65845876Sbostic BTREE tree; 65945876Sbostic { 66045876Sbostic BTREE_P t = (BTREE_P) tree; 66145876Sbostic int i; 66245876Sbostic BTHEADER *h; 66345876Sbostic char *cache; 66445876Sbostic struct HTBUCKET *b, *sb; 66545876Sbostic HTABLE ht; 66645876Sbostic int fd; 66745876Sbostic 66845876Sbostic if (t->bt_cursor.c_key != (char *) NULL) 66945876Sbostic (void) free(t->bt_cursor.c_key); 67045876Sbostic 67145876Sbostic if (!ISDISK(t)) { 67245876Sbostic /* in-memory tree, release hash table memory */ 67345876Sbostic ht = t->bt_s.bt_ht; 67445876Sbostic for (i = 0; i < HTSIZE; i++) { 67545876Sbostic if ((b = ht[i]) == (struct HTBUCKET *) NULL) 67645876Sbostic break; 67745876Sbostic do { 67845876Sbostic sb = b; 67945876Sbostic (void) free((char *) b->ht_page); 68045876Sbostic b = b->ht_next; 68145876Sbostic (void) free((char *) sb); 68245876Sbostic } while (b != (struct HTBUCKET *) NULL); 68345876Sbostic } 68445876Sbostic (void) free ((char *) ht); 68545876Sbostic (void) free ((char *) t); 68645876Sbostic return (RET_SUCCESS); 68745876Sbostic } 68845876Sbostic 68945876Sbostic if ((t->bt_flags & BTF_ISWRITE) && !(t->bt_flags & BTF_METAOK)) { 69045876Sbostic if (_bt_wrtmeta(t) == RET_ERROR) 69145876Sbostic return (RET_ERROR); 69245876Sbostic } 69345876Sbostic 69445876Sbostic if (t->bt_curpage != (BTHEADER *) NULL) { 69545876Sbostic h = t->bt_curpage; 69645876Sbostic if (h->h_flags & F_DIRTY) { 69745876Sbostic if (_bt_write(t, h, RELEASE) == RET_ERROR) 69845876Sbostic return (RET_ERROR); 69945876Sbostic } else { 70045876Sbostic if (_bt_release(t, h) == RET_ERROR) 70145876Sbostic return (RET_ERROR); 70245876Sbostic } 70345876Sbostic 70445876Sbostic /* flush and free the cache, if there is one */ 70545876Sbostic if (ISCACHE(t)) { 70645876Sbostic cache = t->bt_s.bt_d.d_cache; 70746127Smao if (lrusync(cache) == RET_ERROR) 70846127Smao return (RET_ERROR); 70945876Sbostic lrufree(cache); 71045876Sbostic } 71145876Sbostic (void) free ((char *) h); 71245876Sbostic } 71345876Sbostic 71445876Sbostic fd = t->bt_s.bt_d.d_fd; 71545876Sbostic (void) free ((char *) t); 71645876Sbostic return (close(fd)); 71745876Sbostic } 718