~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to extra/innochecksum.c

  • Committer: Padraig O'Sullivan
  • Date: 2009-06-29 17:24:02 UTC
  • mto: This revision was merged to the branch mainline in revision 1081.
  • Revision ID: osullivan.padraig@gmail.com-20090629172402-9c5n1kr7ry7xgau7
Removed the dependency on knowing the position of an I_S table in the
schema_tables array defined in show.cc. This issue crops up in
prepare_schema_table. An issue with my design is that it increases the time
complexity from O(1) to O(n) in numerous places to determine an I_S table to
work on since we don't have an explicit index into the array and instead
need to search by name. However, as n is the number of I_S tables and this
number is quite small (at the moment n is < 30), we don't see this causing
any issue. This design makes the code much more maintainable and easier to
understand. Previously, modifying anything to do with the I_S tables meant
having to tip-toe around the issue of hard-coded indexes into the
schema_tables array.

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
 
#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */
31
 
 
32
 
#include <stdio.h>
33
 
#include <stdlib.h>
34
 
#include <time.h>
35
 
#include <sys/types.h>
36
 
#include <sys/stat.h>
37
 
#include <unistd.h>
38
 
#include <stdint.h>
39
 
 
40
 
/* all of these ripped from InnoDB code from MySQL 4.0.22 */
41
 
#define UT_HASH_RANDOM_MASK     1463735687
42
 
#define UT_HASH_RANDOM_MASK2    1653893711
43
 
#define FIL_PAGE_LSN          16 
44
 
#define FIL_PAGE_FILE_FLUSH_LSN 26
45
 
#define FIL_PAGE_OFFSET     4
46
 
#define FIL_PAGE_DATA       38
47
 
#define FIL_PAGE_END_LSN_OLD_CHKSUM 8
48
 
#define FIL_PAGE_SPACE_OR_CHKSUM 0
49
 
#define UNIV_PAGE_SIZE          (2 * 8192)
50
 
 
51
 
/* command line argument to do page checks (that's it) */
52
 
/* another argument to specify page ranges... seek to right spot and go from there */
53
 
 
54
 
typedef uint32_t ulint;
55
 
typedef unsigned char uchar;
56
 
 
57
 
/* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */
58
 
static ulint mach_read_from_4(uchar *b)
59
 
{
60
 
  return( ((ulint)(b[0]) << 24)
61
 
          + ((ulint)(b[1]) << 16)
62
 
          + ((ulint)(b[2]) << 8)
63
 
          + (ulint)(b[3])
64
 
          );
65
 
}
66
 
 
67
 
static ulint
68
 
ut_fold_ulint_pair(
69
 
/*===============*/
70
 
            /* out: folded value */
71
 
    ulint   n1, /* in: ulint */
72
 
    ulint   n2) /* in: ulint */
73
 
{
74
 
    return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
75
 
                        ^ UT_HASH_RANDOM_MASK) + n2);
76
 
}
77
 
 
78
 
static ulint
79
 
ut_fold_binary(
80
 
/*===========*/
81
 
            /* out: folded value */
82
 
    uchar*   str,    /* in: string of bytes */
83
 
    ulint   len)    /* in: length */
84
 
{
85
 
    ulint   i;
86
 
    ulint   fold= 0;
87
 
 
88
 
    for (i= 0; i < len; i++)
89
 
    {
90
 
      fold= ut_fold_ulint_pair(fold, (ulint)(*str));
91
 
 
92
 
      str++;
93
 
    }
94
 
 
95
 
    return(fold);
96
 
}
97
 
 
98
 
static ulint
99
 
buf_calc_page_new_checksum(
100
 
/*=======================*/
101
 
               /* out: checksum */
102
 
    uchar*    page) /* in: buffer page */
103
 
{
104
 
    ulint checksum;
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
 
 
123
 
static ulint
124
 
buf_calc_page_old_checksum(
125
 
/*=======================*/
126
 
               /* out: checksum */
127
 
    uchar*    page) /* in: buffer page */
128
 
{
129
 
    ulint checksum;
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 */
142
 
  uchar *p;                     /* storage of pages read */
143
 
  int bytes;                   /* bytes read count */
144
 
  ulint ct;                    /* current page number (0 based) */
145
 
  int now;                     /* current time */
146
 
  int lastt;                   /* last time */
147
 
  ulint oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* ulints for checksum storage */
148
 
  struct stat st;              /* for stat, if you couldn't guess */
149
 
  unsigned long long int size; /* size of file (has to be 64 bits) */
150
 
  ulint pages;                 /* number of pages in file */
151
 
  ulint start_page= 0, end_page= 0, use_end_page= 0; /* for starting and ending at certain pages */
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
 
  {
223
 
    printf("%u\n", pages);
224
 
    return 0;
225
 
  }
226
 
  else if (verbose)
227
 
  {
228
 
    printf("file %s= %llu bytes (%u pages)...\n", argv[1], size, pages);
229
 
    printf("checking pages in range %u to %u\n", start_page, use_end_page ? end_page : (pages - 1));
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) */
260
 
  p= (uchar *)malloc(UNIV_PAGE_SIZE);
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)
279
 
      printf("page %u: log sequence number: first = %u; second = %u\n", ct, logseq, logseqfield);
280
 
    if (logseq != logseqfield)
281
 
    {
282
 
      fprintf(stderr, "page %u invalid (fails log sequence number check)\n", ct);
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)
290
 
      printf("page %u: old style: calculated = %u; recorded = %u\n", ct, oldcsum, oldcsumfield);
291
 
    if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum)
292
 
    {
293
 
      fprintf(stderr, "page %u invalid (fails old style checksum)\n", ct);
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)
301
 
      printf("page %u: new style: calculated = %u; recorded = %u\n", ct, csum, csumfield);
302
 
    if (csumfield != 0 && csum != csumfield)
303
 
    {
304
 
      fprintf(stderr, "page %u invalid (fails new style checksum)\n", ct);
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
 
        {
322
 
          printf("page %u okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100);
323
 
          lastt= now;
324
 
        }
325
 
      }
326
 
    }
327
 
  }
328
 
  return 0;
329
 
}
330