1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: hash_upgrade.c,v 12.15 2008/01/08 20:58:34 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/hash.h" 14#include "dbinc/db_upgrade.h" 15 16/* 17 * __ham_30_hashmeta -- 18 * Upgrade the database from version 4/5 to version 6. 19 * 20 * PUBLIC: int __ham_30_hashmeta __P((DB *, char *, u_int8_t *)); 21 */ 22int 23__ham_30_hashmeta(dbp, real_name, obuf) 24 DB *dbp; 25 char *real_name; 26 u_int8_t *obuf; 27{ 28 ENV *env; 29 HASHHDR *oldmeta; 30 HMETA30 newmeta; 31 u_int32_t *o_spares, *n_spares; 32 u_int32_t fillf, i, maxb, max_entry, nelem; 33 int ret; 34 35 env = dbp->env; 36 memset(&newmeta, 0, sizeof(newmeta)); 37 38 oldmeta = (HASHHDR *)obuf; 39 40 /* 41 * The first 32 bytes are similar. The only change is the version 42 * and that we removed the ovfl_point and have the page type now. 43 */ 44 45 newmeta.dbmeta.lsn = oldmeta->lsn; 46 newmeta.dbmeta.pgno = oldmeta->pgno; 47 newmeta.dbmeta.magic = oldmeta->magic; 48 newmeta.dbmeta.version = 6; 49 newmeta.dbmeta.pagesize = oldmeta->pagesize; 50 newmeta.dbmeta.type = P_HASHMETA; 51 52 /* Move flags */ 53 newmeta.dbmeta.flags = oldmeta->flags; 54 55 /* Copy the free list, which has changed its name but works the same. */ 56 newmeta.dbmeta.free = oldmeta->last_freed; 57 58 /* Copy: max_bucket, high_mask, low-mask, ffactor, nelem, h_charkey */ 59 newmeta.max_bucket = oldmeta->max_bucket; 60 newmeta.high_mask = oldmeta->high_mask; 61 newmeta.low_mask = oldmeta->low_mask; 62 newmeta.ffactor = oldmeta->ffactor; 63 newmeta.nelem = oldmeta->nelem; 64 newmeta.h_charkey = oldmeta->h_charkey; 65 66 /* 67 * There was a bug in 2.X versions where the nelem could go negative. 68 * In general, this is considered "bad." If it does go negative 69 * (that is, very large and positive), we'll die trying to dump and 70 * load this database. So, let's see if we can fix it here. 71 */ 72 nelem = newmeta.nelem; 73 fillf = newmeta.ffactor; 74 maxb = newmeta.max_bucket; 75 76 if ((fillf != 0 && fillf * maxb < 2 * nelem) || 77 (fillf == 0 && nelem > 0x8000000)) 78 newmeta.nelem = 0; 79 80 /* 81 * We now have to convert the spares array. The old spares array 82 * contained the total number of extra pages allocated prior to 83 * the bucket that begins the next doubling. The new spares array 84 * contains the page number of the first bucket in the next doubling 85 * MINUS the bucket number of that bucket. 86 */ 87 o_spares = oldmeta->spares; 88 n_spares = newmeta.spares; 89 max_entry = __db_log2(maxb + 1); /* highest spares entry in use */ 90 n_spares[0] = 1; 91 for (i = 1; i < NCACHED && i <= max_entry; i++) 92 n_spares[i] = 1 + o_spares[i - 1]; 93 94 /* Replace the unique ID. */ 95 if ((ret = __os_fileid(env, real_name, 1, newmeta.dbmeta.uid)) != 0) 96 return (ret); 97 98 /* Overwrite the original. */ 99 memcpy(oldmeta, &newmeta, sizeof(newmeta)); 100 101 return (0); 102} 103 104/* 105 * __ham_30_sizefix -- 106 * Make sure that all hash pages belonging to the current 107 * hash doubling are within the bounds of the file. 108 * 109 * PUBLIC: int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *)); 110 */ 111int 112__ham_30_sizefix(dbp, fhp, realname, metabuf) 113 DB *dbp; 114 DB_FH *fhp; 115 char *realname; 116 u_int8_t *metabuf; 117{ 118 u_int8_t buf[DB_MAX_PGSIZE]; 119 ENV *env; 120 HMETA30 *meta; 121 db_pgno_t last_actual, last_desired; 122 int ret; 123 size_t nw; 124 u_int32_t pagesize; 125 126 env = dbp->env; 127 memset(buf, 0, DB_MAX_PGSIZE); 128 129 meta = (HMETA30 *)metabuf; 130 pagesize = meta->dbmeta.pagesize; 131 132 /* 133 * Get the last page number. To do this, we'll need dbp->pgsize 134 * to be set right, so slam it into place. 135 */ 136 dbp->pgsize = pagesize; 137 if ((ret = __db_lastpgno(dbp, realname, fhp, &last_actual)) != 0) 138 return (ret); 139 140 /* 141 * The last bucket in the doubling is equal to high_mask; calculate 142 * the page number that implies. 143 */ 144 last_desired = BS_TO_PAGE(meta->high_mask, meta->spares); 145 146 /* 147 * If last_desired > last_actual, we need to grow the file. Write 148 * a zeroed page where last_desired would go. 149 */ 150 if (last_desired > last_actual) { 151 if ((ret = __os_seek( 152 env, fhp, last_desired, pagesize, 0)) != 0) 153 return (ret); 154 if ((ret = __os_write(env, fhp, buf, pagesize, &nw)) != 0) 155 return (ret); 156 } 157 158 return (0); 159} 160 161/* 162 * __ham_31_hashmeta -- 163 * Upgrade the database from version 6 to version 7. 164 * 165 * PUBLIC: int __ham_31_hashmeta 166 * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); 167 */ 168int 169__ham_31_hashmeta(dbp, real_name, flags, fhp, h, dirtyp) 170 DB *dbp; 171 char *real_name; 172 u_int32_t flags; 173 DB_FH *fhp; 174 PAGE *h; 175 int *dirtyp; 176{ 177 HMETA30 *oldmeta; 178 HMETA31 *newmeta; 179 180 COMPQUIET(dbp, NULL); 181 COMPQUIET(real_name, NULL); 182 COMPQUIET(fhp, NULL); 183 184 newmeta = (HMETA31 *)h; 185 oldmeta = (HMETA30 *)h; 186 187 /* 188 * Copy the fields down the page. 189 * The fields may overlap so start at the bottom and use memmove(). 190 */ 191 memmove(newmeta->spares, oldmeta->spares, sizeof(oldmeta->spares)); 192 newmeta->h_charkey = oldmeta->h_charkey; 193 newmeta->nelem = oldmeta->nelem; 194 newmeta->ffactor = oldmeta->ffactor; 195 newmeta->low_mask = oldmeta->low_mask; 196 newmeta->high_mask = oldmeta->high_mask; 197 newmeta->max_bucket = oldmeta->max_bucket; 198 memmove(newmeta->dbmeta.uid, 199 oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid)); 200 newmeta->dbmeta.flags = oldmeta->dbmeta.flags; 201 newmeta->dbmeta.record_count = 0; 202 newmeta->dbmeta.key_count = 0; 203 ZERO_LSN(newmeta->dbmeta.unused3); 204 205 /* Update the version. */ 206 newmeta->dbmeta.version = 7; 207 208 /* Upgrade the flags. */ 209 if (LF_ISSET(DB_DUPSORT)) 210 F_SET(&newmeta->dbmeta, DB_HASH_DUPSORT); 211 212 *dirtyp = 1; 213 return (0); 214} 215 216/* 217 * __ham_31_hash -- 218 * Upgrade the database hash leaf pages. 219 * 220 * PUBLIC: int __ham_31_hash 221 * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); 222 */ 223int 224__ham_31_hash(dbp, real_name, flags, fhp, h, dirtyp) 225 DB *dbp; 226 char *real_name; 227 u_int32_t flags; 228 DB_FH *fhp; 229 PAGE *h; 230 int *dirtyp; 231{ 232 HKEYDATA *hk; 233 db_pgno_t pgno, tpgno; 234 db_indx_t indx; 235 int ret; 236 237 COMPQUIET(flags, 0); 238 239 ret = 0; 240 for (indx = 0; indx < NUM_ENT(h); indx += 2) { 241 hk = (HKEYDATA *)H_PAIRDATA(dbp, h, indx); 242 if (HPAGE_PTYPE(hk) == H_OFFDUP) { 243 memcpy(&pgno, HOFFDUP_PGNO(hk), sizeof(db_pgno_t)); 244 tpgno = pgno; 245 if ((ret = __db_31_offdup(dbp, real_name, fhp, 246 LF_ISSET(DB_DUPSORT) ? 1 : 0, &tpgno)) != 0) 247 break; 248 if (pgno != tpgno) { 249 *dirtyp = 1; 250 memcpy(HOFFDUP_PGNO(hk), 251 &tpgno, sizeof(db_pgno_t)); 252 } 253 } 254 } 255 256 return (ret); 257} 258 259/* 260 * __ham_46_hashmeta -- 261 * Upgrade the database from version 8 to version 9. 262 * 263 * PUBLIC: int __ham_46_hashmeta 264 * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); 265 */ 266int 267__ham_46_hashmeta(dbp, real_name, flags, fhp, h, dirtyp) 268 DB *dbp; 269 char *real_name; 270 u_int32_t flags; 271 DB_FH *fhp; 272 PAGE *h; 273 int *dirtyp; 274{ 275 HMETA33 *newmeta; 276 277 COMPQUIET(dbp, NULL); 278 COMPQUIET(real_name, NULL); 279 COMPQUIET(flags, 0); 280 COMPQUIET(fhp, NULL); 281 282 newmeta = (HMETA33 *)h; 283 /* Update the version. */ 284 newmeta->dbmeta.version = 9; 285 *dirtyp = 1; 286 287 return (0); 288} 289 290/* 291 * __ham_46_hash -- 292 * Upgrade the database hash leaf pages. 293 * From version 8 databases to version 9. 294 * Involves sorting leaf pages, no format change. 295 * 296 * PUBLIC: int __ham_46_hash 297 * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); 298 */ 299int 300__ham_46_hash(dbp, real_name, flags, fhp, h, dirtyp) 301 DB *dbp; 302 char *real_name; 303 u_int32_t flags; 304 DB_FH *fhp; 305 PAGE *h; 306 int *dirtyp; 307{ 308 DBC *dbc; 309 int ret, t_ret; 310 311 COMPQUIET(real_name, NULL); 312 COMPQUIET(flags, 0); 313 COMPQUIET(fhp, NULL); 314 315 if ((ret = __db_cursor(dbp, NULL, NULL, &dbc, 0)) != 0) 316 return (ret); 317 *dirtyp = 1; 318 ret = __ham_sort_page(dbc, NULL, h); 319 if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0) 320 ret = t_ret; 321 322 return (ret); 323} 324