~drizzle-trunk/drizzle/development

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
139.1.17 by Trond Norbye
Don't define _XOPEN_SOURCE for Solaris
30
#ifndef __sun
1 by brian
clean slate
31
#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */
139.1.17 by Trond Norbye
Don't define _XOPEN_SOURCE for Solaris
32
#endif
1 by brian
clean slate
33
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <time.h>
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
#include <unistd.h>
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
40
#include <stdint.h>
481.1.2 by Monty Taylor
Replaced all unsigned long long with uint64_t.
41
#include <inttypes.h>
1 by brian
clean slate
42
43
/* all of these ripped from InnoDB code from MySQL 4.0.22 */
44
#define UT_HASH_RANDOM_MASK     1463735687
45
#define UT_HASH_RANDOM_MASK2    1653893711
46
#define FIL_PAGE_LSN          16 
47
#define FIL_PAGE_FILE_FLUSH_LSN 26
48
#define FIL_PAGE_OFFSET     4
49
#define FIL_PAGE_DATA       38
50
#define FIL_PAGE_END_LSN_OLD_CHKSUM 8
51
#define FIL_PAGE_SPACE_OR_CHKSUM 0
52
#define UNIV_PAGE_SIZE          (2 * 8192)
53
54
/* command line argument to do page checks (that's it) */
55
/* another argument to specify page ranges... seek to right spot and go from there */
56
57
/* 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.
58
static uint32_t mach_read_from_4(unsigned char *b)
1 by brian
clean slate
59
{
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
60
  return( ((uint32_t)(b[0]) << 24)
61
          + ((uint32_t)(b[1]) << 16)
62
          + ((uint32_t)(b[2]) << 8)
63
          + (uint32_t)(b[3])
1 by brian
clean slate
64
          );
65
}
66
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
67
static uint32_t
68
ut_fold_uint32_t_pair(
1 by brian
clean slate
69
/*===============*/
70
            /* out: folded value */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
71
    uint32_t   n1, /* in: uint32_t */
72
    uint32_t   n2) /* in: uint32_t */
1 by brian
clean slate
73
{
74
    return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
75
                        ^ UT_HASH_RANDOM_MASK) + n2);
76
}
77
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
78
static uint32_t
1 by brian
clean slate
79
ut_fold_binary(
80
/*===========*/
81
            /* out: folded value */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
82
    unsigned char*   str,    /* in: string of bytes */
83
    uint32_t   len)    /* in: length */
1 by brian
clean slate
84
{
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
85
    uint32_t   i;
86
    uint32_t   fold= 0;
1 by brian
clean slate
87
88
    for (i= 0; i < len; i++)
89
    {
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
90
      fold= ut_fold_uint32_t_pair(fold, (uint32_t)(*str));
1 by brian
clean slate
91
92
      str++;
93
    }
94
95
    return(fold);
96
}
97
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
98
static uint32_t
1 by brian
clean slate
99
buf_calc_page_new_checksum(
100
/*=======================*/
101
               /* out: checksum */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
102
    unsigned char*    page) /* in: buffer page */
1 by brian
clean slate
103
{
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
104
    uint32_t checksum;
1 by brian
clean slate
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
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
123
static uint32_t
1 by brian
clean slate
124
buf_calc_page_old_checksum(
125
/*=======================*/
126
               /* out: checksum */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
127
    unsigned char*    page) /* in: buffer page */
1 by brian
clean slate
128
{
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
129
    uint32_t checksum;
1 by brian
clean slate
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 */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
142
  unsigned char *p;                     /* storage of pages read */
1 by brian
clean slate
143
  int bytes;                   /* bytes read count */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
144
  uint32_t ct;                    /* current page number (0 based) */
1 by brian
clean slate
145
  int now;                     /* current time */
146
  int lastt;                   /* last time */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
147
  uint32_t oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* uint32_ts for checksum storage */
1 by brian
clean slate
148
  struct stat st;              /* for stat, if you couldn't guess */
481.1.2 by Monty Taylor
Replaced all unsigned long long with uint64_t.
149
  uint64_t size; /* size of file (has to be 64 bits) */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
150
  uint32_t pages;                 /* number of pages in file */
151
  uint32_t start_page= 0, end_page= 0, use_end_page= 0; /* for starting and ending at certain pages */
1 by brian
clean slate
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
  {
481.1.2 by Monty Taylor
Replaced all unsigned long long with uint64_t.
228
    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.
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) */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
260
  p= (unsigned char *)malloc(UNIV_PAGE_SIZE);
1 by brian
clean slate
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