bt_delete.c File Reference

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

Include dependency graph for bt_delete.c:

Go to the source code of this file.

Functions

static int __bt_bdelete (BTREE *t, const DBT *key)
static int __bt_curdel (BTREE *t, const DBT *key, PAGE *h, u_int idx)
int __bt_delete (DB *dbp, const DBT *key, u_int flags) const
int __bt_dleaf (BTREE *t, const DBT *key, PAGE *h, u_int idx)
static int __bt_pdelete (BTREE *t, PAGE *h)
static int __bt_relink (BTREE *t, PAGE *h)
static int __bt_stkacq (BTREE *t, PAGE **hp, CURSOR *c)
static int __bt_stkacq __P ((BTREE *, PAGE **, CURSOR *))
static int __bt_pdelete __P ((BTREE *, PAGE *))
static int __bt_curdel __P ((BTREE *, const DBT *, PAGE *, u_int))
static int __bt_bdelete __P ((BTREE *, const DBT *))


Function Documentation

static int __bt_bdelete ( BTREE t,
const DBT key 
) [static]

Definition at line 291 of file bt_delete.c.

References __bt_cmp(), __bt_dleaf(), __bt_pdelete(), __bt_search(), B_NODUPS, e, F_ISSET, h, _epg::index, MPOOL_DIRTY, mpool_put, NEXTINDEX, NULL, _epg::page, RET_ERROR, RET_SPECIAL, and RET_SUCCESS.

Referenced by __bt_delete().

00294 {
00295    EPG *e;
00296    PAGE *h;
00297    int deleted, exact, redo;
00298 
00299    deleted = 0;
00300 
00301    /* Find any matching record; __bt_search pins the page. */
00302 loop: if ((e = __bt_search(t, key, &exact)) == NULL)
00303       return (deleted ? RET_SUCCESS : RET_ERROR);
00304    if (!exact) {
00305       mpool_put(t->bt_mp, e->page, 0);
00306       return (deleted ? RET_SUCCESS : RET_SPECIAL);
00307    }
00308 
00309    /*
00310     * Delete forward, then delete backward, from the found key.  If
00311     * there are duplicates and we reach either side of the page, do
00312     * the key search again, so that we get them all.
00313     */
00314    redo = 0;
00315    h = e->page;
00316    do {
00317       if (__bt_dleaf(t, key, h, e->index)) {
00318          mpool_put(t->bt_mp, h, 0);
00319          return (RET_ERROR);
00320       }
00321       if (F_ISSET(t, B_NODUPS)) {
00322          if (NEXTINDEX(h) == 0) {
00323             if (__bt_pdelete(t, h))
00324                return (RET_ERROR);
00325          } else
00326             mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00327          return (RET_SUCCESS);
00328       }
00329       deleted = 1;
00330    } while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
00331 
00332    /* Check for right-hand edge of the page. */
00333    if (e->index == NEXTINDEX(h))
00334       redo = 1;
00335 
00336    /* Delete from the key to the beginning of the page. */
00337    while (e->index-- > 0) {
00338       if (__bt_cmp(t, key, e) != 0)
00339          break;
00340       if (__bt_dleaf(t, key, h, e->index) == RET_ERROR) {
00341          mpool_put(t->bt_mp, h, 0);
00342          return (RET_ERROR);
00343       }
00344       if (e->index == 0)
00345          redo = 1;
00346    }
00347 
00348    /* Check for an empty page. */
00349    if (NEXTINDEX(h) == 0) {
00350       if (__bt_pdelete(t, h))
00351          return (RET_ERROR);
00352       goto loop;
00353    }
00354 
00355    /* Put the page. */
00356    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00357 
00358    if (redo)
00359       goto loop;
00360    return (RET_SUCCESS);
00361 }

static int __bt_curdel ( BTREE t,
const DBT key,
PAGE h,
u_int  idx 
) [static]

Definition at line 539 of file bt_delete.c.

References __bt_cmp(), __bt_ret(), B_NODUPS, c, CURS_ACQUIRE, CURS_AFTER, CURS_BEFORE, e, F_CLR, F_ISSET, F_SET, _epgno::index, _epg::index, _cursor::key, mpool_get, mpool_put, NEXTINDEX, _page::nextpg, NULL, P_INVALID, _epg::page, _cursor::pg, _page::pgno, _epgno::pgno, _page::prevpg, RET_ERROR, RET_SUCCESS, and status.

