mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / ndb / src / kernel / error / ErrorReporter.cpp
bloba24b90543455173d18adfd1530f2044017e7d629
1 /* Copyright (c) 2003-2006 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 */
17 #include <ndb_global.h>
19 #include <ndbd_exit_codes.h>
20 #include "ErrorReporter.hpp"
22 #include <FastScheduler.hpp>
23 #include <DebuggerNames.hpp>
24 #include <NdbHost.h>
25 #include <NdbConfig.h>
26 #include <Configuration.hpp>
27 #include "EventLogger.hpp"
29 #include <NdbAutoPtr.hpp>
31 #define MESSAGE_LENGTH 500
33 static int WriteMessage(int thrdMessageID,
34 const char* thrdProblemData,
35 const char* thrdObjRef,
36 Uint32 thrdTheEmulatedJamIndex,
37 Uint8 thrdTheEmulatedJam[]);
39 static void dumpJam(FILE* jamStream,
40 Uint32 thrdTheEmulatedJamIndex,
41 Uint8 thrdTheEmulatedJam[]);
43 extern EventLogger g_eventLogger;
44 const char*
45 ErrorReporter::formatTimeStampString(){
46 TimeModule DateTime; /* To create "theDateTimeString" */
48 static char theDateTimeString[39];
49 /* Used to store the generated timestamp */
50 /* ex: "Wednesday 18 September 2000 - 18:54:37" */
52 DateTime.setTimeStamp();
54 BaseString::snprintf(theDateTimeString, 39, "%s %d %s %d - %s:%s:%s",
55 DateTime.getDayName(), DateTime.getDayOfMonth(),
56 DateTime.getMonthName(), DateTime.getYear(), DateTime.getHour(),
57 DateTime.getMinute(), DateTime.getSecond());
59 return (const char *)&theDateTimeString;
62 int
63 ErrorReporter::get_trace_no(){
65 FILE *stream;
66 unsigned int traceFileNo;
68 char *file_name= NdbConfig_NextTraceFileName(globalData.ownId);
69 NdbAutoPtr<char> tmp_aptr(file_name);
71 /*
72 * Read last number from tracefile
73 */
74 stream = fopen(file_name, "r+");
75 if (stream == NULL){
76 traceFileNo = 1;
77 } else {
78 char buf[255];
79 fgets(buf, 255, stream);
80 const int scan = sscanf(buf, "%u", &traceFileNo);
81 if(scan != 1){
82 traceFileNo = 1;
84 fclose(stream);
85 traceFileNo++;
88 /**
89 * Wrap tracefile no
91 Uint32 tmp = globalEmulatorData.theConfiguration->maxNoOfErrorLogs();
92 if (traceFileNo > tmp ) {
93 traceFileNo = 1;
96 /**
97 * Save new number to the file
99 stream = fopen(file_name, "w");
100 if(stream != NULL){
101 fprintf(stream, "%u", traceFileNo);
102 fclose(stream);
105 return traceFileNo;
109 void
110 ErrorReporter::formatMessage(int faultID,
111 const char* problemData,
112 const char* objRef,
113 const char* theNameOfTheTraceFile,
114 char* messptr){
115 int processId;
116 ndbd_exit_classification cl;
117 ndbd_exit_status st;
118 const char *exit_msg = ndbd_exit_message(faultID, &cl);
119 const char *exit_cl_msg = ndbd_exit_classification_message(cl, &st);
120 const char *exit_st_msg = ndbd_exit_status_message(st);
122 processId = NdbHost_GetProcessId();
124 BaseString::snprintf(messptr, MESSAGE_LENGTH,
125 "Time: %s\n"
126 "Status: %s\n"
127 "Message: %s (%s)\n"
128 "Error: %d\n"
129 "Error data: %s\n"
130 "Error object: %s\n"
131 "Program: %s\n"
132 "Pid: %d\n"
133 "Trace: %s\n"
134 "Version: %s\n"
135 "***EOM***\n",
136 formatTimeStampString() ,
137 exit_st_msg,
138 exit_msg, exit_cl_msg,
139 faultID,
140 (problemData == NULL) ? "" : problemData,
141 objRef,
142 my_progname,
143 processId,
144 theNameOfTheTraceFile ? theNameOfTheTraceFile : "<no tracefile>",
145 NDB_VERSION_STRING);
147 // Add trailing blanks to get a fixed lenght of the message
148 while (strlen(messptr) <= MESSAGE_LENGTH-3){
149 strcat(messptr, " ");
152 strcat(messptr, "\n");
154 return;
157 NdbShutdownType ErrorReporter::s_errorHandlerShutdownType = NST_ErrorHandler;
159 void
160 ErrorReporter::setErrorHandlerShutdownType(NdbShutdownType nst)
162 s_errorHandlerShutdownType = nst;
165 void childReportError(int error);
167 void
168 ErrorReporter::handleAssert(const char* message, const char* file, int line, int ec)
170 char refMessage[100];
172 #ifdef NO_EMULATED_JAM
173 BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d",
174 file, line);
175 #else
176 const Uint32 blockNumber = theEmulatedJamBlockNumber;
177 const char *blockName = getBlockName(blockNumber);
179 BaseString::snprintf(refMessage, 100, "%s line: %d (block: %s)",
180 file, line, blockName);
181 #endif
182 WriteMessage(ec, message, refMessage,
183 theEmulatedJamIndex, theEmulatedJam);
185 childReportError(ec);
187 NdbShutdown(s_errorHandlerShutdownType);
188 exit(1); // Deadcode
191 void
192 ErrorReporter::handleError(int messageID,
193 const char* problemData,
194 const char* objRef,
195 NdbShutdownType nst)
197 WriteMessage(messageID, problemData,
198 objRef, theEmulatedJamIndex, theEmulatedJam);
200 g_eventLogger.info(problemData);
201 g_eventLogger.info(objRef);
203 childReportError(messageID);
205 if(messageID == NDBD_EXIT_ERROR_INSERT){
206 NdbShutdown(NST_ErrorInsert);
207 } else {
208 if (nst == NST_ErrorHandler)
209 nst = s_errorHandlerShutdownType;
210 NdbShutdown(nst);
214 int
215 WriteMessage(int thrdMessageID,
216 const char* thrdProblemData, const char* thrdObjRef,
217 Uint32 thrdTheEmulatedJamIndex,
218 Uint8 thrdTheEmulatedJam[]){
219 FILE *stream;
220 unsigned offset;
221 unsigned long maxOffset; // Maximum size of file.
222 char theMessage[MESSAGE_LENGTH];
225 * Format trace file name
227 char *theTraceFileName= 0;
228 if (globalData.ownId > 0)
229 theTraceFileName= NdbConfig_TraceFileName(globalData.ownId,
230 ErrorReporter::get_trace_no());
231 NdbAutoPtr<char> tmp_aptr1(theTraceFileName);
233 // The first 69 bytes is info about the current offset
234 Uint32 noMsg = globalEmulatorData.theConfiguration->maxNoOfErrorLogs();
236 maxOffset = (69 + (noMsg * MESSAGE_LENGTH));
238 char *theErrorFileName= (char *)NdbConfig_ErrorFileName(globalData.ownId);
239 NdbAutoPtr<char> tmp_aptr2(theErrorFileName);
241 stream = fopen(theErrorFileName, "r+");
242 if (stream == NULL) { /* If the file could not be opened. */
244 // Create a new file, and skip the first 69 bytes,
245 // which are info about the current offset
246 stream = fopen(theErrorFileName, "w");
247 if(stream == NULL)
249 fprintf(stderr,"Unable to open error log file: %s\n", theErrorFileName);
250 return -1;
252 fprintf(stream, "%s%u%s", "Current byte-offset of file-pointer is: ", 69,
253 " \n\n\n");
255 // ...and write the error-message...
256 ErrorReporter::formatMessage(thrdMessageID,
257 thrdProblemData, thrdObjRef,
258 theTraceFileName, theMessage);
259 fprintf(stream, "%s", theMessage);
260 fflush(stream);
262 /* ...and finally, at the beginning of the file,
263 store the position where to
264 start writing the next message. */
265 offset = ftell(stream);
266 // If we have not reached the maximum number of messages...
267 if (offset <= (maxOffset - MESSAGE_LENGTH)){
268 fseek(stream, 40, SEEK_SET);
269 // ...set the current offset...
270 fprintf(stream,"%d", offset);
271 } else {
272 fseek(stream, 40, SEEK_SET);
273 // ...otherwise, start over from the beginning.
274 fprintf(stream, "%u%s", 69, " ");
276 } else {
277 // Go to the latest position in the file...
278 fseek(stream, 40, SEEK_SET);
279 fscanf(stream, "%u", &offset);
280 fseek(stream, offset, SEEK_SET);
282 // ...and write the error-message there...
283 ErrorReporter::formatMessage(thrdMessageID,
284 thrdProblemData, thrdObjRef,
285 theTraceFileName, theMessage);
286 fprintf(stream, "%s", theMessage);
287 fflush(stream);
289 /* ...and finally, at the beginning of the file,
290 store the position where to
291 start writing the next message. */
292 offset = ftell(stream);
294 // If we have not reached the maximum number of messages...
295 if (offset <= (maxOffset - MESSAGE_LENGTH)){
296 fseek(stream, 40, SEEK_SET);
297 // ...set the current offset...
298 fprintf(stream,"%d", offset);
299 } else {
300 fseek(stream, 40, SEEK_SET);
301 // ...otherwise, start over from the beginning.
302 fprintf(stream, "%u%s", 69, " ");
305 fflush(stream);
306 fclose(stream);
308 if (theTraceFileName) {
309 // Open the tracefile...
310 FILE *jamStream = fopen(theTraceFileName, "w");
312 // ...and "dump the jam" there.
313 // ErrorReporter::dumpJam(jamStream);
314 if(thrdTheEmulatedJam != 0){
315 dumpJam(jamStream, thrdTheEmulatedJamIndex, thrdTheEmulatedJam);
318 /* Dont print the jobBuffers until a way to copy them,
319 like the other variables,
320 is implemented. Otherwise when NDB keeps running,
321 with this function running
322 in the background, the jobBuffers will change during runtime. And when
323 they're printed here, they will not be correct anymore.
325 globalScheduler.dumpSignalMemory(jamStream);
327 fclose(jamStream);
330 return 0;
333 void
334 dumpJam(FILE *jamStream,
335 Uint32 thrdTheEmulatedJamIndex,
336 Uint8 thrdTheEmulatedJam[]) {
337 #ifndef NO_EMULATED_JAM
338 // print header
339 const int maxaddr = 8;
340 fprintf(jamStream, "JAM CONTENTS up->down left->right ?=not block entry\n");
341 fprintf(jamStream, "%-7s ", "BLOCK");
342 for (int i = 0; i < maxaddr; i++)
343 fprintf(jamStream, "%-6s ", "ADDR");
344 fprintf(jamStream, "\n");
346 // treat as array of Uint32
347 const Uint32 *base = (Uint32 *)thrdTheEmulatedJam;
348 const int first = thrdTheEmulatedJamIndex / sizeof(Uint32); // oldest
349 int cnt, idx;
351 // look for first block entry
352 for (cnt = 0, idx = first; cnt < EMULATED_JAM_SIZE; cnt++, idx++) {
353 if (idx >= EMULATED_JAM_SIZE)
354 idx = 0;
355 const Uint32 aJamEntry = base[idx];
356 if (aJamEntry > (1 << 20))
357 break;
360 // 1. if first entry is a block entry, it is printed in the main loop
361 // 2. else if any block entry exists, the jam starts in an unknown block
362 // 3. else if no block entry exists, the block is theEmulatedJamBlockNumber
363 // a "?" indicates first addr is not a block entry
364 if (cnt == 0)
366 else if (cnt < EMULATED_JAM_SIZE)
367 fprintf(jamStream, "%-7s?", "");
368 else {
369 const Uint32 aBlockNumber = theEmulatedJamBlockNumber;
370 const char *aBlockName = getBlockName(aBlockNumber);
371 if (aBlockName != 0)
372 fprintf(jamStream, "%-7s?", aBlockName);
373 else
374 fprintf(jamStream, "0x%-5X?", aBlockNumber);
377 // loop over all entries
378 int cntaddr = 0;
379 for (cnt = 0, idx = first; cnt < EMULATED_JAM_SIZE; cnt++, idx++) {
380 globalData.incrementWatchDogCounter(4); // watchdog not to kill us ?
381 if (idx >= EMULATED_JAM_SIZE)
382 idx = 0;
383 const Uint32 aJamEntry = base[idx];
384 if (aJamEntry > (1 << 20)) {
385 const Uint32 aBlockNumber = aJamEntry >> 20;
386 const char *aBlockName = getBlockName(aBlockNumber);
387 if (cnt > 0)
388 fprintf(jamStream, "\n");
389 if (aBlockName != 0)
390 fprintf(jamStream, "%-7s ", aBlockName);
391 else
392 fprintf(jamStream, "0x%-5X ", aBlockNumber);
393 cntaddr = 0;
395 if (cntaddr == maxaddr) {
396 fprintf(jamStream, "\n%-7s ", "");
397 cntaddr = 0;
399 fprintf(jamStream, "%06u ", aJamEntry & 0xFFFFF);
400 cntaddr++;
402 fprintf(jamStream, "\n");
403 fflush(jamStream);
404 #endif // ifndef NO_EMULATED_JAM