MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
reader.cpp
1 /*
2  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 //----------------------------------------------------------------
19 // REDOLOGFILEREADER
20 // Reads a redo log file and checks it for errors and/or prints
21 // the file in a human readable format.
22 //
23 // Usage: redoLogFileReader <file> [-noprint] [-nocheck]
24 // [-mbyte <0-15>] [-mbyteHeaders] [-pageHeaders]
25 //
26 //----------------------------------------------------------------
27 
28 
29 #include <ndb_global.h>
30 #include <my_dir.h>
31 
32 #include "records.hpp"
33 
34 #define RETURN_ERROR 1
35 #define RETURN_OK 0
36 
37 #define FROM_BEGINNING 0
38 
39 void usage(const char * prg);
40 Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords);
41 void readArguments(int argc, const char** argv);
42 void doExit();
43 
44 FILE * f= 0;
45 char fileName[256];
46 bool theDumpFlag = false;
47 bool thePrintFlag = true;
48 bool theCheckFlag = true;
49 bool onlyPageHeaders = false;
50 bool onlyMbyteHeaders = false;
51 bool onlyFileDesc = false;
52 bool onlyLap = false;
53 bool theTwiddle = false;
54 Uint32 startAtMbyte = 0;
55 Uint32 startAtPage = 0;
56 Uint32 startAtPageIndex = 0;
57 Uint32 *redoLogPage;
58 
59 unsigned NO_MBYTE_IN_FILE = 16;
60 
61 NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read a redo log file", 16384) {
62  ndb_init();
63  Int32 wordIndex = 0;
64  Uint32 oldWordIndex = 0;
65  Uint32 recordType = 1234567890;
66 
67  PageHeader *thePageHeader;
68  CompletedGCIRecord *cGCIrecord;
69  PrepareOperationRecord *poRecord;
70  NextLogRecord *nlRecord;
71  FileDescriptor *fdRecord;
72  CommitTransactionRecord *ctRecord;
74  NextMbyteRecord *nmRecord;
75  AbortTransactionRecord *atRecord;
76 
77  readArguments(argc, argv);
78 
79  f = fopen(fileName, "rb");
80  if(!f){
81  perror("Error: open file");
82  exit(RETURN_ERROR);
83  }
84 
85  {
86  MY_STAT buf;
87  my_stat(fileName, &buf, MYF(0));
88  NO_MBYTE_IN_FILE = buf.st_size / (1024 * 1024);
89  if (NO_MBYTE_IN_FILE != 16)
90  {
91  ndbout_c("Detected %umb files", NO_MBYTE_IN_FILE);
92  }
93  }
94 
95  Uint32 tmpFileOffset = startAtMbyte * PAGESIZE * NO_PAGES_IN_MBYTE * sizeof(Uint32);
96  if (fseek(f, tmpFileOffset, FROM_BEGINNING)) {
97  perror("Error: Move in file");
98  exit(RETURN_ERROR);
99  }
100 
101  redoLogPage = new Uint32[PAGESIZE*NO_PAGES_IN_MBYTE];
102  Uint32 words_from_previous_page = 0;
103 
104  // Loop for every mbyte.
105  bool lastPage = false;
106  for (Uint32 j = startAtMbyte; j < NO_MBYTE_IN_FILE && !lastPage; j++) {
107 
108  ndbout_c("mb: %d", j);
109  readFromFile(f, redoLogPage, PAGESIZE*NO_PAGES_IN_MBYTE);
110 
111  words_from_previous_page = 0;
112 
113  // Loop for every page.
114  for (int i = 0; i < NO_PAGES_IN_MBYTE; i++)
115  {
116  wordIndex = 0;
117  thePageHeader = (PageHeader *) &redoLogPage[i*PAGESIZE];
118  // Print out mbyte number, page number and page index.
119  ndbout << j << ":" << i << ":" << wordIndex << endl
120  << " " << j*32 + i << ":" << wordIndex << " ";
121  if (thePrintFlag) ndbout << (*thePageHeader);
122  if (onlyLap)
123  {
124  ndbout_c("lap: %d maxgcicompleted: %d maxgcistarted: %d",
125  thePageHeader->m_lap,
126  thePageHeader->m_max_gci_completed,
127  thePageHeader->m_max_gci_started);
128  continue;
129  }
130  if (theCheckFlag) {
131  if(!thePageHeader->check()) {
132  ndbout << "Error in thePageHeader->check()" << endl;
133  doExit();
134  }
135 
136  Uint32 checkSum = 37;
137  for (int ps = 1; ps < PAGESIZE; ps++)
138  checkSum = redoLogPage[i*PAGESIZE+ps] ^ checkSum;
139 
140  if (checkSum != redoLogPage[i*PAGESIZE]){
141  ndbout_c("WRONG CHECKSUM: checksum = 0x%x expected: 0x%x",
142  redoLogPage[i*PAGESIZE],
143  checkSum);
144  //doExit();
145  }
146  else
147  ndbout << "expected checksum: " << checkSum << endl;
148 
149  }
150 
151  lastPage = i != 0 && thePageHeader->lastPage();
152  Uint32 lastWord = thePageHeader->lastWord();
153 
154  if (onlyMbyteHeaders) {
155  // Show only the first page header in every mbyte of the file.
156  break;
157  }
158 
159  if (onlyPageHeaders) {
160  // Show only page headers. Continue with the next page in this for loop.
161  continue;
162  }
163 
164 
165  wordIndex = thePageHeader->getLogRecordSize() - words_from_previous_page;
166  Uint32 *redoLogPagePos = redoLogPage + i*PAGESIZE;
167  if (words_from_previous_page)
168  {
169  memmove(redoLogPagePos + wordIndex,
170  redoLogPagePos - words_from_previous_page,
171  words_from_previous_page*4);
172  }
173 
174  do {
175  if (words_from_previous_page)
176  {
177  // Print out mbyte number, page number and word index.
178  ndbout << j << ":" << i-1 << ":" << PAGESIZE-words_from_previous_page << endl
179  << j << ":" << i << ":" << wordIndex+words_from_previous_page << endl
180  << " " << j*32 + i-1 << ":" << PAGESIZE-words_from_previous_page << " ";
181  words_from_previous_page = 0;
182  }
183  else
184  {
185  // Print out mbyte number, page number and word index.
186  ndbout_c("mb: %u fp: %u pos: %u",
187  j, (j*32 + i), wordIndex);
188  }
189  redoLogPagePos = redoLogPage + i*PAGESIZE + wordIndex;
190  oldWordIndex = wordIndex;
191  recordType = *redoLogPagePos;
192  switch(recordType) {
193  case ZFD_TYPE:
194  fdRecord = (FileDescriptor *) redoLogPagePos;
195  if (thePrintFlag) ndbout << (*fdRecord);
196  if (theCheckFlag) {
197  if(!fdRecord->check()) {
198  ndbout << "Error in fdRecord->check()" << endl;
199  doExit();
200  }
201  }
202  if (onlyFileDesc) {
203  delete [] redoLogPage;
204  exit(RETURN_OK);
205  }
206  wordIndex += fdRecord->getLogRecordSize();
207  break;
208 
209  case ZNEXT_LOG_RECORD_TYPE:
210  nlRecord = (NextLogRecord *) redoLogPagePos;
211  wordIndex += nlRecord->getLogRecordSize(wordIndex);
212  if (wordIndex <= PAGESIZE) {
213  if (thePrintFlag) ndbout << (*nlRecord);
214  if (theCheckFlag) {
215  if(!nlRecord->check()) {
216  ndbout << "Error in nlRecord->check()" << endl;
217  doExit();
218  }
219  }
220  }
221  break;
222 
223  case ZCOMPLETED_GCI_TYPE:
224  cGCIrecord = (CompletedGCIRecord *) redoLogPagePos;
225  wordIndex += cGCIrecord->getLogRecordSize();
226  if (wordIndex <= PAGESIZE) {
227  if (thePrintFlag) ndbout << (*cGCIrecord);
228  if (theCheckFlag) {
229  if(!cGCIrecord->check()) {
230  ndbout << "Error in cGCIrecord->check()" << endl;
231  doExit();
232  }
233  }
234  }
235  break;
236 
237  case ZPREP_OP_TYPE:
238  poRecord = (PrepareOperationRecord *) redoLogPagePos;
239  wordIndex += poRecord->getLogRecordSize(PAGESIZE-wordIndex);
240  if (wordIndex <= PAGESIZE) {
241  if (thePrintFlag) ndbout << (*poRecord);
242  if (theCheckFlag) {
243  if(!poRecord->check()) {
244  ndbout << "Error in poRecord->check()" << endl;
245  doExit();
246  }
247  }
248  }
249  break;
250 
251  case ZCOMMIT_TYPE:
252  ctRecord = (CommitTransactionRecord *) redoLogPagePos;
253  wordIndex += ctRecord->getLogRecordSize();
254  if (wordIndex <= PAGESIZE) {
255  if (thePrintFlag) ndbout << (*ctRecord);
256  if (theCheckFlag) {
257  if(!ctRecord->check()) {
258  ndbout << "Error in ctRecord->check()" << endl;
259  doExit();
260  }
261  }
262  }
263  break;
264 
265  case ZINVALID_COMMIT_TYPE:
266  ictRecord = (InvalidCommitTransactionRecord *) redoLogPagePos;
267  wordIndex += ictRecord->getLogRecordSize();
268  if (wordIndex <= PAGESIZE) {
269  if (thePrintFlag) ndbout << (*ictRecord);
270  if (theCheckFlag) {
271  if(!ictRecord->check()) {
272  ndbout << "Error in ictRecord->check()" << endl;
273  doExit();
274  }
275  }
276  }
277  break;
278 
279  case ZNEXT_MBYTE_TYPE:
280  nmRecord = (NextMbyteRecord *) redoLogPagePos;
281  if (thePrintFlag) ndbout << (*nmRecord);
282  i = NO_PAGES_IN_MBYTE;
283  break;
284 
285  case ZABORT_TYPE:
286  atRecord = (AbortTransactionRecord *) redoLogPagePos;
287  wordIndex += atRecord->getLogRecordSize();
288  if (wordIndex <= PAGESIZE) {
289  if (thePrintFlag) ndbout << (*atRecord);
290  if (theCheckFlag) {
291  if(!atRecord->check()) {
292  ndbout << "Error in atRecord->check()" << endl;
293  doExit();
294  }
295  }
296  }
297  break;
298 
299  case ZNEW_PREP_OP_TYPE:
300  case ZFRAG_SPLIT_TYPE:
301  ndbout << endl << "Record type = " << recordType << " not implemented." << endl;
302  doExit();
303 
304  default:
305  ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl;
306 
307  // Print out remaining data in this page
308  for (int k = wordIndex; k < PAGESIZE; k++){
309  Uint32 unknown = redoLogPage[i*PAGESIZE + k];
310  ndbout_c("%-30d%-12u%-12x", k, unknown, unknown);
311  }
312 
313  if (theCheckFlag)
314  {
315  doExit();
316  }
317  else
318  {
319  wordIndex = lastWord;
320  }
321  }
322  } while(wordIndex < (Int32)lastWord && i < NO_PAGES_IN_MBYTE);
323 
324 
325  if (false && lastPage)
326  {
327  if (theDumpFlag)
328  {
329  ndbout << " ------PAGE END: DUMPING REST OF PAGE------" << endl;
330  for (int k = wordIndex > PAGESIZE ? oldWordIndex : wordIndex;
331  k < PAGESIZE; k++)
332  {
333  Uint32 word = redoLogPage[i*PAGESIZE + k];
334  ndbout_c("%-30d%-12u%-12x", k, word, word);
335  }
336  }
337  break;
338  }
339  if (wordIndex > PAGESIZE) {
340  words_from_previous_page = PAGESIZE - oldWordIndex;
341  ndbout << " ----------- Record continues on next page -----------" << endl;
342  } else {
343  wordIndex = 0;
344  words_from_previous_page = 0;
345  }
346  ndbout << endl;
347  }//for
348  ndbout << endl;
349  if (startAtMbyte != 0) {
350  break;
351  }
352  }//for
353  fclose(f);
354  delete [] redoLogPage;
355  exit(RETURN_OK);
356 }
357 
358 static
359 Uint32
360 twiddle_32(Uint32 in)
361 {
362  Uint32 retVal = 0;
363 
364  retVal = ((in & 0x000000FF) << 24) |
365  ((in & 0x0000FF00) << 8) |
366  ((in & 0x00FF0000) >> 8) |
367  ((in & 0xFF000000) >> 24);
368 
369  return(retVal);
370 }
371 
372 //----------------------------------------------------------------
373 //
374 //----------------------------------------------------------------
375 
376 Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords) {
377  Uint32 noOfReadWords;
378  if ( !(noOfReadWords = (Uint32)fread(toPtr, sizeof(Uint32), sizeInWords, f))){
379  ndbout << "Error reading file" << endl;
380  doExit();
381  }
382 
383  if (theTwiddle)
384  {
385  for (Uint32 i = 0; i<noOfReadWords; i++)
386  toPtr[i] = twiddle_32(toPtr[i]);
387  }
388 
389  return noOfReadWords;
390 }
391 
392 
393 //----------------------------------------------------------------
394 //
395 //----------------------------------------------------------------
396 
397 
398 void usage(const char * prg){
399  ndbout << endl << "Usage: " << endl << prg
400  << " <Binary log file> [-noprint] [-nocheck] [-mbyte <0-15>] "
401  << "[-mbyteheaders] [-pageheaders] [-filedescriptors] [-page <0-31>] "
402  << "[-pageindex <12-8191>] -twiddle"
403  << endl << endl;
404 
405 }
406 void readArguments(int argc, const char** argv)
407 {
408  if(argc < 2 || argc > 9){
409  usage(argv[0]);
410  doExit();
411  }
412 
413  strcpy(fileName, argv[1]);
414  argc--;
415 
416  int i = 2;
417  while (argc > 1)
418  {
419  if (strcmp(argv[i], "-noprint") == 0) {
420  thePrintFlag = false;
421  } else if (strcmp(argv[i], "-dump") == 0) {
422  theDumpFlag = true;
423  } else if (strcmp(argv[i], "-twiddle") == 0) {
424  theTwiddle = true;
425  } else if (strcmp(argv[i], "-nocheck") == 0) {
426  theCheckFlag = false;
427  } else if (strcmp(argv[i], "-mbyteheaders") == 0) {
428  onlyMbyteHeaders = true;
429  } else if (strcmp(argv[i], "-pageheaders") == 0) {
430  onlyPageHeaders = true;
431  } else if (strcmp(argv[i], "-filedescriptors") == 0) {
432  onlyFileDesc = true;
433  } else if (strcmp(argv[i], "-lap") == 0) {
434  thePrintFlag = false;
435  onlyLap = true;
436  } else if (strcmp(argv[i], "-mbyte") == 0) {
437  startAtMbyte = atoi(argv[i+1]);
438  argc--;
439  i++;
440  } else if (strcmp(argv[i], "-page") == 0) {
441  startAtPage = atoi(argv[i+1]);
442  if (startAtPage > 31) {
443  usage(argv[0]);
444  doExit();
445  }
446  argc--;
447  i++;
448  } else if (strcmp(argv[i], "-pageindex") == 0) {
449  startAtPageIndex = atoi(argv[i+1]);
450  if (startAtPageIndex > 8191 || startAtPageIndex < 12) {
451  usage(argv[0]);
452  doExit();
453  }
454  argc--;
455  i++;
456  } else {
457  usage(argv[0]);
458  doExit();
459  }
460  argc--;
461  i++;
462  }
463 
464 }
465 
466 void doExit() {
467  ndbout << "Error in redoLogReader(). Exiting!" << endl;
468  if (f) fclose(f);
469  delete [] redoLogPage;
470  exit(RETURN_ERROR);
471 }