summaryrefslogtreecommitdiffstats
path: root/debian/htdig/htdig-3.2.0b6/db/hash_upgrade.c
blob: ace737198fb12d9e72deac2b485ab97e131a8823 (plain)
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);
}