~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to extra/innochecksum.c

  • Committer: Monty Taylor
  • Date: 2009-01-06 18:48:07 UTC
  • mto: This revision was merged to the branch mainline in revision 762.
  • Revision ID: mordred@inaugust.com-20090106184807-cen092lvb8mc3z4k
Enabled deadlock_innodb.

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
#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>
 
32
#include <stdint.h>
 
33
#include <inttypes.h>
 
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) */
 
50
static uint32_t mach_read_from_4(unsigned char *b)
 
51
{
 
52
  return( ((uint32_t)(b[0]) << 24)
 
53
          + ((uint32_t)(b[1]) << 16)
 
54
          + ((uint32_t)(b[2]) << 8)
 
55
          + (uint32_t)(b[3])
 
56
          );
 
57
}
 
58
 
 
59
static uint32_t
 
60
ut_fold_uint32_t_pair(
 
61
/*===============*/
 
62
            /* out: folded value */
 
63
    uint32_t   n1, /* in: uint32_t */
 
64
    uint32_t   n2) /* in: uint32_t */
 
65
{
 
66
    return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
 
67
                        ^ UT_HASH_RANDOM_MASK) + n2);
 
68
}
 
69
 
 
70
static uint32_t
 
71
ut_fold_binary(
 
72
/*===========*/
 
73
            /* out: folded value */
 
74
    unsigned char*   str,    /* in: string of bytes */
 
75
    uint32_t   len)    /* in: length */
 
76
{
 
77
    uint32_t   i;
 
78
    uint32_t   fold= 0;
 
79
 
 
80
    for (i= 0; i < len; i++)
 
81
    {
 
82
      fold= ut_fold_uint32_t_pair(fold, (uint32_t)(*str));
 
83
 
 
84
      str++;
 
85
    }
 
86
 
 
87
    return(fold);
 
88
}
 
89
 
 
90
static uint32_t
 
91
buf_calc_page_new_checksum(
 
92
/*=======================*/
 
93
               /* out: checksum */
 
94
    unsigned char*    page) /* in: buffer page */
 
95
{
 
96
    uint32_t checksum;
 
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
 
 
115
static uint32_t
 
116
buf_calc_page_old_checksum(
 
117
/*=======================*/
 
118
               /* out: checksum */
 
119
    unsigned char*    page) /* in: buffer page */
 
120
{
 
121
    uint32_t checksum;
 
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 */
 
134
  unsigned char *p;                     /* storage of pages read */
 
135
  int bytes;                   /* bytes read count */
 
136
  uint32_t ct;                    /* current page number (0 based) */
 
137
  int now;                     /* current time */
 
138
  int lastt;                   /* last time */
 
139
  uint32_t oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* uint32_ts for checksum storage */
 
140
  struct stat st;              /* for stat, if you couldn't guess */
 
141
  uint64_t size; /* size of file (has to be 64 bits) */
 
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 */
 
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
  {
 
215
    printf("%u\n", pages);
 
216
    return 0;
 
217
  }
 
218
  else if (verbose)
 
219
  {
 
220
    printf("file %s= %"PRIu64" bytes (%u pages)...\n", argv[1], size, pages);
 
221
    printf("checking pages in range %u to %u\n", start_page, use_end_page ? end_page : (pages - 1));
 
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) */
 
252
  p= (unsigned char *)malloc(UNIV_PAGE_SIZE);
 
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)
 
271
      printf("page %u: log sequence number: first = %u; second = %u\n", ct, logseq, logseqfield);
 
272
    if (logseq != logseqfield)
 
273
    {
 
274
      fprintf(stderr, "page %u invalid (fails log sequence number check)\n", ct);
 
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)
 
282
      printf("page %u: old style: calculated = %u; recorded = %u\n", ct, oldcsum, oldcsumfield);
 
283
    if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum)
 
284
    {
 
285
      fprintf(stderr, "page %u invalid (fails old style checksum)\n", ct);
 
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)
 
293
      printf("page %u: new style: calculated = %u; recorded = %u\n", ct, csum, csumfield);
 
294
    if (csumfield != 0 && csum != csumfield)
 
295
    {
 
296
      fprintf(stderr, "page %u invalid (fails new style checksum)\n", ct);
 
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
        {
 
314
          printf("page %u okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100);
 
315
          lastt= now;
 
316
        }
 
317
      }
 
318
    }
 
319
  }
 
320
  return 0;
 
321
}
 
322