bt_put.c File Reference

#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../include/db.h"
#include "btree.h"

Include dependency graph for bt_put.c:

Go to the source code of this file.

Functions

int __bt_put (DB *dbp, DBT *key, const DBT *data, u_int flags) const
static EPG *bt_fast __P ((BTREE *, const DBT *, const DBT *, int *))
static EPGbt_fast (BTREE *t, const DBT *key, const DBT *data, int *exactp)


Function Documentation

int __bt_put ( DB dbp,
DBT key,
const DBT data,
u_int  flags 
) const

Definition at line 67 of file bt_put.c.

References __bt_dleaf(), __bt_search(), __bt_setcur(), __bt_split(), __ovfl_put(), B_MODIFIED, B_NODUPS, B_RDONLY, _btree::bt_cursor, bt_fast(), _btree::bt_last, _btree::bt_mp, _btree::bt_order, _btree::bt_ovflsize, _btree::bt_pinned, CURS_ACQUIRE, CURS_AFTER, CURS_BEFORE, CURS_INIT, DBT::data, db, e, errno, F_ISSET, F_SET, h, _epg::index, _epgno::index, _page::linp, _page::lower, MPOOL_DIRTY, mpool_get, mpool_put, NBLEAFDBT, NEXTINDEX, _page::nextpg, NOVFLSIZE, NULL, P_BIGDATA, P_BIGKEY, P_INVALID, _epg::page, _cursor::pg, _page::pgno, _epgno::pgno, _page::prevpg, R_CURSOR, R_NOOVERWRITE, R_SETCURSOR, RET_ERROR, RET_SPECIAL, RET_SUCCESS, DBT::size, status, _page::upper, and WR_BLEAF.

Referenced by __bt_open().

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 }

static EPG* bt_fast __P ( (BTREE *, const DBT *, const DBT *, int *)   )  [static]

static EPG* bt_fast ( BTREE t,
const DBT key,
const DBT data,
int *  exactp 
) [static]

Definition at line 267 of file bt_put.c.

References __bt_cmp(), h, _page::lower, mpool_get, mpool_put, NBLEAFDBT, NEXTINDEX, NULL, P_INVALID, DBT::size, and _page::upper.

Referenced by __bt_put().

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:29:15 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6