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);
}
|