1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy
|
2 |
||
3 |
This program is free software; you can redistribute it and/or modify
|
|
4 |
it under the terms of the GNU General Public License as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
/*
|
|
17 |
InnoDB offline file checksum utility. 85% of the code in this file
|
|
18 |
was taken wholesale fron the InnoDB codebase.
|
|
19 |
||
20 |
The final 15% was originally written by Mark Smith of Danga
|
|
21 |
Interactive, Inc. <junior@danga.com>
|
|
22 |
||
23 |
Published with a permission.
|
|
24 |
*/
|
|
25 |
||
26 |
/* needed to have access to 64 bit file functions */
|
|
27 |
#define _LARGEFILE_SOURCE
|
|
28 |
#define _LARGEFILE64_SOURCE
|
|
29 |
||
30 |
#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */ |
|
31 |
||
32 |
#include <stdio.h> |
|
33 |
#include <stdlib.h> |
|
34 |
#include <time.h> |
|
35 |
#include <sys/types.h> |
|
36 |
#include <sys/stat.h> |
|
37 |
#include <unistd.h> |
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
38 |
#include <stdint.h> |
1
by brian
clean slate |
39 |
|
40 |
/* all of these ripped from InnoDB code from MySQL 4.0.22 */
|
|
41 |
#define UT_HASH_RANDOM_MASK 1463735687
|
|
42 |
#define UT_HASH_RANDOM_MASK2 1653893711
|
|
43 |
#define FIL_PAGE_LSN 16
|
|
44 |
#define FIL_PAGE_FILE_FLUSH_LSN 26
|
|
45 |
#define FIL_PAGE_OFFSET 4
|
|
46 |
#define FIL_PAGE_DATA 38
|
|
47 |
#define FIL_PAGE_END_LSN_OLD_CHKSUM 8
|
|
48 |
#define FIL_PAGE_SPACE_OR_CHKSUM 0
|
|
49 |
#define UNIV_PAGE_SIZE (2 * 8192)
|
|
50 |
||
51 |
/* command line argument to do page checks (that's it) */
|
|
52 |
/* another argument to specify page ranges... seek to right spot and go from there */
|
|
53 |
||
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
54 |
typedef uint32_t ulint; |
1
by brian
clean slate |
55 |
typedef unsigned char uchar; |
56 |
||
57 |
/* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
58 |
static ulint mach_read_from_4(uchar *b) |
1
by brian
clean slate |
59 |
{
|
60 |
return( ((ulint)(b[0]) << 24) |
|
61 |
+ ((ulint)(b[1]) << 16) |
|
62 |
+ ((ulint)(b[2]) << 8) |
|
63 |
+ (ulint)(b[3]) |
|
64 |
);
|
|
65 |
}
|
|
66 |
||
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
67 |
static ulint |
1
by brian
clean slate |
68 |
ut_fold_ulint_pair( |
69 |
/*===============*/
|
|
70 |
/* out: folded value */
|
|
71 |
ulint n1, /* in: ulint */ |
|
72 |
ulint n2) /* in: ulint */ |
|
73 |
{
|
|
74 |
return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1) |
|
75 |
^ UT_HASH_RANDOM_MASK) + n2); |
|
76 |
}
|
|
77 |
||
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
78 |
static ulint |
1
by brian
clean slate |
79 |
ut_fold_binary( |
80 |
/*===========*/
|
|
81 |
/* out: folded value */
|
|
82 |
uchar* str, /* in: string of bytes */ |
|
83 |
ulint len) /* in: length */ |
|
84 |
{
|
|
85 |
ulint i; |
|
86 |
ulint fold= 0; |
|
87 |
||
88 |
for (i= 0; i < len; i++) |
|
89 |
{
|
|
90 |
fold= ut_fold_ulint_pair(fold, (ulint)(*str)); |
|
91 |
||
92 |
str++; |
|
93 |
}
|
|
94 |
||
95 |
return(fold); |
|
96 |
}
|
|
97 |
||
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
98 |
static ulint |
1
by brian
clean slate |
99 |
buf_calc_page_new_checksum( |
100 |
/*=======================*/
|
|
101 |
/* out: checksum */
|
|
102 |
uchar* page) /* in: buffer page */ |
|
103 |
{
|
|
104 |
ulint checksum; |
|
105 |
||
106 |
/* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO
|
|
107 |
are written outside the buffer pool to the first pages of data
|
|
108 |
files, we have to skip them in the page checksum calculation.
|
|
109 |
We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
|
|
110 |
checksum is stored, and also the last 8 bytes of page because
|
|
111 |
there we store the old formula checksum. */
|
|
112 |
||
113 |
checksum= ut_fold_binary(page + FIL_PAGE_OFFSET, |
|
114 |
FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET) |
|
115 |
+ ut_fold_binary(page + FIL_PAGE_DATA, |
|
116 |
UNIV_PAGE_SIZE - FIL_PAGE_DATA |
|
117 |
- FIL_PAGE_END_LSN_OLD_CHKSUM); |
|
118 |
checksum= checksum & 0xFFFFFFFF; |
|
119 |
||
120 |
return(checksum); |
|
121 |
}
|
|
122 |
||
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
123 |
static ulint |
1
by brian
clean slate |
124 |
buf_calc_page_old_checksum( |
125 |
/*=======================*/
|
|
126 |
/* out: checksum */
|
|
127 |
uchar* page) /* in: buffer page */ |
|
128 |
{
|
|
129 |
ulint checksum; |
|
130 |
||
131 |
checksum= ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN); |
|
132 |
||
133 |
checksum= checksum & 0xFFFFFFFF; |
|
134 |
||
135 |
return(checksum); |
|
136 |
}
|
|
137 |
||
138 |
||
139 |
int main(int argc, char **argv) |
|
140 |
{
|
|
141 |
FILE *f; /* our input file */ |
|
142 |
uchar *p; /* storage of pages read */ |
|
143 |
int bytes; /* bytes read count */ |
|
144 |
ulint ct; /* current page number (0 based) */ |
|
145 |
int now; /* current time */ |
|
146 |
int lastt; /* last time */ |
|
147 |
ulint oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* ulints for checksum storage */ |
|
148 |
struct stat st; /* for stat, if you couldn't guess */ |
|
149 |
unsigned long long int size; /* size of file (has to be 64 bits) */ |
|
150 |
ulint pages; /* number of pages in file */ |
|
151 |
ulint start_page= 0, end_page= 0, use_end_page= 0; /* for starting and ending at certain pages */ |
|
152 |
off_t offset= 0; |
|
153 |
int just_count= 0; /* if true, just print page count */ |
|
154 |
int verbose= 0; |
|
155 |
int debug= 0; |
|
156 |
int c; |
|
157 |
int fd; |
|
158 |
||
159 |
/* remove arguments */
|
|
160 |
while ((c= getopt(argc, argv, "cvds:e:p:")) != -1) |
|
161 |
{
|
|
162 |
switch (c) |
|
163 |
{
|
|
164 |
case 'v': |
|
165 |
verbose= 1; |
|
166 |
break; |
|
167 |
case 'c': |
|
168 |
just_count= 1; |
|
169 |
break; |
|
170 |
case 's': |
|
171 |
start_page= atoi(optarg); |
|
172 |
break; |
|
173 |
case 'e': |
|
174 |
end_page= atoi(optarg); |
|
175 |
use_end_page= 1; |
|
176 |
break; |
|
177 |
case 'p': |
|
178 |
start_page= atoi(optarg); |
|
179 |
end_page= atoi(optarg); |
|
180 |
use_end_page= 1; |
|
181 |
break; |
|
182 |
case 'd': |
|
183 |
debug= 1; |
|
184 |
break; |
|
185 |
case ':': |
|
186 |
fprintf(stderr, "option -%c requires an argument\n", optopt); |
|
187 |
return 1; |
|
188 |
break; |
|
189 |
case '?': |
|
190 |
fprintf(stderr, "unrecognized option: -%c\n", optopt); |
|
191 |
return 1; |
|
192 |
break; |
|
193 |
}
|
|
194 |
}
|
|
195 |
||
196 |
/* debug implies verbose... */
|
|
197 |
if (debug) verbose= 1; |
|
198 |
||
199 |
/* make sure we have the right arguments */
|
|
200 |
if (optind >= argc) |
|
201 |
{
|
|
202 |
printf("InnoDB offline file checksum utility.\n"); |
|
203 |
printf("usage: %s [-c] [-s <start page>] [-e <end page>] [-p <page>] [-v] [-d] <filename>\n", argv[0]); |
|
204 |
printf("\t-c\tprint the count of pages in the file\n"); |
|
205 |
printf("\t-s n\tstart on this page number (0 based)\n"); |
|
206 |
printf("\t-e n\tend at this page number (0 based)\n"); |
|
207 |
printf("\t-p n\tcheck only this page (0 based)\n"); |
|
208 |
printf("\t-v\tverbose (prints progress every 5 seconds)\n"); |
|
209 |
printf("\t-d\tdebug mode (prints checksums for each page)\n"); |
|
210 |
return 1; |
|
211 |
}
|
|
212 |
||
213 |
/* stat the file to get size and page count */
|
|
214 |
if (stat(argv[optind], &st)) |
|
215 |
{
|
|
216 |
perror("error statting file"); |
|
217 |
return 1; |
|
218 |
}
|
|
219 |
size= st.st_size; |
|
220 |
pages= size / UNIV_PAGE_SIZE; |
|
221 |
if (just_count) |
|
222 |
{
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
223 |
printf("%u\n", pages); |
1
by brian
clean slate |
224 |
return 0; |
225 |
}
|
|
226 |
else if (verbose) |
|
227 |
{
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
228 |
printf("file %s= %llu bytes (%u pages)...\n", argv[1], size, pages); |
229 |
printf("checking pages in range %u to %u\n", start_page, use_end_page ? end_page : (pages - 1)); |
|
1
by brian
clean slate |
230 |
}
|
231 |
||
232 |
/* open the file for reading */
|
|
233 |
f= fopen(argv[optind], "r"); |
|
234 |
if (!f) |
|
235 |
{
|
|
236 |
perror("error opening file"); |
|
237 |
return 1; |
|
238 |
}
|
|
239 |
||
240 |
/* seek to the necessary position */
|
|
241 |
if (start_page) |
|
242 |
{
|
|
243 |
fd= fileno(f); |
|
244 |
if (!fd) |
|
245 |
{
|
|
246 |
perror("unable to obtain file descriptor number"); |
|
247 |
return 1; |
|
248 |
}
|
|
249 |
||
250 |
offset= (off_t)start_page * (off_t)UNIV_PAGE_SIZE; |
|
251 |
||
252 |
if (lseek(fd, offset, SEEK_SET) != offset) |
|
253 |
{
|
|
254 |
perror("unable to seek to necessary offset"); |
|
255 |
return 1; |
|
256 |
}
|
|
257 |
}
|
|
258 |
||
259 |
/* allocate buffer for reading (so we don't realloc every time) */
|
|
260 |
p= (uchar *)malloc(UNIV_PAGE_SIZE); |
|
261 |
||
262 |
/* main checksumming loop */
|
|
263 |
ct= start_page; |
|
264 |
lastt= 0; |
|
265 |
while (!feof(f)) |
|
266 |
{
|
|
267 |
bytes= fread(p, 1, UNIV_PAGE_SIZE, f); |
|
268 |
if (!bytes && feof(f)) return 0; |
|
269 |
if (bytes != UNIV_PAGE_SIZE) |
|
270 |
{
|
|
271 |
fprintf(stderr, "bytes read (%d) doesn't match universal page size (%d)\n", bytes, UNIV_PAGE_SIZE); |
|
272 |
return 1; |
|
273 |
}
|
|
274 |
||
275 |
/* check the "stored log sequence numbers" */
|
|
276 |
logseq= mach_read_from_4(p + FIL_PAGE_LSN + 4); |
|
277 |
logseqfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4); |
|
278 |
if (debug) |
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
279 |
printf("page %u: log sequence number: first = %u; second = %u\n", ct, logseq, logseqfield); |
1
by brian
clean slate |
280 |
if (logseq != logseqfield) |
281 |
{
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
282 |
fprintf(stderr, "page %u invalid (fails log sequence number check)\n", ct); |
1
by brian
clean slate |
283 |
return 1; |
284 |
}
|
|
285 |
||
286 |
/* check old method of checksumming */
|
|
287 |
oldcsum= buf_calc_page_old_checksum(p); |
|
288 |
oldcsumfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM); |
|
289 |
if (debug) |
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
290 |
printf("page %u: old style: calculated = %u; recorded = %u\n", ct, oldcsum, oldcsumfield); |
1
by brian
clean slate |
291 |
if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum) |
292 |
{
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
293 |
fprintf(stderr, "page %u invalid (fails old style checksum)\n", ct); |
1
by brian
clean slate |
294 |
return 1; |
295 |
}
|
|
296 |
||
297 |
/* now check the new method */
|
|
298 |
csum= buf_calc_page_new_checksum(p); |
|
299 |
csumfield= mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM); |
|
300 |
if (debug) |
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
301 |
printf("page %u: new style: calculated = %u; recorded = %u\n", ct, csum, csumfield); |
1
by brian
clean slate |
302 |
if (csumfield != 0 && csum != csumfield) |
303 |
{
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
304 |
fprintf(stderr, "page %u invalid (fails new style checksum)\n", ct); |
1
by brian
clean slate |
305 |
return 1; |
306 |
}
|
|
307 |
||
308 |
/* end if this was the last page we were supposed to check */
|
|
309 |
if (use_end_page && (ct >= end_page)) |
|
310 |
return 0; |
|
311 |
||
312 |
/* do counter increase and progress printing */
|
|
313 |
ct++; |
|
314 |
if (verbose) |
|
315 |
{
|
|
316 |
if (ct % 64 == 0) |
|
317 |
{
|
|
318 |
now= time(0); |
|
319 |
if (!lastt) lastt= now; |
|
320 |
if (now - lastt >= 1) |
|
321 |
{
|
|
53.2.26
by Monty Taylor
Fixed unsigned long int, format specifiers and functions. |
322 |
printf("page %u okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100); |
1
by brian
clean slate |
323 |
lastt= now; |
324 |
}
|
|
325 |
}
|
|
326 |
}
|
|
327 |
}
|
|
328 |
return 0; |
|
329 |
}
|
|
330 |