You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.0 KiB
207 lines
5.0 KiB
/*-
|
|
* 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);
|
|
}
|