db_upg.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__upg_8c-source.html,v 1.1 2008/06/08 10:18:20 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <errno.h>
00018 #include <string.h>
00019 #endif
00020 
00021 #include "db_int.h"
00022 #include "db_page.h"
00023 #include "db_swap.h"
00024 #include "btree.h"
00025 #include "hash.h"
00026 #include "qam.h"
00027 
00028 static int (* const func_31_list[P_PAGETYPE_MAX])
00029     __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)) = {
00030         NULL,                   /* P_INVALID */
00031         NULL,                   /* __P_DUPLICATE */
00032         CDB___ham_31_hash,              /* P_HASH */
00033         NULL,                   /* P_IBTREE */
00034         NULL,                   /* P_IRECNO */
00035         CDB___bam_31_lbtree,    /* P_LBTREE */
00036         NULL,                   /* P_LRECNO */
00037         NULL,                   /* P_OVERFLOW */
00038         CDB___ham_31_hashmeta,  /* P_HASHMETA */
00039         CDB___bam_31_btreemeta, /* P_BTREEMETA */
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  * CDB___db_upgrade --
00047  *      Upgrade an existing database.
00048  *
00049  * PUBLIC: int CDB___db_upgrade __P((DB *, const char *, u_int32_t));
00050  */
00051 int
00052 CDB___db_upgrade(dbp, fname, flags)
00053         DB *dbp;
00054         const char *fname;
00055         u_int32_t flags;
00056 {
00057         DB_ENV *dbenv;
00058         DB_FH fh;
00059         size_t n;
00060         int ret, t_ret;
00061         u_int8_t mbuf[256];
00062         char *real_name;
00063 
00064         dbenv = dbp->dbenv;
00065 
00066         /* Validate arguments. */
00067         if ((ret = CDB___db_fchk(dbenv, "DB->upgrade", flags, DB_DUPSORT)) != 0)
00068                 return (ret);
00069 
00070         /* Get the real backing file name. */
00071         if ((ret = CDB___db_appname(dbenv,
00072             DB_APP_DATA, NULL, fname, 0, NULL, &real_name)) != 0)
00073                 return (ret);
00074 
00075         /* Open the file. */
00076         if ((ret = CDB___os_open(dbenv, real_name, 0, 0, &fh)) != 0) {
00077                 CDB___db_err(dbenv, "%s: %s", real_name, CDB_db_strerror(ret));
00078                 return (ret);
00079         }
00080 
00081         /* Initialize the feedback. */
00082         if (dbp->db_feedback != NULL)
00083                 dbp->db_feedback(dbp, DB_UPGRADE, 0);
00084 
00085         /*
00086          * Read the metadata page.  We read 256 bytes, which is larger than
00087          * any access method's metadata page and smaller than any disk sector.
00088          */
00089         if ((ret = CDB___os_read(dbenv, &fh, mbuf, sizeof(mbuf), &n)) != 0)
00090                 goto err;
00091 
00092         switch (((DBMETA *)mbuf)->magic) {
00093         case DB_BTREEMAGIC:
00094                 switch (((DBMETA *)mbuf)->version) {
00095                 case 6:
00096                         /*
00097                          * Before V7 not all pages had page types, so we do the
00098                          * single meta-data page by hand.
00099                          */
00100                         if ((ret =
00101                             CDB___bam_30_btreemeta(dbp, real_name, mbuf)) != 0)
00102                                 goto err;
00103                         if ((ret = CDB___os_seek(dbenv,
00104                             &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00105                                 goto err;
00106                         if ((ret = CDB___os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
00107                                 goto err;
00108                         /* FALLTHROUGH */
00109                 case 7:
00110                         /*
00111                          * We need the page size to do more.  Rip it out of
00112                          * the meta-data page.
00113                          */
00114                         memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
00115 
00116                         if ((ret = __db_page_pass(
00117                             dbp, real_name, flags, func_31_list, &fh)) != 0)
00118                                 goto err;
00119                         /* FALLTHROUGH */
00120                 case 8:
00121                         break;
00122                 default:
00123                         CDB___db_err(dbenv, "%s: unsupported btree version: %lu",
00124                             real_name, (u_long)((DBMETA *)mbuf)->version);
00125                         ret = DB_OLD_VERSION;
00126                         goto err;
00127                 }
00128                 break;
00129         case DB_HASHMAGIC:
00130                 switch (((DBMETA *)mbuf)->version) {
00131                 case 4:
00132                 case 5:
00133                         /*
00134                          * Before V6 not all pages had page types, so we do the
00135                          * single meta-data page by hand.
00136                          */
00137                         if ((ret =
00138                             CDB___ham_30_hashmeta(dbp, real_name, mbuf)) != 0)
00139                                 goto err;
00140                         if ((ret = CDB___os_seek(dbenv,
00141                             &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00142                                 goto err;
00143                         if ((ret = CDB___os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
00144                                 goto err;
00145                         /* FALLTHROUGH */
00146                 case 6:
00147                         /*
00148                          * We need the page size to do more.  Rip it out of
00149                          * the meta-data page.
00150                          */
00151                         memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
00152 
00153                         if ((ret = __db_page_pass(
00154                             dbp, real_name, flags, func_31_list, &fh)) != 0)
00155                                 goto err;
00156                         /* FALLTHROUGH */
00157                 case 7:
00158                         break;
00159                 default:
00160                         CDB___db_err(dbenv, "%s: unsupported hash version: %lu",
00161                             real_name, (u_long)((DBMETA *)mbuf)->version);
00162                         ret = DB_OLD_VERSION;
00163                         goto err;
00164                 }
00165                 break;
00166         case DB_QAMMAGIC:
00167                 switch (((DBMETA *)mbuf)->version) {
00168                 case 1:
00169                         /*
00170                          * If we're in a Queue database, the only page that
00171                          * needs upgrading is the meta-database page, don't
00172                          * bother with a full pass.
00173                          */
00174                         if ((ret = CDB___qam_31_qammeta(dbp, real_name, mbuf)) != 0)
00175                                 return (ret);
00176                         if ((ret = CDB___os_seek(dbenv,
00177                             &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00178                                 goto err;
00179                         if ((ret = CDB___os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
00180                                 goto err;
00181                         /* FALLTHROUGH */
00182                 case 2:
00183                         break;
00184                 default:
00185                         CDB___db_err(dbenv, "%s: unsupported queue version: %lu",
00186                             real_name, (u_long)((DBMETA *)mbuf)->version);
00187                         ret = DB_OLD_VERSION;
00188                         goto err;
00189                 }
00190                 break;
00191         default:
00192                 M_32_SWAP(((DBMETA *)mbuf)->magic);
00193                 switch (((DBMETA *)mbuf)->magic) {
00194                 case DB_BTREEMAGIC:
00195                 case DB_HASHMAGIC:
00196                 case DB_QAMMAGIC:
00197                         CDB___db_err(dbenv,
00198                 "%s: DB->upgrade only supported on native byte-order systems",
00199                             real_name);
00200                         break;
00201                 default:
00202                         CDB___db_err(dbenv,
00203                             "%s: unrecognized file type", real_name);
00204                         break;
00205                 }
00206                 ret = EINVAL;
00207                 goto err;
00208         }
00209 
00210         ret = CDB___os_fsync(dbenv, &fh);
00211 
00212 err:    if ((t_ret = CDB___os_closehandle(&fh)) != 0 && ret == 0)
00213                 ret = t_ret;
00214         CDB___os_freestr(real_name);
00215 
00216         /* We're done. */
00217         if (dbp->db_feedback != NULL)
00218                 dbp->db_feedback(dbp, DB_UPGRADE, 100);
00219 
00220         return (ret);
00221 }
00222 
00223 /*
00224  * __db_page_pass --
00225  *      Walk the pages of the database, upgrading whatever needs it.
00226  */
00227 static int
00228 __db_page_pass(dbp, real_name, flags, fl, fhp)
00229         DB *dbp;
00230         char *real_name;
00231         u_int32_t flags;
00232         int (* const fl[P_PAGETYPE_MAX])
00233             __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
00234         DB_FH *fhp;
00235 {
00236         DB_ENV *dbenv;
00237         PAGE *page;
00238         db_pgno_t i, pgno_last;
00239         size_t n;
00240         int dirty, ret;
00241 
00242         dbenv = dbp->dbenv;
00243 
00244         /* Determine the last page of the file. */
00245         if ((ret = CDB___db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
00246                 return (ret);
00247 
00248         /* Allocate memory for a single page. */
00249         if ((ret = CDB___os_malloc(dbenv, dbp->pgsize, NULL, &page)) != 0)
00250                 return (ret);
00251 
00252         /* Walk the file, calling the underlying conversion functions. */
00253         for (i = 0; i < pgno_last; ++i) {
00254                 if (dbp->db_feedback != NULL)
00255                         dbp->db_feedback(dbp, DB_UPGRADE, (i * 100)/pgno_last);
00256                 if ((ret = CDB___os_seek(dbenv,
00257                     fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
00258                         break;
00259                 if ((ret = CDB___os_read(dbenv, fhp, page, dbp->pgsize, &n)) != 0)
00260                         break;
00261                 dirty = 0;
00262                 if (fl[TYPE(page)] != NULL && (ret = fl[TYPE(page)]
00263                     (dbp, real_name, flags, fhp, page, &dirty)) != 0)
00264                         break;
00265                 if (dirty) {
00266                         if ((ret = CDB___os_seek(dbenv,
00267                             fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
00268                                 break;
00269                         if ((ret = CDB___os_write(dbenv,
00270                             fhp, page, dbp->pgsize, &n)) != 0)
00271                                 break;
00272                 }
00273         }
00274 
00275         CDB___os_free(page, dbp->pgsize);
00276         return (ret);
00277 }
00278 
00279 /*
00280  * CDB___db_lastpgno --
00281  *      Return the current last page number of the file.
00282  *
00283  * PUBLIC: int CDB___db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *));
00284  */
00285 int
00286 CDB___db_lastpgno(dbp, real_name, fhp, pgno_lastp)
00287         DB *dbp;
00288         char *real_name;
00289         DB_FH *fhp;
00290         db_pgno_t *pgno_lastp;
00291 {
00292         DB_ENV *dbenv;
00293         db_pgno_t pgno_last;
00294         u_int32_t mbytes, bytes;
00295         int ret;
00296 
00297         dbenv = dbp->dbenv;
00298 
00299         if ((ret = CDB___os_ioinfo(dbenv,
00300             real_name, fhp, &mbytes, &bytes, NULL)) != 0) {
00301                 CDB___db_err(dbenv, "%s: %s", real_name, CDB_db_strerror(ret));
00302                 return (ret);
00303         }
00304 
00305         /* Page sizes have to be a power-of-two. */
00306         if (bytes % dbp->pgsize != 0) {
00307                 CDB___db_err(dbenv,
00308                     "%s: file size not a multiple of the pagesize", real_name);
00309                 return (EINVAL);
00310         }
00311         pgno_last = mbytes * (MEGABYTE / dbp->pgsize);
00312         pgno_last += bytes / dbp->pgsize;
00313 
00314         *pgno_lastp = pgno_last;
00315         return (0);
00316 }

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