Referenced by __bt_dleaf().

00544 {
00545    CURSOR *c;
00546    EPG e;
00547    PAGE *pg;
00548    int curcopy, status;
00549 
00550    /*
00551     * If there are duplicates, move forward or backward to one.
00552     * Otherwise, copy the key into the cursor area.
00553     */
00554    c = &t->bt_cursor;
00555    F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
00556 
00557    curcopy = 0;
00558    if (!F_ISSET(t, B_NODUPS)) {
00559       /*
00560        * We're going to have to do comparisons.  If we weren't
00561        * provided a copy of the key, i.e. the user is deleting
00562        * the current cursor position, get one.
00563        */
00564       if (key == NULL) {
00565          e.page = h;
00566          e.index = idx;
00567          if ((status = __bt_ret(t, &e,
00568              &c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
00569             return (status);
00570          curcopy = 1;
00571          key = &c->key;
00572       }
00573       /* Check previous key, if not at the beginning of the page. */
00574       if (idx > 0) {
00575          e.page = h;
00576          e.index = idx - 1;
00577          if (__bt_cmp(t, key, &e) == 0) {
00578             F_SET(c, CURS_BEFORE);
00579             goto dup2;
00580          }
00581       }
00582       /* Check next key, if not at the end of the page. */
00583       if (idx < NEXTINDEX(h) - 1) {
00584          e.page = h;
00585          e.index = idx + 1;
00586          if (__bt_cmp(t, key, &e) == 0) {
00587             F_SET(c, CURS_AFTER);
00588             goto dup2;
00589          }
00590       }
00591       /* Check previous key if at the beginning of the page. */
00592       if (idx == 0 && h->prevpg != P_INVALID) {
00593          if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
00594             return (RET_ERROR);
00595          e.page = pg;
00596          e.index = NEXTINDEX(pg) - 1;
00597          if (__bt_cmp(t, key, &e) == 0) {
00598             F_SET(c, CURS_BEFORE);
00599             goto dup1;
00600          }
00601          mpool_put(t->bt_mp, pg, 0);
00602       }
00603       /* Check next key if at the end of the page. */
00604       if (idx == NEXTINDEX(h) - 1 && h->nextpg != P_INVALID) {
00605          if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
00606             return (RET_ERROR);
00607          e.page = pg;
00608          e.index = 0;
00609          if (__bt_cmp(t, key, &e) == 0) {
00610             F_SET(c, CURS_AFTER);
00611 dup1:          mpool_put(t->bt_mp, pg, 0);
00612 dup2:          c->pg.pgno = e.page->pgno;
00613             c->pg.index = e.index;
00614             return (RET_SUCCESS);
00615          }
00616          mpool_put(t->bt_mp, pg, 0);
00617       }
00618    }
00619    e.page = h;
00620    e.index = idx;
00621    if (curcopy || (status =
00622        __bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
00623       F_SET(c, CURS_ACQUIRE);
00624       return (RET_SUCCESS);
00625    }
00626    return (status);
00627 }

int __bt_delete ( DB dbp,
const DBT key,
u_int  flags 
) const

Definition at line 63 of file bt_delete.c.

References __bt_bdelete(), __bt_dleaf(), __bt_pdelete(), __bt_stkacq(), B_MODIFIED, B_RDONLY, _btree::bt_cursor, _btree::bt_mp, _btree::bt_pinned, c, CURS_ACQUIRE, CURS_AFTER, CURS_BEFORE, CURS_INIT, errno, F_ISSET, F_SET, h, _epgno::index, MPOOL_DIRTY, mpool_get, mpool_put, NEXTINDEX, NULL, _cursor::pg, _epgno::pgno, R_CURSOR, RET_ERROR, RET_SPECIAL, RET_SUCCESS, and status.

Referenced by __bt_open().

00067 {
00068    BTREE *t;
00069    CURSOR *c;
00070    PAGE *h;
00071    int status;
00072 
00073    t = dbp->internal;
00074 
00075    /* Toss any page pinned across calls. */
00076    if (t->bt_pinned != NULL) {
00077       mpool_put(t->bt_mp, t->bt_pinned, 0);
00078       t->bt_pinned = NULL;
00079    }
00080 
00081    /* Check for change to a read-only tree. */
00082    if (F_ISSET(t, B_RDONLY)) {
00083       errno = EPERM;
00084       return (RET_ERROR);
00085    }
00086 
00087    switch (flags) {
00088    case 0:
00089       status = __bt_bdelete(t, key);
00090       break;
00091    case R_CURSOR:
00092       /*
00093        * If flags is R_CURSOR, delete the cursor.  Must already
00094        * have started a scan and not have already deleted it.
00095        */
00096       c = &t->bt_cursor;
00097       if (F_ISSET(c, CURS_INIT)) {
00098          if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
00099             return (RET_SPECIAL);
00100          if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
00101             return (RET_ERROR);
00102 
00103          /*
00104           * If the page is about to be emptied, we'll need to
00105           * delete it, which means we have to acquire a stack.
00106           */
00107          if (NEXTINDEX(h) == 1)
00108             if (__bt_stkacq(t, &h, &t->bt_cursor))
00109                return (RET_ERROR);
00110 
00111          status = __bt_dleaf(t, NULL, h, c->pg.index);
00112 
00113          if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
00114             if (__bt_pdelete(t, h))
00115                return (RET_ERROR);
00116          } else
00117             mpool_put(t->bt_mp,
00118                 h, status == RET_SUCCESS ? MPOOL_DIRTY : 0);
00119          break;
00120       }
00121       /* FALLTHROUGH */
00122    default:
00123       errno = EINVAL;
00124       return (RET_ERROR);
00125    }
00126    if (status == RET_SUCCESS)
00127       F_SET(t, B_MODIFIED);
00128    return (status);
00129 }

int __bt_dleaf ( BTREE t,
const DBT key,
PAGE h,
u_int  idx 
)

Definition at line 474 of file bt_delete.c.

References __bt_curdel(), __ovfl_delete(), _bleaf::bytes, CURS_ACQUIRE, CURS_INIT, F_ISSET, _bleaf::flags, GETBLEAF, _bleaf::ksize, _page::linp, _page::lower, NBLEAF, NEXTINDEX, P_BIGDATA, P_BIGKEY, _page::pgno, RET_ERROR, RET_SUCCESS, and _page::upper.

Referenced by __bt_bdelete(), __bt_delete(), and __bt_put().

00479 {
00480    BLEAF *bl;
00481    indx_t cnt, *ip, offset;
00482    u_int32_t nbytes;
00483    void *to;
00484    char *from;
00485 
00486    /* If this record is referenced by the cursor, delete the cursor. */
00487    if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
00488        !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
00489        t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == idx &&
00490        __bt_curdel(t, key, h, idx))
00491       return (RET_ERROR);
00492 
00493    /* If the entry uses overflow pages, make them available for reuse. */
00494    to = bl = GETBLEAF(h, idx);
00495    if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
00496       return (RET_ERROR);
00497    if (bl->flags & P_BIGDATA &&
00498        __ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
00499       return (RET_ERROR);
00500 
00501    /* Pack the remaining key/data items at the end of the page. */
00502    nbytes = NBLEAF(bl);
00503    from = (char *)h + h->upper;
00504    memmove(from + nbytes, from, (char *)to - from);
00505    h->upper += nbytes;
00506 
00507    /* Adjust the indices' offsets, shift the indices down. */
00508    offset = h->linp[idx];
00509    for (cnt = idx, ip = &h->linp[0]; cnt--; ++ip)
00510       if (ip[0] < offset)
00511          ip[0] += nbytes;
00512    for (cnt = NEXTINDEX(h) - idx; --cnt; ++ip)
00513       ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
00514    h->lower -= sizeof(indx_t);
00515 
00516    /* If the cursor is on this page, adjust it as necessary. */
00517    if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
00518        !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
00519        t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > idx)
00520       --t->bt_cursor.pg.index;
00521 
00522    return (RET_SUCCESS);
00523 }

static int __bt_pdelete ( BTREE t,
PAGE h 
) [static]

Definition at line 378 of file bt_delete.c.

References __bt_free(), __bt_relink(), __ovfl_delete(), BT_POP, BTDATAOFF, _binternal::bytes, _page::flags, _binternal::flags, GETBINTERNAL, _epgno::index, _binternal::ksize, _page::linp, _page::lower, MPOOL_DIRTY, mpool_get, mpool_put, NBINTERNAL, NEXTINDEX, NULL, P_BIGKEY, P_BLEAF, P_ROOT, _page::pgno, _epgno::pgno, RET_ERROR, RET_SUCCESS, and _page::upper.

Referenced by __bt_bdelete(), and __bt_delete().

00381 {
00382    BINTERNAL *bi;
00383    PAGE *pg;
00384    EPGNO *parent;
00385    indx_t cnt, idx, *ip, offset;
00386    u_int32_t nksize;
00387    char *from;
00388 
00389    /*
00390     * Walk the parent page stack -- a LIFO stack of the pages that were
00391     * traversed when we searched for the page where the delete occurred.
00392     * Each stack entry is a page number and a page index offset.  The
00393     * offset is for the page traversed on the search.  We've just deleted
00394     * a page, so we have to delete the key from the parent page.
00395     *
00396     * If the delete from the parent page makes it empty, this process may
00397     * continue all the way up the tree.  We stop if we reach the root page
00398     * (which is never deleted, it's just not worth the effort) or if the
00399     * delete does not empty the page.
00400     */
00401    while ((parent = BT_POP(t)) != NULL) {
00402       /* Get the parent page. */
00403       if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
00404          return (RET_ERROR);
00405 
00406       idx = parent->index;
00407       bi = GETBINTERNAL(pg, idx);
00408 
00409       /* Free any overflow pages. */
00410       if (bi->flags & P_BIGKEY &&
00411           __ovfl_delete(t, bi->bytes) == RET_ERROR) {
00412          mpool_put(t->bt_mp, pg, 0);
00413          return (RET_ERROR);
00414       }
00415 
00416       /*
00417        * Free the parent if it has only the one key and it's not the
00418        * root page. If it's the rootpage, turn it back into an empty
00419        * leaf page.
00420        */
00421       if (NEXTINDEX(pg) == 1) {
00422          if (pg->pgno == P_ROOT) {
00423             pg->lower = BTDATAOFF;
00424             pg->upper = t->bt_psize;
00425             pg->flags = P_BLEAF;
00426          } else {
00427             if (__bt_relink(t, pg) || __bt_free(t, pg))
00428                return (RET_ERROR);
00429             continue;
00430          }
00431       } else {
00432          /* Pack remaining key items at the end of the page. */
00433          nksize = NBINTERNAL(bi->ksize);
00434          from = (char *)pg + pg->upper;
00435          memmove(from + nksize, from, (char *)bi - from);
00436          pg->upper += nksize;
00437 
00438          /* Adjust indices' offsets, shift the indices down. */
00439          offset = pg->linp[idx];
00440          for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
00441             if (ip[0] < offset)
00442                ip[0] += nksize;
00443          for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
00444             ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
00445          pg->lower -= sizeof(indx_t);
00446       }
00447 
00448       mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
00449       break;
00450    }
00451 
00452    /* Free the leaf page, as long as it wasn't the root. */
00453    if (h->pgno == P_ROOT) {
00454       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00455       return (RET_SUCCESS);
00456    }
00457    return (__bt_relink(t, h) || __bt_free(t, h));
00458 }

static int __bt_relink ( BTREE t,
PAGE h 
) [static]

Definition at line 638 of file bt_delete.c.

References MPOOL_DIRTY, mpool_get, mpool_put, _page::nextpg, NULL, P_INVALID, _page::prevpg, and RET_ERROR.

Referenced by __bt_pdelete().

00641 {
00642    PAGE *pg;
00643 
00644    if (h->nextpg != P_INVALID) {
00645       if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
00646          return (RET_ERROR);
00647       pg->prevpg = h->prevpg;
00648       mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
00649    }
00650    if (h->prevpg != P_INVALID) {
00651       if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
00652          return (RET_ERROR);
00653       pg->nextpg = h->nextpg;
00654       mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
00655    }
00656    return (0);
00657 }

static int __bt_stkacq ( BTREE t,
PAGE **  hp,
CURSOR c 
) [static]

Definition at line 144 of file bt_delete.c.

References __bt_search(), BT_POP, BT_PUSH, e, GETBINTERNAL, h, _epgno::index, _cursor::key, mpool_get, mpool_put, NEXTINDEX, _page::nextpg, NULL, P_INVALID, _epg::page, _cursor::pg, _binternal::pgno, _epgno::pgno, _page::pgno, and _page::prevpg.

Referenced by __bt_delete().

00148 {
00149    BINTERNAL *bi;
00150    EPG *e;
00151    EPGNO *parent;
00152    PAGE *h;
00153    indx_t idx = 0;
00154    pgno_t pgno;
00155    recno_t nextpg, prevpg;
00156    int exact, level;
00157 
00158    /*
00159     * Find the first occurrence of the key in the tree.  Toss the
00160     * currently locked page so we don't hit an already-locked page.
00161     */
00162    h = *hp;
00163    mpool_put(t->bt_mp, h, 0);
00164    if ((e = __bt_search(t, &c->key, &exact)) == NULL)
00165       return (1);
00166    h = e->page;
00167 
00168    /* See if we got it in one shot. */
00169    if (h->pgno == c->pg.pgno)
00170       goto ret;
00171 
00172    /*
00173     * Move right, looking for the page.  At each move we have to move
00174     * up the stack until we don't have to move to the next page.  If
00175     * we have to change pages at an internal level, we have to fix the
00176     * stack back up.
00177     */
00178    while (h->pgno != c->pg.pgno) {
00179       if ((nextpg = h->nextpg) == P_INVALID)
00180          break;
00181       mpool_put(t->bt_mp, h, 0);
00182 
00183       /* Move up the stack. */
00184       for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
00185          /* Get the parent page. */
00186          if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
00187             return (1);
00188 
00189          /* Move to the next index. */
00190          if (parent->index != NEXTINDEX(h) - 1) {
00191             idx = parent->index + 1;
00192             BT_PUSH(t, h->pgno, idx);
00193             break;
00194          }
00195          mpool_put(t->bt_mp, h, 0);
00196       }
00197 
00198       /* Restore the stack. */
00199       while (level--) {
00200          /* Push the next level down onto the stack. */
00201          bi = GETBINTERNAL(h, idx);
00202          pgno = bi->pgno;
00203          BT_PUSH(t, pgno, 0);
00204 
00205          /* Lose the currently pinned page. */
00206          mpool_put(t->bt_mp, h, 0);
00207 
00208          /* Get the next level down. */
00209          if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
00210             return (1);
00211          idx = 0;
00212       }
00213       mpool_put(t->bt_mp, h, 0);
00214       if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
00215          return (1);
00216    }
00217 
00218    if (h->pgno == c->pg.pgno)
00219       goto ret;
00220 
00221    /* Reacquire the original stack. */
00222    mpool_put(t->bt_mp, h, 0);
00223    if ((e = __bt_search(t, &c->key, &exact)) == NULL)
00224       return (1);
00225    h = e->page;
00226 
00227    /*
00228     * Move left, looking for the page.  At each move we have to move
00229     * up the stack until we don't have to change pages to move to the
00230     * next page.  If we have to change pages at an internal level, we
00231     * have to fix the stack back up.
00232     */
00233    while (h->pgno != c->pg.pgno) {
00234       if ((prevpg = h->prevpg) == P_INVALID)
00235          break;
00236       mpool_put(t->bt_mp, h, 0);
00237 
00238       /* Move up the stack. */
00239       for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
00240          /* Get the parent page. */
00241          if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
00242             return (1);
00243 
00244          /* Move to the next index. */
00245          if (parent->index != 0) {
00246             idx = parent->index - 1;
00247             BT_PUSH(t, h->pgno, idx);
00248             break;
00249          }
00250          mpool_put(t->bt_mp, h, 0);
00251       }
00252 
00253       /* Restore the stack. */
00254       while (level--) {
00255          /* Push the next level down onto the stack. */
00256          bi = GETBINTERNAL(h, idx);
00257          pgno = bi->pgno;
00258 
00259          /* Lose the currently pinned page. */
00260          mpool_put(t->bt_mp, h, 0);
00261 
00262          /* Get the next level down. */
00263          if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
00264             return (1);
00265 
00266          idx = NEXTINDEX(h) - 1;
00267          BT_PUSH(t, pgno, idx);
00268       }
00269       mpool_put(t->bt_mp, h, 0);
00270       if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
00271          return (1);
00272    }
00273 
00274 
00275 ret:  mpool_put(t->bt_mp, h, 0);
00276    return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
00277 }

static int __bt_stkacq __P ( (BTREE *, PAGE **, CURSOR *)   )  [static]

static int __bt_relink __P ( (BTREE *, PAGE *)   )  [static]

static int __bt_curdel __P ( (BTREE *, const DBT *, PAGE *, u_int)   )  [static]

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


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