bt_split.c File Reference

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

Include dependency graph for bt_split.c:

Go to the source code of this file.

Functions

int __bt_split (BTREE *t, PAGE *sp, const DBT *key, const DBT *data, int flags, size_t ilen, u_int32_t argskip)
static recno_t rec_total __P ((PAGE *))
static PAGE *bt_psplit __P ((BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t))
static int bt_preserve __P ((BTREE *, pgno_t))
static PAGE *bt_page __P ((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t))
static int bt_broot __P ((BTREE *, PAGE *, PAGE *, PAGE *))
static int bt_broot (BTREE *t, PAGE *h, PAGE *l, PAGE *r)
static PAGEbt_page (BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
static int bt_preserve (BTREE *t, pgno_t pg)
static PAGEbt_psplit (BTREE *t, PAGE *h, PAGE *l, PAGE *r, indx_t *pskip, size_t ilen)
static PAGEbt_root (BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
static int bt_rroot (BTREE *t, PAGE *h, PAGE *l, PAGE *r)
static recno_t rec_total (PAGE *h)


Function Documentation

int __bt_split ( BTREE t,
PAGE sp,
const DBT key,
const DBT data,
int  flags,
size_t  ilen,
u_int32_t  argskip 
)

Definition at line 82 of file bt_split.c.

References __dbpanic(), a, b, bt_broot(), bt_page(), BT_POP, bt_preserve(), bt_root(), bt_rroot(), _bleaf::bytes, DBT::data, F_ISSET, _bleaf::flags, _page::flags, GETBINTERNAL, GETBLEAF, h, _epgno::index, _bleaf::ksize, _binternal::ksize, _page::linp, _page::lower, MPOOL_DIRTY, mpool_get, mpool_put, NBINTERNAL, NEXTINDEX, NRINTERNAL, NULL, P_BIGKEY, P_BINTERNAL, P_BLEAF, P_INVALID, P_RINTERNAL, P_RLEAF, P_ROOT, P_TYPE, _epgno::pgno, _page::pgno, _page::prevpg, R_RECNO, rec_total(), RET_ERROR, RET_SUCCESS, DBT::size, _page::upper, WR_BINTERNAL, WR_BLEAF, and WR_RLEAF.

Referenced by __bt_put(), and __rec_iput().

00089 {
00090    BINTERNAL *bi = 0;
00091    BLEAF *bl = 0, *tbl;
00092    DBT a, b;
00093    EPGNO *parent;
00094    PAGE *h, *l, *r, *lchild, *rchild;
00095    indx_t nxtindex;
00096    u_int16_t skip;
00097    u_int32_t n, nbytes, nksize = 0;
00098    int parentsplit;
00099    char *dest;
00100 
00101    /*
00102     * Split the page into two pages, l and r.  The split routines return
00103     * a pointer to the page into which the key should be inserted and with
00104     * skip set to the offset which should be used.  Additionally, l and r
00105     * are pinned.
00106     */
00107    skip = argskip;
00108    h = sp->pgno == P_ROOT ?
00109        bt_root(t, sp, &l, &r, &skip, ilen) :
00110        bt_page(t, sp, &l, &r, &skip, ilen);
00111    if (h == NULL)
00112       return (RET_ERROR);
00113 
00114    /*
00115     * Insert the new key/data pair into the leaf page.  (Key inserts
00116     * always cause a leaf page to split first.)
00117     */
00118    h->linp[skip] = h->upper -= ilen;
00119    dest = (char *)h + h->upper;
00120    if (F_ISSET(t, R_RECNO))
00121       WR_RLEAF(dest, data, flags)
00122    else
00123       WR_BLEAF(dest, key, data, flags)
00124 
00125    /* If the root page was split, make it look right. */
00126    if (sp->pgno == P_ROOT &&
00127        (F_ISSET(t, R_RECNO) ?
00128        bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
00129       goto err2;
00130 
00131    /*
00132     * Now we walk the parent page stack -- a LIFO stack of the pages that
00133     * were traversed when we searched for the page that split.  Each stack
00134     * entry is a page number and a page index offset.  The offset is for
00135     * the page traversed on the search.  We've just split a page, so we
00136     * have to insert a new key into the parent page.
00137     *
00138     * If the insert into the parent page causes it to split, may have to
00139     * continue splitting all the way up the tree.  We stop if the root
00140     * splits or the page inserted into didn't have to split to hold the
00141     * new key.  Some algorithms replace the key for the old page as well
00142     * as the new page.  We don't, as there's no reason to believe that the
00143     * first key on the old page is any better than the key we have, and,
00144     * in the case of a key being placed at index 0 causing the split, the
00145     * key is unavailable.
00146     *
00147     * There are a maximum of 5 pages pinned at any time.  We keep the left
00148     * and right pages pinned while working on the parent.   The 5 are the
00149     * two children, left parent and right parent (when the parent splits)
00150     * and the root page or the overflow key page when calling bt_preserve.
00151     * This code must make sure that all pins are released other than the
00152     * root page or overflow page which is unlocked elsewhere.
00153     */
00154    while ((parent = BT_POP(t)) != NULL) {
00155       lchild = l;
00156       rchild = r;
00157 
00158       /* Get the parent page. */
00159       if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
00160          goto err2;
00161 
00162       /*
00163        * The new key goes ONE AFTER the index, because the split
00164        * was to the right.
00165        */
00166       skip = parent->index + 1;
00167 
00168       /*
00169        * Calculate the space needed on the parent page.
00170        *
00171        * Prefix trees: space hack when inserting into BINTERNAL
00172        * pages.  Retain only what's needed to distinguish between
00173        * the new entry and the LAST entry on the page to its left.
00174        * If the keys compare equal, retain the entire key.  Note,
00175        * we don't touch overflow keys, and the entire key must be
00176        * retained for the next-to-left most key on the leftmost
00177        * page of each level, or the search will fail.  Applicable
00178        * ONLY to internal pages that have leaf pages as children.
00179        * Further reduction of the key between pairs of internal
00180        * pages loses too much information.
00181        */
00182       switch (rchild->flags & P_TYPE) {
00183       case P_BINTERNAL:
00184          bi = GETBINTERNAL(rchild, 0);
00185          nbytes = NBINTERNAL(bi->ksize);
00186          break;
00187       case P_BLEAF:
00188          bl = GETBLEAF(rchild, 0);
00189          nbytes = NBINTERNAL(bl->ksize);
00190          if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
00191              (h->prevpg != P_INVALID || skip > 1)) {
00192             tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
00193             a.size = tbl->ksize;
00194             a.data = tbl->bytes;
00195             b.size = bl->ksize;
00196             b.data = bl->bytes;
00197             nksize = t->bt_pfx(&a, &b);
00198             n = NBINTERNAL(nksize);
00199             if (n < nbytes) {
00200 #ifdef STATISTICS
00201                bt_pfxsaved += nbytes - n;
00202 #endif
00203                nbytes = n;
00204             } else
00205                nksize = 0;
00206          } else
00207             nksize = 0;
00208          break;
00209       case P_RINTERNAL:
00210       case P_RLEAF:
00211          nbytes = NRINTERNAL;
00212          break;
00213       default:
00214          abort();
00215       }
00216 
00217       /* Split the parent page if necessary or shift the indices. */
00218       if ((u_int32_t) (h->upper - h->lower)
00219           < nbytes + sizeof(indx_t)) {
00220          sp = h;
00221          h = h->pgno == P_ROOT ?
00222              bt_root(t, h, &l, &r, &skip, nbytes) :
00223              bt_page(t, h, &l, &r, &skip, nbytes);
00224          if (h == NULL)
00225             goto err1;
00226          parentsplit = 1;
00227       } else {
00228          if (skip < (nxtindex = NEXTINDEX(h)))
00229             memmove(h->linp + skip + 1, h->linp + skip,
00230                 (nxtindex - skip) * sizeof(indx_t));
00231          h->lower += sizeof(indx_t);
00232          parentsplit = 0;
00233       }
00234 
00235       /* Insert the key into the parent page. */
00236       switch (rchild->flags & P_TYPE) {
00237       case P_BINTERNAL:
00238          h->linp[skip] = h->upper -= nbytes;
00239          dest = (char *)h + h->linp[skip];
00240          memmove(dest, bi, nbytes);
00241          ((BINTERNAL *)dest)->pgno = rchild->pgno;
00242          break;
00243       case P_BLEAF:
00244          h->linp[skip] = h->upper -= nbytes;
00245          dest = (char *)h + h->linp[skip];
00246          WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
00247              rchild->pgno, bl->flags & P_BIGKEY);
00248          memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
00249          if (bl->flags & P_BIGKEY &&
00250              bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
00251             goto err1;
00252          break;
00253       case P_RINTERNAL:
00254          /*
00255           * Update the left page count.  If split
00256           * added at index 0, fix the correct page.
00257           */
00258          if (skip > 0)
00259             dest = (char *)h + h->linp[skip - 1];
00260          else
00261             dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
00262          ((RINTERNAL *)dest)->nrecs = rec_total(lchild);
00263          ((RINTERNAL *)dest)->pgno = lchild->pgno;
00264 
00265          /* Update the right page count. */
00266          h->linp[skip] = h->upper -= nbytes;
00267          dest = (char *)h + h->linp[skip];
00268          ((RINTERNAL *)dest)->nrecs = rec_total(rchild);
00269          ((RINTERNAL *)dest)->pgno = rchild->pgno;
00270          break;
00271       case P_RLEAF:
00272          /*
00273           * Update the left page count.  If split
00274           * added at index 0, fix the correct page.
00275           */
00276          if (skip > 0)
00277             dest = (char *)h + h->linp[skip - 1];
00278          else
00279             dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
00280          ((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
00281          ((RINTERNAL *)dest)->pgno = lchild->pgno;
00282 
00283          /* Update the right page count. */
00284          h->linp[skip] = h->upper -= nbytes;
00285          dest = (char *)h + h->linp[skip];
00286          ((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
00287          ((RINTERNAL *)dest)->pgno = rchild->pgno;
00288          break;
00289       default:
00290          abort();
00291       }
00292 
00293       /* Unpin the held pages. */
00294       if (!parentsplit) {
00295          mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00296          break;
00297       }
00298 
00299       /* If the root page was split, make it look right. */
00300       if (sp->pgno == P_ROOT &&
00301           (F_ISSET(t, R_RECNO) ?
00302           bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
00303          goto err1;
00304 
00305       mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
00306       mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
00307    }
00308 
00309    /* Unpin the held pages. */
00310    mpool_put(t->bt_mp, l, MPOOL_DIRTY);
00311    mpool_put(t->bt_mp, r, MPOOL_DIRTY);
00312 
00313    /* Clear any pages left on the stack. */
00314    return (RET_SUCCESS);
00315 
00316    /*
00317     * If something fails in the above loop we were already walking back
00318     * up the tree and the tree is now inconsistent.  Nothing much we can
00319     * do about it but release any memory we're holding.
00320     */
00321 err1: mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
00322    mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
00323 
00324 err2: mpool_put(t->bt_mp, l, 0);
00325    mpool_put(t->bt_mp, r, 0);
00326    __dbpanic(t->bt_dbp);
00327    return (RET_ERROR);
00328 }

static recno_t rec_total __P ( (PAGE *)   )  [static]

static PAGE* bt_psplit __P ( (BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t)   )  [static]

static int bt_preserve __P ( (BTREE *, pgno_t  )  [static]

static PAGE *bt_root __P ( (BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t)   )  [static]

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

static int bt_broot ( BTREE t,
PAGE h,
PAGE l,
PAGE r 
) [static]

Definition at line 537 of file bt_split.c.

References bt_preserve(), BTDATAOFF, _bleaf::bytes, _bleaf::flags, _page::flags, GETBINTERNAL, GETBLEAF, _binternal::ksize, _bleaf::ksize, _page::linp, _page::lower, MPOOL_DIRTY, mpool_put, NBINTERNAL, P_BIGKEY, P_BINTERNAL, P_BLEAF, P_TYPE, _page::pgno, RET_ERROR, RET_SUCCESS, _page::upper, and WR_BINTERNAL.

Referenced by __bt_split().

00540 {
00541    BINTERNAL *bi;
00542    BLEAF *bl;
00543    u_int32_t nbytes;
00544    char *dest;
00545 
00546    /*
00547     * If the root page was a leaf page, change it into an internal page.
00548     * We copy the key we split on (but not the key's data, in the case of
00549     * a leaf page) to the new root page.
00550     *
00551     * The btree comparison code guarantees that the left-most key on any
00552     * level of the tree is never used, so it doesn't need to be filled in.
00553     */
00554    nbytes = NBINTERNAL(0);
00555    h->linp[0] = h->upper = t->bt_psize - nbytes;
00556    dest = (char *)h + h->upper;
00557    WR_BINTERNAL(dest, 0, l->pgno, 0);
00558 
00559    switch (h->flags & P_TYPE) {
00560    case P_BLEAF:
00561       bl = GETBLEAF(r, 0);
00562       nbytes = NBINTERNAL(bl->ksize);
00563       h->linp[1] = h->upper -= nbytes;
00564       dest = (char *)h + h->upper;
00565       WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
00566       memmove(dest, bl->bytes, bl->ksize);
00567 
00568       /*
00569        * If the key is on an overflow page, mark the overflow chain
00570        * so it isn't deleted when the leaf copy of the key is deleted.
00571        */
00572       if (bl->flags & P_BIGKEY &&
00573           bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
00574          return (RET_ERROR);
00575       break;
00576    case P_BINTERNAL:
00577       bi = GETBINTERNAL(r, 0);
00578       nbytes = NBINTERNAL(bi->ksize);
00579       h->linp[1] = h->upper -= nbytes;
00580       dest = (char *)h + h->upper;
00581       memmove(dest, bi, nbytes);
00582       ((BINTERNAL *)dest)->pgno = r->pgno;
00583       break;
00584    default:
00585       abort();
00586    }
00587 
00588    /* There are two keys on the page. */
00589    h->lower = BTDATAOFF + 2 * sizeof(indx_t);
00590 
00591    /* Unpin the root page, set to btree internal page. */
00592    h->flags &= ~P_TYPE;
00593    h->flags |= P_BINTERNAL;
00594    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00595 
00596    return (RET_SUCCESS);
00597 }

static PAGE* bt_page ( BTREE t,
PAGE h,
PAGE **  lp,
PAGE **  rp,
indx_t skip,
size_t  ilen 
) [static]

Definition at line 345 of file bt_split.c.

References __bt_new(), bt_psplit(), BTDATAOFF, _page::flags, free, _page::lower, malloc, MPOOL_DIRTY, mpool_get, mpool_put, NEXTINDEX, _page::nextpg, NULL, P_INVALID, P_TYPE, _page::pgno, _page::prevpg, and _page::upper.

Referenced by __bt_split().

00350 {
00351    PAGE *l, *r, *tp;
00352    pgno_t npg;
00353 
00354 #ifdef STATISTICS
00355    ++bt_split;
00356 #endif
00357    /* Put the new right page for the split into place. */
00358    if ((r = __bt_new(t, &npg)) == NULL)
00359       return (NULL);
00360    r->pgno = npg;
00361    r->lower = BTDATAOFF;
00362    r->upper = t->bt_psize;
00363    r->nextpg = h->nextpg;
00364    r->prevpg = h->pgno;
00365    r->flags = h->flags & P_TYPE;
00366 
00367    /*
00368     * If we're splitting the last page on a level because we're appending
00369     * a key to it (skip is NEXTINDEX()), it's likely that the data is
00370     * sorted.  Adding an empty page on the side of the level is less work
00371     * and can push the fill factor much higher than normal.  If we're
00372     * wrong it's no big deal, we'll just do the split the right way next
00373     * time.  It may look like it's equally easy to do a similar hack for
00374     * reverse sorted data, that is, split the tree left, but it's not.
00375     * Don't even try.
00376     */
00377    if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
00378 #ifdef STATISTICS
00379       ++bt_sortsplit;
00380 #endif
00381       h->nextpg = r->pgno;
00382       r->lower = BTDATAOFF + sizeof(indx_t);
00383       *skip = 0;
00384       *lp = h;
00385       *rp = r;
00386       return (r);
00387    }
00388 
00389    /* Put the new left page for the split into place. */
00390    if ((l = (PAGE *)malloc(t->bt_psize)) == NULL) {
00391       mpool_put(t->bt_mp, r, 0);
00392       return (NULL);
00393    }
00394 #ifdef PURIFY
00395    memset(l, 0xff, t->bt_psize);
00396 #endif
00397    l->pgno = h->pgno;
00398    l->nextpg = r->pgno;
00399    l->prevpg = h->prevpg;
00400    l->lower = BTDATAOFF;
00401    l->upper = t->bt_psize;
00402    l->flags = h->flags & P_TYPE;
00403 
00404    /* Fix up the previous pointer of the page after the split page. */
00405    if (h->nextpg != P_INVALID) {
00406       if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
00407          free(l);
00408          /* XXX mpool_free(t->bt_mp, r->pgno); */
00409          return (NULL);
00410       }
00411       tp->prevpg = r->pgno;
00412       mpool_put(t->bt_mp, tp, MPOOL_DIRTY);
00413    }
00414 
00415    /*
00416     * Split right.  The key/data pairs aren't sorted in the btree page so
00417     * it's simpler to copy the data from the split page onto two new pages
00418     * instead of copying half the data to the right page and compacting
00419     * the left page in place.  Since the left page can't change, we have
00420     * to swap the original and the allocated left page after the split.
00421     */
00422    tp = bt_psplit(t, h, l, r, skip, ilen);
00423 
00424    /* Move the new left page onto the old left page. */
00425    memmove(h, l, t->bt_psize);
00426    if (tp == l)
00427       tp = h;
00428    free(l);
00429 
00430    *lp = h;
00431    *rp = r;
00432    return (tp);
00433 }

static int bt_preserve ( BTREE t,
pgno_t  pg 
) [static]

Definition at line 792 of file bt_split.c.

References _page::flags, h, MPOOL_DIRTY, mpool_get, mpool_put, NULL, P_PRESERVE, RET_ERROR, and RET_SUCCESS.

Referenced by __bt_split(), and bt_broot().

00795 {
00796    PAGE *h;
00797 
00798    if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
00799       return (RET_ERROR);
00800    h->flags |= P_PRESERVE;
00801    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00802    return (RET_SUCCESS);
00803 }

static PAGE* bt_psplit ( BTREE t,
PAGE h,
PAGE l,
PAGE r,
indx_t pskip,
size_t  ilen 
) [static]

Definition at line 614 of file bt_split.c.

References BTDATAOFF, c, CURS_INIT, F_ISSET, _bleaf::flags, _binternal::flags, _page::flags, GETBINTERNAL, GETBLEAF, GETRINTERNAL, GETRLEAF, _epgno::index, _binternal::ksize, _page::linp, _page::lower, NBINTERNAL, NBLEAF, NEXTINDEX, NRINTERNAL, NRLEAF, P_BIGKEY, P_BINTERNAL, P_BLEAF, P_RINTERNAL, P_RLEAF, P_TYPE, _cursor::pg, _page::pgno, _epgno::pgno, and _page::upper.

Referenced by bt_page(), and bt_root().

00619 {
00620    BINTERNAL *bi;
00621    BLEAF *bl;
00622    CURSOR *c;
00623    RLEAF *rl;
00624    PAGE *rval;
00625    void *src = 0;
00626    indx_t full, half, nxt, off, skip, top, used;
00627    u_int32_t nbytes;
00628    int bigkeycnt, isbigkey;
00629 
00630    /*
00631     * Split the data to the left and right pages.  Leave the skip index
00632     * open.  Additionally, make some effort not to split on an overflow
00633     * key.  This makes internal page processing faster and can save
00634     * space as overflow keys used by internal pages are never deleted.
00635     */
00636    bigkeycnt = 0;
00637    skip = *pskip;
00638    full = t->bt_psize - BTDATAOFF;
00639    half = full / 2;
00640    used = 0;
00641    for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
00642       if (skip == off) {
00643          nbytes = ilen;
00644          isbigkey = 0;     /* XXX: not really known. */
00645       } else
00646          switch (h->flags & P_TYPE) {
00647          case P_BINTERNAL:
00648             src = bi = GETBINTERNAL(h, nxt);
00649             nbytes = NBINTERNAL(bi->ksize);
00650             isbigkey = bi->flags & P_BIGKEY;
00651             break;
00652          case P_BLEAF:
00653             src = bl = GETBLEAF(h, nxt);
00654             nbytes = NBLEAF(bl);
00655             isbigkey = bl->flags & P_BIGKEY;
00656             break;
00657          case P_RINTERNAL:
00658             src = GETRINTERNAL(h, nxt);
00659             nbytes = NRINTERNAL;
00660             isbigkey = 0;
00661             break;
00662          case P_RLEAF:
00663             src = rl = GETRLEAF(h, nxt);
00664             nbytes = NRLEAF(rl);
00665             isbigkey = 0;
00666             break;
00667          default:
00668             abort();
00669          }
00670 
00671       /*
00672        * If the key/data pairs are substantial fractions of the max
00673        * possible size for the page, it's possible to get situations
00674        * where we decide to try and copy too much onto the left page.
00675        * Make sure that doesn't happen.
00676        */
00677       if ((skip <= off && used + nbytes + sizeof(indx_t) >= full)
00678           || nxt == top - 1) {
00679          --off;
00680          break;
00681       }
00682 
00683       /* Copy the key/data pair, if not the skipped index. */
00684       if (skip != off) {
00685          ++nxt;
00686 
00687          l->linp[off] = l->upper -= nbytes;
00688          memmove((char *)l + l->upper, src, nbytes);
00689       }
00690 
00691       used += nbytes + sizeof(indx_t);
00692       if (used >= half) {
00693          if (!isbigkey || bigkeycnt == 3)
00694             break;
00695          else
00696             ++bigkeycnt;
00697       }
00698    }
00699 
00700    /*
00701     * Off is the last offset that's valid for the left page.
00702     * Nxt is the first offset to be placed on the right page.
00703     */
00704    l->lower += (off + 1) * sizeof(indx_t);
00705 
00706    /*
00707     * If splitting the page that the cursor was on, the cursor has to be
00708     * adjusted to point to the same record as before the split.  If the
00709     * cursor is at or past the skipped slot, the cursor is incremented by
00710     * one.  If the cursor is on the right page, it is decremented by the
00711     * number of records split to the left page.
00712     */
00713    c = &t->bt_cursor;
00714    if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {
00715       if (c->pg.index >= skip)
00716          ++c->pg.index;
00717       if (c->pg.index < nxt)        /* Left page. */
00718          c->pg.pgno = l->pgno;
00719       else {               /* Right page. */
00720          c->pg.pgno = r->pgno;
00721          c->pg.index -= nxt;
00722       }
00723    }
00724 
00725    /*
00726     * If the skipped index was on the left page, just return that page.
00727     * Otherwise, adjust the skip index to reflect the new position on
00728     * the right page.
00729     */
00730    if (skip <= off) {
00731       skip = 0;
00732       rval = l;
00733    } else {
00734       rval = r;
00735       *pskip -= nxt;
00736    }
00737 
00738    for (off = 0; nxt < top; ++off) {
00739       if (skip == nxt) {
00740          ++off;
00741          skip = 0;
00742       }
00743       switch (h->flags & P_TYPE) {
00744       case P_BINTERNAL:
00745          src = bi = GETBINTERNAL(h, nxt);
00746          nbytes = NBINTERNAL(bi->ksize);
00747          break;
00748       case P_BLEAF:
00749          src = bl = GETBLEAF(h, nxt);
00750          nbytes = NBLEAF(bl);
00751          break;
00752       case P_RINTERNAL:
00753          src = GETRINTERNAL(h, nxt);
00754          nbytes = NRINTERNAL;
00755          break;
00756       case P_RLEAF:
00757          src = rl = GETRLEAF(h, nxt);
00758          nbytes = NRLEAF(rl);
00759          break;
00760       default:
00761          abort();
00762       }
00763       ++nxt;
00764       r->linp[off] = r->upper -= nbytes;
00765       memmove((char *)r + r->upper, src, nbytes);
00766    }
00767    r->lower += off * sizeof(indx_t);
00768 
00769    /* If the key is being appended to the page, adjust the index. */
00770    if (skip == top)
00771       r->lower += sizeof(indx_t);
00772 
00773    return (rval);
00774 }

static PAGE* bt_root ( BTREE t,
PAGE h,
PAGE **  lp,
PAGE **  rp,
indx_t skip,
size_t  ilen 
) [static]

Definition at line 450 of file bt_split.c.

References __bt_new(), bt_psplit(), BTDATAOFF, _page::flags, _page::lower, _page::nextpg, NULL, P_INVALID, P_TYPE, _page::pgno, _page::prevpg, and _page::upper.

Referenced by __bt_split().

00455 {
00456    PAGE *l, *r, *tp;
00457    pgno_t lnpg, rnpg;
00458 
00459 #ifdef STATISTICS
00460    ++bt_split;
00461    ++bt_rootsplit;
00462 #endif
00463    /* Put the new left and right pages for the split into place. */
00464    if ((l = __bt_new(t, &lnpg)) == NULL ||
00465        (r = __bt_new(t, &rnpg)) == NULL)
00466       return (NULL);
00467    l->pgno = lnpg;
00468    r->pgno = rnpg;
00469    l->nextpg = r->pgno;
00470    r->prevpg = l->pgno;
00471    l->prevpg = r->nextpg = P_INVALID;
00472    l->lower = r->lower = BTDATAOFF;
00473    l->upper = r->upper = t->bt_psize;
00474    l->flags = r->flags = h->flags & P_TYPE;
00475 
00476    /* Split the root page. */
00477    tp = bt_psplit(t, h, l, r, skip, ilen);
00478 
00479    *lp = l;
00480    *rp = r;
00481    return (tp);
00482 }

static int bt_rroot ( BTREE t,
PAGE h,
PAGE l,
PAGE r 
) [static]

Definition at line 497 of file bt_split.c.

References BTDATAOFF, _page::flags, _page::linp, _page::lower, MPOOL_DIRTY, mpool_put, NEXTINDEX, NRINTERNAL, P_RINTERNAL, P_RLEAF, P_TYPE, _page::pgno, rec_total(), RET_SUCCESS, _page::upper, and WR_RINTERNAL.

Referenced by __bt_split().

00500 {
00501    char *dest;
00502 
00503    /* Insert the left and right keys, set the header information. */
00504    h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;
00505    dest = (char *)h + h->upper;
00506    WR_RINTERNAL(dest,
00507        l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
00508 
00509    h->linp[1] = h->upper -= NRINTERNAL;
00510    dest = (char *)h + h->upper;
00511    WR_RINTERNAL(dest,
00512        r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
00513 
00514    h->lower = BTDATAOFF + 2 * sizeof(indx_t);
00515 
00516    /* Unpin the root page, set to recno internal page. */
00517    h->flags &= ~P_TYPE;
00518    h->flags |= P_RINTERNAL;
00519    mpool_put(t->bt_mp, h, MPOOL_DIRTY);
00520 
00521    return (RET_SUCCESS);
00522 }

static recno_t rec_total ( PAGE h  )  [static]

Definition at line 820 of file bt_split.c.

References GETRINTERNAL, and NEXTINDEX.

Referenced by __bt_split(), and bt_rroot().

00822 {
00823    recno_t recs;
00824    indx_t nxt, top;
00825 
00826    for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
00827       recs += GETRINTERNAL(h, nxt)->nrecs;
00828    return (recs);
00829 }


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