123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /* $XConsortium: bt_put.c /main/3 1996/06/11 17:12:56 cde-hal $ */
- /*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Olson.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #if defined(LIBC_SCCS) && !defined(lint)
- static char sccsid[] = "@(#)bt_put.c 8.2 (Berkeley) 9/7/93";
- #endif /* LIBC_SCCS and not lint */
- #include <sys/types.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <db.h>
- #include "btree.h"
- static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
- /*
- * __BT_PUT -- Add a btree item to the tree.
- *
- * Parameters:
- * dbp: pointer to access method
- * key: key
- * data: data
- * flag: R_NOOVERWRITE
- *
- * Returns:
- * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
- * tree and R_NOOVERWRITE specified.
- */
- int
- __bt_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
- {
- BTREE *t;
- DBT tkey, tdata;
- EPG *e = NULL;
- PAGE *h;
- indx_t index, nxtindex;
- pgno_t pg;
- size_t nbytes;
- int dflags, exact, status;
- char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
- t = dbp->internal;
- /* Toss any page pinned across calls. */
- if (t->bt_pinned != NULL) {
- mpool_put(t->bt_mp, t->bt_pinned, 0);
- t->bt_pinned = NULL;
- }
- switch (flags) {
- case R_CURSOR:
- if (!ISSET(t, B_SEQINIT))
- goto einval;
- if (ISSET(t, B_DELCRSR))
- goto einval;
- break;
- case 0:
- case R_NOOVERWRITE:
- break;
- default:
- einval: errno = EINVAL;
- return (RET_ERROR);
- }
- if (ISSET(t, B_RDONLY)) {
- errno = EPERM;
- return (RET_ERROR);
- }
- /*
- * If the key/data won't fit on a page, store it on indirect pages.
- * Only store the key on the overflow page if it's too big after the
- * data is on an overflow page.
- *
- * XXX
- * If the insert fails later on, these pages aren't recovered.
- */
- dflags = 0;
- if (key->size + data->size > t->bt_ovflsize) {
- if (key->size > t->bt_ovflsize) {
- storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR)
- return (RET_ERROR);
- tkey.data = kb;
- tkey.size = NOVFLSIZE;
- memmove(kb, &pg, sizeof(pgno_t));
- memmove(kb + sizeof(pgno_t),
- &key->size, sizeof(size_t));
- dflags |= P_BIGKEY;
- key = &tkey;
- }
- if (key->size + data->size > t->bt_ovflsize) {
- if (__ovfl_put(t, data, &pg) == RET_ERROR)
- return (RET_ERROR);
- tdata.data = db;
- tdata.size = NOVFLSIZE;
- memmove(db, &pg, sizeof(pgno_t));
- memmove(db + sizeof(pgno_t),
- &data->size, sizeof(size_t));
- dflags |= P_BIGDATA;
- data = &tdata;
- }
- if (key->size + data->size > t->bt_ovflsize)
- goto storekey;
- }
- /* Replace the cursor. */
- if (flags == R_CURSOR) {
- if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL)
- return (RET_ERROR);
- index = t->bt_bcursor.index;
- goto delete;
- }
- /*
- * Find the key to delete, or, the location at which to insert. Bt_fast
- * and __bt_search pin the returned page.
- */
- if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
- if ((e = __bt_search(t, key, &exact)) == NULL)
- return (RET_ERROR);
- h = e->page;
- index = e->index;
- /*
- * Add the specified key/data pair to the tree. If an identical key
- * is already in the tree, and R_NOOVERWRITE is set, an error is
- * returned. If R_NOOVERWRITE is not set, the key is either added (if
- * duplicates are permitted) or an error is returned.
- *
- * Pages are split as required.
- */
- switch (flags) {
- case R_NOOVERWRITE:
- if (!exact)
- break;
- /*
- * One special case is if the cursor references the record and
- * it's been flagged for deletion. Then, we delete the record,
- * leaving the cursor there -- this means that the inserted
- * record will not be seen in a cursor scan.
- */
- if (ISSET(t, B_DELCRSR) && t->bt_bcursor.pgno == h->pgno &&
- t->bt_bcursor.index == index) {
- CLR(t, B_DELCRSR);
- goto delete;
- }
- mpool_put(t->bt_mp, h, 0);
- return (RET_SPECIAL);
- default:
- if (!exact || !ISSET(t, B_NODUPS))
- break;
- delete: if (__bt_dleaf(t, h, index) == RET_ERROR) {
- mpool_put(t->bt_mp, h, 0);
- return (RET_ERROR);
- }
- break;
- }
- /*
- * If not enough room, or the user has put a ceiling on the number of
- * keys permitted in the page, split the page. The split code will
- * insert the key and data and unpin the current page. If inserting
- * into the offset array, shift the pointers up.
- */
- nbytes = NBLEAFDBT(key->size, data->size);
- if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
- if ((status = __bt_split(t, h, key,
- data, dflags, nbytes, index)) != RET_SUCCESS)
- return (status);
- goto success;
- }
- if (index < (nxtindex = NEXTINDEX(h)))
- memmove(h->linp + index + 1, h->linp + index,
- (nxtindex - index) * sizeof(indx_t));
- h->lower += sizeof(indx_t);
- h->linp[index] = h->upper -= nbytes;
- dest = (char *)h + h->upper;
- WR_BLEAF(dest, key, data, dflags);
- if (t->bt_order == NOT) {
- if (h->nextpg == P_INVALID) {
- if (index == NEXTINDEX(h) - 1) {
- t->bt_order = FORWARD;
- t->bt_last.index = index;
- t->bt_last.pgno = h->pgno;
- }
- } else if (h->prevpg == P_INVALID) {
- if (index == 0) {
- t->bt_order = BACK;
- t->bt_last.index = 0;
- t->bt_last.pgno = h->pgno;
- }
- }
- }
- mpool_put(t->bt_mp, h, MPOOL_DIRTY);
- success:
- if (flags == R_SETCURSOR) {
- t->bt_bcursor.pgno = e->page->pgno;
- t->bt_bcursor.index = e->index;
- }
- SET(t, B_MODIFIED);
- return (RET_SUCCESS);
- }
- #ifdef STATISTICS
- u_long bt_cache_hit, bt_cache_miss;
- #endif
- /*
- * BT_FAST -- Do a quick check for sorted data.
- *
- * Parameters:
- * t: tree
- * key: key to insert
- *
- * Returns:
- * EPG for new record or NULL if not found.
- */
- static EPG *
- bt_fast(BTREE *t, const DBT *key, const DBT *data, int *exactp)
- {
- static EPG e;
- PAGE *h;
- size_t nbytes;
- int cmp;
- if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
- t->bt_order = NOT;
- return (NULL);
- }
- e.page = h;
- e.index = t->bt_last.index;
- /*
- * If won't fit in this page or have too many keys in this page, have
- * to search to get split stack.
- */
- nbytes = NBLEAFDBT(key->size, data->size);
- if (h->upper - h->lower < nbytes + sizeof(indx_t))
- goto miss;
- if (t->bt_order == FORWARD) {
- if (e.page->nextpg != P_INVALID)
- goto miss;
- if (e.index != NEXTINDEX(h) - 1)
- goto miss;
- if ((cmp = __bt_cmp(t, key, &e)) < 0)
- goto miss;
- t->bt_last.index = cmp ? ++e.index : e.index;
- } else {
- if (e.page->prevpg != P_INVALID)
- goto miss;
- if (e.index != 0)
- goto miss;
- if ((cmp = __bt_cmp(t, key, &e)) > 0)
- goto miss;
- t->bt_last.index = 0;
- }
- *exactp = cmp == 0;
- #ifdef STATISTICS
- ++bt_cache_hit;
- #endif
- return (&e);
- miss:
- #ifdef STATISTICS
- ++bt_cache_miss;
- #endif
- t->bt_order = NOT;
- mpool_put(t->bt_mp, h, 0);
- return (NULL);
- }
|