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