1 /* Copyright (c) 2003-2005, 2007 MySQL AB
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16 //----------------------------------------------------------------
18 // Reads a redo log file and checks it for errors and/or prints
19 // the file in a human readable format.
21 // Usage: redoLogFileReader <file> [-noprint] [-nocheck]
22 // [-mbyte <0-15>] [-mbyteHeaders] [-pageHeaders]
24 //----------------------------------------------------------------
27 #include <ndb_global.h>
29 #include "records.hpp"
31 #define RETURN_ERROR 1
34 #define FROM_BEGINNING 0
36 void usage(const char * prg
);
37 Uint32
readFromFile(FILE * f
, Uint32
*toPtr
, Uint32 sizeInWords
);
38 void readArguments(int argc
, const char** argv
);
43 bool theDumpFlag
= false;
44 bool thePrintFlag
= true;
45 bool theCheckFlag
= true;
46 bool onlyPageHeaders
= false;
47 bool onlyMbyteHeaders
= false;
48 bool onlyFileDesc
= false;
50 Uint32 startAtMbyte
= 0;
51 Uint32 startAtPage
= 0;
52 Uint32 startAtPageIndex
= 0;
55 NDB_COMMAND(redoLogFileReader
, "redoLogFileReader", "redoLogFileReader", "Read a redo log file", 16384) {
58 Uint32 recordType
= 1234567890;
60 PageHeader
*thePageHeader
;
61 CompletedGCIRecord
*cGCIrecord
;
62 PrepareOperationRecord
*poRecord
;
63 NextLogRecord
*nlRecord
;
64 FileDescriptor
*fdRecord
;
65 CommitTransactionRecord
*ctRecord
;
66 InvalidCommitTransactionRecord
*ictRecord
;
67 NextMbyteRecord
*nmRecord
;
68 AbortTransactionRecord
*atRecord
;
70 readArguments(argc
, argv
);
72 f
= fopen(fileName
, "rb");
74 perror("Error: open file");
78 Uint32 tmpFileOffset
= startAtMbyte
* PAGESIZE
* NO_PAGES_IN_MBYTE
* sizeof(Uint32
);
79 if (fseek(f
, tmpFileOffset
, FROM_BEGINNING
)) {
80 perror("Error: Move in file");
84 redoLogPage
= new Uint32
[PAGESIZE
*NO_PAGES_IN_MBYTE
];
85 Uint32 words_from_previous_page
= 0;
87 // Loop for every mbyte.
88 bool lastPage
= false;
89 for (Uint32 j
= startAtMbyte
; j
< NO_MBYTE_IN_FILE
&& !lastPage
; j
++) {
91 readFromFile(f
, redoLogPage
, PAGESIZE
*NO_PAGES_IN_MBYTE
);
93 words_from_previous_page
= 0;
95 // Loop for every page.
96 for (int i
= 0; i
< NO_PAGES_IN_MBYTE
; i
++) {
98 thePageHeader
= (PageHeader
*) &redoLogPage
[i
*PAGESIZE
];
99 // Print out mbyte number, page number and page index.
100 ndbout
<< j
<< ":" << i
<< ":" << wordIndex
<< endl
101 << " " << j
*32 + i
<< ":" << wordIndex
<< " ";
102 if (thePrintFlag
) ndbout
<< (*thePageHeader
);
104 if(!thePageHeader
->check()) {
105 ndbout
<< "Error in thePageHeader->check()" << endl
;
109 Uint32 checkSum
= 37;
110 for (int ps
= 1; ps
< PAGESIZE
; ps
++)
111 checkSum
= redoLogPage
[i
*PAGESIZE
+ps
] ^ checkSum
;
113 if (checkSum
!= redoLogPage
[i
*PAGESIZE
]){
114 ndbout
<< "WRONG CHECKSUM: checksum = " << redoLogPage
[i
*PAGESIZE
]
115 << " expected = " << checkSum
<< endl
;
119 ndbout
<< "expected checksum: " << checkSum
<< endl
;
123 lastPage
= i
!= 0 && thePageHeader
->lastPage();
124 Uint32 lastWord
= thePageHeader
->lastWord();
126 if (onlyMbyteHeaders
) {
127 // Show only the first page header in every mbyte of the file.
131 if (onlyPageHeaders
) {
132 // Show only page headers. Continue with the next page in this for loop.
137 wordIndex
= thePageHeader
->getLogRecordSize() - words_from_previous_page
;
138 Uint32
*redoLogPagePos
= redoLogPage
+ i
*PAGESIZE
;
139 if (words_from_previous_page
)
141 memmove(redoLogPagePos
+ wordIndex
,
142 redoLogPagePos
- words_from_previous_page
,
143 words_from_previous_page
*4);
147 if (words_from_previous_page
)
149 // Print out mbyte number, page number and word index.
150 ndbout
<< j
<< ":" << i
-1 << ":" << PAGESIZE
-words_from_previous_page
<< endl
151 << j
<< ":" << i
<< ":" << wordIndex
+words_from_previous_page
<< endl
152 << " " << j
*32 + i
-1 << ":" << PAGESIZE
-words_from_previous_page
<< " ";
153 words_from_previous_page
= 0;
157 // Print out mbyte number, page number and word index.
158 ndbout
<< j
<< ":" << i
<< ":" << wordIndex
<< endl
159 << " " << j
*32 + i
<< ":" << wordIndex
<< " ";
161 redoLogPagePos
= redoLogPage
+ i
*PAGESIZE
+ wordIndex
;
162 oldWordIndex
= wordIndex
;
163 recordType
= *redoLogPagePos
;
166 fdRecord
= (FileDescriptor
*) redoLogPagePos
;
167 if (thePrintFlag
) ndbout
<< (*fdRecord
);
169 if(!fdRecord
->check()) {
170 ndbout
<< "Error in fdRecord->check()" << endl
;
175 delete [] redoLogPage
;
178 wordIndex
+= fdRecord
->getLogRecordSize();
181 case ZNEXT_LOG_RECORD_TYPE
:
182 nlRecord
= (NextLogRecord
*) redoLogPagePos
;
183 wordIndex
+= nlRecord
->getLogRecordSize(wordIndex
);
184 if (wordIndex
<= PAGESIZE
) {
185 if (thePrintFlag
) ndbout
<< (*nlRecord
);
187 if(!nlRecord
->check()) {
188 ndbout
<< "Error in nlRecord->check()" << endl
;
195 case ZCOMPLETED_GCI_TYPE
:
196 cGCIrecord
= (CompletedGCIRecord
*) redoLogPagePos
;
197 wordIndex
+= cGCIrecord
->getLogRecordSize();
198 if (wordIndex
<= PAGESIZE
) {
199 if (thePrintFlag
) ndbout
<< (*cGCIrecord
);
201 if(!cGCIrecord
->check()) {
202 ndbout
<< "Error in cGCIrecord->check()" << endl
;
210 poRecord
= (PrepareOperationRecord
*) redoLogPagePos
;
211 wordIndex
+= poRecord
->getLogRecordSize(PAGESIZE
-wordIndex
);
212 if (wordIndex
<= PAGESIZE
) {
213 if (thePrintFlag
) ndbout
<< (*poRecord
);
215 if(!poRecord
->check()) {
216 ndbout
<< "Error in poRecord->check()" << endl
;
224 ctRecord
= (CommitTransactionRecord
*) redoLogPagePos
;
225 wordIndex
+= ctRecord
->getLogRecordSize();
226 if (wordIndex
<= PAGESIZE
) {
227 if (thePrintFlag
) ndbout
<< (*ctRecord
);
229 if(!ctRecord
->check()) {
230 ndbout
<< "Error in ctRecord->check()" << endl
;
237 case ZINVALID_COMMIT_TYPE
:
238 ictRecord
= (InvalidCommitTransactionRecord
*) redoLogPagePos
;
239 wordIndex
+= ictRecord
->getLogRecordSize();
240 if (wordIndex
<= PAGESIZE
) {
241 if (thePrintFlag
) ndbout
<< (*ictRecord
);
243 if(!ictRecord
->check()) {
244 ndbout
<< "Error in ictRecord->check()" << endl
;
251 case ZNEXT_MBYTE_TYPE
:
252 nmRecord
= (NextMbyteRecord
*) redoLogPagePos
;
253 if (thePrintFlag
) ndbout
<< (*nmRecord
);
254 i
= NO_PAGES_IN_MBYTE
;
258 atRecord
= (AbortTransactionRecord
*) redoLogPagePos
;
259 wordIndex
+= atRecord
->getLogRecordSize();
260 if (wordIndex
<= PAGESIZE
) {
261 if (thePrintFlag
) ndbout
<< (*atRecord
);
263 if(!atRecord
->check()) {
264 ndbout
<< "Error in atRecord->check()" << endl
;
271 case ZNEW_PREP_OP_TYPE
:
272 case ZFRAG_SPLIT_TYPE
:
273 ndbout
<< endl
<< "Record type = " << recordType
<< " not implemented." << endl
;
277 ndbout
<< " ------ERROR: UNKNOWN RECORD TYPE------" << endl
;
279 // Print out remaining data in this page
280 for (int k
= wordIndex
; k
< PAGESIZE
; k
++){
281 Uint32 unknown
= redoLogPage
[i
*PAGESIZE
+ k
];
282 ndbout_c("%-30d%-12u%-12x", k
, unknown
, unknown
);
287 } while(wordIndex
< lastWord
&& i
< NO_PAGES_IN_MBYTE
);
294 ndbout
<< " ------PAGE END: DUMPING REST OF PAGE------" << endl
;
295 for (int k
= wordIndex
> PAGESIZE
? oldWordIndex
: wordIndex
;
298 Uint32 word
= redoLogPage
[i
*PAGESIZE
+ k
];
299 ndbout_c("%-30d%-12u%-12x", k
, word
, word
);
304 if (wordIndex
> PAGESIZE
) {
305 words_from_previous_page
= PAGESIZE
- oldWordIndex
;
306 ndbout
<< " ----------- Record continues on next page -----------" << endl
;
309 words_from_previous_page
= 0;
314 if (startAtMbyte
!= 0) {
319 delete [] redoLogPage
;
323 //----------------------------------------------------------------
325 //----------------------------------------------------------------
327 Uint32
readFromFile(FILE * f
, Uint32
*toPtr
, Uint32 sizeInWords
) {
328 Uint32 noOfReadWords
;
329 if ( !(noOfReadWords
= fread(toPtr
, sizeof(Uint32
), sizeInWords
, f
)) ) {
330 ndbout
<< "Error reading file" << endl
;
334 return noOfReadWords
;
338 //----------------------------------------------------------------
340 //----------------------------------------------------------------
343 void usage(const char * prg
){
344 ndbout
<< endl
<< "Usage: " << endl
<< prg
345 << " <Binary log file> [-noprint] [-nocheck] [-mbyte <0-15>] "
346 << "[-mbyteheaders] [-pageheaders] [-filedescriptors] [-page <0-31>] "
347 << "[-pageindex <12-8191>]"
351 void readArguments(int argc
, const char** argv
)
353 if(argc
< 2 || argc
> 9){
358 strcpy(fileName
, argv
[1]);
364 if (strcmp(argv
[i
], "-noprint") == 0) {
365 thePrintFlag
= false;
366 } else if (strcmp(argv
[i
], "-dump") == 0) {
368 } else if (strcmp(argv
[i
], "-nocheck") == 0) {
369 theCheckFlag
= false;
370 } else if (strcmp(argv
[i
], "-mbyteheaders") == 0) {
371 onlyMbyteHeaders
= true;
372 } else if (strcmp(argv
[i
], "-pageheaders") == 0) {
373 onlyPageHeaders
= true;
374 } else if (strcmp(argv
[i
], "-filedescriptors") == 0) {
376 } else if (strcmp(argv
[i
], "-mbyte") == 0) {
377 startAtMbyte
= atoi(argv
[i
+1]);
378 if (startAtMbyte
> 15) {
384 } else if (strcmp(argv
[i
], "-page") == 0) {
385 startAtPage
= atoi(argv
[i
+1]);
386 if (startAtPage
> 31) {
392 } else if (strcmp(argv
[i
], "-pageindex") == 0) {
393 startAtPageIndex
= atoi(argv
[i
+1]);
394 if (startAtPageIndex
> 8191 || startAtPageIndex
< 12) {
411 ndbout
<< "Error in redoLogReader(). Exiting!" << endl
;
413 delete [] redoLogPage
;