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

hash_upgrade.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: hash_upgrade.c,v 12.1 2005/06/16 20:22:54 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/hash.h"
00021 #include "dbinc/db_upgrade.h"
00022 
00023 /*
00024  * __ham_30_hashmeta --
00025  *      Upgrade the database from version 4/5 to version 6.
00026  *
00027  * PUBLIC: int __ham_30_hashmeta __P((DB *, char *, u_int8_t *));
00028  */
00029 int
00030 __ham_30_hashmeta(dbp, real_name, obuf)
00031         DB *dbp;
00032         char *real_name;
00033         u_int8_t *obuf;
00034 {
00035         DB_ENV *dbenv;
00036         HASHHDR *oldmeta;
00037         HMETA30 newmeta;
00038         u_int32_t *o_spares, *n_spares;
00039         u_int32_t fillf, i, maxb, max_entry, nelem;
00040         int ret;
00041 
00042         dbenv = dbp->dbenv;
00043         memset(&newmeta, 0, sizeof(newmeta));
00044 
00045         oldmeta = (HASHHDR *)obuf;
00046 
00047         /*
00048          * The first 32 bytes are similar.  The only change is the version
00049          * and that we removed the ovfl_point and have the page type now.
00050          */
00051 
00052         newmeta.dbmeta.lsn = oldmeta->lsn;
00053         newmeta.dbmeta.pgno = oldmeta->pgno;
00054         newmeta.dbmeta.magic = oldmeta->magic;
00055         newmeta.dbmeta.version = 6;
00056         newmeta.dbmeta.pagesize = oldmeta->pagesize;
00057         newmeta.dbmeta.type = P_HASHMETA;
00058 
00059         /* Move flags */
00060         newmeta.dbmeta.flags = oldmeta->flags;
00061 
00062         /* Copy the free list, which has changed its name but works the same. */
00063         newmeta.dbmeta.free = oldmeta->last_freed;
00064 
00065         /* Copy: max_bucket, high_mask, low-mask, ffactor, nelem, h_charkey */
00066         newmeta.max_bucket = oldmeta->max_bucket;
00067         newmeta.high_mask = oldmeta->high_mask;
00068         newmeta.low_mask = oldmeta->low_mask;
00069         newmeta.ffactor = oldmeta->ffactor;
00070         newmeta.nelem = oldmeta->nelem;
00071         newmeta.h_charkey = oldmeta->h_charkey;
00072 
00073         /*
00074          * There was a bug in 2.X versions where the nelem could go negative.
00075          * In general, this is considered "bad."  If it does go negative
00076          * (that is, very large and positive), we'll die trying to dump and
00077          * load this database.  So, let's see if we can fix it here.
00078          */
00079         nelem = newmeta.nelem;
00080         fillf = newmeta.ffactor;
00081         maxb = newmeta.max_bucket;
00082 
00083         if ((fillf != 0 && fillf * maxb < 2 * nelem) ||
00084             (fillf == 0 && nelem > 0x8000000))
00085                 newmeta.nelem = 0;
00086 
00087         /*
00088          * We now have to convert the spares array.  The old spares array
00089          * contained the total number of extra pages allocated prior to
00090          * the bucket that begins the next doubling.  The new spares array
00091          * contains the page number of the first bucket in the next doubling
00092          * MINUS the bucket number of that bucket.
00093          */
00094         o_spares = oldmeta->spares;
00095         n_spares = newmeta.spares;
00096         max_entry = __db_log2(maxb + 1);   /* highest spares entry in use */
00097         n_spares[0] = 1;
00098         for (i = 1; i < NCACHED && i <= max_entry; i++)
00099                 n_spares[i] = 1 + o_spares[i - 1];
00100 
00101                                         /* Replace the unique ID. */
00102         if ((ret = __os_fileid(dbenv, real_name, 1, newmeta.dbmeta.uid)) != 0)
00103                 return (ret);
00104 
00105         /* Overwrite the original. */
00106         memcpy(oldmeta, &newmeta, sizeof(newmeta));
00107 
00108         return (0);
00109 }
00110 
00111 /*
00112  * __ham_30_sizefix --
00113  *      Make sure that all hash pages belonging to the current
00114  *      hash doubling are within the bounds of the file.
00115  *
00116  * PUBLIC: int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *));
00117  */
00118 int
00119 __ham_30_sizefix(dbp, fhp, realname, metabuf)
00120         DB *dbp;
00121         DB_FH *fhp;
00122         char *realname;
00123         u_int8_t *metabuf;
00124 {
00125         u_int8_t buf[DB_MAX_PGSIZE];
00126         DB_ENV *dbenv;
00127         HMETA30 *meta;
00128         db_pgno_t last_actual, last_desired;
00129         int ret;
00130         size_t nw;
00131         u_int32_t pagesize;
00132 
00133         dbenv = dbp->dbenv;
00134         memset(buf, 0, DB_MAX_PGSIZE);
00135 
00136         meta = (HMETA30 *)metabuf;
00137         pagesize = meta->dbmeta.pagesize;
00138 
00139         /*
00140          * Get the last page number.  To do this, we'll need dbp->pgsize
00141          * to be set right, so slam it into place.
00142          */
00143         dbp->pgsize = pagesize;
00144         if ((ret = __db_lastpgno(dbp, realname, fhp, &last_actual)) != 0)
00145                 return (ret);
00146 
00147         /*
00148          * The last bucket in the doubling is equal to high_mask;  calculate
00149          * the page number that implies.
00150          */
00151         last_desired = BS_TO_PAGE(meta->high_mask, meta->spares);
00152 
00153         /*
00154          * If last_desired > last_actual, we need to grow the file.  Write
00155          * a zeroed page where last_desired would go.
00156          */
00157         if (last_desired > last_actual) {
00158                 if ((ret = __os_seek(dbenv,
00159                     fhp, pagesize, last_desired, 0, 0, DB_OS_SEEK_SET)) != 0)
00160                         return (ret);
00161                 if ((ret = __os_write(dbenv, fhp, buf, pagesize, &nw)) != 0)
00162                         return (ret);
00163         }
00164 
00165         return (0);
00166 }
00167 
00168 /*
00169  * __ham_31_hashmeta --
00170  *      Upgrade the database from version 6 to version 7.
00171  *
00172  * PUBLIC: int __ham_31_hashmeta
00173  * PUBLIC:      __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
00174  */
00175 int
00176 __ham_31_hashmeta(dbp, real_name, flags, fhp, h, dirtyp)
00177         DB *dbp;
00178         char *real_name;
00179         u_int32_t flags;
00180         DB_FH *fhp;
00181         PAGE *h;
00182         int *dirtyp;
00183 {
00184         HMETA31 *newmeta;
00185         HMETA30 *oldmeta;
00186 
00187         COMPQUIET(dbp, NULL);
00188         COMPQUIET(real_name, NULL);
00189         COMPQUIET(fhp, NULL);
00190 
00191         newmeta = (HMETA31 *)h;
00192         oldmeta = (HMETA30 *)h;
00193 
00194         /*
00195          * Copy the fields down the page.
00196          * The fields may overlap so start at the bottom and use memmove().
00197          */
00198         memmove(newmeta->spares, oldmeta->spares, sizeof(oldmeta->spares));
00199         newmeta->h_charkey = oldmeta->h_charkey;
00200         newmeta->nelem = oldmeta->nelem;
00201         newmeta->ffactor = oldmeta->ffactor;
00202         newmeta->low_mask = oldmeta->low_mask;
00203         newmeta->high_mask = oldmeta->high_mask;
00204         newmeta->max_bucket = oldmeta->max_bucket;
00205         memmove(newmeta->dbmeta.uid,
00206             oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid));
00207         newmeta->dbmeta.flags = oldmeta->dbmeta.flags;
00208         newmeta->dbmeta.record_count = 0;
00209         newmeta->dbmeta.key_count = 0;
00210         ZERO_LSN(newmeta->dbmeta.unused3);
00211 
00212         /* Update the version. */
00213         newmeta->dbmeta.version = 7;
00214 
00215         /* Upgrade the flags. */
00216         if (LF_ISSET(DB_DUPSORT))
00217                 F_SET(&newmeta->dbmeta, DB_HASH_DUPSORT);
00218 
00219         *dirtyp = 1;
00220         return (0);
00221 }
00222 
00223 /*
00224  * __ham_31_hash --
00225  *      Upgrade the database hash leaf pages.
00226  *
00227  * PUBLIC: int __ham_31_hash
00228  * PUBLIC:      __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
00229  */
00230 int
00231 __ham_31_hash(dbp, real_name, flags, fhp, h, dirtyp)
00232         DB *dbp;
00233         char *real_name;
00234         u_int32_t flags;
00235         DB_FH *fhp;
00236         PAGE *h;
00237         int *dirtyp;
00238 {
00239         HKEYDATA *hk;
00240         db_pgno_t pgno, tpgno;
00241         db_indx_t indx;
00242         int ret;
00243 
00244         COMPQUIET(flags, 0);
00245 
00246         ret = 0;
00247         for (indx = 0; indx < NUM_ENT(h); indx += 2) {
00248                 hk = (HKEYDATA *)H_PAIRDATA(dbp, h, indx);
00249                 if (HPAGE_PTYPE(hk) == H_OFFDUP) {
00250                         memcpy(&pgno, HOFFDUP_PGNO(hk), sizeof(db_pgno_t));
00251                         tpgno = pgno;
00252                         if ((ret = __db_31_offdup(dbp, real_name, fhp,
00253                             LF_ISSET(DB_DUPSORT) ? 1 : 0, &tpgno)) != 0)
00254                                 break;
00255                         if (pgno != tpgno) {
00256                                 *dirtyp = 1;
00257                                 memcpy(HOFFDUP_PGNO(hk),
00258                                     &tpgno, sizeof(db_pgno_t));
00259                         }
00260                 }
00261         }
00262 
00263         return (ret);
00264 }

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