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