db_dup.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: db__dup_8c-source.html,v 1.1 2008/06/08 10:17:27 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <string.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 #include "db_page.h"
00022 #include "db_shash.h"
00023 #include "btree.h"
00024 #include "hash.h"
00025 #include "lock.h"
00026 #include "db_am.h"
00027 
00028 /*
00029  * CDB___db_ditem --
00030  *      Remove an item from a page.
00031  *
00032  * PUBLIC:  int CDB___db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t));
00033  */
00034 int
00035 CDB___db_ditem(dbc, pagep, indx, nbytes)
00036         DBC *dbc;
00037         PAGE *pagep;
00038         u_int32_t indx, nbytes;
00039 {
00040         DB *dbp;
00041         DBT ldbt;
00042         db_indx_t cnt, offset;
00043         int ret;
00044         u_int8_t *from;
00045 
00046         dbp = dbc->dbp;
00047         if (DB_LOGGING(dbc)) {
00048                 ldbt.data = P_ENTRY(pagep, indx);
00049                 ldbt.size = nbytes;
00050                 if ((ret = CDB___db_addrem_log(dbp->dbenv, dbc->txn,
00051                     &LSN(pagep), 0, DB_REM_DUP, dbp->log_fileid, PGNO(pagep),
00052                     (u_int32_t)indx, nbytes, &ldbt, NULL, &LSN(pagep))) != 0)
00053                         return (ret);
00054         }
00055 
00056         /*
00057          * If there's only a single item on the page, we don't have to
00058          * work hard.
00059          */
00060         if (NUM_ENT(pagep) == 1) {
00061                 NUM_ENT(pagep) = 0;
00062                 HOFFSET(pagep) = dbp->pgsize;
00063                 return (0);
00064         }
00065 
00066         /*
00067          * Pack the remaining key/data items at the end of the page.  Use
00068          * memmove(3), the regions may overlap.
00069          */
00070         from = (u_int8_t *)pagep + HOFFSET(pagep);
00071         memmove(from + nbytes, from, pagep->inp[indx] - HOFFSET(pagep));
00072         HOFFSET(pagep) += nbytes;
00073 
00074         /* Adjust the indices' offsets. */
00075         offset = pagep->inp[indx];
00076         for (cnt = 0; cnt < NUM_ENT(pagep); ++cnt)
00077                 if (pagep->inp[cnt] < offset)
00078                         pagep->inp[cnt] += nbytes;
00079 
00080         /* Shift the indices down. */
00081         --NUM_ENT(pagep);
00082         if (indx != NUM_ENT(pagep))
00083                 memmove(&pagep->inp[indx], &pagep->inp[indx + 1],
00084                     sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
00085 
00086         return (0);
00087 }
00088 
00089 /*
00090  * CDB___db_pitem --
00091  *      Put an item on a page.
00092  *
00093  * PUBLIC: int CDB___db_pitem
00094  * PUBLIC:     __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
00095  */
00096 int
00097 CDB___db_pitem(dbc, pagep, indx, nbytes, hdr, data)
00098         DBC *dbc;
00099         PAGE *pagep;
00100         u_int32_t indx;
00101         u_int32_t nbytes;
00102         DBT *hdr, *data;
00103 {
00104         DB *dbp;
00105         BKEYDATA bk;
00106         DBT thdr;
00107         int ret;
00108         u_int8_t *p;
00109 
00110         /*
00111          * Put a single item onto a page.  The logic figuring out where to
00112          * insert and whether it fits is handled in the caller.  All we do
00113          * here is manage the page shuffling.  We cheat a little bit in that
00114          * we don't want to copy the dbt on a normal put twice.  If hdr is
00115          * NULL, we create a BKEYDATA structure on the page, otherwise, just
00116          * copy the caller's information onto the page.
00117          *
00118          * This routine is also used to put entries onto the page where the
00119          * entry is pre-built, e.g., during recovery.  In this case, the hdr
00120          * will point to the entry, and the data argument will be NULL.
00121          *
00122          * !!!
00123          * There's a tremendous potential for off-by-one errors here, since
00124          * the passed in header sizes must be adjusted for the structure's
00125          * placeholder for the trailing variable-length data field.
00126          */
00127         dbp = dbc->dbp;
00128         if (DB_LOGGING(dbc))
00129                 if ((ret = CDB___db_addrem_log(dbp->dbenv, dbc->txn,
00130                     &LSN(pagep), 0, DB_ADD_DUP, dbp->log_fileid, PGNO(pagep),
00131                     (u_int32_t)indx, nbytes, hdr, data, &LSN(pagep))) != 0)
00132                         return (ret);
00133 
00134         if (hdr == NULL) {
00135                 B_TSET(bk.type, B_KEYDATA, 0);
00136                 bk.len = data == NULL ? 0 : data->size;
00137 
00138                 thdr.data = &bk;
00139                 thdr.size = SSZA(BKEYDATA, data);
00140                 hdr = &thdr;
00141         }
00142 
00143         /* Adjust the index table, then put the item on the page. */
00144         if (indx != NUM_ENT(pagep))
00145                 memmove(&pagep->inp[indx + 1], &pagep->inp[indx],
00146                     sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
00147         HOFFSET(pagep) -= nbytes;
00148         pagep->inp[indx] = HOFFSET(pagep);
00149         ++NUM_ENT(pagep);
00150 
00151         p = P_ENTRY(pagep, indx);
00152         memcpy(p, hdr->data, hdr->size);
00153         if (data != NULL)
00154                 memcpy(p + hdr->size, data->data, data->size);
00155 
00156         return (0);
00157 }
00158 
00159 /*
00160  * CDB___db_relink --
00161  *      Relink around a deleted page.
00162  *
00163  * PUBLIC: int CDB___db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int));
00164  */
00165 int
00166 CDB___db_relink(dbc, add_rem, pagep, new_next, needlock)
00167         DBC *dbc;
00168         u_int32_t add_rem;
00169         PAGE *pagep, **new_next;
00170         int needlock;
00171 {
00172         DB *dbp;
00173         PAGE *np, *pp;
00174         DB_LOCK npl, ppl;
00175         DB_LSN *nlsnp, *plsnp, ret_lsn;
00176         int ret;
00177 
00178         ret = 0;
00179         np = pp = NULL;
00180         npl.off = ppl.off = LOCK_INVALID;
00181         nlsnp = plsnp = NULL;
00182         dbp = dbc->dbp;
00183 
00184         /*
00185          * Retrieve and lock the one/two pages.  For a remove, we may need
00186          * two pages (the before and after).  For an add, we only need one
00187          * because, the split took care of the prev.
00188          */
00189         if (pagep->next_pgno != PGNO_INVALID) {
00190                 if (needlock && (ret = CDB___db_lget(dbc,
00191                     0, pagep->next_pgno, DB_LOCK_WRITE, 0, &npl)) != 0)
00192                         goto err;
00193                 if ((ret = CDB_memp_fget(dbp->mpf,
00194                     &pagep->next_pgno, 0, &np)) != 0) {
00195                         (void)CDB___db_pgerr(dbp, pagep->next_pgno);
00196                         goto err;
00197                 }
00198                 nlsnp = &np->lsn;
00199         }
00200         if (add_rem == DB_REM_PAGE && pagep->prev_pgno != PGNO_INVALID) {
00201                 if (needlock && (ret = CDB___db_lget(dbc,
00202                     0, pagep->prev_pgno, DB_LOCK_WRITE, 0, &ppl)) != 0)
00203                         goto err;
00204                 if ((ret = CDB_memp_fget(dbp->mpf,
00205                     &pagep->prev_pgno, 0, &pp)) != 0) {
00206                         (void)CDB___db_pgerr(dbp, pagep->next_pgno);
00207                         goto err;
00208                 }
00209                 plsnp = &pp->lsn;
00210         }
00211 
00212         /* Log the change. */
00213         if (DB_LOGGING(dbc)) {
00214                 if ((ret = CDB___db_relink_log(dbp->dbenv, dbc->txn,
00215                     &ret_lsn, 0, add_rem, dbp->log_fileid,
00216                     pagep->pgno, &pagep->lsn,
00217                     pagep->prev_pgno, plsnp, pagep->next_pgno, nlsnp)) != 0)
00218                         goto err;
00219                 if (np != NULL)
00220                         np->lsn = ret_lsn;
00221                 if (pp != NULL)
00222                         pp->lsn = ret_lsn;
00223                 if (add_rem == DB_REM_PAGE)
00224                         pagep->lsn = ret_lsn;
00225         }
00226 
00227         /*
00228          * Modify and release the two pages.
00229          *
00230          * !!!
00231          * The parameter new_next gets set to the page following the page we
00232          * are removing.  If there is no following page, then new_next gets
00233          * set to NULL.
00234          */
00235         if (np != NULL) {
00236                 if (add_rem == DB_ADD_PAGE)
00237                         np->prev_pgno = pagep->pgno;
00238                 else
00239                         np->prev_pgno = pagep->prev_pgno;
00240                 if (new_next == NULL)
00241                         ret = CDB_memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
00242                 else {
00243                         *new_next = np;
00244                         ret = CDB_memp_fset(dbp->mpf, np, DB_MPOOL_DIRTY);
00245                 }
00246                 if (ret != 0)
00247                         goto err;
00248                 if (needlock)
00249                         (void)__TLPUT(dbc, npl);
00250         } else if (new_next != NULL)
00251                 *new_next = NULL;
00252 
00253         if (pp != NULL) {
00254                 pp->next_pgno = pagep->next_pgno;
00255                 if ((ret = CDB_memp_fput(dbp->mpf, pp, DB_MPOOL_DIRTY)) != 0)
00256                         goto err;
00257                 if (needlock)
00258                         (void)__TLPUT(dbc, ppl);
00259         }
00260         return (0);
00261 
00262 err:    if (np != NULL)
00263                 (void)CDB_memp_fput(dbp->mpf, np, 0);
00264         if (needlock && npl.off != LOCK_INVALID)
00265                 (void)__TLPUT(dbc, npl);
00266         if (pp != NULL)
00267                 (void)CDB_memp_fput(dbp->mpf, pp, 0);
00268         if (needlock && ppl.off != LOCK_INVALID)
00269                 (void)__TLPUT(dbc, ppl);
00270         return (ret);
00271 }

Generated on Sun Jun 8 10:56:36 2008 for GNUmifluz by  doxygen 1.5.5