MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ErrorReporter.cpp
1 /*
2  Copyright (c) 2003, 2010, 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 
19 #include <ndb_global.h>
20 
21 #include <ndbd_exit_codes.h>
22 #include "ErrorReporter.hpp"
23 
24 #include <FastScheduler.hpp>
25 #include <DebuggerNames.hpp>
26 #include <NdbHost.h>
27 #include <NdbConfig.h>
28 #include <Configuration.hpp>
29 #include "EventLogger.hpp"
30 extern EventLogger * g_eventLogger;
31 
32 #include "TimeModule.hpp"
33 
34 #include <NdbAutoPtr.hpp>
35 
36 #define MESSAGE_LENGTH 500
37 
38 static int WriteMessage(int thrdMessageID,
39  const char* thrdProblemData,
40  const char* thrdObjRef,
41  NdbShutdownType & nst);
42 
43 static void dumpJam(FILE* jamStream,
44  Uint32 thrdTheEmulatedJamIndex,
45  const Uint32 thrdTheEmulatedJam[],
46  Uint32 aBlockNumber);
47 
48 
49 const char*
50 ErrorReporter::formatTimeStampString(){
51  TimeModule DateTime; /* To create "theDateTimeString" */
52 
53  static char theDateTimeString[39];
54  /* Used to store the generated timestamp */
55  /* ex: "Wednesday 18 September 2000 - 18:54:37" */
56 
57  DateTime.setTimeStamp();
58 
59  BaseString::snprintf(theDateTimeString, 39, "%s %d %s %d - %s:%s:%s",
60  DateTime.getDayName(), DateTime.getDayOfMonth(),
61  DateTime.getMonthName(), DateTime.getYear(), DateTime.getHour(),
62  DateTime.getMinute(), DateTime.getSecond());
63 
64  return (const char *)&theDateTimeString;
65 }
66 
67 int
69 
70  FILE *stream;
71  unsigned int traceFileNo;
72 
73  char *file_name= NdbConfig_NextTraceFileName(globalData.ownId);
74  NdbAutoPtr<char> tmp_aptr(file_name);
75 
76  /*
77  * Read last number from tracefile
78  */
79  stream = fopen(file_name, "r+");
80  if (stream == NULL){
81  traceFileNo = 1;
82  } else {
83  char buf[255];
84  fgets(buf, 255, stream);
85  const int scan = sscanf(buf, "%u", &traceFileNo);
86  if(scan != 1){
87  traceFileNo = 1;
88  }
89  fclose(stream);
90  traceFileNo++;
91  }
92 
96  Uint32 tmp = globalEmulatorData.theConfiguration->maxNoOfErrorLogs();
97  if (traceFileNo > tmp ) {
98  traceFileNo = 1;
99  }
100 
104  stream = fopen(file_name, "w");
105  if(stream != NULL){
106  fprintf(stream, "%u", traceFileNo);
107  fclose(stream);
108  }
109 
110  return traceFileNo;
111 }
112 
113 // Using my_progname without including all of mysys
114 extern "C" const char* my_progname;
115 
116 void
117 ErrorReporter::formatMessage(int thr_no,
118  Uint32 num_threads, int faultID,
119  const char* problemData,
120  const char* objRef,
121  const char* theNameOfTheTraceFile,
122  char* messptr){
123  int processId;
124  ndbd_exit_classification cl;
125  ndbd_exit_status st;
126  const char *exit_msg = ndbd_exit_message(faultID, &cl);
127  const char *exit_cl_msg = ndbd_exit_classification_message(cl, &st);
128  const char *exit_st_msg = ndbd_exit_status_message(st);
129  int sofar;
130 
131  processId = NdbHost_GetProcessId();
132  char thrbuf[100] = "";
133  if (thr_no >= 0)
134  {
135  BaseString::snprintf(thrbuf, sizeof(thrbuf), " thr: %u", thr_no);
136  }
137 
138  BaseString::snprintf(messptr, MESSAGE_LENGTH,
139  "Time: %s\n"
140  "Status: %s\n"
141  "Message: %s (%s)\n"
142  "Error: %d\n"
143  "Error data: %s\n"
144  "Error object: %s\n"
145  "Program: %s\n"
146  "Pid: %d%s\n"
147  "Version: %s\n"
148  "Trace: %s",
149  formatTimeStampString() ,
150  exit_st_msg,
151  exit_msg, exit_cl_msg,
152  faultID,
153  (problemData == NULL) ? "" : problemData,
154  objRef,
155  my_progname,
156  processId,
157  thrbuf,
158  NDB_VERSION_STRING,
159  theNameOfTheTraceFile ?
160  theNameOfTheTraceFile : "<no tracefile>");
161 
162  if (theNameOfTheTraceFile)
163  {
164  for (Uint32 i = 1 ; i < num_threads; i++)
165  {
166  sofar = strlen(messptr);
167  if(sofar < MESSAGE_LENGTH)
168  {
169  BaseString::snprintf(messptr + sofar, MESSAGE_LENGTH - sofar,
170  " %s_t%u", theNameOfTheTraceFile, i);
171  }
172  }
173  }
174 
175  sofar = strlen(messptr);
176  if(sofar < MESSAGE_LENGTH)
177  {
178  BaseString::snprintf(messptr + sofar, MESSAGE_LENGTH - sofar,
179  "\n"
180  "***EOM***\n");
181  }
182 
183  // Add trailing blanks to get a fixed length of the message
184  while (strlen(messptr) <= MESSAGE_LENGTH-3){
185  strcat(messptr, " ");
186  }
187 
188  messptr[MESSAGE_LENGTH -2]='\n';
189  messptr[MESSAGE_LENGTH -1]=0;
190 
191  return;
192 }
193 
194 NdbShutdownType ErrorReporter::s_errorHandlerShutdownType = NST_ErrorHandler;
195 
196 void
197 ErrorReporter::handleAssert(const char* message, const char* file, int line, int ec)
198 {
199  char refMessage[100];
200  Uint32 jamBlockNumber;
201 
202 #ifdef NO_EMULATED_JAM
203  BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d",
204  file, line);
205  jam = NULL;
206  jamIndex = 0;
207  jamBlockNumber = 0;
208 #else
209  const EmulatedJamBuffer *jamBuffer =
210  (EmulatedJamBuffer *)NdbThread_GetTlsKey(NDB_THREAD_TLS_JAM);
211  jamBlockNumber = jamBuffer->theEmulatedJamBlockNumber;
212  const char *blockName = getBlockName(jamBlockNumber);
213 
214  BaseString::snprintf(refMessage, 100, "%s line: %d (block: %s)",
215  file, line, blockName);
216 #endif
217  NdbShutdownType nst = s_errorHandlerShutdownType;
218  WriteMessage(ec, message, refMessage, nst);
219 
220  NdbShutdown(ec, nst);
221  exit(1); // Deadcode
222 }
223 
224 void
225 ErrorReporter::handleError(int messageID,
226  const char* problemData,
227  const char* objRef,
228  NdbShutdownType nst)
229 {
230  if(messageID == NDBD_EXIT_ERROR_INSERT)
231  {
232  nst = NST_ErrorInsert;
233  }
234  else
235  {
236  if (nst == NST_ErrorHandler)
237  nst = s_errorHandlerShutdownType;
238  }
239 
240  WriteMessage(messageID, problemData, objRef, nst);
241 
242  g_eventLogger->info("%s", problemData);
243  g_eventLogger->info("%s", objRef);
244 
245  NdbShutdown(messageID, nst);
246  exit(1); // kill warning
247 }
248 
249 int
250 WriteMessage(int thrdMessageID,
251  const char* thrdProblemData,
252  const char* thrdObjRef,
253  NdbShutdownType & nst){
254  FILE *stream;
255  unsigned offset;
256  unsigned long maxOffset; // Maximum size of file.
257  char theMessage[MESSAGE_LENGTH];
258  Uint32 thrdTheEmulatedJamIndex;
259  const Uint32 *thrdTheEmulatedJam;
260  Uint32 jamBlockNumber;
261 
262  Uint32 threadCount = globalScheduler.traceDumpGetNumThreads();
263  int thr_no = globalScheduler.traceDumpGetCurrentThread();
264 
268  char *theTraceFileName= 0;
269  if (globalData.ownId > 0)
270  theTraceFileName= NdbConfig_TraceFileName(globalData.ownId,
272  NdbAutoPtr<char> tmp_aptr1(theTraceFileName);
273 
274  // The first 69 bytes is info about the current offset
275  Uint32 noMsg = globalEmulatorData.theConfiguration->maxNoOfErrorLogs();
276 
277  maxOffset = (69 + (noMsg * MESSAGE_LENGTH));
278 
279  char *theErrorFileName= (char *)NdbConfig_ErrorFileName(globalData.ownId);
280  NdbAutoPtr<char> tmp_aptr2(theErrorFileName);
281 
282  stream = fopen(theErrorFileName, "r+");
283  if (stream == NULL) { /* If the file could not be opened. */
284 
285  // Create a new file, and skip the first 69 bytes,
286  // which are info about the current offset
287  stream = fopen(theErrorFileName, "w");
288  if(stream == NULL)
289  {
290  fprintf(stderr,"Unable to open error log file: %s\n", theErrorFileName);
291  return -1;
292  }
293  fprintf(stream, "%s%u%s", "Current byte-offset of file-pointer is: ", 69,
294  " \n\n\n");
295 
296  // ...and write the error-message...
297  ErrorReporter::formatMessage(thr_no,
298  threadCount, thrdMessageID,
299  thrdProblemData, thrdObjRef,
300  theTraceFileName, theMessage);
301  fprintf(stream, "%s", theMessage);
302  fflush(stream);
303 
304  /* ...and finally, at the beginning of the file,
305  store the position where to
306  start writing the next message. */
307  offset = ftell(stream);
308  // If we have not reached the maximum number of messages...
309  if (offset <= (maxOffset - MESSAGE_LENGTH)){
310  fseek(stream, 40, SEEK_SET);
311  // ...set the current offset...
312  fprintf(stream,"%d", offset);
313  } else {
314  fseek(stream, 40, SEEK_SET);
315  // ...otherwise, start over from the beginning.
316  fprintf(stream, "%u%s", 69, " ");
317  }
318  } else {
319  // Go to the latest position in the file...
320  fseek(stream, 40, SEEK_SET);
321  fscanf(stream, "%u", &offset);
322  fseek(stream, offset, SEEK_SET);
323 
324  // ...and write the error-message there...
325  ErrorReporter::formatMessage(thr_no,
326  threadCount, thrdMessageID,
327  thrdProblemData, thrdObjRef,
328  theTraceFileName, theMessage);
329  fprintf(stream, "%s", theMessage);
330  fflush(stream);
331 
332  /* ...and finally, at the beginning of the file,
333  store the position where to
334  start writing the next message. */
335  offset = ftell(stream);
336 
337  // If we have not reached the maximum number of messages...
338  if (offset <= (maxOffset - MESSAGE_LENGTH)){
339  fseek(stream, 40, SEEK_SET);
340  // ...set the current offset...
341  fprintf(stream,"%d", offset);
342  } else {
343  fseek(stream, 40, SEEK_SET);
344  // ...otherwise, start over from the beginning.
345  fprintf(stream, "%u%s", 69, " ");
346  }
347  }
348  fflush(stream);
349  fclose(stream);
350 
351  if (theTraceFileName) {
352  /* Attempt to stop all processing to be able to dump a consistent state. */
353  globalScheduler.traceDumpPrepare(nst);
354 
355  char *traceFileEnd = theTraceFileName + strlen(theTraceFileName);
356  for (Uint32 i = 0; i < threadCount; i++)
357  {
358  // Open the tracefile...
359  if (i > 0)
360  sprintf(traceFileEnd, "_t%u", i);
361  FILE *jamStream = fopen(theTraceFileName, "w");
362 
363  // ...and "dump the jam" there.
364  bool ok = globalScheduler.traceDumpGetJam(i, jamBlockNumber,
365  thrdTheEmulatedJam,
366  thrdTheEmulatedJamIndex);
367  if(ok && thrdTheEmulatedJam != 0)
368  {
369  dumpJam(jamStream, thrdTheEmulatedJamIndex,
370  thrdTheEmulatedJam, jamBlockNumber);
371  }
372 
373  globalScheduler.dumpSignalMemory(i, jamStream);
374 
375  fclose(jamStream);
376  }
377  }
378 
379  return 0;
380 }
381 
382 void
383 dumpJam(FILE *jamStream,
384  Uint32 thrdTheEmulatedJamIndex,
385  const Uint32 thrdTheEmulatedJam[],
386  Uint32 aBlockNumber) {
387 #ifndef NO_EMULATED_JAM
388  // print header
389  const int maxaddr = 8;
390  fprintf(jamStream, "JAM CONTENTS up->down left->right ?=not block entry\n");
391  fprintf(jamStream, "%-7s ", "BLOCK");
392  for (int i = 0; i < maxaddr; i++)
393  fprintf(jamStream, "%-6s ", "ADDR");
394  fprintf(jamStream, "\n");
395 
396  const int first = thrdTheEmulatedJamIndex; // oldest
397  int cnt, idx;
398 
399  // look for first block entry
400  for (cnt = 0, idx = first; cnt < EMULATED_JAM_SIZE; cnt++, idx++) {
401  if (idx >= EMULATED_JAM_SIZE)
402  idx = 0;
403  const Uint32 aJamEntry = thrdTheEmulatedJam[idx];
404  if (aJamEntry > (1 << 20))
405  break;
406  }
407 
408  // 1. if first entry is a block entry, it is printed in the main loop
409  // 2. else if any block entry exists, the jam starts in an unknown block
410  // 3. else if no block entry exists, the block is theEmulatedJamBlockNumber
411  // a "?" indicates first addr is not a block entry
412  if (cnt == 0)
413  ;
414  else if (cnt < EMULATED_JAM_SIZE)
415  fprintf(jamStream, "%-7s?", "");
416  else {
417  const char *aBlockName = getBlockName(aBlockNumber);
418  if (aBlockName != 0)
419  fprintf(jamStream, "%-7s?", aBlockName);
420  else
421  fprintf(jamStream, "0x%-5X?", aBlockNumber);
422  }
423 
424  // loop over all entries
425  int cntaddr = 0;
426  for (cnt = 0, idx = first; cnt < EMULATED_JAM_SIZE; cnt++, idx++) {
427  globalData.incrementWatchDogCounter(4); // watchdog not to kill us ?
428  if (idx >= EMULATED_JAM_SIZE)
429  idx = 0;
430  const Uint32 aJamEntry = thrdTheEmulatedJam[idx];
431  if (aJamEntry > (1 << 20)) {
432  const Uint32 aBlockNumber = aJamEntry >> 20;
433  const char *aBlockName = getBlockName(aBlockNumber);
434  if (cnt > 0)
435  fprintf(jamStream, "\n");
436  if (aBlockName != 0)
437  fprintf(jamStream, "%-7s ", aBlockName);
438  else
439  fprintf(jamStream, "0x%-5X ", aBlockNumber);
440  cntaddr = 0;
441  }
442  if (cntaddr == maxaddr) {
443  fprintf(jamStream, "\n%-7s ", "");
444  cntaddr = 0;
445  }
446  fprintf(jamStream, "%06u ", aJamEntry & 0xFFFFF);
447  cntaddr++;
448  }
449  fprintf(jamStream, "\n");
450  fflush(jamStream);
451 #endif // ifndef NO_EMULATED_JAM
452 }