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>
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
;
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
;
63 ErrorReporter::get_trace_no(){
66 unsigned int traceFileNo
;
68 char *file_name
= NdbConfig_NextTraceFileName(globalData
.ownId
);
69 NdbAutoPtr
<char> tmp_aptr(file_name
);
72 * Read last number from tracefile
74 stream
= fopen(file_name
, "r+");
79 fgets(buf
, 255, stream
);
80 const int scan
= sscanf(buf
, "%u", &traceFileNo
);
91 Uint32 tmp
= globalEmulatorData
.theConfiguration
->maxNoOfErrorLogs();
92 if (traceFileNo
> tmp
) {
97 * Save new number to the file
99 stream
= fopen(file_name
, "w");
101 fprintf(stream
, "%u", traceFileNo
);
110 ErrorReporter::formatMessage(int faultID
,
111 const char* problemData
,
113 const char* theNameOfTheTraceFile
,
116 ndbd_exit_classification cl
;
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
,
136 formatTimeStampString() ,
138 exit_msg
, exit_cl_msg
,
140 (problemData
== NULL
) ? "" : problemData
,
144 theNameOfTheTraceFile
? theNameOfTheTraceFile
: "<no tracefile>",
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");
157 NdbShutdownType
ErrorReporter::s_errorHandlerShutdownType
= NST_ErrorHandler
;
160 ErrorReporter::setErrorHandlerShutdownType(NdbShutdownType nst
)
162 s_errorHandlerShutdownType
= nst
;
165 void childReportError(int error
);
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",
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
);
182 WriteMessage(ec
, message
, refMessage
,
183 theEmulatedJamIndex
, theEmulatedJam
);
185 childReportError(ec
);
187 NdbShutdown(s_errorHandlerShutdownType
);
192 ErrorReporter::handleError(int messageID
,
193 const char* problemData
,
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
);
208 if (nst
== NST_ErrorHandler
)
209 nst
= s_errorHandlerShutdownType
;
215 WriteMessage(int thrdMessageID
,
216 const char* thrdProblemData
, const char* thrdObjRef
,
217 Uint32 thrdTheEmulatedJamIndex
,
218 Uint8 thrdTheEmulatedJam
[]){
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");
249 fprintf(stderr
,"Unable to open error log file: %s\n", theErrorFileName
);
252 fprintf(stream
, "%s%u%s", "Current byte-offset of file-pointer is: ", 69,
255 // ...and write the error-message...
256 ErrorReporter::formatMessage(thrdMessageID
,
257 thrdProblemData
, thrdObjRef
,
258 theTraceFileName
, theMessage
);
259 fprintf(stream
, "%s", theMessage
);
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
);
272 fseek(stream
, 40, SEEK_SET
);
273 // ...otherwise, start over from the beginning.
274 fprintf(stream
, "%u%s", 69, " ");
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
);
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
);
300 fseek(stream
, 40, SEEK_SET
);
301 // ...otherwise, start over from the beginning.
302 fprintf(stream
, "%u%s", 69, " ");
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
);
334 dumpJam(FILE *jamStream
,
335 Uint32 thrdTheEmulatedJamIndex
,
336 Uint8 thrdTheEmulatedJam
[]) {
337 #ifndef NO_EMULATED_JAM
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
351 // look for first block entry
352 for (cnt
= 0, idx
= first
; cnt
< EMULATED_JAM_SIZE
; cnt
++, idx
++) {
353 if (idx
>= EMULATED_JAM_SIZE
)
355 const Uint32 aJamEntry
= base
[idx
];
356 if (aJamEntry
> (1 << 20))
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
366 else if (cnt
< EMULATED_JAM_SIZE
)
367 fprintf(jamStream
, "%-7s?", "");
369 const Uint32 aBlockNumber
= theEmulatedJamBlockNumber
;
370 const char *aBlockName
= getBlockName(aBlockNumber
);
372 fprintf(jamStream
, "%-7s?", aBlockName
);
374 fprintf(jamStream
, "0x%-5X?", aBlockNumber
);
377 // loop over all entries
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
)
383 const Uint32 aJamEntry
= base
[idx
];
384 if (aJamEntry
> (1 << 20)) {
385 const Uint32 aBlockNumber
= aJamEntry
>> 20;
386 const char *aBlockName
= getBlockName(aBlockNumber
);
388 fprintf(jamStream
, "\n");
390 fprintf(jamStream
, "%-7s ", aBlockName
);
392 fprintf(jamStream
, "0x%-5X ", aBlockNumber
);
395 if (cntaddr
== maxaddr
) {
396 fprintf(jamStream
, "\n%-7s ", "");
399 fprintf(jamStream
, "%06u ", aJamEntry
& 0xFFFFF);
402 fprintf(jamStream
, "\n");
404 #endif // ifndef NO_EMULATED_JAM