bt_delete.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_delete.c   8.13 (Berkeley) 7/28/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 <string.h>
00046 
00047 #include "../include/db.h"
00048 #include "btree.h"
00049 
00050 static int __bt_bdelete __P((BTREE *, const DBT *));
00051 static int __bt_curdel __P((BTREE *, const DBT *, PAGE *, u_int));
00052 static int __bt_pdelete __P((BTREE *, PAGE *));
00053 static int __bt_relink __P((BTREE *, PAGE *));
00054 static int __bt_stkacq __P((BTREE *, PAGE **, CURSOR *));
00055 
00056 /*
00057  * __bt_delete
00058  * Delete the item(s) referenced by a key.
00059  *
00060  * Return RET_SPECIAL if the key is not found.
00061  */
00062 int
00063 __bt_delete(dbp, key, flags)
00064    const DB *dbp;
00065    const DBT *key;
00066    u_int flags;
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 }
00130 
00131 /*
00132  * __bt_stkacq --
00133  * Acquire a stack so we can delete a cursor entry.
00134  *
00135  * Parameters:
00136  *   t:  tree
00137  *  hp:  pointer to current, pinned PAGE pointer
00138  *   c:  pointer to the cursor
00139  *
00140  * Returns:
00141  * 0 on success, 1 on failure
00142  */
00143 static int
00144 __bt_stkacq(t, hp, c)
00145    BTREE *t;
00146    PAGE **hp;
00147    CURSOR *c;
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 }
00278 
00279 /*
00280  * __bt_bdelete --
00281  * Delete all key/data pairs matching the specified key.
00282  *
00283  * Parameters:
00284  *   t:  tree
00285  * key:  key to delete
00286  *
00287  * Returns:
00288  * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
00289  */
00290 static int
00291 __bt_bdelete(t, key)
00292    BTREE *t;
00293    const DBT *key;
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 }
00362 
00363 /*
00364  * __bt_pdelete --
00365  * Delete a single page from the tree.
00366  *
00367  * Parameters:
00368  * t: tree
00369  * h: leaf page
00370  *
00371  * Returns:
00372  * RET_SUCCESS, RET_ERROR.
00373  *
00374  * Side-effects:
00375  * mpool_put's the page
00376  */
00377 static int
00378 __bt_pdelete(t, h)
00379    BTREE *t;
00380    PAGE *h;
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 }
00459 
00460 /*
00461  * __bt_dleaf --
00462  * Delete a single record from a leaf page.
00463  *
00464  * Parameters:
00465  * t: tree
00466  *    key:  referenced key
00467  * h: page
00468  * index:   index on page to delete
00469  *
00470  * Returns:
00471  * RET_SUCCESS, RET_ERROR.
00472  */
00473 int
00474 __bt_dleaf(t, key, h, idx)
00475    BTREE *t;
00476    const DBT *key;
00477    PAGE *h;
00478    u_int idx;
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 }
00524 
00525 /*
00526  * __bt_curdel --
00527  * Delete the cursor.
00528  *
00529  * Parameters:
00530  * t: tree
00531  *    key:  referenced key (or NULL)
00532  * h: page
00533  *  index:  index on page to delete
00534  *
00535  * Returns:
00536  * RET_SUCCESS, RET_ERROR.
00537  */
00538 static int
00539 __bt_curdel(t, key, h, idx)
00540    BTREE *t;
00541    const DBT *key;
00542    PAGE *h;
00543    u_int idx;
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 }
00628 
00629 /*
00630  * __bt_relink --
00631  * Link around a deleted page.
00632  *
00633  * Parameters:
00634  * t: tree
00635  * h: page to be deleted
00636  */
00637 static int
00638 __bt_relink(t, h)
00639    BTREE *t;
00640    PAGE *h;
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 }

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