~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
#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
38
#define FIL_PAGE_LSN          16 
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
      break;
181
    case '?':
182
      fprintf(stderr, "unrecognized option: -%c\n", optopt);
183
      return 1;
184
      break;
185
    }
186
  }
187
188
  /* debug implies verbose... */
189
  if (debug) verbose= 1;
190
191
  /* make sure we have the right arguments */
192
  if (optind >= argc)
193
  {
194
    printf("InnoDB offline file checksum utility.\n");
195
    printf("usage: %s [-c] [-s <start page>] [-e <end page>] [-p <page>] [-v] [-d] <filename>\n", argv[0]);
196
    printf("\t-c\tprint the count of pages in the file\n");
197
    printf("\t-s n\tstart on this page number (0 based)\n");
198
    printf("\t-e n\tend at this page number (0 based)\n");
199
    printf("\t-p n\tcheck only this page (0 based)\n");
200
    printf("\t-v\tverbose (prints progress every 5 seconds)\n");
201
    printf("\t-d\tdebug mode (prints checksums for each page)\n");
202
    return 1;
203
  }
204
205
  /* stat the file to get size and page count */
206
  if (stat(argv[optind], &st))
207
  {
208
    perror("error statting file");
209
    return 1;
210
  }
211
  size= st.st_size;
212
  pages= size / UNIV_PAGE_SIZE;
213
  if (just_count)
214
  {
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
215
    printf("%u\n", pages);
1 by brian
clean slate
216
    return 0;
217
  }
218
  else if (verbose)
219
  {
481.1.2 by Monty Taylor
Replaced all unsigned long long with uint64_t.
220
    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.
221
    printf("checking pages in range %u to %u\n", start_page, use_end_page ? end_page : (pages - 1));
1 by brian
clean slate
222
  }
223
224
  /* open the file for reading */
225
  f= fopen(argv[optind], "r");
226
  if (!f)
227
  {
228
    perror("error opening file");
229
    return 1;
230
  }
231
232
  /* seek to the necessary position */
233
  if (start_page)
234
  {
235
    fd= fileno(f);
236
    if (!fd)
237
    {
238
      perror("unable to obtain file descriptor number");
239
      return 1;
240
    }
241
242
    offset= (off_t)start_page * (off_t)UNIV_PAGE_SIZE;
243
244
    if (lseek(fd, offset, SEEK_SET) != offset)
245
    {
246
      perror("unable to seek to necessary offset");
247
      return 1;
248
    }
249
  }
250
251
  /* allocate buffer for reading (so we don't realloc every time) */
481.1.1 by Monty Taylor
Remove ulint and uchar from innochecksum.
252
  p= (unsigned char *)malloc(UNIV_PAGE_SIZE);
1 by brian
clean slate
253
254
  /* main checksumming loop */
255
  ct= start_page;
256
  lastt= 0;
257
  while (!feof(f))
258
  {
259
    bytes= fread(p, 1, UNIV_PAGE_SIZE, f);
260
    if (!bytes && feof(f)) return 0;
261
    if (bytes != UNIV_PAGE_SIZE)
262
    {
263
      fprintf(stderr, "bytes read (%d) doesn't match universal page size (%d)\n", bytes, UNIV_PAGE_SIZE);
264
      return 1;
265
    }
266
267
    /* check the "stored log sequence numbers" */
268
    logseq= mach_read_from_4(p + FIL_PAGE_LSN + 4);
269
    logseqfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4);
270
    if (debug)
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
271
      printf("page %u: log sequence number: first = %u; second = %u\n", ct, logseq, logseqfield);
1 by brian
clean slate
272
    if (logseq != logseqfield)
273
    {
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
274
      fprintf(stderr, "page %u invalid (fails log sequence number check)\n", ct);
1 by brian
clean slate
275
      return 1;
276
    }
277
278
    /* check old method of checksumming */
279
    oldcsum= buf_calc_page_old_checksum(p);
280
    oldcsumfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
281
    if (debug)
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
282
      printf("page %u: old style: calculated = %u; recorded = %u\n", ct, oldcsum, oldcsumfield);
1 by brian
clean slate
283
    if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum)
284
    {
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
285
      fprintf(stderr, "page %u invalid (fails old style checksum)\n", ct);
1 by brian
clean slate
286
      return 1;
287
    }
288
289
    /* now check the new method */
290
    csum= buf_calc_page_new_checksum(p);
291
    csumfield= mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM);
292
    if (debug)
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
293
      printf("page %u: new style: calculated = %u; recorded = %u\n", ct, csum, csumfield);
1 by brian
clean slate
294
    if (csumfield != 0 && csum != csumfield)
295
    {
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
296
      fprintf(stderr, "page %u invalid (fails new style checksum)\n", ct);
1 by brian
clean slate
297
      return 1;
298
    }
299
300
    /* end if this was the last page we were supposed to check */
301
    if (use_end_page && (ct >= end_page))
302
      return 0;
303
304
    /* do counter increase and progress printing */
305
    ct++;
306
    if (verbose)
307
    {
308
      if (ct % 64 == 0)
309
      {
310
        now= time(0);
311
        if (!lastt) lastt= now;
312
        if (now - lastt >= 1)
313
        {
53.2.26 by Monty Taylor
Fixed unsigned long int, format specifiers and functions.
314
          printf("page %u okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100);
1 by brian
clean slate
315
          lastt= now;
316
        }
317
      }
318
    }
319
  }
320
  return 0;
321
}
322