1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998, 1999
* Sleepycat Software. All rights reserved.
*/
#include "db_config.h"
#ifndef lint
static const char sccsid[] = "@(#)hash_upgrade.c 11.7 (Sleepycat) 10/20/99";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#endif
#include "db_int.h"
#include "db_page.h"
#include "db_swap.h"
#include "hash.h"
static int CDB___ham_upgrade5 __P((DB *, int, char *, DB_FH *));
/*
* CDB___ham_upgrade --
* Upgrade Hash databases.
*
* PUBLIC: int CDB___ham_upgrade __P((DB *, int, char *, DB_FH *, char *));
*/
int
CDB___ham_upgrade(dbp, swapped, real_name, fhp, mbuf)
DB *dbp;
int swapped;
char *real_name, *mbuf;
DB_FH *fhp;
{
DB_ENV *dbenv;
int ret;
dbenv = dbp->dbenv;
/* Check the version. */
switch (((DBMETA *)mbuf)->version) {
case 4:
case 5:
if ((ret = CDB___ham_upgrade5(dbp, swapped, real_name, fhp)) != 0)
return (ret);
/* FALLTHROUGH */
case 6:
break;
default:
CDB___db_err(dbenv, "%s: unsupported hash version: %lu",
real_name, (u_long)((DBMETA *)mbuf)->version);
return (DB_OLD_VERSION);
}
return (0);
}
/*
* CDB___ham_upgrade5 --
* Upgrade the database from version 4/5 to version 6.
*/
static int
CDB___ham_upgrade5(dbp, swapped, real_name, fhp)
DB *dbp;
int swapped;
char *real_name;
DB_FH *fhp;
{
DB_ENV *dbenv;
ssize_t n;
u_int32_t *o_spares, *n_spares, version;
u_int32_t fillf, maxb, nelem;
int i, non_zero, ret;
u_int8_t nbuf[256], *new, obuf[256];
dbenv = dbp->dbenv;
if (dbp->db_feedback != NULL)
dbp->db_feedback(dbp, DB_UPGRADE, 0);
/*
* Seek to the beginning of the file and read the metadata page. We
* read 256 bytes, which is larger than any access method's metadata
* page.
*/
if ((ret = CDB___os_seek(fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
return (ret);
if ((ret = CDB___os_read(fhp, obuf, sizeof(obuf), &n)) != 0)
return (ret);
/*
* Upgrade a Hash meta-data page.
* Version 5: byte range: Version 6: byte range:
* lsn 00-07 lsn 00-07
* pgno 08-11 pgno 08-11
* magic 12-15 magic 12-15
* version 16-19 version 16-19
* pagesize 20-23 pagesize 20-23
* ovfl_point 24-27 unused 24
* type 25
* unused 26-27
* last_freed 28-31 free 28-31
* max_bucket 32-35 flags 32-35
* high_mask 36-39 uid 36-55
* low_mask 40-43 max_bucket 56-59
* ffactor 44-47 high_mask 60-63
* nelem 48-51 low_mask 64-67
* h_charkey 52-55 ffactor 68-71
* flags 56-59 nelem 72-75
* spares 60-187 h_charkey 76-79
* uid 188-207 spares 80-207
*
*/
/*
* The first 32 bytes are similar. The only change is the version
* and that we removed the ovfl_point and have the page type now.
*/
memcpy(nbuf, obuf, 32);
/* Update the version. */
version = 6;
if (swapped)
M_32_SWAP(version);
memcpy(nbuf + 16, &version, sizeof(u_int32_t));
/* Assign unused and type fields. */
new = nbuf + 24;
*new++ = '\0';
*new++ = P_HASHMETA;
*new++ = '\0';
*new = '\0';
/* Move flags */
memcpy(nbuf + 32, obuf + 56, 4);
/* Copy: max_bucket, high_mask, low-mask, ffactor, nelem, h_charkey */
memcpy(nbuf + 56, obuf + 32, 24);
/*
* There was a bug in 2.X versions where the nelem could go negative.
* In general, this is considered "bad." If it does go negative
* (that is, very large and positive), we'll die trying to dump and
* load this database. So, let's see if we can fix it here.
*/
memcpy(&nelem, nbuf + 72, sizeof(u_int32_t));
memcpy(&fillf, nbuf + 68, sizeof(u_int32_t));
memcpy(&maxb, nbuf + 56, sizeof(u_int32_t));
if (swapped) {
M_32_SWAP(nelem);
M_32_SWAP(fillf);
M_32_SWAP(maxb);
}
if ((fillf != 0 && fillf * maxb < 2 * nelem) ||
(fillf == 0 && nelem > 0x8000000)) {
nelem = 0;
memcpy(nbuf + 72, &nelem, sizeof(u_int32_t));
}
/*
* We now have to convert the spares array. The old spares array
* contained the total number of extra pages allocated prior to
* the bucket that begins the next doubling. The new spares array
* contains the page number of the first bucket in the next doubling
* MINUS the bucket number of that bucket.
*/
o_spares = (u_int32_t *)(obuf + 60);
n_spares = (u_int32_t *)(nbuf + 80);
non_zero = 0;
n_spares[0] = 1;
for (i = 1; i < NCACHED; i++) {
if (swapped)
M_32_SWAP(o_spares[i -1]);
non_zero = non_zero || o_spares[i - 1] != 0;
if (o_spares[i - 1] == 0 && non_zero)
n_spares[i] = 0;
else
n_spares[i] = 1 + o_spares[i - 1];
}
if (swapped)
for (i = 0; i < NCACHED; i++)
M_32_SWAP(n_spares[i]);
/* Replace the unique ID. */
if ((ret = CDB___os_fileid(dbenv, real_name, 1, nbuf + 36)) != 0)
return (ret);
if ((ret = CDB___os_seek(fhp, 0, 0, 0, 1, DB_OS_SEEK_SET)) != 0)
return (ret);
if ((ret = CDB___os_write(fhp, nbuf, 256, &n)) != 0)
return (ret);
if ((ret = CDB___os_fsync(fhp)) != 0)
return (ret);
if (dbp->db_feedback != NULL)
dbp->db_feedback(dbp, DB_UPGRADE, 100);
return (0);
}
|