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