Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_upg_opd.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_upg_opd.c,v 12.1 2005/06/16 20:21:15 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/btree.h"
00021 
00022 static int __db_build_bi __P((DB *, DB_FH *, PAGE *, PAGE *, u_int32_t, int *));
00023 static int __db_build_ri __P((DB *, DB_FH *, PAGE *, PAGE *, u_int32_t, int *));
00024 static int __db_up_ovref __P((DB *, DB_FH *, db_pgno_t));
00025 
00026 #define GET_PAGE(dbp, fhp, pgno, page) {                                \
00027         if ((ret = __os_seek(dbp->dbenv,                                \
00028             fhp, (dbp)->pgsize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0)      \
00029                 goto err;                                               \
00030         if ((ret = __os_read(dbp->dbenv,                                \
00031             fhp, page, (dbp)->pgsize, &n)) != 0)                        \
00032                 goto err;                                               \
00033 }
00034 #define PUT_PAGE(dbp, fhp, pgno, page) {                                \
00035         if ((ret = __os_seek(dbp->dbenv,                                \
00036             fhp, (dbp)->pgsize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0)      \
00037                 goto err;                                               \
00038         if ((ret = __os_write(dbp->dbenv,                               \
00039             fhp, page, (dbp)->pgsize, &n)) != 0)                        \
00040                 goto err;                                               \
00041 }
00042 
00043 /*
00044  * __db_31_offdup --
00045  *      Convert 3.0 off-page duplicates to 3.1 off-page duplicates.
00046  *
00047  * PUBLIC: int __db_31_offdup __P((DB *, char *, DB_FH *, int, db_pgno_t *));
00048  */
00049 int
00050 __db_31_offdup(dbp, real_name, fhp, sorted, pgnop)
00051         DB *dbp;
00052         char *real_name;
00053         DB_FH *fhp;
00054         int sorted;
00055         db_pgno_t *pgnop;
00056 {
00057         PAGE *ipage, *page;
00058         db_indx_t indx;
00059         db_pgno_t cur_cnt, i, next_cnt, pgno, *pgno_cur, pgno_last;
00060         db_pgno_t *pgno_next, pgno_max, *tmp;
00061         db_recno_t nrecs;
00062         size_t n;
00063         int level, nomem, ret;
00064 
00065         ipage = page = NULL;
00066         pgno_cur = pgno_next = NULL;
00067 
00068         /* Allocate room to hold a page. */
00069         if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &page)) != 0)
00070                 goto err;
00071 
00072         /*
00073          * Walk the chain of 3.0 off-page duplicates.  Each one is converted
00074          * in place to a 3.1 off-page duplicate page.  If the duplicates are
00075          * sorted, they are converted to a Btree leaf page, otherwise to a
00076          * Recno leaf page.
00077          */
00078         for (nrecs = 0, cur_cnt = pgno_max = 0,
00079             pgno = *pgnop; pgno != PGNO_INVALID;) {
00080                 if (pgno_max == cur_cnt) {
00081                         pgno_max += 20;
00082                         if ((ret = __os_realloc(dbp->dbenv, pgno_max *
00083                             sizeof(db_pgno_t), &pgno_cur)) != 0)
00084                                 goto err;
00085                 }
00086                 pgno_cur[cur_cnt++] = pgno;
00087 
00088                 GET_PAGE(dbp, fhp, pgno, page);
00089                 nrecs += NUM_ENT(page);
00090                 LEVEL(page) = LEAFLEVEL;
00091                 TYPE(page) = sorted ? P_LDUP : P_LRECNO;
00092                 /*
00093                  * !!!
00094                  * DB didn't zero the LSNs on off-page duplicates pages.
00095                  */
00096                 ZERO_LSN(LSN(page));
00097                 PUT_PAGE(dbp, fhp, pgno, page);
00098 
00099                 pgno = NEXT_PGNO(page);
00100         }
00101 
00102         /* If we only have a single page, it's easy. */
00103         if (cur_cnt <= 1)
00104                 goto done;
00105 
00106         /*
00107          * pgno_cur is the list of pages we just converted.  We're
00108          * going to walk that list, but we'll need to create a new
00109          * list while we do so.
00110          */
00111         if ((ret = __os_malloc(dbp->dbenv,
00112             cur_cnt * sizeof(db_pgno_t), &pgno_next)) != 0)
00113                 goto err;
00114 
00115         /* Figure out where we can start allocating new pages. */
00116         if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
00117                 goto err;
00118 
00119         /* Allocate room for an internal page. */
00120         if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &ipage)) != 0)
00121                 goto err;
00122         PGNO(ipage) = PGNO_INVALID;
00123 
00124         /*
00125          * Repeatedly walk the list of pages, building internal pages, until
00126          * there's only one page at a level.
00127          */
00128         for (level = LEAFLEVEL + 1; cur_cnt > 1; ++level) {
00129                 for (indx = 0, i = next_cnt = 0; i < cur_cnt;) {
00130                         if (indx == 0) {
00131                                 P_INIT(ipage, dbp->pgsize, pgno_last,
00132                                     PGNO_INVALID, PGNO_INVALID,
00133                                     level, sorted ? P_IBTREE : P_IRECNO);
00134                                 ZERO_LSN(LSN(ipage));
00135 
00136                                 pgno_next[next_cnt++] = pgno_last++;
00137                         }
00138 
00139                         GET_PAGE(dbp, fhp, pgno_cur[i], page);
00140 
00141                         /*
00142                          * If the duplicates are sorted, put the first item on
00143                          * the lower-level page onto a Btree internal page. If
00144                          * the duplicates are not sorted, create an internal
00145                          * Recno structure on the page.  If either case doesn't
00146                          * fit, push out the current page and start a new one.
00147                          */
00148                         nomem = 0;
00149                         if (sorted) {
00150                                 if ((ret = __db_build_bi(
00151                                     dbp, fhp, ipage, page, indx, &nomem)) != 0)
00152                                         goto err;
00153                         } else
00154                                 if ((ret = __db_build_ri(
00155                                     dbp, fhp, ipage, page, indx, &nomem)) != 0)
00156                                         goto err;
00157                         if (nomem) {
00158                                 indx = 0;
00159                                 PUT_PAGE(dbp, fhp, PGNO(ipage), ipage);
00160                         } else {
00161                                 ++indx;
00162                                 ++NUM_ENT(ipage);
00163                                 ++i;
00164                         }
00165                 }
00166 
00167                 /*
00168                  * Push out the last internal page.  Set the top-level record
00169                  * count if we've reached the top.
00170                  */
00171                 if (next_cnt == 1)
00172                         RE_NREC_SET(ipage, nrecs);
00173                 PUT_PAGE(dbp, fhp, PGNO(ipage), ipage);
00174 
00175                 /* Swap the current and next page number arrays. */
00176                 cur_cnt = next_cnt;
00177                 tmp = pgno_cur;
00178                 pgno_cur = pgno_next;
00179                 pgno_next = tmp;
00180         }
00181 
00182 done:   *pgnop = pgno_cur[0];
00183 
00184 err:    if (pgno_cur != NULL)
00185                 __os_free(dbp->dbenv, pgno_cur);
00186         if (pgno_next != NULL)
00187                 __os_free(dbp->dbenv, pgno_next);
00188         if (ipage != NULL)
00189                 __os_free(dbp->dbenv, ipage);
00190         if (page != NULL)
00191                 __os_free(dbp->dbenv, page);
00192 
00193         return (ret);
00194 }
00195 
00196 /*
00197  * __db_build_bi --
00198  *      Build a BINTERNAL entry for a parent page.
00199  */
00200 static int
00201 __db_build_bi(dbp, fhp, ipage, page, indx, nomemp)
00202         DB *dbp;
00203         DB_FH *fhp;
00204         PAGE *ipage, *page;
00205         u_int32_t indx;
00206         int *nomemp;
00207 {
00208         BINTERNAL bi, *child_bi;
00209         BKEYDATA *child_bk;
00210         u_int8_t *p;
00211         int ret;
00212         db_indx_t *inp;
00213 
00214         inp = P_INP(dbp, ipage);
00215         switch (TYPE(page)) {
00216         case P_IBTREE:
00217                 child_bi = GET_BINTERNAL(dbp, page, 0);
00218                 if (P_FREESPACE(dbp, ipage) < BINTERNAL_PSIZE(child_bi->len)) {
00219                         *nomemp = 1;
00220                         return (0);
00221                 }
00222                 inp[indx] =
00223                     HOFFSET(ipage) -= BINTERNAL_SIZE(child_bi->len);
00224                 p = P_ENTRY(dbp, ipage, indx);
00225 
00226                 bi.len = child_bi->len;
00227                 B_TSET(bi.type, child_bi->type, 0);
00228                 bi.pgno = PGNO(page);
00229                 bi.nrecs = __bam_total(dbp, page);
00230                 memcpy(p, &bi, SSZA(BINTERNAL, data));
00231                 p += SSZA(BINTERNAL, data);
00232                 memcpy(p, child_bi->data, child_bi->len);
00233 
00234                 /* Increment the overflow ref count. */
00235                 if (B_TYPE(child_bi->type) == B_OVERFLOW)
00236                         if ((ret = __db_up_ovref(dbp, fhp,
00237                             ((BOVERFLOW *)(child_bi->data))->pgno)) != 0)
00238                                 return (ret);
00239                 break;
00240         case P_LDUP:
00241                 child_bk = GET_BKEYDATA(dbp, page, 0);
00242                 switch (B_TYPE(child_bk->type)) {
00243                 case B_KEYDATA:
00244                         if (P_FREESPACE(dbp, ipage) <
00245                             BINTERNAL_PSIZE(child_bk->len)) {
00246                                 *nomemp = 1;
00247                                 return (0);
00248                         }
00249                         inp[indx] =
00250                             HOFFSET(ipage) -= BINTERNAL_SIZE(child_bk->len);
00251                         p = P_ENTRY(dbp, ipage, indx);
00252 
00253                         bi.len = child_bk->len;
00254                         B_TSET(bi.type, child_bk->type, 0);
00255                         bi.pgno = PGNO(page);
00256                         bi.nrecs = __bam_total(dbp, page);
00257                         memcpy(p, &bi, SSZA(BINTERNAL, data));
00258                         p += SSZA(BINTERNAL, data);
00259                         memcpy(p, child_bk->data, child_bk->len);
00260                         break;
00261                 case B_OVERFLOW:
00262                         if (P_FREESPACE(dbp, ipage) <
00263                             BINTERNAL_PSIZE(BOVERFLOW_SIZE)) {
00264                                 *nomemp = 1;
00265                                 return (0);
00266                         }
00267                         inp[indx] =
00268                             HOFFSET(ipage) -= BINTERNAL_SIZE(BOVERFLOW_SIZE);
00269                         p = P_ENTRY(dbp, ipage, indx);
00270 
00271                         bi.len = BOVERFLOW_SIZE;
00272                         B_TSET(bi.type, child_bk->type, 0);
00273                         bi.pgno = PGNO(page);
00274                         bi.nrecs = __bam_total(dbp, page);
00275                         memcpy(p, &bi, SSZA(BINTERNAL, data));
00276                         p += SSZA(BINTERNAL, data);
00277                         memcpy(p, child_bk, BOVERFLOW_SIZE);
00278 
00279                         /* Increment the overflow ref count. */
00280                         if ((ret = __db_up_ovref(dbp, fhp,
00281                             ((BOVERFLOW *)child_bk)->pgno)) != 0)
00282                                 return (ret);
00283                         break;
00284                 default:
00285                         return (__db_pgfmt(dbp->dbenv, PGNO(page)));
00286                 }
00287                 break;
00288         default:
00289                 return (__db_pgfmt(dbp->dbenv, PGNO(page)));
00290         }
00291 
00292         return (0);
00293 }
00294 
00295 /*
00296  * __db_build_ri --
00297  *      Build a RINTERNAL entry for an internal parent page.
00298  */
00299 static int
00300 __db_build_ri(dbp, fhp, ipage, page, indx, nomemp)
00301         DB *dbp;
00302         DB_FH *fhp;
00303         PAGE *ipage, *page;
00304         u_int32_t indx;
00305         int *nomemp;
00306 {
00307         RINTERNAL ri;
00308         db_indx_t *inp;
00309 
00310         COMPQUIET(fhp, NULL);
00311         inp = P_INP(dbp, ipage);
00312         if (P_FREESPACE(dbp, ipage) < RINTERNAL_PSIZE) {
00313                 *nomemp = 1;
00314                 return (0);
00315         }
00316 
00317         ri.pgno = PGNO(page);
00318         ri.nrecs = __bam_total(dbp, page);
00319         inp[indx] = HOFFSET(ipage) -= RINTERNAL_SIZE;
00320         memcpy(P_ENTRY(dbp, ipage, indx), &ri, RINTERNAL_SIZE);
00321 
00322         return (0);
00323 }
00324 
00325 /*
00326  * __db_up_ovref --
00327  *      Increment/decrement the reference count on an overflow page.
00328  */
00329 static int
00330 __db_up_ovref(dbp, fhp, pgno)
00331         DB *dbp;
00332         DB_FH *fhp;
00333         db_pgno_t pgno;
00334 {
00335         PAGE *page;
00336         size_t n;
00337         int ret;
00338 
00339         /* Allocate room to hold a page. */
00340         if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &page)) != 0)
00341                 return (ret);
00342 
00343         GET_PAGE(dbp, fhp, pgno, page);
00344         ++OV_REF(page);
00345         PUT_PAGE(dbp, fhp, pgno, page);
00346 
00347 err:    __os_free(dbp->dbenv, page);
00348 
00349         return (ret);
00350 }

Generated on Sun Dec 25 12:14:21 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2