1 /* Copyright (c) 2003-2005, 2007 MySQL AB
2 Use is subject to license terms
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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17 //----------------------------------------------------------------
18 // REDOLOGFILEREADER
19 // Reads a redo log file and checks it for errors and/or prints
20 // the file in a human readable format.
21 //
22 // Usage: redoLogFileReader <file> [-noprint] [-nocheck]
23 // [-mbyte <0-15>] [-mbyteHeaders] [-pageHeaders]
24 //
25 //----------------------------------------------------------------
26
27
28 #include <ndb_global.h>
29
30 #include "records.hpp"
31
32 #define RETURN_ERROR 1
33 #define RETURN_OK 0
34
35 #define FROM_BEGINNING 0
36
37 void usage(const char * prg);
38 Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords);
39 void readArguments(int argc, const char** argv);
40 void doExit();
41
42 FILE * f= 0;
43 char fileName[256];
44 bool theDumpFlag = false;
45 bool thePrintFlag = true;
46 bool theCheckFlag = true;
47 bool onlyPageHeaders = false;
48 bool onlyMbyteHeaders = false;
49 bool onlyFileDesc = false;
50 bool firstLap = true;
51 Uint32 startAtMbyte = 0;
52 Uint32 startAtPage = 0;
53 Uint32 startAtPageIndex = 0;
54 Uint32 *redoLogPage;
55
56 NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read a redo log file", 16384) {
57 int wordIndex = 0;
58 int oldWordIndex = 0;
59 Uint32 recordType = 1234567890;
60
61 PageHeader *thePageHeader;
62 CompletedGCIRecord *cGCIrecord;
63 PrepareOperationRecord *poRecord;
64 NextLogRecord *nlRecord;
65 FileDescriptor *fdRecord;
66 CommitTransactionRecord *ctRecord;
67 InvalidCommitTransactionRecord *ictRecord;
68 NextMbyteRecord *nmRecord;
69 AbortTransactionRecord *atRecord;
70
71 readArguments(argc, argv);
72
73 f = fopen(fileName, "rb");
74 if(!f){
75 perror("Error: open file");
76 exit(RETURN_ERROR);
77 }
78
79 Uint32 tmpFileOffset = startAtMbyte * PAGESIZE * NO_PAGES_IN_MBYTE * sizeof(Uint32);
80 if (fseek(f, tmpFileOffset, FROM_BEGINNING)) {
81 perror("Error: Move in file");
82 exit(RETURN_ERROR);
83 }
84
85 redoLogPage = new Uint32[PAGESIZE*NO_PAGES_IN_MBYTE];
86 Uint32 words_from_previous_page = 0;
87
88 // Loop for every mbyte.
89 bool lastPage = false;
90 for (Uint32 j = startAtMbyte; j < NO_MBYTE_IN_FILE && !lastPage; j++) {
91
92 readFromFile(f, redoLogPage, PAGESIZE*NO_PAGES_IN_MBYTE);
93
94 words_from_previous_page = 0;
95
96 // Loop for every page.
97 for (int i = 0; i < NO_PAGES_IN_MBYTE; i++) {
98 wordIndex = 0;
99 thePageHeader = (PageHeader *) &redoLogPage[i*PAGESIZE];
100 // Print out mbyte number, page number and page index.
101 ndbout << j << ":" << i << ":" << wordIndex << endl
102 << " " << j*32 + i << ":" << wordIndex << " ";
103 if (thePrintFlag) ndbout << (*thePageHeader);
104 if (theCheckFlag) {
105 if(!thePageHeader->check()) {
106 ndbout << "Error in thePageHeader->check()" << endl;
107 doExit();
108 }
109
110 Uint32 checkSum = 37;
111 for (int ps = 1; ps < PAGESIZE; ps++)
112 checkSum = redoLogPage[i*PAGESIZE+ps] ^ checkSum;
113
114 if (checkSum != redoLogPage[i*PAGESIZE]){
115 ndbout << "WRONG CHECKSUM: checksum = " << redoLogPage[i*PAGESIZE]
116 << " expected = " << checkSum << endl;
117 doExit();
118 }
119 else
120 ndbout << "expected checksum: " << checkSum << endl;
121
122 }
123
124 lastPage = i != 0 && thePageHeader->lastPage();
125 Uint32 lastWord = thePageHeader->lastWord();
126
127 if (onlyMbyteHeaders) {
128 // Show only the first page header in every mbyte of the file.
129 break;
130 }
131
132 if (onlyPageHeaders) {
133 // Show only page headers. Continue with the next page in this for loop.
134 continue;
135 }
136
137
138 wordIndex = thePageHeader->getLogRecordSize() - words_from_previous_page;
139 Uint32 *redoLogPagePos = redoLogPage + i*PAGESIZE;
140 if (words_from_previous_page)
141 {
142 memmove(redoLogPagePos + wordIndex ,
143 redoLogPagePos - words_from_previous_page,
144 words_from_previous_page*4);
145 }
146
147 do {
148 if (words_from_previous_page)
149 {
150 // Print out mbyte number, page number and word index.
151 ndbout << j << ":" << i-1 << ":" << PAGESIZE-words_from_previous_page << endl
152 << j << ":" << i << ":" << wordIndex+words_from_previous_page << endl
153 << " " << j*32 + i-1 << ":" << PAGESIZE-words_from_previous_page << " ";
154 words_from_previous_page = 0;
155 }
156 else
157 {
158 // Print out mbyte number, page number and word index.
159 ndbout << j << ":" << i << ":" << wordIndex << endl
160 << " " << j*32 + i << ":" << wordIndex << " ";
161 }
162 redoLogPagePos = redoLogPage + i*PAGESIZE + wordIndex;
163 oldWordIndex = wordIndex;
164 recordType = *redoLogPagePos;
165 switch(recordType) {
166 case ZFD_TYPE:
167 fdRecord = (FileDescriptor *) redoLogPagePos;
168 if (thePrintFlag) ndbout << (*fdRecord);
169 if (theCheckFlag) {
170 if(!fdRecord->check()) {
171 ndbout << "Error in fdRecord->check()" << endl;
172 doExit();
173 }
174 }
175 if (onlyFileDesc) {
176 delete [] redoLogPage;
177 exit(RETURN_OK);
178 }
179 wordIndex += fdRecord->getLogRecordSize();
180 break;
181
182 case ZNEXT_LOG_RECORD_TYPE:
183 nlRecord = (NextLogRecord *) redoLogPagePos;
184 wordIndex += nlRecord->getLogRecordSize(wordIndex);
185 if (wordIndex <= PAGESIZE) {
186 if (thePrintFlag) ndbout << (*nlRecord);
187 if (theCheckFlag) {
188 if(!nlRecord->check()) {
189 ndbout << "Error in nlRecord->check()" << endl;
190 doExit();
191 }
192 }
193 }
194 break;
195
196 case ZCOMPLETED_GCI_TYPE:
197 cGCIrecord = (CompletedGCIRecord *) redoLogPagePos;
198 wordIndex += cGCIrecord->getLogRecordSize();
199 if (wordIndex <= PAGESIZE) {
200 if (thePrintFlag) ndbout << (*cGCIrecord);
201 if (theCheckFlag) {
202 if(!cGCIrecord->check()) {
203 ndbout << "Error in cGCIrecord->check()" << endl;
204 doExit();
205 }
206 }
207 }
208 break;
209
210 case ZPREP_OP_TYPE:
211 poRecord = (PrepareOperationRecord *) redoLogPagePos;
212 wordIndex += poRecord->getLogRecordSize(PAGESIZE-wordIndex);
213 if (wordIndex <= PAGESIZE) {
214 if (thePrintFlag) ndbout << (*poRecord);
215 if (theCheckFlag) {
216 if(!poRecord->check()) {
217 ndbout << "Error in poRecord->check()" << endl;
218 doExit();
219 }
220 }
221 }
222 break;
223
224 case ZCOMMIT_TYPE:
225 ctRecord = (CommitTransactionRecord *) redoLogPagePos;
226 wordIndex += ctRecord->getLogRecordSize();
227 if (wordIndex <= PAGESIZE) {
228 if (thePrintFlag) ndbout << (*ctRecord);
229 if (theCheckFlag) {
230 if(!ctRecord->check()) {
231 ndbout << "Error in ctRecord->check()" << endl;
232 doExit();
233 }
234 }
235 }
236 break;
237
238 case ZINVALID_COMMIT_TYPE:
239 ictRecord = (InvalidCommitTransactionRecord *) redoLogPagePos;
240 wordIndex += ictRecord->getLogRecordSize();
241 if (wordIndex <= PAGESIZE) {
242 if (thePrintFlag) ndbout << (*ictRecord);
243 if (theCheckFlag) {
244 if(!ictRecord->check()) {
245 ndbout << "Error in ictRecord->check()" << endl;
246 doExit();
247 }
248 }
249 }
250 break;
251
252 case ZNEXT_MBYTE_TYPE:
253 nmRecord = (NextMbyteRecord *) redoLogPagePos;
254 if (thePrintFlag) ndbout << (*nmRecord);
255 i = NO_PAGES_IN_MBYTE;
256 break;
257
258 case ZABORT_TYPE:
259 atRecord = (AbortTransactionRecord *) redoLogPagePos;
260 wordIndex += atRecord->getLogRecordSize();
261 if (wordIndex <= PAGESIZE) {
262 if (thePrintFlag) ndbout << (*atRecord);
263 if (theCheckFlag) {
264 if(!atRecord->check()) {
265 ndbout << "Error in atRecord->check()" << endl;
266 doExit();
267 }
268 }
269 }
270 break;
271
272 case ZNEW_PREP_OP_TYPE:
273 case ZFRAG_SPLIT_TYPE:
274 ndbout << endl << "Record type = " << recordType << " not implemented." << endl;
275 doExit();
276
277 default:
278 ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl;
279
280 // Print out remaining data in this page
281 for (int k = wordIndex; k < PAGESIZE; k++){
282 Uint32 unknown = redoLogPage[i*PAGESIZE + k];
283 ndbout_c("%-30d%-12u%-12x", k, unknown, unknown);
284 }
285
286 doExit();
287 }
288 } while(wordIndex < lastWord && i < NO_PAGES_IN_MBYTE);
289
290
291 if (lastPage)
292 {
293 if (theDumpFlag)
294 {
295 ndbout << " ------PAGE END: DUMPING REST OF PAGE------" << endl;
296 for (int k = wordIndex > PAGESIZE ? oldWordIndex : wordIndex;
297 k < PAGESIZE; k++)
298 {
299 Uint32 word = redoLogPage[i*PAGESIZE + k];
300 ndbout_c("%-30d%-12u%-12x", k, word, word);
301 }
302 }
303 break;
304 }
305 if (wordIndex > PAGESIZE) {
306 words_from_previous_page = PAGESIZE - oldWordIndex;
307 ndbout << " ----------- Record continues on next page -----------" << endl;
308 } else {
309 wordIndex = 0;
310 words_from_previous_page = 0;
311 }
312 ndbout << endl;
313 }//for
314 ndbout << endl;
315 if (startAtMbyte != 0) {
316 break;
317 }
318 }//for
319 fclose(f);
320 delete [] redoLogPage;
321 exit(RETURN_OK);
322 }
323
324 //----------------------------------------------------------------
325 //
326 //----------------------------------------------------------------
327
readFromFile(FILE * f,Uint32 * toPtr,Uint32 sizeInWords)328 Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords) {
329 Uint32 noOfReadWords;
330 if ( !(noOfReadWords = fread(toPtr, sizeof(Uint32), sizeInWords, f)) ) {
331 ndbout << "Error reading file" << endl;
332 doExit();
333 }
334
335 return noOfReadWords;
336 }
337
338
339 //----------------------------------------------------------------
340 //
341 //----------------------------------------------------------------
342
343
usage(const char * prg)344 void usage(const char * prg){
345 ndbout << endl << "Usage: " << endl << prg
346 << " <Binary log file> [-noprint] [-nocheck] [-mbyte <0-15>] "
347 << "[-mbyteheaders] [-pageheaders] [-filedescriptors] [-page <0-31>] "
348 << "[-pageindex <12-8191>]"
349 << endl << endl;
350
351 }
readArguments(int argc,const char ** argv)352 void readArguments(int argc, const char** argv)
353 {
354 if(argc < 2 || argc > 9){
355 usage(argv[0]);
356 doExit();
357 }
358
359 strcpy(fileName, argv[1]);
360 argc--;
361
362 int i = 2;
363 while (argc > 1)
364 {
365 if (strcmp(argv[i], "-noprint") == 0) {
366 thePrintFlag = false;
367 } else if (strcmp(argv[i], "-dump") == 0) {
368 theDumpFlag = true;
369 } else if (strcmp(argv[i], "-nocheck") == 0) {
370 theCheckFlag = false;
371 } else if (strcmp(argv[i], "-mbyteheaders") == 0) {
372 onlyMbyteHeaders = true;
373 } else if (strcmp(argv[i], "-pageheaders") == 0) {
374 onlyPageHeaders = true;
375 } else if (strcmp(argv[i], "-filedescriptors") == 0) {
376 onlyFileDesc = true;
377 } else if (strcmp(argv[i], "-mbyte") == 0) {
378 startAtMbyte = atoi(argv[i+1]);
379 if (startAtMbyte > 15) {
380 usage(argv[0]);
381 doExit();
382 }
383 argc--;
384 i++;
385 } else if (strcmp(argv[i], "-page") == 0) {
386 startAtPage = atoi(argv[i+1]);
387 if (startAtPage > 31) {
388 usage(argv[0]);
389 doExit();
390 }
391 argc--;
392 i++;
393 } else if (strcmp(argv[i], "-pageindex") == 0) {
394 startAtPageIndex = atoi(argv[i+1]);
395 if (startAtPageIndex > 8191 || startAtPageIndex < 12) {
396 usage(argv[0]);
397 doExit();
398 }
399 argc--;
400 i++;
401 } else {
402 usage(argv[0]);
403 doExit();
404 }
405 argc--;
406 i++;
407 }
408
409 }
410
doExit()411 void doExit() {
412 ndbout << "Error in redoLogReader(). Exiting!" << endl;
413 if (f) fclose(f);
414 delete [] redoLogPage;
415 exit(RETURN_ERROR);
416 }
417