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

db_upg.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.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/db_swap.h"
00021 #include "dbinc/btree.h"
00022 #include "dbinc/hash.h"
00023 #include "dbinc/qam.h"
00024 
00025 static int (* const func_31_list[P_PAGETYPE_MAX])
00026     __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)) = {
00027         NULL,                   /* P_INVALID */
00028         NULL,                   /* __P_DUPLICATE */
00029         __ham_31_hash,          /* P_HASH */
00030         NULL,                   /* P_IBTREE */
00031         NULL,                   /* P_IRECNO */
00032         __bam_31_lbtree,        /* P_LBTREE */
00033         NULL,                   /* P_LRECNO */
00034         NULL,                   /* P_OVERFLOW */
00035         __ham_31_hashmeta,      /* P_HASHMETA */
00036         __bam_31_btreemeta,     /* P_BTREEMETA */
00037         NULL,                   /* P_QAMMETA */
00038         NULL,                   /* P_QAMDATA */
00039         NULL,                   /* P_LDUP */
00040 };
00041 
00042 static int __db_page_pass __P((DB *, char *, u_int32_t, int (* const [])
00043                (DB *, char *, u_int32_t, DB_FH *, PAGE *, int *), DB_FH *));
00044 
00045 /*
00046  * __db_upgrade_pp --
00047  *      DB->upgrade pre/post processing.
00048  *
00049  * PUBLIC: int __db_upgrade_pp __P((DB *, const char *, u_int32_t));
00050  */
00051 int
00052 __db_upgrade_pp(dbp, fname, flags)
00053         DB *dbp;
00054         const char *fname;
00055         u_int32_t flags;
00056 {
00057         DB_ENV *dbenv;
00058         int ret;
00059 
00060         dbenv = dbp->dbenv;
00061 
00062         PANIC_CHECK(dbp->dbenv);
00063 
00064         /*
00065          * !!!
00066          * The actual argument checking is simple, do it inline.
00067          */
00068         if ((ret = __db_fchk(dbenv, "DB->upgrade", flags, DB_DUPSORT)) != 0)
00069                 return (ret);
00070 
00071         return (__db_upgrade(dbp, fname, flags));
00072 }
00073 
00074 /*
00075  * __db_upgrade --
00076  *      Upgrade an existing database.
00077  *
00078  * PUBLIC: int __db_upgrade __P((DB *, const char *, u_int32_t));
00079  */
00080 int
00081 __db_upgrade(dbp, fname, flags)
00082         DB *dbp;
00083         const char *fname;
00084         u_int32_t flags;
00085 {
00086         DB_ENV *dbenv;
00087         DB_FH *fhp;
00088         size_t n;
00089         int ret, t_ret;
00090         u_int8_t mbuf[256];
00091         char *real_name;
00092 
00093         dbenv = dbp->dbenv;
00094         fhp = NULL;
00095 
00096         /* Get the real backing file name. */
00097         if ((ret = __db_appname(dbenv,
00098             DB_APP_DATA, fname, 0, NULL, &real_name)) != 0)
00099                 return (ret);
00100 
00101         /* Open the file. */
00102         if ((ret = __os_open(dbenv, real_name, 0, 0, &fhp)) != 0) {
00103                 __db_err(dbenv, "%s: %s", real_name, db_strerror(ret));
00104                 return (ret);
00105         }
00106 
00107         /* Initialize the feedback. */
00108         if (dbp->db_feedback != NULL)
00109                 dbp->db_feedback(dbp, DB_UPGRADE, 0);
00110 
00111         /*
00112          * Read the metadata page.  We read 256 bytes, which is larger than
00113          * any access method's metadata page and smaller than any disk sector.
00114          */
00115         if ((ret = __os_read(dbenv, fhp, mbuf, sizeof(mbuf), &n)) != 0)
00116                 goto err;
00117 
00118         switch (((DBMETA *)mbuf)->magic) {
00119         case DB_BTREEMAGIC:
00120                 switch (((DBMETA *)mbuf)->version) {
00121                 case 6:
00122                         /*
00123                          * Before V7 not all pages had page types, so we do the
00124                          * single meta-data page by hand.
00125                          */
00126                         if ((ret =
00127                             __bam_30_btreemeta(dbp, real_name, mbuf)) != 0)
00128                                 goto err;
00129                         if ((ret = __os_seek(dbenv,
00130                             fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00131                                 goto err;
00132                         if ((ret = __os_write(dbenv, fhp, mbuf, 256, &n)) != 0)
00133                                 goto err;
00134                         /* FALLTHROUGH */
00135                 case 7:
00136                         /*
00137                          * We need the page size to do more.  Rip it out of
00138                          * the meta-data page.
00139                          */
00140                         memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
00141 
00142                         if ((ret = __db_page_pass(
00143                             dbp, real_name, flags, func_31_list, fhp)) != 0)
00144                                 goto err;
00145                         /* FALLTHROUGH */
00146                 case 8:
00147                 case 9:
00148                         break;
00149                 default:
00150                         __db_err(dbenv, "%s: unsupported btree version: %lu",
00151                             real_name, (u_long)((DBMETA *)mbuf)->version);
00152                         ret = DB_OLD_VERSION;
00153                         goto err;
00154                 }
00155                 break;
00156         case DB_HASHMAGIC:
00157                 switch (((DBMETA *)mbuf)->version) {
00158                 case 4:
00159                 case 5:
00160                         /*
00161                          * Before V6 not all pages had page types, so we do the
00162                          * single meta-data page by hand.
00163                          */
00164                         if ((ret =
00165                             __ham_30_hashmeta(dbp, real_name, mbuf)) != 0)
00166                                 goto err;
00167                         if ((ret = __os_seek(dbenv,
00168                             fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00169                                 goto err;
00170                         if ((ret = __os_write(dbenv, fhp, mbuf, 256, &n)) != 0)
00171                                 goto err;
00172 
00173                         /*
00174                          * Before V6, we created hash pages one by one as they
00175                          * were needed, using hashhdr.ovfl_point to reserve
00176                          * a block of page numbers for them.  A consequence
00177                          * of this was that, if no overflow pages had been
00178                          * created, the current doubling might extend past
00179                          * the end of the database file.
00180                          *
00181                          * In DB 3.X, we now create all the hash pages
00182                          * belonging to a doubling atomically; it's not
00183                          * safe to just save them for later, because when
00184                          * we create an overflow page we'll just create
00185                          * a new last page (whatever that may be).  Grow
00186                          * the database to the end of the current doubling.
00187                          */
00188                         if ((ret =
00189                             __ham_30_sizefix(dbp, fhp, real_name, mbuf)) != 0)
00190                                 goto err;
00191                         /* FALLTHROUGH */
00192                 case 6:
00193                         /*
00194                          * We need the page size to do more.  Rip it out of
00195                          * the meta-data page.
00196                          */
00197                         memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
00198 
00199                         if ((ret = __db_page_pass(
00200                             dbp, real_name, flags, func_31_list, fhp)) != 0)
00201                                 goto err;
00202                         /* FALLTHROUGH */
00203                 case 7:
00204                 case 8:
00205                         break;
00206                 default:
00207                         __db_err(dbenv, "%s: unsupported hash version: %lu",
00208                             real_name, (u_long)((DBMETA *)mbuf)->version);
00209                         ret = DB_OLD_VERSION;
00210                         goto err;
00211                 }
00212                 break;
00213         case DB_QAMMAGIC:
00214                 switch (((DBMETA *)mbuf)->version) {
00215                 case 1:
00216                         /*
00217                          * If we're in a Queue database, the only page that
00218                          * needs upgrading is the meta-database page, don't
00219                          * bother with a full pass.
00220                          */
00221                         if ((ret = __qam_31_qammeta(dbp, real_name, mbuf)) != 0)
00222                                 return (ret);
00223                         /* FALLTHROUGH */
00224                 case 2:
00225                         if ((ret = __qam_32_qammeta(dbp, real_name, mbuf)) != 0)
00226                                 return (ret);
00227                         if ((ret = __os_seek(dbenv,
00228                             fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00229                                 goto err;
00230                         if ((ret = __os_write(dbenv, fhp, mbuf, 256, &n)) != 0)
00231                                 goto err;
00232                         /* FALLTHROUGH */
00233                 case 3:
00234                 case 4:
00235                         break;
00236                 default:
00237                         __db_err(dbenv, "%s: unsupported queue version: %lu",
00238                             real_name, (u_long)((DBMETA *)mbuf)->version);
00239                         ret = DB_OLD_VERSION;
00240                         goto err;
00241                 }
00242                 break;
00243         default:
00244                 M_32_SWAP(((DBMETA *)mbuf)->magic);
00245                 switch (((DBMETA *)mbuf)->magic) {
00246                 case DB_BTREEMAGIC:
00247                 case DB_HASHMAGIC:
00248                 case DB_QAMMAGIC:
00249                         __db_err(dbenv,
00250                 "%s: DB->upgrade only supported on native byte-order systems",
00251                             real_name);
00252                         break;
00253                 default:
00254                         __db_err(dbenv,
00255                             "%s: unrecognized file type", real_name);
00256                         break;
00257                 }
00258                 ret = EINVAL;
00259                 goto err;
00260         }
00261 
00262         ret = __os_fsync(dbenv, fhp);
00263 
00264 err:    if (fhp != NULL &&
00265             (t_ret = __os_closehandle(dbenv, fhp)) != 0 && ret == 0)
00266                 ret = t_ret;
00267         __os_free(dbenv, real_name);
00268 
00269         /* We're done. */
00270         if (dbp->db_feedback != NULL)
00271                 dbp->db_feedback(dbp, DB_UPGRADE, 100);
00272 
00273         return (ret);
00274 }
00275 
00276 /*
00277  * __db_page_pass --
00278  *      Walk the pages of the database, upgrading whatever needs it.
00279  */
00280 static int
00281 __db_page_pass(dbp, real_name, flags, fl, fhp)
00282         DB *dbp;
00283         char *real_name;
00284         u_int32_t flags;
00285         int (* const fl[P_PAGETYPE_MAX])
00286             __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
00287         DB_FH *fhp;
00288 {
00289         DB_ENV *dbenv;
00290         PAGE *page;
00291         db_pgno_t i, pgno_last;
00292         size_t n;
00293         int dirty, ret;
00294 
00295         dbenv = dbp->dbenv;
00296 
00297         /* Determine the last page of the file. */
00298         if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
00299                 return (ret);
00300 
00301         /* Allocate memory for a single page. */
00302         if ((ret = __os_malloc(dbenv, dbp->pgsize, &page)) != 0)
00303                 return (ret);
00304 
00305         /* Walk the file, calling the underlying conversion functions. */
00306         for (i = 0; i < pgno_last; ++i) {
00307                 if (dbp->db_feedback != NULL)
00308                         dbp->db_feedback(
00309                             dbp, DB_UPGRADE, (int)((i * 100)/pgno_last));
00310                 if ((ret = __os_seek(dbenv,
00311                     fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
00312                         break;
00313                 if ((ret = __os_read(dbenv, fhp, page, dbp->pgsize, &n)) != 0)
00314                         break;
00315                 dirty = 0;
00316                 if (fl[TYPE(page)] != NULL && (ret = fl[TYPE(page)]
00317                     (dbp, real_name, flags, fhp, page, &dirty)) != 0)
00318                         break;
00319                 if (dirty) {
00320                         if ((ret = __os_seek(dbenv,
00321                             fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
00322                                 break;
00323                         if ((ret = __os_write(dbenv,
00324                             fhp, page, dbp->pgsize, &n)) != 0)
00325                                 break;
00326                 }
00327         }
00328 
00329         __os_free(dbp->dbenv, page);
00330         return (ret);
00331 }
00332 
00333 /*
00334  * __db_lastpgno --
00335  *      Return the current last page number of the file.
00336  *
00337  * PUBLIC: int __db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *));
00338  */
00339 int
00340 __db_lastpgno(dbp, real_name, fhp, pgno_lastp)
00341         DB *dbp;
00342         char *real_name;
00343         DB_FH *fhp;
00344         db_pgno_t *pgno_lastp;
00345 {
00346         DB_ENV *dbenv;
00347         db_pgno_t pgno_last;
00348         u_int32_t mbytes, bytes;
00349         int ret;
00350 
00351         dbenv = dbp->dbenv;
00352 
00353         if ((ret = __os_ioinfo(dbenv,
00354             real_name, fhp, &mbytes, &bytes, NULL)) != 0) {
00355                 __db_err(dbenv, "%s: %s", real_name, db_strerror(ret));
00356                 return (ret);
00357         }
00358 
00359         /* Page sizes have to be a power-of-two. */
00360         if (bytes % dbp->pgsize != 0) {
00361                 __db_err(dbenv,
00362                     "%s: file size not a multiple of the pagesize", real_name);
00363                 return (EINVAL);
00364         }
00365         pgno_last = mbytes * (MEGABYTE / dbp->pgsize);
00366         pgno_last += bytes / dbp->pgsize;
00367 
00368         *pgno_lastp = pgno_last;
00369         return (0);
00370 }

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