~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
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