diff options
Diffstat (limited to 'storage/ndb/src/kernel/error/ErrorReporter.cpp')
-rw-r--r-- | storage/ndb/src/kernel/error/ErrorReporter.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/storage/ndb/src/kernel/error/ErrorReporter.cpp b/storage/ndb/src/kernel/error/ErrorReporter.cpp new file mode 100644 index 00000000000..35cd3f099d9 --- /dev/null +++ b/storage/ndb/src/kernel/error/ErrorReporter.cpp @@ -0,0 +1,393 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +#include "Error.hpp" +#include "ErrorReporter.hpp" +#include "ErrorMessages.hpp" + +#include <FastScheduler.hpp> +#include <DebuggerNames.hpp> +#include <NdbHost.h> +#include <NdbConfig.h> +#include <Configuration.hpp> + +#include <NdbAutoPtr.hpp> + +#define MESSAGE_LENGTH 400 + +const char* errorType[] = { + "warning", + "error", + "fatal", + "assert" +}; + + +static int WriteMessage(ErrorCategory thrdType, int thrdMessageID, + const char* thrdProblemData, + const char* thrdObjRef, + Uint32 thrdTheEmulatedJamIndex, + Uint8 thrdTheEmulatedJam[]); + +static void dumpJam(FILE* jamStream, + Uint32 thrdTheEmulatedJamIndex, + Uint8 thrdTheEmulatedJam[]); + + +const char* +ErrorReporter::formatTimeStampString(){ + TimeModule DateTime; /* To create "theDateTimeString" */ + + static char theDateTimeString[39]; + /* Used to store the generated timestamp */ + /* ex: "Wednesday 18 September 2000 - 18:54:37" */ + + DateTime.setTimeStamp(); + + BaseString::snprintf(theDateTimeString, 39, "%s %d %s %d - %s:%s:%s", + DateTime.getDayName(), DateTime.getDayOfMonth(), + DateTime.getMonthName(), DateTime.getYear(), DateTime.getHour(), + DateTime.getMinute(), DateTime.getSecond()); + + return (const char *)&theDateTimeString; +} + +int +ErrorReporter::get_trace_no(){ + + FILE *stream; + unsigned int traceFileNo; + + char *file_name= NdbConfig_NextTraceFileName(globalData.ownId); + NdbAutoPtr<char> tmp_aptr(file_name); + + /* + * Read last number from tracefile + */ + stream = fopen(file_name, "r+"); + if (stream == NULL){ + traceFileNo = 1; + } else { + char buf[255]; + fgets(buf, 255, stream); + const int scan = sscanf(buf, "%u", &traceFileNo); + if(scan != 1){ + traceFileNo = 1; + } + fclose(stream); + traceFileNo++; + } + + /** + * Wrap tracefile no + */ + Uint32 tmp = globalEmulatorData.theConfiguration->maxNoOfErrorLogs(); + if (traceFileNo > tmp ) { + traceFileNo = 1; + } + + /** + * Save new number to the file + */ + stream = fopen(file_name, "w"); + if(stream != NULL){ + fprintf(stream, "%u", traceFileNo); + fclose(stream); + } + + return traceFileNo; +} + + +void +ErrorReporter::formatMessage(ErrorCategory type, + int faultID, + const char* problemData, + const char* objRef, + const char* theNameOfTheTraceFile, + char* messptr){ + int processId; + + processId = NdbHost_GetProcessId(); + + BaseString::snprintf(messptr, MESSAGE_LENGTH, + "Date/Time: %s\nType of error: %s\n" + "Message: %s\nFault ID: %d\nProblem data: %s" + "\nObject of reference: %s\nProgramName: %s\n" + "ProcessID: %d\nTraceFile: %s\n***EOM***\n", + formatTimeStampString() , + errorType[type], + lookupErrorMessage(faultID), + faultID, + (problemData == NULL) ? "" : problemData, + objRef, + my_progname, + processId, + theNameOfTheTraceFile ? theNameOfTheTraceFile : "<no tracefile>"); + + // Add trailing blanks to get a fixed lenght of the message + while (strlen(messptr) <= MESSAGE_LENGTH-3){ + strcat(messptr, " "); + } + + strcat(messptr, "\n"); + + return; +} + +void +ErrorReporter::handleAssert(const char* message, const char* file, int line) +{ + char refMessage[100]; + +#ifdef NO_EMULATED_JAM + BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d", + file, line); +#else + const Uint32 blockNumber = theEmulatedJamBlockNumber; + const char *blockName = getBlockName(blockNumber); + + BaseString::snprintf(refMessage, 100, "%s line: %d (block: %s)", + file, line, blockName); +#endif + WriteMessage(assert, ERR_ERROR_PRGERR, message, refMessage, + theEmulatedJamIndex, theEmulatedJam); + + NdbShutdown(NST_ErrorHandler); +} + +void +ErrorReporter::handleThreadAssert(const char* message, + const char* file, + int line) +{ + char refMessage[100]; + BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d - %s", + file, line, message); + + NdbShutdown(NST_ErrorHandler); +}//ErrorReporter::handleThreadAssert() + + +void +ErrorReporter::handleError(ErrorCategory type, int messageID, + const char* problemData, + const char* objRef, + NdbShutdownType nst) +{ + type = ecError; + // The value for type is not always set correctly in the calling function. + // So, to correct this, we set it set it to the value corresponding to + // the function that is called. + WriteMessage(type, messageID, problemData, + objRef, theEmulatedJamIndex, theEmulatedJam); + if(messageID == ERR_ERROR_INSERT){ + NdbShutdown(NST_ErrorInsert); + } else { + NdbShutdown(nst); + } +} + +int +WriteMessage(ErrorCategory thrdType, int thrdMessageID, + const char* thrdProblemData, const char* thrdObjRef, + Uint32 thrdTheEmulatedJamIndex, + Uint8 thrdTheEmulatedJam[]){ + FILE *stream; + unsigned offset; + unsigned long maxOffset; // Maximum size of file. + char theMessage[MESSAGE_LENGTH]; + + /** + * Format trace file name + */ + char *theTraceFileName= 0; + if (globalData.ownId > 0) + theTraceFileName= NdbConfig_TraceFileName(globalData.ownId, + ErrorReporter::get_trace_no()); + NdbAutoPtr<char> tmp_aptr1(theTraceFileName); + + // The first 69 bytes is info about the current offset + Uint32 noMsg = globalEmulatorData.theConfiguration->maxNoOfErrorLogs(); + + maxOffset = (69 + (noMsg * MESSAGE_LENGTH)); + + char *theErrorFileName= (char *)NdbConfig_ErrorFileName(globalData.ownId); + NdbAutoPtr<char> tmp_aptr2(theErrorFileName); + + stream = fopen(theErrorFileName, "r+"); + if (stream == NULL) { /* If the file could not be opened. */ + + // Create a new file, and skip the first 69 bytes, + // which are info about the current offset + stream = fopen(theErrorFileName, "w"); + fprintf(stream, "%s%u%s", "Current byte-offset of file-pointer is: ", 69, + " \n\n\n"); + + // ...and write the error-message... + ErrorReporter::formatMessage(thrdType, thrdMessageID, + thrdProblemData, thrdObjRef, + theTraceFileName, theMessage); + fprintf(stream, "%s", theMessage); + fflush(stream); + + /* ...and finally, at the beginning of the file, + store the position where to + start writing the next message. */ + offset = ftell(stream); + // If we have not reached the maximum number of messages... + if (offset <= (maxOffset - MESSAGE_LENGTH)){ + fseek(stream, 40, SEEK_SET); + // ...set the current offset... + fprintf(stream,"%d", offset); + } else { + fseek(stream, 40, SEEK_SET); + // ...otherwise, start over from the beginning. + fprintf(stream, "%u%s", 69, " "); + } + } else { + // Go to the latest position in the file... + fseek(stream, 40, SEEK_SET); + fscanf(stream, "%u", &offset); + fseek(stream, offset, SEEK_SET); + + // ...and write the error-message there... + ErrorReporter::formatMessage(thrdType, thrdMessageID, + thrdProblemData, thrdObjRef, + theTraceFileName, theMessage); + fprintf(stream, "%s", theMessage); + fflush(stream); + + /* ...and finally, at the beginning of the file, + store the position where to + start writing the next message. */ + offset = ftell(stream); + + // If we have not reached the maximum number of messages... + if (offset <= (maxOffset - MESSAGE_LENGTH)){ + fseek(stream, 40, SEEK_SET); + // ...set the current offset... + fprintf(stream,"%d", offset); + } else { + fseek(stream, 40, SEEK_SET); + // ...otherwise, start over from the beginning. + fprintf(stream, "%u%s", 69, " "); + } + } + fflush(stream); + fclose(stream); + + if (theTraceFileName) { + // Open the tracefile... + FILE *jamStream = fopen(theTraceFileName, "w"); + + // ...and "dump the jam" there. + // ErrorReporter::dumpJam(jamStream); + if(thrdTheEmulatedJam != 0){ + dumpJam(jamStream, thrdTheEmulatedJamIndex, thrdTheEmulatedJam); + } + + /* Dont print the jobBuffers until a way to copy them, + like the other variables, + is implemented. Otherwise when NDB keeps running, + with this function running + in the background, the jobBuffers will change during runtime. And when + they're printed here, they will not be correct anymore. + */ + globalScheduler.dumpSignalMemory(jamStream); + + fclose(jamStream); + } + + return 0; +} + +void +dumpJam(FILE *jamStream, + Uint32 thrdTheEmulatedJamIndex, + Uint8 thrdTheEmulatedJam[]) { +#ifndef NO_EMULATED_JAM + // print header + const int maxaddr = 8; + fprintf(jamStream, "JAM CONTENTS up->down left->right ?=not block entry\n"); + fprintf(jamStream, "%-7s ", "BLOCK"); + for (int i = 0; i < maxaddr; i++) + fprintf(jamStream, "%-6s ", "ADDR"); + fprintf(jamStream, "\n"); + + // treat as array of Uint32 + const Uint32 *base = (Uint32 *)thrdTheEmulatedJam; + const int first = thrdTheEmulatedJamIndex / sizeof(Uint32); // oldest + int cnt, idx; + + // look for first block entry + for (cnt = 0, idx = first; cnt < EMULATED_JAM_SIZE; cnt++, idx++) { + if (idx >= EMULATED_JAM_SIZE) + idx = 0; + const Uint32 aJamEntry = base[idx]; + if (aJamEntry > (1 << 20)) + break; + } + + // 1. if first entry is a block entry, it is printed in the main loop + // 2. else if any block entry exists, the jam starts in an unknown block + // 3. else if no block entry exists, the block is theEmulatedJamBlockNumber + // a "?" indicates first addr is not a block entry + if (cnt == 0) + ; + else if (cnt < EMULATED_JAM_SIZE) + fprintf(jamStream, "%-7s?", ""); + else { + const Uint32 aBlockNumber = theEmulatedJamBlockNumber; + const char *aBlockName = getBlockName(aBlockNumber); + if (aBlockName != 0) + fprintf(jamStream, "%-7s?", aBlockName); + else + fprintf(jamStream, "0x%-5X?", aBlockNumber); + } + + // loop over all entries + int cntaddr = 0; + for (cnt = 0, idx = first; cnt < EMULATED_JAM_SIZE; cnt++, idx++) { + globalData.incrementWatchDogCounter(4); // watchdog not to kill us ? + if (idx >= EMULATED_JAM_SIZE) + idx = 0; + const Uint32 aJamEntry = base[idx]; + if (aJamEntry > (1 << 20)) { + const Uint32 aBlockNumber = aJamEntry >> 20; + const char *aBlockName = getBlockName(aBlockNumber); + if (cnt > 0) + fprintf(jamStream, "\n"); + if (aBlockName != 0) + fprintf(jamStream, "%-7s ", aBlockName); + else + fprintf(jamStream, "0x%-5X ", aBlockNumber); + cntaddr = 0; + } + if (cntaddr == maxaddr) { + fprintf(jamStream, "\n%-7s ", ""); + cntaddr = 0; + } + fprintf(jamStream, "%06u ", aJamEntry & 0xFFFFF); + cntaddr++; + } + fprintf(jamStream, "\n"); + fflush(jamStream); +#endif // ifndef NO_EMULATED_JAM +} |