bt_put.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1990, 1993, 1994
00003  * The Regents of the University of California.  All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Mike Olson.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  * This product includes software developed by the University of
00019  * California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #if defined(LIBC_SCCS) && !defined(lint)
00038 static char sccsid[] = "@(#)bt_put.c   8.8 (Berkeley) 7/26/94";
00039 #endif /* LIBC_SCCS and not lint */
00040 
00041 #include <sys/types.h>
00042 
00043 #include <errno.h>
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <string.h>
00047 
00048 #include "../include/db.h"
00049 #include "btree.h"
00050 
00051 static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
00052 
00053 /*
00054  * __BT_PUT -- Add a btree item to the tree.
00055  *
00056  * Parameters:
00057  * dbp:  pointer to access method
00058  * key:  key
00059  * data: data
00060  * flag: R_NOOVERWRITE
00061  *
00062  * Returns:
00063  * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
00064  * tree and R_NOOVERWRITE specified.
00065  */
00066 int
00067 __bt_put(dbp, key, data, flags)
00068    const DB *dbp;
00069    DBT *key;
00070    const DBT *data;
00071    u_int flags;
00072 {
00073    BTREE *t;
00074    DBT tkey, tdata;
00075    EPG *e = 0;
00076    PAGE *h;
00077    indx_t idx, nxtindex;
00078    pgno_t pg;
00079    u_int32_t nbytes;
00080    int dflags, exact, status;
00081    char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
00082 
00083    t = dbp->internal;
00084 
00085    /* Toss any page pinned across calls. */
00086    if (t->bt_pinned != NULL) {
00087       mpool_put(t->bt_mp, t->bt_pinned, 0);
00088       t->bt_pinned = NULL;
00089    }
00090 
00091    /* Check for change to a read-only tree. */
00092    if (F_ISSET(t, B_RDONLY)) {
00093       errno = EPERM;
00094       return (RET_ERROR);
00095    }
00096 
00097    switch (flags) {
00098    case 0:
00099    case R_NOOVERWRITE:
00100       break;
00101    case R_CURSOR:
00102       /*
00103        * If flags is R_CURSOR, put the cursor.  Must already
00104        * have started a scan and not have already deleted it.
00105        */
00106       if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
00107           !F_ISSET(&t->bt_cursor,
00108               CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
00109          break;
00110       /* FALLTHROUGH */
00111    default:
00112       errno = EINVAL;
00113       return (RET_ERROR);
00114    }
00115 
00116    /*
00117     * If the key/data pair won't fit on a page, store it on overflow
00118     * pages.  Only put the key on the overflow page if the pair are
00119     * still too big after moving the data to an overflow page.
00120     *
00121     * XXX
00122     * If the insert fails later on, the overflow pages aren't recovered.
00123     */
00124    dflags = 0;
00125    if (key->size + data->size > t->bt_ovflsize) {
00126       if (key->size > t->bt_ovflsize) {
00127 storekey:      if (__ovfl_put(t, key, &pg) == RET_ERROR)
00128             return (RET_ERROR);
00129          tkey.data = kb;
00130          tkey.size = NOVFLSIZE;
00131          memmove(kb, &pg, sizeof(pgno_t));
00132          memmove(kb + sizeof(pgno_t),
00133              &key->size, sizeof(u_int32_t));
00134          dflags |= P_BIGKEY;
00135          key = &tkey;
00136       }
00137       if (key->size + data->size > t->bt_ovflsize) {
00138          if (__ovfl_put(t, data, &pg) == RET_ERROR)
00139             return (RET_ERROR);
00140          tdata.data = db;
00141          tdata.size = NOVFLSIZE;
00142          memmove(db, &pg, sizeof(pgno_t));
00143          memmove(db + sizeof(pgno_t),
00144              &data->size, sizeof(u_int32_t));
00145          dflags |= P_BIGDATA;
00146          data = &tdata;
00147       }
00148       if (key->size + data->size > t->bt_ovflsize)
00149          goto storekey;
00150    }
00151 
00152    /* Replace the cursor. */
00153    if (flags == R_CURSOR) {
00154       if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
00155          return (RET_ERROR);
00156       idx = t->bt_cursor.pg.index;
00157       goto delete;
00158    }
00159 
00160    /*
00161     * Find the key to delete, or, the location at which to insert.
00162     * Bt_fast and __bt_search both pin the returned page.
00163     */
00164    if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
00165       if ((e = __bt_search(t, key, &exact)) == NULL)
00166          return (RET_ERROR);
00167    h = e->page;
00168    idx = e->index;
00169 
00170    /*
00171     * Add the key/data pair to the tree.  If an identical key is already
00172     * in the tree, and R_NOOVERWRITE is set, an error is returned.  If
00173     * R_NOOVERWRITE is not set, the key is either added (if duplicates are
00174     * permitted) or an error is returned.
00175     */
00176    switch (flags) {
00177    case R_NOOVERWRITE:
00178       if (!exact)
00179          break;
00180       mpool_put(t->bt_mp, h, 0);
00181       return (RET_SPECIAL);
00182    default:
00183       if (!exact || !F_ISSET(t, B_NODUPS))
00184          break;
00185       /*
00186        * !!!
00187        * Note, the delete may empty the page, so we need to put a
00188        * new entry into the page immediately.
00189        */
00190 delete:     if (__bt_dleaf(t, key, h, idx) == RET_ERROR) {
00191          mpool_put(t->bt_mp, h, 0);
00192          return (RET_ERROR);
00193       }
00194       break;
00195    }
00196 
00197    /*
00198     * If not enough room, or the user has put a ceiling on the number of
00199     * keys permitted in the page, split the page.  The split code will
00200     * insert the key and data and unpin the current page.  If inserting
00201     * into the offset array, shift the pointers up.
00202     */
00203    nbytes = NBLEAFDBT(key->size, data->size);
00204    if ((u_int32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) {
00205       if ((status = __bt_split(t, h, key,
00206           data, dflags, nbytes, idx)) != RET_SUCCESS)
00207          return (status);
00208       goto success;
00209    }
00210 
00211    if (idx < (nxtindex = NEXTINDEX(h)))
00212       memmove(h->linp + idx + 1, h->linp + idx,
00213           (nxtindex - idx) * sizeof(indx_t));
00214    h->lower += sizeof(indx_t);
00215 
00216    h->linp[idx] = h->upper -= nbytes;
00217    dest = (char *)h + h->upper;
00218    WR_BLEAF(dest, key, data, dflags);
00219 
00220    /* If the cursor is on this page, adjust it as necessary. */
00221    if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
00222        !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
00223        t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= idx)
00224       ++t->bt_cursor.pg.index;
00225 
00226    if (t->bt_order == NOT) {
00227       if (h->nextpg == P_INVALID) {
00228          if (idx == NEXTINDEX(h) - 1) {
00229             t->bt_order = FORWARD;
00230             t->bt_last.index = idx;
00231             t->bt_last.pgno = h->pgno;
00232          }
00233       } else if (h->prevpg == P_INVALID) {
00234          if (idx == 0) {
00235             t->bt_order = BACK;
00236             t->bt_last.index = 0;
00237             t->bt_last.pgno = h->pgno;
00238          }
00239       }
00240    }
00241 
00242    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00243 
00244 success:
00245    if (flags == R_SETCURSOR)
00246       __bt_setcur(t, e->page->pgno, e->index);
00247 
00248    F_SET(t, B_MODIFIED);
00249    return (RET_SUCCESS);
00250 }
00251 
00252 #ifdef STATISTICS
00253 u_long bt_cache_hit, bt_cache_miss;
00254 #endif
00255 
00256 /*
00257  * BT_FAST -- Do a quick check for sorted data.
00258  *
00259  * Parameters:
00260  * t: tree
00261  * key:  key to insert
00262  *
00263  * Returns:
00264  *    EPG for new record or NULL if not found.
00265  */
00266 static EPG *
00267 bt_fast(t, key, data, exactp)
00268    BTREE *t;
00269    const DBT *key, *data;
00270    int *exactp;
00271 {
00272    PAGE *h;
00273    u_int32_t nbytes;
00274    int cmp;
00275 
00276    if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
00277       t->bt_order = NOT;
00278       return (NULL);
00279    }
00280    t->bt_cur.page = h;
00281    t->bt_cur.index = t->bt_last.index;
00282 
00283    /*
00284     * If won't fit in this page or have too many keys in this page,
00285     * have to search to get split stack.
00286     */
00287    nbytes = NBLEAFDBT(key->size, data->size);
00288    if ((u_int32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t))
00289       goto miss;
00290 
00291    if (t->bt_order == FORWARD) {
00292       if (t->bt_cur.page->nextpg != P_INVALID)
00293          goto miss;
00294       if (t->bt_cur.index != NEXTINDEX(h) - 1)
00295          goto miss;
00296       if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
00297          goto miss;
00298       t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
00299    } else {
00300       if (t->bt_cur.page->prevpg != P_INVALID)
00301          goto miss;
00302       if (t->bt_cur.index != 0)
00303          goto miss;
00304       if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
00305          goto miss;
00306       t->bt_last.index = 0;
00307    }
00308    *exactp = cmp == 0;
00309 #ifdef STATISTICS
00310    ++bt_cache_hit;
00311 #endif
00312    return (&t->bt_cur);
00313 
00314 miss:
00315 #ifdef STATISTICS
00316    ++bt_cache_miss;
00317 #endif
00318    t->bt_order = NOT;
00319    mpool_put(t->bt_mp, h, 0);
00320    return (NULL);
00321 }

Generated on Thu Apr 16 06:27:16 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6