~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to extra/innochecksum.c

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

Show diffs side-by-side

added added

removed removed

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