diff options
Diffstat (limited to 'ndb/src/common')
232 files changed, 40278 insertions, 0 deletions
diff --git a/ndb/src/common/Makefile b/ndb/src/common/Makefile new file mode 100644 index 00000000000..ebde75bf3ec --- /dev/null +++ b/ndb/src/common/Makefile @@ -0,0 +1,15 @@ +include .defs.mk + +LIB_DIRS := \ + portlib \ + debugger \ + util \ + logger + +ifneq ($(USE_EDITLINE), N) +LIB_DIRS += editline +endif + +DIRS := transporter mgmcommon + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/debugger/BlockNames.cpp b/ndb/src/common/debugger/BlockNames.cpp new file mode 100644 index 00000000000..44650b84c5c --- /dev/null +++ b/ndb/src/common/debugger/BlockNames.cpp @@ -0,0 +1,39 @@ +/* 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 <BlockNumbers.h> + +const BlockName BlockNames[] = { + { "CMVMI", CMVMI }, + { "DBACC", DBACC }, + { "DBDICT", DBDICT }, + { "DBDIH", DBDIH }, + { "DBLQH", DBLQH }, + { "DBTC", DBTC }, + { "DBTUP", DBTUP }, + { "NDBFS", NDBFS }, + { "NDBCNTR", NDBCNTR }, + { "QMGR", QMGR }, + { "TRIX", TRIX }, + { "BACKUP", BACKUP }, + { "DBUTIL", DBUTIL }, + { "SUMA", SUMA }, + { "GREP", GREP }, + { "DBTUX", DBTUX } +}; + +const BlockNumber NO_OF_BLOCK_NAMES = sizeof(BlockNames) / sizeof(BlockName); diff --git a/ndb/src/common/debugger/DebuggerNames.cpp b/ndb/src/common/debugger/DebuggerNames.cpp new file mode 100644 index 00000000000..fdee978ab54 --- /dev/null +++ b/ndb/src/common/debugger/DebuggerNames.cpp @@ -0,0 +1,154 @@ +/* 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 "DebuggerNames.hpp" + +#include <BlockNumbers.h> +#include <GlobalSignalNumbers.h> +#include <signaldata/SignalDataPrint.hpp> + +#include <NdbStdio.h> +#include <stdlib.h> +#include <string.h> + +static const char * localSignalNames[MAX_GSN+1]; +static SignalDataPrintFunction localPrintFunctions[MAX_GSN+1]; +static const char * localBlockNames[NO_OF_BLOCKS]; + +static +int +initSignalNames(const char * dst[], const GsnName src[], unsigned short len){ + for(int i = 0; i<=MAX_GSN; i++) + dst[i] = 0; + + for(int i = 0; i<len; i++){ + unsigned short gsn = src[i].gsn; + const char * name = src[i].name; + + if(dst[gsn] != 0 && name != 0){ + if(strcmp(dst[gsn], name) != 0){ + fprintf(stderr, + "Multiple definition of signal name for gsn: %d (%s, %s)\n", + gsn, dst[gsn], name); + exit(0); + } + } + dst[gsn] = name; + } + return 0; +} + +static +int +initSignalPrinters(SignalDataPrintFunction dst[], + const NameFunctionPair src[], + unsigned short len){ + for(int i = 0; i<=MAX_GSN; i++) + dst[i] = 0; + + for(int i = 0; i<len; i++){ + unsigned short gsn = src[i].gsn; + SignalDataPrintFunction fun = src[i].function; + + if(dst[gsn] != 0 && fun != 0){ + if(dst[gsn] != fun){ + fprintf(stderr, + "Multiple definition of signal print function for gsn: %d\n", + gsn); + exit(0); + } + } + dst[gsn] = fun; + } + return 0; +} + +static +int +initBlockNames(const char * dst[], + const BlockName src[], + unsigned len){ + for(int i = 0; i<NO_OF_BLOCKS; i++) + dst[i] = 0; + + for(unsigned i = 0; i<len; i++){ + const int index = src[i].number - MIN_BLOCK_NO; + if(index < 0 && index >= NO_OF_BLOCKS || dst[index] != 0){ + fprintf(stderr, + "Invalid block name definition: %d %s\n", + src[i].number, src[i].name); + exit(0); + } + dst[index] = src[i].name; + } + return 0; +} + +/** + * Run static initializer + */ +static const int +xxx_DUMMY_SIGNAL_NAMES_xxx = initSignalNames(localSignalNames, + SignalNames, + NO_OF_SIGNAL_NAMES); +static const int +xxx_DUMMY_PRINT_FUNCTIONS_xxx = initSignalPrinters(localPrintFunctions, + SignalDataPrintFunctions, + NO_OF_PRINT_FUNCTIONS); + +static const int +xxx_DUMMY_BLOCK_NAMES_xxx = initBlockNames(localBlockNames, + BlockNames, + NO_OF_BLOCK_NAMES); + +const char * +getSignalName(unsigned short gsn, const char * defVal){ + if(gsn > 0 && gsn <= MAX_GSN) + return (localSignalNames[gsn] ? localSignalNames[gsn] : defVal); + return defVal; +} + +unsigned short +getGsn(const char * signalName){ + return 0; +} + +const char * +getBlockName(unsigned short blockNo, const char * ret){ + if(blockNo >= MIN_BLOCK_NO && blockNo <= MAX_BLOCK_NO) + return localBlockNames[blockNo-MIN_BLOCK_NO]; + if (ret == 0) { + static char buf[20]; + snprintf(buf, sizeof(buf), "BLOCK#%d", (int)blockNo); + return buf; + } + return ret; +} + +unsigned short +getBlockNo(const char * blockName){ + for(int i = 0; i<NO_OF_BLOCKS; i++) + if(localBlockNames[i] != 0 && strcmp(localBlockNames[i], blockName) == 0) + return i + MIN_BLOCK_NO; + return 0; +} + +SignalDataPrintFunction +findPrintFunction(unsigned short gsn){ + if(gsn > 0 && gsn <= MAX_GSN) + return localPrintFunctions[gsn]; + return 0; +} diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp new file mode 100644 index 00000000000..12f01890c54 --- /dev/null +++ b/ndb/src/common/debugger/EventLogger.cpp @@ -0,0 +1,1454 @@ +/* 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 "EventLogger.hpp" + +#include <NdbConfig.h> +#include <kernel/BlockNumbers.h> +#include <signaldata/ArbitSignalData.hpp> +#include <GrepEvent.hpp> +#include <NodeState.hpp> +#include <version.h> +#include <NdbStdio.h> + +#include <string.h> +#include <ctype.h> + +// +// PUBLIC +// + +/** + * This matrix defines which event should be printed when + * + * threshold - is in range [0-15] + * severity - DEBUG to ALERT (Type of log message) + */ +const EventLogger::EventRepLogLevelMatrix EventLogger::matrix[] = { + // CONNECTION + { EventReport::Connected, LogLevel::llConnection, 8, LL_INFO }, + { EventReport::Disconnected, LogLevel::llConnection, 8, LL_ALERT }, + { EventReport::CommunicationClosed, LogLevel::llConnection, 8, LL_INFO }, + { EventReport::CommunicationOpened, LogLevel::llConnection, 8, LL_INFO }, + { EventReport::ConnectedApiVersion, LogLevel::llConnection, 8, LL_INFO }, + // CHECKPOINT + { EventReport::GlobalCheckpointStarted, LogLevel::llCheckpoint, 9, LL_INFO }, + { EventReport::GlobalCheckpointCompleted,LogLevel::llCheckpoint,10, LL_INFO }, + { EventReport::LocalCheckpointStarted, LogLevel::llCheckpoint, 7, LL_INFO }, + { EventReport::LocalCheckpointCompleted,LogLevel::llCheckpoint, 8, LL_INFO }, + { EventReport::LCPStoppedInCalcKeepGci, LogLevel::llCheckpoint, 0, LL_ALERT }, + { EventReport::LCPFragmentCompleted, LogLevel::llCheckpoint, 11, LL_INFO }, + { EventReport::UndoLogBlocked, LogLevel::llCheckpoint, 7, LL_INFO }, + + // STARTUP + { EventReport::NDBStartStarted, LogLevel::llStartUp, 1, LL_INFO }, + { EventReport::NDBStartCompleted, LogLevel::llStartUp, 1, LL_INFO }, + { EventReport::STTORRYRecieved, LogLevel::llStartUp,15, LL_INFO }, + { EventReport::StartPhaseCompleted, LogLevel::llStartUp, 4, LL_INFO }, + { EventReport::CM_REGCONF, LogLevel::llStartUp, 3, LL_INFO }, + { EventReport::CM_REGREF, LogLevel::llStartUp, 8, LL_INFO }, + { EventReport::FIND_NEIGHBOURS, LogLevel::llStartUp, 8, LL_INFO }, + { EventReport::NDBStopStarted, LogLevel::llStartUp, 1, LL_INFO }, + { EventReport::NDBStopAborted, LogLevel::llStartUp, 1, LL_INFO }, + { EventReport::StartREDOLog, LogLevel::llStartUp, 10, LL_INFO }, + { EventReport::StartLog, LogLevel::llStartUp, 10, LL_INFO }, + { EventReport::UNDORecordsExecuted, LogLevel::llStartUp, 15, LL_INFO }, + + // NODERESTART + { EventReport::NR_CopyDict, LogLevel::llNodeRestart, 8, LL_INFO }, + { EventReport::NR_CopyDistr, LogLevel::llNodeRestart, 8, LL_INFO }, + { EventReport::NR_CopyFragsStarted, LogLevel::llNodeRestart, 8, LL_INFO }, + { EventReport::NR_CopyFragDone, LogLevel::llNodeRestart, 10, LL_INFO }, + { EventReport::NR_CopyFragsCompleted, LogLevel::llNodeRestart, 8, LL_INFO }, + + { EventReport::NodeFailCompleted, LogLevel::llNodeRestart, 8, LL_ALERT}, + { EventReport::NODE_FAILREP, LogLevel::llNodeRestart, 8, LL_ALERT}, + { EventReport::ArbitState, LogLevel::llNodeRestart, 6, LL_INFO }, + { EventReport::ArbitResult, LogLevel::llNodeRestart, 2, LL_ALERT}, + { EventReport::GCP_TakeoverStarted, LogLevel::llNodeRestart, 7, LL_INFO }, + { EventReport::GCP_TakeoverCompleted, LogLevel::llNodeRestart, 7, LL_INFO }, + { EventReport::LCP_TakeoverStarted, LogLevel::llNodeRestart, 7, LL_INFO }, + { EventReport::LCP_TakeoverCompleted, LogLevel::llNodeRestart, 7, LL_INFO }, + + // STATISTIC + { EventReport::TransReportCounters, LogLevel::llStatistic, 8, LL_INFO }, + { EventReport::OperationReportCounters, LogLevel::llStatistic, 8, LL_INFO }, + { EventReport::TableCreated, LogLevel::llStatistic, 7, LL_INFO }, + { EventReport::JobStatistic, LogLevel::llStatistic, 9, LL_INFO }, + { EventReport::SendBytesStatistic, LogLevel::llStatistic, 9, LL_INFO }, + { EventReport::ReceiveBytesStatistic, LogLevel::llStatistic, 9, LL_INFO }, + { EventReport::MemoryUsage, LogLevel::llStatistic, 5, LL_INFO }, + + // ERROR + { EventReport::TransporterError, LogLevel::llError, 2, LL_ERROR }, + { EventReport::TransporterWarning, LogLevel::llError, 8, LL_WARNING }, + { EventReport::MissedHeartbeat, LogLevel::llError, 8, LL_WARNING }, + { EventReport::DeadDueToHeartbeat, LogLevel::llError, 8, LL_ALERT }, + { EventReport::WarningEvent, LogLevel::llError, 2, LL_WARNING }, + // INFO + { EventReport::SentHeartbeat, LogLevel::llInfo, 12, LL_INFO }, + { EventReport::CreateLogBytes, LogLevel::llInfo, 11, LL_INFO }, + { EventReport::InfoEvent, LogLevel::llInfo, 2, LL_INFO }, + + //Global replication + { EventReport::GrepSubscriptionInfo, LogLevel::llGrep, 7, LL_INFO}, + { EventReport::GrepSubscriptionAlert, LogLevel::llGrep, 7, LL_ALERT} +}; + +const Uint32 EventLogger::matrixSize = sizeof(EventLogger::matrix)/ + sizeof(EventRepLogLevelMatrix); + +/** + * Default log levels for management nodes. + * + * threshold - is in range [0-15] + */ +const EventLogger::EventLogMatrix EventLogger::defEventLogMatrix[] = { + { LogLevel::llStartUp, 7 }, + { LogLevel::llShutdown, 7 }, + { LogLevel::llStatistic, 7 }, + { LogLevel::llCheckpoint, 7 }, + { LogLevel::llNodeRestart, 7 }, + { LogLevel::llConnection, 7 }, + { LogLevel::llError, 15 }, + { LogLevel::llInfo, 7 }, + { LogLevel::llGrep, 7 } +}; + +const Uint32 +EventLogger::defEventLogMatrixSize = sizeof(EventLogger::defEventLogMatrix)/ + sizeof(EventLogMatrix); +/** + * Specifies allowed event categories/log levels that can be set from + * the Management API/interactive shell. + */ +const EventLogger::EventCategoryName EventLogger::eventCategoryNames[] = { + { LogLevel::llStartUp, "STARTUP" }, + { LogLevel::llStatistic, "STATISTIC" }, + { LogLevel::llCheckpoint, "CHECKPOINT" }, + { LogLevel::llNodeRestart, "NODERESTART" }, + { LogLevel::llConnection, "CONNECTION" }, + { LogLevel::llInfo, "INFO" }, + { LogLevel::llGrep, "GREP" } +}; + +const Uint32 +EventLogger::noOfEventCategoryNames = sizeof(EventLogger::eventCategoryNames)/ + sizeof(EventLogger::EventCategoryName); + +char EventLogger::m_text[MAX_TEXT_LENGTH]; + +const char* +EventLogger::getText(int type, + const Uint32* theData, NodeId nodeId) +{ + // TODO: Change the switch implementation... + char theNodeId[32]; + if (nodeId != 0){ + ::snprintf(theNodeId, 32, "Node %u: ", nodeId); + } else { + theNodeId[0] = 0; + } + + EventReport::EventType eventType = (EventReport::EventType)type; + switch (eventType){ + case EventReport::Connected: + ::snprintf(m_text, sizeof(m_text), + "%sNode %u Connected", + theNodeId, + theData[1]); + break; + case EventReport::ConnectedApiVersion: + ::snprintf(m_text, sizeof(m_text), + "%sNode %u: API version %d.%d.%d", + theNodeId, + theData[1], + getMajor(theData[2]), + getMinor(theData[2]), + getBuild(theData[2])); + break; + case EventReport::Disconnected: + ::snprintf(m_text, sizeof(m_text), + "%sNode %u Disconnected", + theNodeId, + theData[1]); + break; + case EventReport::CommunicationClosed: + //----------------------------------------------------------------------- + // REPORT communication to node closed. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sCommunication to Node %u closed", + theNodeId, + theData[1]); + break; + case EventReport::CommunicationOpened: + //----------------------------------------------------------------------- + // REPORT communication to node opened. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sCommunication to Node %u opened", + theNodeId, + theData[1]); + break; + case EventReport::NDBStartStarted: + //----------------------------------------------------------------------- + // Start of NDB has been initiated. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sStart initiated (version %d.%d.%d)", + theNodeId , + getMajor(theData[1]), + getMinor(theData[1]), + getBuild(theData[1])); + break; + case EventReport::NDBStopStarted: + ::snprintf(m_text, sizeof(m_text), + "%s%s shutdown initiated", + theNodeId, + (theData[1] == 1 ? "Cluster" : "Node")); + break; + case EventReport::NDBStopAborted: + ::snprintf(m_text, sizeof(m_text), + "%sNode shutdown aborted", + theNodeId); + break; + case EventReport::NDBStartCompleted: + //----------------------------------------------------------------------- + // Start of NDB has been completed. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sStarted (version %d.%d.%d)", + theNodeId , + getMajor(theData[1]), + getMinor(theData[1]), + getBuild(theData[1])); + + break; + case EventReport::STTORRYRecieved: + //----------------------------------------------------------------------- + // STTORRY recevied after restart finished. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sSTTORRY received after restart finished", + theNodeId); + break; + case EventReport::StartPhaseCompleted:{ + //----------------------------------------------------------------------- + // REPORT Start phase completed. + //----------------------------------------------------------------------- + const char * type = "<Unknown>"; + switch((NodeState::StartType)theData[2]){ + case NodeState::ST_INITIAL_START: + type = "(initial start)"; + break; + case NodeState::ST_SYSTEM_RESTART: + type = "(system restart)"; + break; + case NodeState::ST_NODE_RESTART: + type = "(node restart)"; + break; + case NodeState::ST_INITIAL_NODE_RESTART: + type = "(initial node restart)"; + break; + case NodeState::ST_ILLEGAL_TYPE: + type = ""; + break; + default:{ + ::snprintf(m_text, sizeof(m_text), + "%sStart phase %u completed (unknown = %d)", + theNodeId, + theData[1], + theData[2]); + return m_text; + } + } + ::snprintf(m_text, sizeof(m_text), + "%sStart phase %u completed %s", + theNodeId, + theData[1], + type); + return m_text; + break; + } + case EventReport::CM_REGCONF: + ::snprintf(m_text, sizeof(m_text), + "%sCM_REGCONF president = %u, own Node = %u, our dynamic id = %u" + , + theNodeId, + theData[2], + theData[1], + theData[3]); + break; + case EventReport::CM_REGREF: + { + const char* line = ""; + switch (theData[3]) { + case 0: + line = "Busy"; + break; + case 1: + line = "Election with wait = false"; + break; + case 2: + line = "Election with wait = false"; + break; + case 3: + line = "Not president"; + break; + case 4: + line = "Election without selecting new candidate"; + break; + default: + line = "No such cause"; + break; + }//switch + + ::snprintf(m_text, sizeof(m_text), + "%sCM_REGREF from Node %u to our Node %u. Cause = %s", + theNodeId, + theData[2], + theData[1], + line); + } + break; + case EventReport::FIND_NEIGHBOURS: + //----------------------------------------------------------------------- + // REPORT Node Restart copied a fragment. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sWe are Node %u with dynamic ID %u, our left neighbour " + "is Node %u, our right is Node %u", + theNodeId, + theData[1], + theData[4], + theData[2], + theData[3]); + break; + case EventReport::NodeFailCompleted: + //----------------------------------------------------------------------- + // REPORT Node failure phase completed. + //----------------------------------------------------------------------- + if (theData[1] == 0) + { + if (theData[3] != 0) { + ::snprintf(m_text, sizeof(m_text), + "%sNode %u completed failure of Node %u", + theNodeId, + theData[3], + theData[2]); + } else { + ::snprintf(m_text, sizeof(m_text), + "%sAll nodes completed failure of Node %u", + theNodeId, + theData[2]); + }//if + } else { + const char* line = ""; + if (theData[1] == DBTC){ + line = "DBTC"; + }else if (theData[1] == DBDICT){ + line = "DBDICT"; + }else if (theData[1] == DBDIH){ + line = "DBDIH"; + }else if (theData[1] == DBLQH){ + line = "DBLQH"; + } + + ::snprintf(m_text, sizeof(m_text), + "%sNode failure of %u %s completed", + theNodeId, + theData[2], + line); + } + break; + case EventReport::NODE_FAILREP: + ::snprintf(m_text, + sizeof(m_text), + "%sNode %u has failed. The Node state at failure " + "was %u", + theNodeId, + theData[1], + theData[2]); + + break; + case EventReport::ArbitState: + //----------------------------------------------------------------------- + // REPORT arbitrator found or lost. + //----------------------------------------------------------------------- + { const ArbitSignalData* sd = (ArbitSignalData*)theData; + char ticketText[ArbitTicket::TextLength + 1]; + char errText[ArbitCode::ErrTextLength + 1]; + const unsigned code = sd->code & 0xFFFF; + const unsigned state = sd->code >> 16; + switch (code) { + case ArbitCode::ThreadStart: + ::snprintf(m_text, sizeof(m_text), + "%sPresident restarts arbitration thread [state=%u]", + theNodeId, state); + break; + case ArbitCode::PrepPart2: + sd->ticket.getText(ticketText, sizeof(ticketText)); + ::snprintf(m_text, sizeof(m_text), + "%sPrepare arbitrator node %u [ticket=%s]", + theNodeId, sd->node, ticketText); + break; + case ArbitCode::PrepAtrun: + sd->ticket.getText(ticketText, sizeof(ticketText)); + ::snprintf(m_text, sizeof(m_text), + "%sReceive arbitrator node %u [ticket=%s]", + theNodeId, sd->node, ticketText); + break; + case ArbitCode::ApiStart: + sd->ticket.getText(ticketText, sizeof(ticketText)); + ::snprintf(m_text, sizeof(m_text), + "%sStarted arbitrator node %u [ticket=%s]", + theNodeId, sd->node, ticketText); + break; + case ArbitCode::ApiFail: + ::snprintf(m_text, sizeof(m_text), + "%sLost arbitrator node %u - process failure [state=%u]", + theNodeId, sd->node, state); + break; + case ArbitCode::ApiExit: + ::snprintf(m_text, sizeof(m_text), + "%sLost arbitrator node %u - process exit [state=%u]", + theNodeId, sd->node, state); + break; + default: + ArbitCode::getErrText(code, errText, sizeof(errText)); + ::snprintf(m_text, sizeof(m_text), + "%sLost arbitrator node %u - %s [state=%u]", + theNodeId, sd->node, errText, state); + break; + } + } + break; + case EventReport::ArbitResult: + //----------------------------------------------------------------------- + // REPORT arbitration result (the failures may not reach us). + //----------------------------------------------------------------------- + { const ArbitSignalData* sd = (ArbitSignalData*)theData; + char errText[ArbitCode::ErrTextLength + 1]; + const unsigned code = sd->code & 0xFFFF; + const unsigned state = sd->code >> 16; + switch (code) { + case ArbitCode::LoseNodes: + ::snprintf(m_text, sizeof(m_text), + "%sArbitration check lost - less than 1/2 nodes left", + theNodeId); + break; + case ArbitCode::WinGroups: + ::snprintf(m_text, sizeof(m_text), + "%sArbitration check won - node group majority", + theNodeId); + break; + case ArbitCode::LoseGroups: + ::snprintf(m_text, sizeof(m_text), + "%sArbitration check lost - missing node group", + theNodeId); + break; + case ArbitCode::Partitioning: + ::snprintf(m_text, sizeof(m_text), + "%sNetwork partitioning - arbitration required", + theNodeId); + break; + case ArbitCode::WinChoose: + ::snprintf(m_text, sizeof(m_text), + "%sArbitration won - positive reply from node %u", + theNodeId, sd->node); + break; + case ArbitCode::LoseChoose: + ::snprintf(m_text, sizeof(m_text), + "%sArbitration lost - negative reply from node %u", + theNodeId, sd->node); + break; + case ArbitCode::LoseNorun: + ::snprintf(m_text, sizeof(m_text), + "%sNetwork partitioning - no arbitrator available", + theNodeId); + break; + case ArbitCode::LoseNocfg: + ::snprintf(m_text, sizeof(m_text), + "%sNetwork partitioning - no arbitrator configured", + theNodeId); + break; + default: + ArbitCode::getErrText(code, errText, sizeof(errText)); + ::snprintf(m_text, sizeof(m_text), + "%sArbitration failure - %s [state=%u]", + theNodeId, errText, state); + break; + } + } + break; + case EventReport::GlobalCheckpointStarted: + //----------------------------------------------------------------------- + // This event reports that a global checkpoint has been started and this + // node is the master of this global checkpoint. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sGlobal checkpoint %u started", + theNodeId, + theData[1]); + break; + case EventReport::GlobalCheckpointCompleted: + //----------------------------------------------------------------------- + // This event reports that a global checkpoint has been completed on this + // node and the node is the master of this global checkpoint. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sGlobal checkpoint %u completed", + theNodeId, + theData[1]); + break; + case EventReport::LocalCheckpointStarted: + //----------------------------------------------------------------------- + // This event reports that a local checkpoint has been started and this + // node is the master of this local checkpoint. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sLocal checkpoint %u started. " + "Keep GCI = %u oldest restorable GCI = %u", + theNodeId, + theData[1], + theData[2], + theData[3]); + break; + case EventReport::LocalCheckpointCompleted: + //----------------------------------------------------------------------- + // This event reports that a local checkpoint has been completed on this + // node and the node is the master of this local checkpoint. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sLocal checkpoint %u completed", + theNodeId, + theData[1]); + break; + case EventReport::TableCreated: + //----------------------------------------------------------------------- + // This event reports that a table has been created. + //----------------------------------------------------------------------- + ::snprintf(m_text, sizeof(m_text), + "%sTable with ID = %u created", + theNodeId, + theData[1]); + break; + case EventReport::LCPStoppedInCalcKeepGci: + if (theData[1] == 0) + ::snprintf(m_text, sizeof(m_text), + "%sLocal Checkpoint stopped in CALCULATED_KEEP_GCI", + theNodeId); + break; + case EventReport::NR_CopyDict: + //----------------------------------------------------------------------- + // REPORT Node Restart completed copy of dictionary information. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sNode restart completed copy of dictionary information", + theNodeId); + break; + case EventReport::NR_CopyDistr: + //----------------------------------------------------------------------- + // REPORT Node Restart completed copy of distribution information. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sNode restart completed copy of distribution information", + theNodeId); + break; + case EventReport::NR_CopyFragsStarted: + //----------------------------------------------------------------------- + // REPORT Node Restart is starting to copy the fragments. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sNode restart starting to copy the fragments " + "to Node %u", + theNodeId, + theData[1]); + break; + case EventReport::NR_CopyFragDone: + //----------------------------------------------------------------------- + // REPORT Node Restart copied a fragment. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sTable ID = %u, fragment ID = %u have been copied " + "to Node %u", + theNodeId, + theData[2], + theData[3], + theData[1]); + break; + case EventReport::NR_CopyFragsCompleted: + ::snprintf(m_text, + sizeof(m_text), + "%sNode restart completed copying the fragments " + "to Node %u", + theNodeId, + theData[1]); + break; + case EventReport::LCPFragmentCompleted: + ::snprintf(m_text, + sizeof(m_text), + "%sTable ID = %u, fragment ID = %u has completed LCP " + "on Node %u", + theNodeId, + theData[2], + theData[3], + theData[1]); + break; + case EventReport::TransReportCounters: + // ------------------------------------------------------------------- + // Report information about transaction activity once per 10 seconds. + // ------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sTrans. Count = %u, Commit Count = %u, " + "Read Count = %u, Simple Read Count = %u,\n" + "Write Count = %u, AttrInfo Count = %u, " + "Concurrent Operations = %u, Abort Count = %u", + theNodeId, + theData[1], + theData[2], + theData[3], + theData[4], + theData[5], + theData[6], + theData[7], + theData[8]); + break; + case EventReport::OperationReportCounters: + ::snprintf(m_text, sizeof(m_text), + "%sOperations=%u", + theNodeId, + theData[1]); + break; + case EventReport::UndoLogBlocked: + //----------------------------------------------------------------------- + // REPORT Undo Logging blocked due to buffer near to overflow. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sACC Blocked %u and TUP Blocked %u times last second", + theNodeId, + theData[1], + theData[2]); + break; + case EventReport::TransporterError: + case EventReport::TransporterWarning: + ::snprintf(m_text, + sizeof(m_text), + "%sTransporter to node %d reported error 0x%x", + theNodeId, + theData[1], + theData[2]); + break; + case EventReport::MissedHeartbeat: + //----------------------------------------------------------------------- + // REPORT Undo Logging blocked due to buffer near to overflow. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sNode %d missed heartbeat %d", + theNodeId, + theData[1], + theData[2]); + break; + case EventReport::DeadDueToHeartbeat: + //----------------------------------------------------------------------- + // REPORT Undo Logging blocked due to buffer near to overflow. + //----------------------------------------------------------------------- + ::snprintf(m_text, + sizeof(m_text), + "%sNode %d declared dead due to missed heartbeat", + theNodeId, + theData[1]); + break; + case EventReport::JobStatistic: + ::snprintf(m_text, + sizeof(m_text), + "%sMean loop Counter in doJob last 8192 times = %u", + theNodeId, + theData[1]); + break; + case EventReport::SendBytesStatistic: + ::snprintf(m_text, + sizeof(m_text), + "%sMean send size to Node = %d last 4096 sends = %u bytes", + theNodeId, + theData[1], + theData[2]); + break; + case EventReport::ReceiveBytesStatistic: + ::snprintf(m_text, + sizeof(m_text), + "%sMean receive size to Node = %d last 4096 sends = %u bytes", + theNodeId, + theData[1], + theData[2]); + break; + case EventReport::SentHeartbeat: + ::snprintf(m_text, + sizeof(m_text), + "%sNode Sent Heartbeat to node = %d", + theNodeId, + theData[1]); + break; + case EventReport::CreateLogBytes: + ::snprintf(m_text, + sizeof(m_text), + "%sLog part %u, log file %u, MB %u", + theNodeId, + theData[1], + theData[2], + theData[3]); + break; + case EventReport::StartLog: + ::snprintf(m_text, + sizeof(m_text), + "%sLog part %u, start MB %u, stop MB %u, last GCI, log exec %u", + theNodeId, + theData[1], + theData[2], + theData[3], + theData[4]); + break; + case EventReport::StartREDOLog: + ::snprintf(m_text, + sizeof(m_text), + "%sNode: %d StartLog: [GCI Keep: %d LastCompleted: %d NewestRestorable: %d]", + theNodeId, + theData[1], + theData[2], + theData[3], + theData[4]); + break; + case EventReport::UNDORecordsExecuted:{ + const char* line = ""; + if (theData[1] == DBTUP){ + line = "DBTUP"; + }else if (theData[1] == DBACC){ + line = "DBACC"; + } + + ::snprintf(m_text, + sizeof(m_text), + "%s UNDO %s %d [%d %d %d %d %d %d %d %d %d]", + theNodeId, + line, + theData[2], + theData[3], + theData[4], + theData[5], + theData[6], + theData[7], + theData[8], + theData[9], + theData[10], + theData[11]); + } + break; + case EventReport::InfoEvent: + ::snprintf(m_text, + sizeof(m_text), + "%s%s", + theNodeId, + (char *)&theData[1]); + break; + case EventReport::WarningEvent: + ::snprintf(m_text, + sizeof(m_text), + "%s%s", + theNodeId, + (char *)&theData[1]); + break; + case EventReport::GCP_TakeoverStarted: + ::snprintf(m_text, + sizeof(m_text), + "%sGCP Take over started", theNodeId); + break; + case EventReport::GCP_TakeoverCompleted: + ::snprintf(m_text, + sizeof(m_text), + "%sGCP Take over completed", theNodeId); + break; + case EventReport::LCP_TakeoverStarted: + ::snprintf(m_text, + sizeof(m_text), + "%sLCP Take over started", theNodeId); + break; + case EventReport::LCP_TakeoverCompleted: + ::snprintf(m_text, + sizeof(m_text), + "%sLCP Take over completed (state = %d)", + theNodeId, theData[1]); + break; + case EventReport::MemoryUsage:{ + const int gth = theData[1]; + const int size = theData[2]; + const int used = theData[3]; + const int total = theData[4]; + const int block = theData[5]; + const int percent = (used*100)/total; + + ::snprintf(m_text, sizeof(m_text), + "%s%s usage %s %d%s(%d %dK pages of total %d)", + theNodeId, + (block==DBACC ? "Index" : (block == DBTUP ?"Data":"<unknown>")), + (gth == 0 ? "is" : (gth > 0 ? "increased to" : "decreased to")), + percent, "%", + used, size/1024, total + ); + break; + } + + + case EventReport::GrepSubscriptionInfo : + { + GrepEvent::Subscription event = (GrepEvent::Subscription)theData[1]; + switch(event) { + case GrepEvent::GrepSS_CreateSubIdConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Created subscription id" + " (subId=%d,SubKey=%d)" + " Return code: %d.", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepPS_CreateSubIdConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Created subscription id" + " (subId=%d,SubKey=%d)" + " Return code: %d.", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepSS_SubCreateConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + const int nodegrp = theData[5]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Created subscription using" + " (subId=%d,SubKey=%d)" + " in primary system. Primary system has %d nodegroup(s)." + " Return code: %d", + subId, + subKey, + nodegrp, + err); + break; + } + case GrepEvent::GrepPS_SubCreateConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: All participants have created " + "subscriptions" + " using (subId=%d,SubKey=%d)." + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepSS_SubStartMetaConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Logging started on meta data changes." + " using (subId=%d,SubKey=%d)" + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepPS_SubStartMetaConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: All participants have started " + "logging meta data" + " changes on the subscription subId=%d,SubKey=%d) " + "(N.I yet)." + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepSS_SubStartDataConf: { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Logging started on table data changes " + " using (subId=%d,SubKey=%d)" + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepPS_SubStartDataConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: All participants have started logging " + "table data changes on the subscription " + "subId=%d,SubKey=%d)." + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepPS_SubSyncMetaConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: All participants have started " + " synchronization on meta data (META SCAN) using " + "(subId=%d,SubKey=%d)." + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepSS_SubSyncMetaConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Synchronization started (META SCAN) on " + " meta data using (subId=%d,SubKey=%d)" + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepPS_SubSyncDataConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: All participants have started " + "synchronization " + " on table data (DATA SCAN) using (subId=%d,SubKey=%d)." + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepSS_SubSyncDataConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + const int gci = theData[5]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Synchronization started (DATA SCAN) on " + "table data using (subId=%d,SubKey=%d). GCI = %d" + " Return code: %d", + subId, + subKey, + gci, + err); + break; + } + case GrepEvent::GrepPS_SubRemoveConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: All participants have removed " + "subscription (subId=%d,SubKey=%d). I have cleaned " + "up resources I've used." + " Return code: %d", + subId, + subKey, + err); + break; + } + case GrepEvent::GrepSS_SubRemoveConf: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Removed subscription " + "(subId=%d,SubKey=%d)" + " Return code: %d", + subId, + subKey, + err); + break; + } + default: + ::snprintf(m_text, + sizeof(m_text), + "%sUnknown GrepSubscriptonInfo event: %d", + theNodeId, + theData[1]); + } + break; + } + + case EventReport::GrepSubscriptionAlert : + { + GrepEvent::Subscription event = (GrepEvent::Subscription)theData[1]; + switch(event) + { + case GrepEvent::GrepSS_CreateSubIdRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord:Error code: %d Error message: %s" + " (subId=%d,SubKey=%d)", + err, + GrepError::getErrorDesc((GrepError::Code)err), + subId, + subKey); + break; + } + case GrepEvent::GrepSS_SubCreateRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: FAILED to Created subscription using" + " (subId=%d,SubKey=%d)in primary system." + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepSS_SubStartMetaRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Logging failed to start on meta " + "data changes." + " using (subId=%d,SubKey=%d)" + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepSS_SubStartDataRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Logging FAILED to start on table data " + " changes using (subId=%d,SubKey=%d)" + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepSS_SubSyncMetaRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Synchronization FAILED (META SCAN) on " + " meta data using (subId=%d,SubKey=%d)" + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepSS_SubSyncDataRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + const int gci = theData[5]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Synchronization FAILED (DATA SCAN) on " + "table data using (subId=%d,SubKey=%d). GCI = %d" + " Error code: %d Error Message: %s", + subId, + subKey, + gci, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepSS_SubRemoveRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::SSCoord: Failed to remove subscription " + "(subId=%d,SubKey=%d). " + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err) + ); + break; + } + + case GrepEvent::GrepPS_CreateSubIdRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Error code: %d Error Message: %s" + " (subId=%d,SubKey=%d)", + err, + GrepError::getErrorDesc((GrepError::Code)err), + subId, + subKey); + break; + } + case GrepEvent::GrepPS_SubCreateRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: FAILED to Created subscription using" + " (subId=%d,SubKey=%d)in primary system." + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepPS_SubStartMetaRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Logging failed to start on meta " + "data changes." + " using (subId=%d,SubKey=%d)" + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepPS_SubStartDataRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Logging FAILED to start on table data " + " changes using (subId=%d,SubKey=%d)" + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepPS_SubSyncMetaRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Synchronization FAILED (META SCAN) on " + " meta data using (subId=%d,SubKey=%d)" + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepPS_SubSyncDataRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + const int gci = theData[5]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Synchronization FAILED (DATA SCAN) on " + "table data using (subId=%d,SubKey=%d). GCI = %d. " + " Error code: %d Error Message: %s", + subId, + subKey, + gci, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::GrepPS_SubRemoveRef: + { + const int subId = theData[2]; + const int subKey = theData[3]; + const int err = theData[4]; + ::snprintf(m_text, sizeof(m_text), + "Grep::PSCoord: Failed to remove subscription " + "(subId=%d,SubKey=%d)." + " Error code: %d Error Message: %s", + subId, + subKey, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + case GrepEvent::Rep_Disconnect: + { + const int err = theData[4]; + const int nodeId = theData[5]; + ::snprintf(m_text, sizeof(m_text), + "Rep: Node %d." + " Error code: %d Error Message: %s", + nodeId, + err, + GrepError::getErrorDesc((GrepError::Code)err)); + break; + } + + + default: + ::snprintf(m_text, + sizeof(m_text), + "%sUnknown GrepSubscriptionAlert event: %d", + theNodeId, + theData[1]); + break; + } + break; + } + + default: + ::snprintf(m_text, + sizeof(m_text), + "%sUnknown event: %d", + theNodeId, + theData[0]); + + } + return m_text; +} + +bool +EventLogger::matchEventCategory(const char * str, + LogLevel::EventCategory * cat, + bool exactMatch){ + if(cat == 0 || str == 0) + return false; + + char * tmp = strdup(str); + for(size_t i = 0; i<strlen(tmp); i++) + tmp[i] = toupper(tmp[i]); + + for(Uint32 i = 0; i<noOfEventCategoryNames; i++){ + if(strcmp(tmp, eventCategoryNames[i].name) == 0){ + * cat = eventCategoryNames[i].category; + free(tmp); + return true; + } + } + free(tmp); + return false; +} + +const char * +EventLogger::getEventCategoryName(LogLevel::EventCategory cat){ + + for(unsigned i = 0; i<noOfEventCategoryNames; i++){ + if(cat == eventCategoryNames[i].category){ + return eventCategoryNames[i].name; + } + } + return 0; +} + + +EventLogger::EventLogger() : Logger(), m_logLevel(), m_filterLevel(15) +{ + setCategory("EventLogger"); + m_logLevel.setLogLevel(LogLevel::llStartUp, m_filterLevel); + m_logLevel.setLogLevel(LogLevel::llShutdown, m_filterLevel); + // m_logLevel.setLogLevel(LogLevel::llStatistic, m_filterLevel); + // m_logLevel.setLogLevel(LogLevel::llCheckpoint, m_filterLevel); + m_logLevel.setLogLevel(LogLevel::llNodeRestart, m_filterLevel); + m_logLevel.setLogLevel(LogLevel::llConnection, m_filterLevel); + m_logLevel.setLogLevel(LogLevel::llError, m_filterLevel); + m_logLevel.setLogLevel(LogLevel::llInfo, m_filterLevel); + enable(Logger::LL_INFO, Logger::LL_ALERT); // Log INFO to ALERT + +} + +EventLogger::~EventLogger() +{ + +} + +bool +EventLogger::open() +{ + char clusterLog[128]; + NdbConfig_ClusterLogFileName(clusterLog, 128); + return open(clusterLog); +} + +bool +EventLogger::open(const char* logFileName, int maxNoFiles, long maxFileSize, + unsigned int maxLogEntries) +{ + return addHandler(new FileLogHandler(logFileName, maxNoFiles, maxFileSize, + maxLogEntries)); +} + +void +EventLogger::close() +{ + removeAllHandlers(); +} + +void +EventLogger::log(NodeId nodeId, int eventType, const Uint32* theData) +{ + log(eventType, theData, nodeId); +} + +void +EventLogger::log(int eventType, const Uint32* theData, NodeId nodeId) +{ + Uint32 threshold = 0; + Logger::LoggerLevel severity = LL_WARNING; + + for(unsigned i = 0; i<EventLogger::matrixSize; i++){ + if(EventLogger::matrix[i].eventType == eventType){ + const LogLevel::EventCategory cat = EventLogger::matrix[i].eventCategory; + threshold = m_logLevel.getLogLevel(cat); + severity = EventLogger::matrix[i].severity; + break; + } + } + + if (threshold <= m_filterLevel){ + switch (severity){ + case LL_ALERT: + alert(EventLogger::getText(eventType, theData, nodeId)); + break; + + case LL_CRITICAL: + critical(EventLogger::getText(eventType, theData, nodeId)); + break; + + case LL_WARNING: + warning(EventLogger::getText(eventType, theData, nodeId)); + break; + + case LL_ERROR: + error(EventLogger::getText(eventType, theData, nodeId)); + break; + + case LL_INFO: + info(EventLogger::getText(eventType, theData, nodeId)); + break; + + case LL_DEBUG: + debug(EventLogger::getText(eventType, theData, nodeId)); + break; + + default: + info(EventLogger::getText(eventType, theData, nodeId)); + break; + } + } // if (.. +} + +LogLevel& +EventLogger::getLoglevel() +{ + return m_logLevel; +} + +int +EventLogger::getFilterLevel() const +{ + return m_filterLevel; +} + +void +EventLogger::setFilterLevel(int filterLevel) +{ + m_filterLevel = filterLevel; +} + +// +// PRIVATE +// diff --git a/ndb/src/common/debugger/GrepError.cpp b/ndb/src/common/debugger/GrepError.cpp new file mode 100644 index 00000000000..ec0c26a5855 --- /dev/null +++ b/ndb/src/common/debugger/GrepError.cpp @@ -0,0 +1,133 @@ +/* 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 <GrepError.hpp> + +/** + * Error descriptions. + */ + +const GrepError::ErrorDescription GrepError::errorDescriptions[] = { + { GrepError::NO_ERROR, + "No error" }, + { GrepError::SUBSCRIPTION_ID_NOMEM, + "Not enough resources to allocate the subscription" }, + { GrepError::SUBSCRIPTION_ID_NOT_FOUND, + "The requested subscription (id, key) does not exist"}, + { GrepError::SUBSCRIPTION_ID_NOT_UNIQUE, + "A subscription with (id, key) does already exist"}, + { GrepError::SUBSCRIPTION_ID_SUMA_FAILED_CREATE, + "Suma failed to create a new subscription id"}, + { GrepError::NULL_VALUE, + "NULL"}, + { GrepError::SEQUENCE_ERROR, + "Error when creating or using sequence."}, + { GrepError::NOSPACE_IN_POOL, + "No space left in pool when trying to seize data"}, + { GrepError::SUBSCRIPTION_ID_ALREADY_EXIST, + "A subscription for this replication channel does already exist"}, + { GrepError::SUBSCRIPTION_NOT_STARTED, + "No subscription is started"}, + { GrepError::SUBSCRIBER_NOT_FOUND, + "The subscriber does not exist in SUMA."}, + { GrepError::WRONG_NO_OF_SECTIONS, + "Something is wrong with the supplied arguments"}, + { GrepError::ILLEGAL_ACTION_WHEN_STOPPING, + "Action can not be performed while channel is in stopping state"}, + { GrepError::SELECTED_TABLE_NOT_FOUND, + "The selected table was not found. "}, + { GrepError::REP_APPLY_LOGRECORD_FAILED, + "Failed applying a log record (permanent error)"}, + { GrepError::REP_APPLY_METARECORD_FAILED, + "Failed applying a meta record (permanent error)"}, + { GrepError::REP_DELETE_NEGATIVE_EPOCH, + "Trying to delete a GCI Buffer using a negative epoch."}, + { GrepError::REP_DELETE_NONEXISTING_EPOCH, + "Trying to delete a non-existing GCI Buffer."}, + { GrepError::REP_NO_CONNECTED_NODES, + "There are no connected nodes in the node group."}, + { GrepError::REP_DISCONNECT, + "Global Replication Server disconnected."}, + { GrepError::COULD_NOT_ALLOCATE_MEM_FOR_SIGNAL, + "Could not allocate memory for signal."}, + { GrepError::REP_NOT_PROPER_TABLE, + "Specified table is not a valid table. " + "Either the format is not <db>/<schema>/<tablename> or " + "the table name is too long "}, + { GrepError::REP_TABLE_ALREADY_SELECTED, + "The specified table is already selected for replication" }, + { GrepError::REP_TABLE_NOT_FOUND, + "The specified table was not found" }, + { GrepError::START_OF_COMPONENT_IN_WRONG_STATE, + "Component or protocol can not be started in the current state."}, + { GrepError::START_ALREADY_IN_PROGRESS, + "Start of replication protocol is already in progress."}, + { GrepError::ILLEGAL_STOP_EPOCH_ID, + "It is not possible to stop on the requested epoch id."}, + { GrepError::ILLEGAL_USE_OF_COMMAND, + "The command cannot be executed in this state."}, + { GrepError::CHANNEL_NOT_STOPPABLE, + "It is not possible to stop the in this state."}, + + /** + * Applier stuff + */ + { GrepError::REP_APPLY_NONCOMPLETE_GCIBUFFER, + "Applier: Ordered to apply an incomplete GCI Buffer."}, + { GrepError::REP_APPLY_NULL_GCIBUFFER, + "Applier: Tried to apply a NULL GCI Buffer."}, + { GrepError::REP_APPLIER_START_TRANSACTION, + "Applier: Could not start a transaction."}, + { GrepError::REP_APPLIER_NO_TABLE, + "Applier: Table does not exist"}, + { GrepError::REP_APPLIER_NO_OPERATION, + "Applier: Cannot get NdbOperation record."}, + { GrepError::REP_APPLIER_EXECUTE_TRANSACTION, + "Applier: Execute transaction failed."}, + { GrepError::REP_APPLIER_CREATE_TABLE, + "Applier: Create table failed."}, + { GrepError::REP_APPLIER_PREPARE_TABLE, + "Applier: Prepare table for create failed."}, + + { GrepError::NOT_YET_IMPLEMENTED, + "Command or event not yet implemented."} +}; + + + + + +const Uint32 +GrepError::noOfErrorDescs = sizeof(GrepError::errorDescriptions) / + sizeof(GrepError::ErrorDescription); + + +/** + * gets the corresponding error message to an err code + */ +const char * +GrepError::getErrorDesc(GrepError::Code err) { + + for(Uint32 i = 0; i<noOfErrorDescs; i++){ + if(err == errorDescriptions[i].errCode){ + return errorDescriptions[i].name; + } + } + return 0; +} + + + diff --git a/ndb/src/common/debugger/LogLevel.cpp b/ndb/src/common/debugger/LogLevel.cpp new file mode 100644 index 00000000000..5348924bbbb --- /dev/null +++ b/ndb/src/common/debugger/LogLevel.cpp @@ -0,0 +1,29 @@ +/* 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 <LogLevel.hpp> + +const LogLevel::LogLevelCategoryName LogLevel::LOGLEVEL_CATEGORY_NAME[] = { + {"LogLevelStartup"}, + {"LogLevelShutdown"}, + {"LogLevelStatistic"}, + {"LogLevelCheckpoint"}, + {"LogLevelNodeRestart"}, + {"LogLevelConnection"}, + {"LogLevelError"}, + {"LogLevelInfo"}, + {"LogLevelGrep"} +}; diff --git a/ndb/src/common/debugger/Makefile b/ndb/src/common/debugger/Makefile new file mode 100644 index 00000000000..ac3a4475a54 --- /dev/null +++ b/ndb/src/common/debugger/Makefile @@ -0,0 +1,11 @@ +include .defs.mk + +TYPE := kernel +DIRS := signaldata + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := trace + +SOURCES = SignalLoggerManager.cpp DebuggerNames.cpp BlockNames.cpp LogLevel.cpp EventLogger.cpp GrepError.cpp + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/debugger/SignalLoggerManager.cpp b/ndb/src/common/debugger/SignalLoggerManager.cpp new file mode 100644 index 00000000000..e51edbba169 --- /dev/null +++ b/ndb/src/common/debugger/SignalLoggerManager.cpp @@ -0,0 +1,513 @@ +/* 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 "SignalLoggerManager.hpp" +#include <LongSignal.hpp> + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <time.h> +#include <NdbString.h> + +#include <DebuggerNames.hpp> + +SignalLoggerManager::SignalLoggerManager() +{ + for (int i = 0; i < NO_OF_BLOCKS; i++){ + logModes[i] = 0; + } + outputStream = 0; +} + +SignalLoggerManager::~SignalLoggerManager() +{ + if(outputStream != 0){ + fflush(outputStream); + fclose(outputStream); + outputStream = 0; + } +} + +FILE * +SignalLoggerManager::setOutputStream(FILE * output) +{ + if(outputStream != 0){ + fflush(outputStream); + } + + FILE * out = outputStream; + outputStream = output; + return out; +} + +FILE * +SignalLoggerManager::getOutputStream() const +{ + return outputStream; +} + +void +SignalLoggerManager::flushSignalLog() +{ + if(outputStream != 0) + fflush(outputStream); +} + +void +SignalLoggerManager::setTrace(unsigned long trace) +{ + traceId = trace; +} + +unsigned long +SignalLoggerManager::getTrace() const +{ + return traceId; +} + +int +getParameter(char *blocks[NO_OF_BLOCKS], const char * par, const char * line) +{ + const char * loc = strstr(line, par); + if(loc == NULL) + return 0; + + loc += strlen(par); + + int found = 0; + + char * copy = strdup(loc); + char * tmp = copy; + bool done = false; + while(!done){ + int len = strcspn(tmp, ", ;:\0"); + if(len == 0) + done = true; + else { + if(* (tmp + len) != ',') + done = true; + * (tmp + len) = 0; + blocks[found] = strdup(tmp); + found ++; + tmp += (len + 1); + } + } + free(copy); + return found; +} + + +#define SLM_OFF 0 +#define SLM_ON 1 +#define SLM_TOGGLE 2 + +int +SignalLoggerManager::log(LogMode logMode, const char * params) +{ + char * blocks[NO_OF_BLOCKS]; + const int count = getParameter(blocks, "BLOCK=", params); + + int cnt = 0; + if((count == 1 && blocks[0] == "ALL") || + count == 0){ + + for (int number = 0; number < NO_OF_BLOCKS; ++number){ + cnt += log(SLM_ON, number, logMode); + } + } else { + for (int i = 0; i < count; ++i){ + BlockNumber number = getBlockNo(blocks[i]); + cnt += log(SLM_ON, number-MIN_BLOCK_NO, logMode); + } + } + for(int i = 0; i<count; i++){ + free(blocks[i]); + } + + return cnt; +} + +int +SignalLoggerManager::log(int cmd, BlockNumber bno, LogMode logMode) +{ + // Normalise blocknumber for use in logModes array + const BlockNumber bno2 = bno-MIN_BLOCK_NO; + assert(bno2<NO_OF_BLOCKS); + switch(cmd){ + case SLM_ON: + logModes[bno2] |= logMode; + return 1; + break; + case SLM_OFF: + logModes[bno2] &= (~logMode); + return 1; + break; + case SLM_TOGGLE: + logModes[bno2] ^= logMode; + return 1; + break; + } + return 0; +} + +int +SignalLoggerManager::logOn(bool allBlocks, BlockNumber bno, LogMode logMode) +{ + if(!allBlocks){ + return log(SLM_ON, bno, logMode); + } + int cnt = 0; + for(unsigned int i = MIN_BLOCK_NO; i <= MAX_BLOCK_NO; i++) + cnt += log(SLM_ON, i, logMode); + return cnt; +} + +int +SignalLoggerManager::logOff(bool allBlocks, BlockNumber bno, LogMode logMode) +{ + if(!allBlocks){ + return log(SLM_OFF, bno, logMode); + } + int cnt = 0; + for(unsigned int i = MIN_BLOCK_NO; i <= MAX_BLOCK_NO; i++) + cnt += log(SLM_OFF, i, logMode); + return cnt; + +} + +int +SignalLoggerManager::logToggle(bool allBlocks, BlockNumber bno, LogMode logMode) +{ + if(!allBlocks){ + return log(SLM_TOGGLE, bno, logMode); + } + int cnt = 0; + for(unsigned int i = MIN_BLOCK_NO; i <= MAX_BLOCK_NO; i++) + cnt += log(SLM_TOGGLE, i, logMode); + return cnt; +} + +void +SignalLoggerManager::executeDirect(const SignalHeader& sh, + Uint8 prio, // in-out flag + const Uint32 * theData, Uint32 node) +{ + Uint32 trace = sh.theTrace; + Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + + if(outputStream != 0 && + (traceId == 0 || traceId == trace) && + (logMatch(senderBlockNo, LogOut) || logMatch(receiverBlockNo, LogIn))){ + const char* inOutStr = prio == 0 ? "In" : "Out"; +#ifdef VM_TRACE_TIME + fprintf(outputStream, "---- Direct --- Signal --- %s - %d ----\n", inOutStr, time(0)); +#else + fprintf(outputStream, "---- Direct --- Signal --- %s ----------------\n", inOutStr); +#endif + // XXX pass in/out to print* function somehow + printSignalHeader(outputStream, sh, 0, node, true); + printSignalData(outputStream, sh, theData); + } +} + +/** + * For input signals + */ +void +SignalLoggerManager::executeSignal(const SignalHeader& sh, Uint8 prio, + const Uint32 * theData, Uint32 node, + const SegmentedSectionPtr ptr[3], Uint32 secs) +{ + Uint32 trace = sh.theTrace; + //Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + + if(outputStream != 0 && + (traceId == 0 || traceId == trace) && + logMatch(receiverBlockNo, LogIn)){ +#ifdef VM_TRACE_TIME + fprintf(outputStream, "---- Received - Signal - %d ----\n", time(0)); +#else + fprintf(outputStream, "---- Received - Signal ----------------\n"); +#endif + + printSignalHeader(outputStream, sh, prio, node, true); + printSignalData(outputStream, sh, theData); + for (unsigned i = 0; i < secs; i++) + printSegmentedSection(outputStream, sh, ptr, i); + } +} + +void +SignalLoggerManager::executeSignal(const SignalHeader& sh, Uint8 prio, + const Uint32 * theData, Uint32 node, + const LinearSectionPtr ptr[3], Uint32 secs) +{ + Uint32 trace = sh.theTrace; + //Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + + if(outputStream != 0 && + (traceId == 0 || traceId == trace) && + logMatch(receiverBlockNo, LogIn)){ +#ifdef VM_TRACE_TIME + fprintf(outputStream, "---- Received - Signal - %d ----\n", time(0)); +#else + fprintf(outputStream, "---- Received - Signal ----------------\n"); +#endif + + printSignalHeader(outputStream, sh, prio, node, true); + printSignalData(outputStream, sh, theData); + for (unsigned i = 0; i < secs; i++) + printLinearSection(outputStream, sh, ptr, i); + } +} + +/** + * For output signals + */ +void +SignalLoggerManager::sendSignal(const SignalHeader& sh, + Uint8 prio, + const Uint32 * theData, Uint32 node, + const LinearSectionPtr ptr[3], Uint32 secs) +{ + Uint32 trace = sh.theTrace; + Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + //Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + + if(outputStream != 0 && + (traceId == 0 || traceId == trace) && + logMatch(senderBlockNo, LogOut)){ +#ifdef VM_TRACE_TIME + fprintf(outputStream, "---- Send ----- Signal - %d ----\n", time(0)); +#else + fprintf(outputStream, "---- Send ----- Signal ----------------\n"); +#endif + + printSignalHeader(outputStream, sh, prio, node, false); + printSignalData(outputStream, sh, theData); + for (unsigned i = 0; i < secs; i++) + printLinearSection(outputStream, sh, ptr, i); + } +} + +/** + * For output signals + */ +void +SignalLoggerManager::sendSignal(const SignalHeader& sh, Uint8 prio, + const Uint32 * theData, Uint32 node, + const SegmentedSectionPtr ptr[3], Uint32 secs) +{ + Uint32 trace = sh.theTrace; + Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + //Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + + if(outputStream != 0 && + (traceId == 0 || traceId == trace) && + logMatch(senderBlockNo, LogOut)){ +#ifdef VM_TRACE_TIME + fprintf(outputStream, "---- Send ----- Signal - %d ----\n", time(0)); +#else + fprintf(outputStream, "---- Send ----- Signal ----------------\n"); +#endif + + printSignalHeader(outputStream, sh, prio, node, false); + printSignalData(outputStream, sh, theData); + for (unsigned i = 0; i < secs; i++) + printSegmentedSection(outputStream, sh, ptr, i); + } +} + +void +SignalLoggerManager::sendSignalWithDelay(Uint32 delayInMilliSeconds, + const SignalHeader & sh, Uint8 prio, + const Uint32 * theData, Uint32 node, + const SegmentedSectionPtr ptr[3], Uint32 secs) +{ + Uint32 trace = sh.theTrace; + Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + //Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + + if(outputStream != 0 && + (traceId == 0 || traceId == trace) && + logMatch(senderBlockNo, LogOut)){ +#ifdef VM_TRACE_TIME + fprintf(outputStream, + "---- Send ----- Signal (%d ms) %d\n", + delayInMilliSeconds, + time(0)); +#else + fprintf(outputStream, "---- Send delay Signal (%d ms) ----------\n", + delayInMilliSeconds); +#endif + + printSignalHeader(outputStream, sh, prio, node, false); + printSignalData(outputStream, sh, theData); + for (unsigned i = 0; i < secs; i++) + printSegmentedSection(outputStream, sh, ptr, i); + } +} + +/** + * Generic messages in the signal log + */ +void +SignalLoggerManager::log(BlockNumber bno, const char * msg) +{ + // Normalise blocknumber for use in logModes array + const BlockNumber bno2 = bno - MIN_BLOCK_NO; + assert(bno2<NO_OF_BLOCKS); + + if(outputStream != 0 && + logModes[bno2] != LogOff){ + fprintf(outputStream, "%s: %s\n", getBlockName(bno, "API"), msg); + } +} + + +void +SignalLoggerManager::printSignalHeader(FILE * output, + const SignalHeader & sh, + Uint8 prio, + Uint32 node, + bool printReceiversSignalId) +{ + Uint32 receiverBlockNo = sh.theReceiversBlockNumber; + Uint32 receiverProcessor = node; + Uint32 gsn = sh.theVerId_signalNumber; + Uint32 senderBlockNo = refToBlock(sh.theSendersBlockRef); + Uint32 senderProcessor = refToNode(sh.theSendersBlockRef); + Uint32 length = sh.theLength; + Uint32 trace = sh.theTrace; + Uint32 rSigId = sh.theSignalId; + Uint32 sSigId = sh.theSendersSignalId; + + const char * signalName = getSignalName(gsn); + const char * rBlockName = getBlockName(receiverBlockNo, "API"); + const char * sBlockName = getBlockName(senderBlockNo, "API"); + + if(printReceiversSignalId) + fprintf(output, + "r.bn: %d \"%s\", r.proc: %d, r.sigId: %d gsn: %d \"%s\" prio: %d\n" + ,receiverBlockNo, rBlockName, receiverProcessor, rSigId, + gsn, signalName, prio); + else + fprintf(output, + "r.bn: %d \"%s\", r.proc: %d, gsn: %d \"%s\" prio: %d\n", + receiverBlockNo, rBlockName, receiverProcessor, gsn, + signalName, prio); + + fprintf(output, + "s.bn: %d \"%s\", s.proc: %d, s.sigId: %d length: %d trace: %d " + "#sec: %d fragInf: %d\n", + senderBlockNo, sBlockName, senderProcessor, sSigId, length, trace, + sh.m_noOfSections, sh.m_fragmentInfo); +} + +void +SignalLoggerManager::printSignalData(FILE * output, + const SignalHeader & sh, + const Uint32 * signalData) +{ + Uint32 len = sh.theLength; + SignalDataPrintFunction printFunction = + findPrintFunction(sh.theVerId_signalNumber); + + bool ok = false; // done with printing + if(printFunction != 0){ + ok = (* printFunction)(output, signalData, len, sh.theReceiversBlockNumber); + } + if(!ok){ + while(len >= 7){ + fprintf(output, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + signalData[0], signalData[1], signalData[2], signalData[3], + signalData[4], signalData[5], signalData[6]); + len -= 7; + signalData += 7; + } + if(len > 0){ + for(Uint32 i = 0; i<len; i++) + fprintf(output, " H\'%.8x", signalData[i]); + fprintf(output, "\n"); + } + } +} + +void +SignalLoggerManager::printLinearSection(FILE * output, + const SignalHeader & sh, + const LinearSectionPtr ptr[3], + unsigned i) +{ + fprintf(output, "SECTION %u type=linear", i); + if (i >= 3) { + fprintf(output, " *** invalid ***\n"); + return; + } + const Uint32 len = ptr[i].sz; + const Uint32 * data = ptr[i].p; + Uint32 pos = 0; + fprintf(output, " size=%u\n", (unsigned)len); + while (pos < len) { + printDataWord(output, pos, data[pos]); + } + if (len > 0) + putc('\n', output); +} + +void +SignalLoggerManager::printSegmentedSection(FILE * output, + const SignalHeader & sh, + const SegmentedSectionPtr ptr[3], + unsigned i) +{ + fprintf(output, "SECTION %u type=segmented", i); + if (i >= 3) { + fprintf(output, " *** invalid ***\n"); + return; + } + const Uint32 len = ptr[i].sz; + SectionSegment * ssp = ptr[i].p; + Uint32 pos = 0; + fprintf(output, " size=%u\n", (unsigned)len); + while (pos < len) { + if (pos > 0 && pos % SectionSegment::DataLength == 0) { + ssp = g_sectionSegmentPool.getPtr(ssp->m_nextSegment); + } + printDataWord(output, pos, ssp->theData[pos % SectionSegment::DataLength]); + } + if (len > 0) + putc('\n', output); +} + +void +SignalLoggerManager::printDataWord(FILE * output, Uint32 & pos, const Uint32 data) +{ + const char* const hex = "0123456789abcdef"; + if (pos > 0 && pos % 7 == 0) + putc('\n', output); + putc(' ', output); + putc('H', output); + putc('\'', output); + for (int i = 7; i >= 0; i--) + putc(hex[(data >> (i << 2)) & 0xf], output); + pos++; +} diff --git a/ndb/src/common/debugger/signaldata/AccLock.cpp b/ndb/src/common/debugger/signaldata/AccLock.cpp new file mode 100644 index 00000000000..affed431957 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/AccLock.cpp @@ -0,0 +1,75 @@ +/* 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 <signaldata/AccLock.hpp> +#include <SignalLoggerManager.hpp> + +bool +printACC_LOCKREQ(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn) +{ + const AccLockReq* const sig = (const AccLockReq*)theData; + Uint32 reqtype = sig->requestInfo & 0xFF; + switch (sig->returnCode) { + case RNIL: + fprintf(output, " returnCode=RNIL"); + break; + case AccLockReq::Success: + fprintf(output, " returnCode=Success"); + break; + case AccLockReq::IsBlocked: + fprintf(output, " returnCode=IsBlocked"); + break; + case AccLockReq::WouldBlock: + fprintf(output, " returnCode=WouldBlock"); + break; + case AccLockReq::Refused: + fprintf(output, " returnCode=Refused"); + break; + case AccLockReq::NoFreeOp: + fprintf(output, " returnCode=NoFreeOp"); + break; + default: + fprintf(output, " returnCode=%u?", sig->returnCode); + break; + } + switch (reqtype) { + case AccLockReq::LockShared: + fprintf(output, " req=LockShared\n"); + break; + case AccLockReq::LockExclusive: + fprintf(output, " req=LockExclusive\n"); + break; + case AccLockReq::Unlock: + fprintf(output, " req=Unlock\n"); + break; + case AccLockReq::Abort: + fprintf(output, " req=Abort\n"); + break; + default: + fprintf(output, " req=%u\n", reqtype); + break; + } + fprintf(output, " accOpPtr: 0x%x\n", sig->accOpPtr); + if (reqtype == AccLockReq::LockShared || + reqtype == AccLockReq::LockExclusive) { + fprintf(output, " userPtr: 0x%x userRef: 0x%x\n", sig->userPtr, sig->userRef); + fprintf(output, " table: id=%u", sig->tableId); + fprintf(output, " fragment: id=%u ptr=0x%x\n", sig->fragId, sig->fragPtrI); + fprintf(output, " tuple: addr=0x%x hashValue=%x\n", sig->tupAddr, sig->hashValue); + fprintf(output, " transid: %08x %08x\n", sig->transId1, sig->transId2); + } + return true; +} diff --git a/ndb/src/common/debugger/signaldata/AlterIndx.cpp b/ndb/src/common/debugger/signaldata/AlterIndx.cpp new file mode 100644 index 00000000000..e1865136fc3 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/AlterIndx.cpp @@ -0,0 +1,35 @@ +/* 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 <signaldata/AlterIndx.hpp> + +bool printALTER_INDX_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterIndxReq * const sig = (AlterIndxReq *) theData; + return false; +} + +bool printALTER_INDX_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterIndxConf * const sig = (AlterIndxConf *) theData; + return false; +} + +bool printALTER_INDX_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterIndxRef * const sig = (AlterIndxRef *) theData; + return false; +} diff --git a/ndb/src/common/debugger/signaldata/AlterTab.cpp b/ndb/src/common/debugger/signaldata/AlterTab.cpp new file mode 100644 index 00000000000..f9521984095 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/AlterTab.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/AlterTab.hpp> + +bool printALTER_TAB_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterTabReq * const sig = (AlterTabReq *) theData; + + return false; +} + +bool printALTER_TAB_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterTabConf * const sig = (AlterTabConf *) theData; + + return false; +} + +bool printALTER_TAB_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterTabRef * const sig = (AlterTabRef *) theData; + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/AlterTable.cpp b/ndb/src/common/debugger/signaldata/AlterTable.cpp new file mode 100644 index 00000000000..59909c8e490 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/AlterTable.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/AlterTable.hpp> + +bool printALTER_TABLE_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterTableReq * const sig = (AlterTableReq *) theData; + + return false; +} + +bool printALTER_TABLE_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterTableConf * const sig = (AlterTableConf *) theData; + + return false; +} + +bool printALTER_TABLE_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const AlterTableRef * const sig = (AlterTableRef *) theData; + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/AlterTrig.cpp b/ndb/src/common/debugger/signaldata/AlterTrig.cpp new file mode 100644 index 00000000000..d488fd6e348 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/AlterTrig.cpp @@ -0,0 +1,51 @@ +/* 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 <signaldata/AlterTrig.hpp> + +bool printALTER_TRIG_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const AlterTrigReq * const sig = (AlterTrigReq *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "\n"); + + return false; +} + +bool printALTER_TRIG_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const AlterTrigConf * const sig = (AlterTrigConf *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "\n"); + + return false; +} + +bool printALTER_TRIG_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const AlterTrigRef * const sig = (AlterTrigRef *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Error code: %u, ", sig->getErrorCode()); + fprintf(output, "\n"); + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/BackupImpl.cpp b/ndb/src/common/debugger/signaldata/BackupImpl.cpp new file mode 100644 index 00000000000..be9e43e3df1 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/BackupImpl.cpp @@ -0,0 +1,142 @@ +/* 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 <trigger_definitions.h> +#include <signaldata/BackupImpl.hpp> + +bool +printDEFINE_BACKUP_REQ(FILE * out, const Uint32 * data, Uint32 len, Uint16 bno){ + DefineBackupReq* sig = (DefineBackupReq*)data; + fprintf(out, " backupPtr: %d backupId: %d clientRef: %d clientData: %d\n", + sig->backupPtr, sig->backupId, sig->clientRef, sig->clientData); + fprintf(out, " backupKey: [ %08x%08x ] DataLength: %d\n", + sig->backupKey[0], sig->backupKey[1], sig->backupDataLen); + char buf[sig->nodes.TextLength + 1]; + fprintf(out, " Nodes: %s\n", sig->nodes.getText(buf)); + return true; +} + +bool +printDEFINE_BACKUP_REF(FILE * out, const Uint32 * data, Uint32 len, Uint16 bno){ + DefineBackupRef* sig = (DefineBackupRef*)data; + fprintf(out, " backupPtr: %d backupId: %d errorCode: %d\n", + sig->backupPtr, sig->backupId, sig->errorCode); + return true; +} + +bool +printDEFINE_BACKUP_CONF(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + DefineBackupConf* sig = (DefineBackupConf*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; +} + +bool +printSTART_BACKUP_REQ(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + StartBackupReq* sig = (StartBackupReq*)data; + fprintf(out, " backupPtr: %d backupId: %d signalNo: %d of %d\n", + sig->backupPtr, sig->backupId, + sig->signalNo + 1, sig->noOfSignals); + for(Uint32 i = 0; i<sig->noOfTableTriggers; i++) + fprintf(out, + " Table: %d Triggers = [ insert: %d update: %d delete: %d ]\n", + sig->tableTriggers[i].tableId, + sig->tableTriggers[i].triggerIds[TriggerEvent::TE_INSERT], + sig->tableTriggers[i].triggerIds[TriggerEvent::TE_UPDATE], + sig->tableTriggers[i].triggerIds[TriggerEvent::TE_DELETE]); + return true; +} + +bool +printSTART_BACKUP_REF(FILE * out, const Uint32 * data, Uint32 len, Uint16 bno){ + StartBackupRef* sig = (StartBackupRef*)data; + fprintf(out, " backupPtr: %d backupId: %d errorCode: %d\n", + sig->backupPtr, sig->backupId, sig->errorCode); + return true; +} + +bool +printSTART_BACKUP_CONF(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + StartBackupConf* sig = (StartBackupConf*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; +} + +bool +printBACKUP_FRAGMENT_REQ(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + BackupFragmentReq* sig = (BackupFragmentReq*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + fprintf(out, " tableId: %d fragmentNo: %d (count = %d)\n", + sig->tableId, sig->fragmentNo, sig->count); + return true; +} + +bool +printBACKUP_FRAGMENT_REF(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + BackupFragmentRef* sig = (BackupFragmentRef*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + fprintf(out, " tableId: %d fragmentNo: %d errorCode: %d\n", + sig->tableId, sig->fragmentNo, sig->errorCode); + return true; +} + +bool +printBACKUP_FRAGMENT_CONF(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + BackupFragmentConf* sig = (BackupFragmentConf*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + fprintf(out, " tableId: %d fragmentNo: %d records: %d bytes: %d\n", + sig->tableId, sig->fragmentNo, sig->noOfRecords, sig->noOfBytes); + return true; +} + +bool +printSTOP_BACKUP_REQ(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + StopBackupReq* sig = (StopBackupReq*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; +} + +bool +printSTOP_BACKUP_REF(FILE * out, const Uint32 * data, Uint32 len, Uint16 bno){ + StopBackupRef* sig = (StopBackupRef*)data; + fprintf(out, " backupPtr: %d backupId: %d errorCode: %d\n", + sig->backupPtr, sig->backupId, sig->errorCode); + return true; +} + +bool +printSTOP_BACKUP_CONF(FILE * out, const Uint32 * data, Uint32 l, Uint16 bno){ + StopBackupConf* sig = (StopBackupConf*)data; + fprintf(out, " backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; +} + +bool +printBACKUP_STATUS_REQ(FILE *, const Uint32 *, Uint32, Uint16){ + return false; +} + +bool +printBACKUP_STATUS_CONF(FILE *, const Uint32 *, Uint32, Uint16){ + return false; +} diff --git a/ndb/src/common/debugger/signaldata/BackupSignalData.cpp b/ndb/src/common/debugger/signaldata/BackupSignalData.cpp new file mode 100644 index 00000000000..4b0a0e07b66 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/BackupSignalData.cpp @@ -0,0 +1,129 @@ +/* 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 <signaldata/BackupSignalData.hpp> + +bool +printBACKUP_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 bno){ + BackupReq* sig = (BackupReq*)theData; + fprintf(output, " senderData: %d DataLength: %d\n", + sig->senderData, + sig->backupDataLen); + return true; +} + +bool +printBACKUP_DATA(FILE * output, const Uint32 * theData, Uint32 len, Uint16 bno){ + BackupData * sig = (BackupData*)theData; + if(sig->requestType == BackupData::ClientToMaster){ + fprintf(output, " ClientToMaster: senderData: %d backupId: %d\n", + sig->senderData, sig->backupId); + } else if(sig->requestType == BackupData::MasterToSlave){ + fprintf(output, " MasterToSlave: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + } + return false; +} + +bool +printBACKUP_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 bno){ + + BackupRef* sig = (BackupRef*)theData; + fprintf(output, " senderData: %d errorCode: %d masterRef: %d\n", + sig->senderData, + sig->errorCode, + sig->masterRef); + return true; +} + +bool +printBACKUP_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 bno){ + BackupConf* sig = (BackupConf*)theData; + fprintf(output, " senderData: %d backupId: %d\n", + sig->senderData, + sig->backupId); + return true; +} + +bool +printBACKUP_ABORT_REP(FILE * out, const Uint32 * data, Uint32 len, Uint16 bno){ + BackupAbortRep* sig = (BackupAbortRep*)data; + fprintf(out, " senderData: %d backupId: %d reason: %d\n", + sig->senderData, + sig->backupId, + sig->reason); + return true; +} + +bool +printBACKUP_COMPLETE_REP(FILE * out, const Uint32 * data, Uint32 len, Uint16 b){ + BackupCompleteRep* sig = (BackupCompleteRep*)data; + fprintf(out, " senderData: %d backupId: %d records: %d bytes: %d\n", + sig->senderData, + sig->backupId, + sig->noOfRecords, + sig->noOfBytes); + return true; +} + +bool +printBACKUP_NF_COMPLETE_REP(FILE*, const Uint32*, Uint32, Uint16){ + return false; +} + +bool +printABORT_BACKUP_ORD(FILE * out, const Uint32 * data, Uint32 len, Uint16 b){ + AbortBackupOrd* sig = (AbortBackupOrd*)data; + + AbortBackupOrd::RequestType rt =(AbortBackupOrd::RequestType)sig->requestType; + switch(rt){ + case AbortBackupOrd::ClientAbort: + fprintf(out, " ClientAbort: senderData: %d backupId: %d\n", + sig->senderData, sig->backupId); + return true; + break; + case AbortBackupOrd::BackupComplete: + fprintf(out, " BackupComplete: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; + case AbortBackupOrd::BackupFailure: + fprintf(out, " BackupFailure: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; + case AbortBackupOrd::LogBufferFull: + fprintf(out, " LogBufferFull: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; + break; + case AbortBackupOrd::FileOrScanError: + fprintf(out, " FileOrScanError: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; + break; + case AbortBackupOrd::BackupFailureDueToNodeFail: + fprintf(out, " BackupFailureDueToNodeFail: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; + break; + case AbortBackupOrd::OkToClean: + fprintf(out, " OkToClean: backupPtr: %d backupId: %d\n", + sig->backupPtr, sig->backupId); + return true; + break; + } + return false; +} diff --git a/ndb/src/common/debugger/signaldata/CloseComReqConf.cpp b/ndb/src/common/debugger/signaldata/CloseComReqConf.cpp new file mode 100644 index 00000000000..11ee0948c17 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/CloseComReqConf.cpp @@ -0,0 +1,53 @@ +/* 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 <NdbStdio.h> +#include <kernel_types.h> +#include <BlockNumbers.h> +#include <signaldata/CloseComReqConf.hpp> + +bool +printCLOSECOMREQCONF(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 receiverBlockNo){ + + CloseComReqConf * cc = (CloseComReqConf*)theData; + + fprintf(output, " xxxBlockRef = (%d, %d) failNo = %d noOfNodes = %d\n", + refToBlock(cc->xxxBlockRef), refToNode(cc->xxxBlockRef), + cc->failNo, cc->noOfNodes); + + int hits = 0; + fprintf(output, " Nodes: "); + for(int i = 0; i<MAX_NODES; i++){ + if(NodeBitmask::get(cc->theNodes, i)){ + hits++; + fprintf(output, " %d", i); + } + if(hits == 16){ + fprintf(output, "\n Nodes: "); + hits = 0; + } + } + if(hits != 0) + fprintf(output, "\n"); + + return true; +} + + diff --git a/ndb/src/common/debugger/signaldata/ContinueB.cpp b/ndb/src/common/debugger/signaldata/ContinueB.cpp new file mode 100644 index 00000000000..054909d961e --- /dev/null +++ b/ndb/src/common/debugger/signaldata/ContinueB.cpp @@ -0,0 +1,36 @@ +/* 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 <NdbStdio.h> +#include <kernel_types.h> +#include <BlockNumbers.h> +#include <signaldata/DihContinueB.hpp> +#include <signaldata/NdbfsContinueB.hpp> + +bool +printCONTINUEB(FILE * output, const Uint32 * theData, Uint32 len, + Uint16 receiverBlockNo){ + if(receiverBlockNo == DBDIH){ + return printCONTINUEB_DBDIH(output, theData, len); + } else if(receiverBlockNo == NDBFS) { + return printCONTINUEB_NDBFS(output, theData, len); + } + + return false; +} + + diff --git a/ndb/src/common/debugger/signaldata/CopyGCI.cpp b/ndb/src/common/debugger/signaldata/CopyGCI.cpp new file mode 100644 index 00000000000..96186e82525 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/CopyGCI.cpp @@ -0,0 +1,58 @@ +/* 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 <signaldata/CopyGCIReq.hpp> + +static +void +print(char * buf, size_t buf_len, CopyGCIReq::CopyReason r){ + switch(r){ + case CopyGCIReq::IDLE: + snprintf(buf, buf_len, "IDLE"); + break; + case CopyGCIReq::LOCAL_CHECKPOINT: + snprintf(buf, buf_len, "LOCAL_CHECKPOINT"); + break; + case CopyGCIReq::RESTART: + snprintf(buf, buf_len, "RESTART"); + break; + case CopyGCIReq::GLOBAL_CHECKPOINT: + snprintf(buf, buf_len, "GLOBAL_CHECKPOINT"); + break; + case CopyGCIReq::INITIAL_START_COMPLETED: + snprintf(buf, buf_len, "INITIAL_START_COMPLETED"); + break; + default: + snprintf(buf, buf_len, "<Unknown>"); + } +} + +bool +printCOPY_GCI_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + CopyGCIReq * sig = (CopyGCIReq*)theData; + + static char buf[255]; + print(buf, sizeof(buf), (CopyGCIReq::CopyReason)sig->copyReason); + + fprintf(output, " SenderData: %d CopyReason: %s StartWord: %d\n", + sig->anyData, + buf, + sig->startWord); + return false; +} diff --git a/ndb/src/common/debugger/signaldata/CreateEvnt.cpp b/ndb/src/common/debugger/signaldata/CreateEvnt.cpp new file mode 100644 index 00000000000..7b497d6a974 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/CreateEvnt.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/CreateEvnt.hpp> + +bool printCREATE_EVNT_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const CreateEvntReq * const sig = (CreateEvntReq *) theData; + + return false; +} + +bool printCREATE_EVNT_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const CreateEvntConf * const sig = (CreateEvntConf *) theData; + + return false; +} + +bool printCREATE_EVNT_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const CreateEvntRef * const sig = (CreateEvntRef *) theData; + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/CreateFragmentation.cpp b/ndb/src/common/debugger/signaldata/CreateFragmentation.cpp new file mode 100644 index 00000000000..6685345f17a --- /dev/null +++ b/ndb/src/common/debugger/signaldata/CreateFragmentation.cpp @@ -0,0 +1,56 @@ +/* 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 <signaldata/CreateFragmentation.hpp> + +bool +printCREATE_FRAGMENTATION_REQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const CreateFragmentationReq * const sig = (CreateFragmentationReq *)theData; + fprintf(output, " senderRef: %x\n", sig->senderRef); + fprintf(output, " senderData: %x\n", sig->senderData); + fprintf(output, " fragmentationType: %x\n", sig->fragmentationType); + fprintf(output, " noOfFragments: %x\n", sig->noOfFragments); + fprintf(output, " fragmentNode: %x\n", sig->fragmentNode); + if (sig->primaryTableId == RNIL) + fprintf(output, " primaryTableId: none\n", sig->primaryTableId); + else + fprintf(output, " primaryTableId: %x\n", sig->primaryTableId); + return true; +} + +bool +printCREATE_FRAGMENTATION_REF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const CreateFragmentationRef * const sig = (CreateFragmentationRef *)theData; + fprintf(output, " senderRef: %x\n", sig->senderRef); + fprintf(output, " senderData: %x\n", sig->senderData); + fprintf(output, " errorCode: %x\n", sig->errorCode); + return true; +} + +bool +printCREATE_FRAGMENTATION_CONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const CreateFragmentationConf * const sig = + (CreateFragmentationConf *)theData; + fprintf(output, " senderRef: %x\n", sig->senderRef); + fprintf(output, " senderData: %x\n", sig->senderData); + fprintf(output, " noOfReplicas: %x\n", sig->noOfReplicas); + fprintf(output, " noOfFragments: %x\n", sig->noOfFragments); + return true; +} + diff --git a/ndb/src/common/debugger/signaldata/CreateIndx.cpp b/ndb/src/common/debugger/signaldata/CreateIndx.cpp new file mode 100644 index 00000000000..8fcbb9279ed --- /dev/null +++ b/ndb/src/common/debugger/signaldata/CreateIndx.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/CreateIndx.hpp> + +bool printCREATE_INDX_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const CreateIndxReq * const sig = (CreateIndxReq *) theData; + + return false; +} + +bool printCREATE_INDX_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const CreateIndxConf * const sig = (CreateIndxConf *) theData; + + return false; +} + +bool printCREATE_INDX_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const CreateIndxRef * const sig = (CreateIndxRef *) theData; + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/CreateTrig.cpp b/ndb/src/common/debugger/signaldata/CreateTrig.cpp new file mode 100644 index 00000000000..d8360dec4d5 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/CreateTrig.cpp @@ -0,0 +1,120 @@ +/* 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 <signaldata/CreateTrig.hpp> + +bool printCREATE_TRIG_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const CreateTrigReq * const sig = (CreateTrigReq *) theData; + + //char triggerName[MAX_TAB_NAME_SIZE]; + char triggerType[32]; + char triggerActionTime[32]; + char triggerEvent[32]; + + //sig->getTriggerName((char *) &triggerName); + switch (sig->getTriggerType()) { + case(TriggerType::SECONDARY_INDEX): + snprintf(triggerType, sizeof(triggerType), "SECONDARY_INDEX"); + break; + case(TriggerType::SUBSCRIPTION): + snprintf(triggerType, sizeof(triggerType), "SUBSCRIPTION"); + break; + case(TriggerType::ORDERED_INDEX): + snprintf(triggerType, sizeof(triggerType), "ORDERED_INDEX"); + break; + default: + snprintf(triggerType, sizeof(triggerType), "UNKNOWN [%d]", (int)sig->getTriggerType()); + break; + } + switch (sig->getTriggerActionTime()) { + case (TriggerActionTime::TA_BEFORE): + snprintf(triggerActionTime, sizeof(triggerActionTime), "BEFORE"); + break; + case(TriggerActionTime::TA_AFTER): + snprintf(triggerActionTime, sizeof(triggerActionTime), "AFTER"); + break; + case (TriggerActionTime::TA_DEFERRED): + snprintf(triggerActionTime, sizeof(triggerActionTime), "DEFERRED"); + break; + case (TriggerActionTime::TA_DETACHED): + snprintf(triggerActionTime, sizeof(triggerActionTime), "DETACHED"); + break; + default: + snprintf(triggerActionTime, sizeof(triggerActionTime), + "UNKNOWN [%d]", (int)sig->getTriggerActionTime()); + break; + } + switch (sig->getTriggerEvent()) { + case (TriggerEvent::TE_INSERT): + snprintf(triggerEvent, sizeof(triggerEvent), "INSERT"); + break; + case(TriggerEvent::TE_DELETE): + snprintf(triggerEvent, sizeof(triggerEvent), "DELETE"); + break; + case(TriggerEvent::TE_UPDATE): + snprintf(triggerEvent, sizeof(triggerEvent), "UPDATE"); + break; + case(TriggerEvent::TE_CUSTOM): + snprintf(triggerEvent, sizeof(triggerEvent), "CUSTOM"); + break; + default: + snprintf(triggerEvent, sizeof(triggerEvent), "UNKNOWN [%d]", (int)sig->getTriggerEvent()); + break; + } + + fprintf(output, "User: %u, ", sig->getUserRef()); + //fprintf(output, "Trigger name: \"%s\"\n", triggerName); + fprintf(output, "Type: %s, ", triggerType); + fprintf(output, "Action: %s, ", triggerActionTime); + fprintf(output, "Event: %s, ", triggerEvent); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Table id: %u, ", sig->getTableId()); + fprintf(output, "Monitor replicas: %s ", (sig->getMonitorReplicas())?"true":"false"); + fprintf(output, "Monitor all attributes: %s ", (sig->getMonitorAllAttributes())?"true":"false"); + const AttributeMask& attributeMask = sig->getAttributeMask(); + + char buf[attributeMask.TextLength + 1]; + fprintf(output, "Attribute mask: %s", attributeMask.getText(buf)); + fprintf(output, "\n"); + + return false; +} + +bool printCREATE_TRIG_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const CreateTrigConf * const sig = (CreateTrigConf *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Table id: %u, ", sig->getTableId()); + fprintf(output, "\n"); + + return false; +} + +bool printCREATE_TRIG_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const CreateTrigRef * const sig = (CreateTrigRef *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Table id: %u, ", sig->getTableId()); + fprintf(output, "Error code: %u, ", sig->getErrorCode()); + fprintf(output, "\n"); + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/DictTabInfo.cpp b/ndb/src/common/debugger/signaldata/DictTabInfo.cpp new file mode 100644 index 00000000000..a0e0195adad --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DictTabInfo.cpp @@ -0,0 +1,153 @@ +/* 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 <signaldata/DictTabInfo.hpp> +#include <ndb_limits.h> + +//static +const +SimpleProperties::SP2StructMapping +DictTabInfo::TableMapping[] = { + DTIMAPS(Table, TableName, TableName, 0, MAX_TAB_NAME_SIZE), + DTIMAP(Table, TableId, TableId), + DTIMAP(Table, SecondTableId, SecondTableId), + DTIMAPS(Table, PrimaryTable, PrimaryTable, 0, MAX_TAB_NAME_SIZE), + DTIMAP(Table, PrimaryTableId, PrimaryTableId), + DTIMAP2(Table, TableLoggedFlag, TableLoggedFlag, 0, 1), + DTIMAP2(Table, TableKValue, TableKValue, 6, 6), + DTIMAP2(Table, MinLoadFactor, MinLoadFactor, 0, 90), + DTIMAP2(Table, MaxLoadFactor, MaxLoadFactor, 25, 110), + DTIMAP2(Table, FragmentTypeVal, FragmentType, 0, 3), + DTIMAP2(Table, TableStorageVal, TableStorage, 0, 0), + DTIMAP2(Table, ScanOptimised, ScanOptimised, 0, 0), + DTIMAP2(Table, FragmentKeyTypeVal, FragmentKeyType, 0, 2), + DTIMAP2(Table, TableTypeVal, TableType, 1, 3), + DTIMAP(Table, NoOfKeyAttr, NoOfKeyAttr), + DTIMAP2(Table, NoOfAttributes, NoOfAttributes, 1, MAX_ATTRIBUTES_IN_TABLE), + DTIMAP(Table, NoOfNullable, NoOfNullable), + DTIMAP2(Table, NoOfVariable, NoOfVariable, 0, 0), + DTIMAP(Table, KeyLength, KeyLength), + DTIMAP(Table, TableVersion, TableVersion), + DTIMAP(Table, IndexState, IndexState), + DTIMAP(Table, InsertTriggerId, InsertTriggerId), + DTIMAP(Table, UpdateTriggerId, UpdateTriggerId), + DTIMAP(Table, DeleteTriggerId, DeleteTriggerId), + DTIMAP(Table, CustomTriggerId, CustomTriggerId), + DTIMAP2(Table, FrmLen, FrmLen, 0, MAX_FRM_DATA_SIZE), + DTIMAPB(Table, FrmData, FrmData, 0, MAX_FRM_DATA_SIZE, FrmLen), + DTIBREAK(AttributeName) +}; + +//static +const Uint32 DictTabInfo::TableMappingSize = +sizeof(DictTabInfo::TableMapping) / sizeof(SimpleProperties::SP2StructMapping); + +//static +const +SimpleProperties::SP2StructMapping +DictTabInfo::AttributeMapping[] = { + DTIMAPS(Attribute, AttributeName, AttributeName, 0, MAX_ATTR_NAME_SIZE), + DTIMAP(Attribute, AttributeId, AttributeId), + DTIMAP2(Attribute, AttributeType, AttributeType, 0, 3), + DTIMAP2(Attribute, AttributeSize, AttributeSize, 3, 7), + DTIMAP2(Attribute, AttributeArraySize, AttributeArraySize, 0, 65535), + DTIMAP2(Attribute, AttributeKeyFlag, AttributeKeyFlag, 0, 1), + DTIMAP2(Attribute, AttributeStorage, AttributeStorage, 0, 0), + DTIMAP2(Attribute, AttributeNullableFlag, AttributeNullableFlag, 0, 1), + DTIMAP2(Attribute, AttributeDGroup, AttributeDGroup, 0, 1), + DTIMAP2(Attribute, AttributeDKey, AttributeDKey, 0, 1), + DTIMAP2(Attribute, AttributeStoredInd, AttributeStoredInd, 0, 1), + DTIMAP2(Attribute, AttributeGroup, AttributeGroup, 0, 0), + DTIMAP(Attribute, AttributeExtType, AttributeExtType), + DTIMAP(Attribute, AttributeExtPrecision, AttributeExtPrecision), + DTIMAP(Attribute, AttributeExtScale, AttributeExtScale), + DTIMAP(Attribute, AttributeExtLength, AttributeExtLength), + DTIMAP2(Attribute, AttributeAutoIncrement, AttributeAutoIncrement, 0, 1), + DTIMAPS(Attribute, AttributeDefaultValue, AttributeDefaultValue, + 0, MAX_ATTR_DEFAULT_VALUE_SIZE), + DTIBREAK(AttributeEnd) +}; + +//static +const Uint32 DictTabInfo::AttributeMappingSize = +sizeof(DictTabInfo::AttributeMapping) / +sizeof(SimpleProperties::SP2StructMapping); + +bool printDICTTABINFO(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ +// const DictTabInfo * const sig = (DictTabInfo *) theData; + + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + return true; +} + +void +DictTabInfo::Table::init(){ + memset(TableName, 0, sizeof(TableName));//TableName[0] = 0; + TableId = ~0; + SecondTableId = ~0; + memset(PrimaryTable, 0, sizeof(PrimaryTable));//PrimaryTable[0] = 0; // Only used when "index" + PrimaryTableId = RNIL; + TableLoggedFlag = 1; + NoOfKeyAttr = 0; + NoOfAttributes = 0; + NoOfNullable = 0; + NoOfVariable = 0; + TableKValue = 6; + MinLoadFactor = 78; + MaxLoadFactor = 80; + KeyLength = 0; + FragmentType = DictTabInfo::AllNodesSmallTable; + TableStorage = 0; + ScanOptimised = 0; + FragmentKeyType = DictTabInfo::PrimaryKey; + TableType = DictTabInfo::UndefTableType; + TableVersion = 0; + IndexState = ~0; + InsertTriggerId = RNIL; + UpdateTriggerId = RNIL; + DeleteTriggerId = RNIL; + CustomTriggerId = RNIL; + FrmLen = 0; + memset(FrmData, 0, sizeof(FrmData)); +} + +void +DictTabInfo::Attribute::init(){ + memset(AttributeName, 0, sizeof(AttributeName));//AttributeName[0] = 0; + AttributeId = 0; + AttributeType = DictTabInfo::UnSignedType; + AttributeSize = DictTabInfo::a32Bit; + AttributeArraySize = 1; + AttributeKeyFlag = 0; + AttributeStorage = 1; + AttributeNullableFlag = 0; + AttributeDGroup = 0; + AttributeDKey = 0; + AttributeStoredInd = 1; + AttributeGroup = 0; + AttributeExtType = 0, + AttributeExtPrecision = 0, + AttributeExtScale = 0, + AttributeExtLength = 0, + AttributeAutoIncrement = false; + memset(AttributeDefaultValue, 0, sizeof(AttributeDefaultValue));//AttributeDefaultValue[0] = 0; +}; diff --git a/ndb/src/common/debugger/signaldata/DihContinueB.cpp b/ndb/src/common/debugger/signaldata/DihContinueB.cpp new file mode 100644 index 00000000000..94453e76d72 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DihContinueB.cpp @@ -0,0 +1,217 @@ +/* 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 <signaldata/DihContinueB.hpp> + +bool +printCONTINUEB_DBDIH(FILE * output, const Uint32 * theData, Uint32 len){ + + switch (theData[0]) { + case DihContinueB::ZPACK_TABLE_INTO_PAGES: + fprintf(output, " Pack Table Into Pages: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZPACK_FRAG_INTO_PAGES: + fprintf(output, " Pack Frag Into Pages: Table: %d Fragment: %d PageIndex: %d WordIndex: %d\n", + theData[1], theData[2], theData[3], theData[4]); + return true; + break; + case DihContinueB::ZREAD_PAGES_INTO_TABLE: + fprintf(output, " Read Pages Into Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZREAD_PAGES_INTO_FRAG: + fprintf(output, " Read Pages Into Frag: Table: %d Fragment: %d PageIndex: %d WordIndex: %d\n", + theData[1], theData[2], theData[3], theData[4]); + return true; + break; +#if 0 + case DihContinueB::ZREAD_TAB_DESCRIPTION: + fprintf(output, " Read Table description: %d\n", theData[1]); + return true; + break; +#endif + case DihContinueB::ZCOPY_TABLE: + fprintf(output, " Copy Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZCOPY_TABLE_NODE: + fprintf(output, " Copy table node: TableId: %d NodeId: %d\n", + theData[1], theData[2]); + fprintf(output, "PageIndex: %d WordIndex: %d NoOfWords: %d\n", + theData[3], theData[4], theData[5]); + return true; + break; + case DihContinueB::ZSTART_FRAGMENT: + fprintf(output, " Start fragment: Table: %d Fragment: %d\n", + theData[1], theData[2]); + return true; + break; + case DihContinueB::ZCOMPLETE_RESTART: + fprintf(output, "Complete Restart\n"); + return true; + break; + case DihContinueB::ZREAD_TABLE_FROM_PAGES: + fprintf(output, " Read Table From Pages: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZSR_PHASE2_READ_TABLE: + fprintf(output, " Phase 2 Read Table: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZCHECK_TC_COUNTER: + fprintf(output, " Check Tc Counter from place %d\n", theData[1]); + return true; + break; + case DihContinueB::ZCALCULATE_KEEP_GCI: + fprintf(output, " Calc Keep GCI: Table: %d Fragment: %d\n", + theData[1], theData[2]); + return true; + break; + case DihContinueB::ZSTORE_NEW_LCP_ID: + fprintf(output, " Store New LCP Id\n"); + return true; + break; + case DihContinueB::ZTABLE_UPDATE: + fprintf(output, " Table Update: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZCHECK_LCP_COMPLETED: + fprintf(output, " Check LCP Completed: TableId %d\n", theData[1]); + return true; + break; + case DihContinueB::ZINIT_LCP: + fprintf(output, " Init LCP: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZADD_TABLE_MASTER_PAGES: + fprintf(output, " Add Table Master Pages: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZDIH_ADD_TABLE_MASTER: + fprintf(output, " Dih Add Table Master: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZADD_TABLE_SLAVE_PAGES: + fprintf(output, " Add Table Slave Pages: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZDIH_ADD_TABLE_SLAVE: + fprintf(output, " Add Table Slave: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZSTART_GCP: + fprintf(output, " Start GCP\n"); + return true; + break; + case DihContinueB::ZCOPY_GCI: + fprintf(output, " Copy GCI\n"); + return true; + break; + case DihContinueB::ZEMPTY_VERIFY_QUEUE: + fprintf(output, " Empty Verify Queue\n"); + return true; + break; + case DihContinueB::ZCHECK_GCP_STOP: + fprintf(output, " Check GCP Stop\n"); + if (len == 6){ + fprintf(output, "coldGcpStatus = %d\n", theData[1]); + fprintf(output, "cgcpStatus = %d\n", theData[2]); + fprintf(output, "coldGcpId = %d\n", theData[3]); + fprintf(output, "cnewgcp = %d\n", theData[4]); + fprintf(output, "cgcpSameCounter = %d\n", theData[5]); + } + return true; + break; + case DihContinueB::ZREMOVE_NODE_FROM_TABLE: + fprintf(output, " Remove Node From Table: Node: %d Table: %d\n", + theData[1], theData[2]); + return true; + break; + case DihContinueB::ZCOPY_NODE: + fprintf(output, " Copy Node: Table: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZSTART_TAKE_OVER: + fprintf(output, " Start Take Over: TakeOverPtr: %d, startNode: %d, toNode: %d\n", + theData[1], theData[2], theData[3]); + return true; + break; + case DihContinueB::ZCHECK_START_TAKE_OVER: + fprintf(output, " Check Start Take Over\n"); + return true; + break; + case DihContinueB::ZTO_START_COPY_FRAG: + fprintf(output, " To Start Copy Frag: TakeOverPtr: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZINVALIDATE_NODE_LCP: + fprintf(output, " Invalide LCP: NodeId: %d TableId %d\n", + theData[1], theData[2]); + return true; + break; + case DihContinueB::ZINITIALISE_RECORDS: + fprintf(output, " Initialise Records: tdata0: %d\n", theData[1]); + return true; + break; + case DihContinueB::ZSTART_PERMREQ_AGAIN: + fprintf(output, " START_PERMREQ again for node: %d\n", theData[1]); + return true; + break; + case DihContinueB::SwitchReplica: + fprintf(output, " NodeId = %d TableId = %d FragNo = %d\n", + theData[1], theData[2], theData[3]); + return true; + break; + case DihContinueB::ZSEND_START_TO: + fprintf(output, " Send Start Take Over: TakeOverPtr: %d, startNode: %d, toNode: %d\n", + theData[1], theData[2], theData[3]); + return true; + break; + case DihContinueB::ZSEND_UPDATE_TO: + fprintf(output, " Send Update Take Over: TakeOverPtr: %d, startNode: %d, toNode: %d\n", + theData[1], theData[2], theData[3]); + return true; + break; + case DihContinueB::ZSEND_END_TO: + fprintf(output, " Send End Take Over: TakeOverPtr: %d, startNode: %d, toNode: %d\n", + theData[1], theData[2], theData[3]); + return true; + break; + case DihContinueB::ZSEND_ADD_FRAG: + fprintf(output, " Send Add Fragment: TakeOverPtr: %d, startNode: %d, toNode: %d\n", + theData[1], theData[2], theData[3]); + return true; + break; + case DihContinueB::ZSEND_CREATE_FRAG: + fprintf(output, " Send Create Fragment: TakeOverPtr: %d, storedType: %d, start Gci: %d, startNode: %d, toNode: %d\n", + theData[1], theData[2], theData[3], theData[4], theData[5]); + return true; + break; + case DihContinueB::WAIT_DROP_TAB_WRITING_TO_FILE: + fprintf(output, " Wait drop tab writing to file TableId: %d\n", theData[1]); + return true; + case DihContinueB::CHECK_WAIT_DROP_TAB_FAILED_LQH: + fprintf(output, " Wait drop tab FailedNodeId: %d TableId: %d\n", + theData[1], theData[2]); + return true; + default: + fprintf(output, " Default system error lab...\n"); + break; + }//switch + return false; +} diff --git a/ndb/src/common/debugger/signaldata/DihSwitchReplicaReq.cpp b/ndb/src/common/debugger/signaldata/DihSwitchReplicaReq.cpp new file mode 100644 index 00000000000..2e4318f4033 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DihSwitchReplicaReq.cpp @@ -0,0 +1,48 @@ +/* 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 <signaldata/DihSwitchReplicaReq.hpp> + +bool +printDIH_SWITCH_REPLICA_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + + DihSwitchReplicaReq * req = (DihSwitchReplicaReq *)&theData[0]; + + const Uint32 requestInfo = req->requestInfo; + + switch(DihSwitchReplicaReq::getRequestType(requestInfo)){ + case DihSwitchReplicaReq::RemoveNodeAsPrimary:{ + fprintf(output, " RemoveNodeAsPrimary: Node=%d", req->nodeId); + if(DihSwitchReplicaReq::getAllTables(requestInfo)) + fprintf(output, " All Tables"); + else + fprintf(output, " TableId=%d", req->tableId); + + if(DihSwitchReplicaReq::getDistribute(requestInfo)) + fprintf(output, " Distribute"); + fprintf(output, "\n"); + return true; + } + break; + default: + fprintf(output, " Unknown request type:\n"); + } + return false; +} diff --git a/ndb/src/common/debugger/signaldata/DisconnectRep.cpp b/ndb/src/common/debugger/signaldata/DisconnectRep.cpp new file mode 100644 index 00000000000..3a73747a978 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DisconnectRep.cpp @@ -0,0 +1,30 @@ +/* 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 <signaldata/DisconnectRep.hpp> + +bool +printDISCONNECT_REP(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const DisconnectRep * const sig = (DisconnectRep *) theData; + + fprintf(output, " NodeId: %d, ErrorCode: %d\n", + sig->nodeId, sig->err); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/DropIndx.cpp b/ndb/src/common/debugger/signaldata/DropIndx.cpp new file mode 100644 index 00000000000..0d59a981a18 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DropIndx.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/DropIndx.hpp> + +bool printDROP_INDX_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const DropIndxReq * const sig = (DropIndxReq *) theData; + + return false; +} + +bool printDROP_INDX_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const DropIndxConf * const sig = (DropIndxConf *) theData; + + return false; +} + +bool printDROP_INDX_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ +// const DropIndxRef * const sig = (DropIndxRef *) theData; + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/DropTab.cpp b/ndb/src/common/debugger/signaldata/DropTab.cpp new file mode 100644 index 00000000000..83c95b0e344 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DropTab.cpp @@ -0,0 +1,50 @@ +/* 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 <signaldata/DropTab.hpp> + +bool +printDROP_TAB_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const DropTabReq * const sig = (DropTabReq *) theData; + + fprintf(output, + " senderRef: %x senderData: %d TableId: %d requestType: %d\n", + sig->senderRef, sig->senderData, sig->tableId, sig->requestType); + return true; +} + +bool printDROP_TAB_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const DropTabConf * const sig = (DropTabConf *) theData; + + fprintf(output, + " senderRef: %x senderData: %d TableId: %d\n", + sig->senderRef, sig->senderData, sig->tableId); + + return true; +} + +bool printDROP_TAB_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const DropTabRef * const sig = (DropTabRef *) theData; + + fprintf(output, + " senderRef: %x senderData: %d TableId: %d errorCode: %d\n", + sig->senderRef, sig->senderData, sig->tableId, sig->errorCode); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/DropTrig.cpp b/ndb/src/common/debugger/signaldata/DropTrig.cpp new file mode 100644 index 00000000000..54e8734439f --- /dev/null +++ b/ndb/src/common/debugger/signaldata/DropTrig.cpp @@ -0,0 +1,89 @@ +/* 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 <signaldata/DropTrig.hpp> + +bool printDROP_TRIG_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const DropTrigReq * const sig = (DropTrigReq *) theData; + + //char triggerName[MAX_TAB_NAME_SIZE]; + //char triggerType[32]; + //char triggerActionTime[32]; + //char triggerEvent[32]; + + //sig->getTriggerName((char *) &triggerName); + //switch(sig->getTriggerType()) { + //case(TriggerType::SECONDARY_INDEX): + //strcpy(triggerType, "SECONDARY_INDEX"); + //break; + //case(TriggerType::SUBSCRIPTION): + //strcpy(triggerType, "SUBSCRIPTION"); + //break; + //default: + //strcpy(triggerType, "UNSUPPORTED"); + //} + //strcpy(triggerActionTime, + //(sig->getTriggerActionTime() == TriggerActionTime::BEFORE)? + //"BEFORE":"AFTER"); + //switch(sig->getTriggerEvent()) { + //case (TriggerEvent::TE_INSERT): + //strcpy(triggerEvent, "INSERT"); + //break; + //case(TriggerEvent::TE_DELETE): + //strcpy(triggerEvent, "DELETE"); + //break; + //case(TriggerEvent::TE_UPDATE): + //strcpy(triggerEvent, "UPDATE"); + //break; + //} + + fprintf(output, "User: %u, ", sig->getUserRef()); + //fprintf(output, "Trigger name: \"%s\"\n", triggerName); + //fprintf(output, "Type: %s, ", triggerType); + //fprintf(output, "Action: %s, ", triggerActionTime); + //fprintf(output, "Event: %s, ", triggerEvent); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Table id: %u, ", sig->getTableId()); + fprintf(output, "\n"); + + return false; +} + +bool printDROP_TRIG_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const DropTrigConf * const sig = (DropTrigConf *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Table id: %u, ", sig->getTableId()); + fprintf(output, "\n"); + + return false; +} + +bool printDROP_TRIG_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const DropTrigRef * const sig = (DropTrigRef *) theData; + + fprintf(output, "User: %u, ", sig->getUserRef()); + fprintf(output, "Trigger id: %u, ", sig->getTriggerId()); + fprintf(output, "Table id: %u, ", sig->getTableId()); + fprintf(output, "Error code: %u, ", sig->getErrorCode()); + fprintf(output, "\n"); + + return false; +} diff --git a/ndb/src/common/debugger/signaldata/FailRep.cpp b/ndb/src/common/debugger/signaldata/FailRep.cpp new file mode 100644 index 00000000000..d70912fe8c7 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FailRep.cpp @@ -0,0 +1,31 @@ +/* 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 <signaldata/FailRep.hpp> + +bool +printFAIL_REP(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const FailRep * const sig = (FailRep *) theData; + + fprintf(output, " FailedNode: %d, FailCause: %d\n", + sig->failNodeId, sig->failCause); + + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/FireTrigOrd.cpp b/ndb/src/common/debugger/signaldata/FireTrigOrd.cpp new file mode 100644 index 00000000000..d86aa2e06de --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FireTrigOrd.cpp @@ -0,0 +1,56 @@ +/* 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 <signaldata/FireTrigOrd.hpp> +#include <RefConvert.hpp> + +static +const char * +trigEvent(Uint32 i){ + switch(i){ + case TriggerEvent::TE_INSERT: + return "insert"; + break; + case TriggerEvent::TE_UPDATE: + return "update"; + break; + case TriggerEvent::TE_DELETE: + return "delete"; + break; + } + return "UNKNOWN"; +} + +bool +printFIRE_TRIG_ORD(FILE * output, const Uint32 * theData, Uint32 len, + Uint16 receiverBlockNo) +{ + const FireTrigOrd * const sig = (FireTrigOrd *) theData; + + fprintf(output, " TriggerId: %d TriggerEvent: %s\n", + sig->getTriggerId(), + trigEvent(sig->getTriggerEvent())); + fprintf(output, " UserRef: (%d, %d) User data: %x\n", + refToNode(sig->getUserRef()), + refToBlock(sig->getUserRef()), + sig->getConnectionPtr()); + fprintf(output, " Signal: PK=%d BEFORE=%d AFTER=%d\n", + sig->getNoOfPrimaryKeyWords(), + sig->getNoOfBeforeValueWords(), + sig->getNoOfAfterValueWords()); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/FsAppendReq.cpp b/ndb/src/common/debugger/signaldata/FsAppendReq.cpp new file mode 100644 index 00000000000..6e443ffe5fc --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FsAppendReq.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/FsAppendReq.hpp> + +bool +printFSAPPENDREQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + bool ret = true; + + const FsAppendReq * const sig = (FsAppendReq *) theData; + + fprintf(output, " FilePointer: %d\n", sig->filePointer); + fprintf(output, " UserReference: H\'%.8x, UserPointer: H\'%.8x\n", + sig->userReference, sig->userPointer); + + fprintf(output, " varIndex: %d offset: %d size: %d\n", + sig->varIndex, + sig->offset, + sig->size); + return ret; +} diff --git a/ndb/src/common/debugger/signaldata/FsCloseReq.cpp b/ndb/src/common/debugger/signaldata/FsCloseReq.cpp new file mode 100644 index 00000000000..143250b7db1 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FsCloseReq.cpp @@ -0,0 +1,40 @@ +/* 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 <signaldata/FsCloseReq.hpp> + +bool +printFSCLOSEREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const FsCloseReq * const sig = (FsCloseReq *) theData; + + fprintf(output, " UserPointer: %d\n", + sig->userPointer); + fprintf(output, " FilePointer: %d\n", + sig->filePointer); + fprintf(output, " UserReference: H\'%.8x\n", + sig->userReference); + + fprintf(output, " Flags: H\'%.8x, ", sig->fileFlag); + if (sig->getRemoveFileFlag(sig->fileFlag) == true) + fprintf(output, "Remove file"); + else + fprintf(output, "Don't remove file"); + fprintf(output, "\n"); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/FsConf.cpp b/ndb/src/common/debugger/signaldata/FsConf.cpp new file mode 100644 index 00000000000..f0ab57aadcf --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FsConf.cpp @@ -0,0 +1,33 @@ +/* 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 <signaldata/FsConf.hpp> + +bool +printFSCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const FsConf * const sig = (FsConf *) theData; + + fprintf(output, " UserPointer: %d\n", sig->userPointer); + + if (len > 1){ + // Only valid if this is a FSOPENCONF + fprintf(output, " FilePointer: %d\n", sig->filePointer); + } + return true; +} diff --git a/ndb/src/common/debugger/signaldata/FsOpenReq.cpp b/ndb/src/common/debugger/signaldata/FsOpenReq.cpp new file mode 100644 index 00000000000..31d351a8a84 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FsOpenReq.cpp @@ -0,0 +1,59 @@ +/* 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 <signaldata/FsOpenReq.hpp> + +bool +printFSOPENREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const FsOpenReq * const sig = (FsOpenReq *) theData; + + + fprintf(output, " UserReference: H\'%.8x, userPointer: H\'%.8x\n", + sig->userReference, sig->userPointer); + fprintf(output, " FileNumber[1-4]: H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + sig->fileNumber[0], sig->fileNumber[1], sig->fileNumber[2], sig->fileNumber[3]); + fprintf(output, " FileFlags: H\'%.8x ", + sig->fileFlags); + + // File open mode must be one of ReadOnly, WriteOnly or ReadWrite + const Uint32 flags = sig->fileFlags; + switch(flags & 3){ + case FsOpenReq::OM_READONLY: + fprintf(output, "Open read only"); + break; + case FsOpenReq::OM_WRITEONLY: + fprintf(output, "Open write only"); + break; + case FsOpenReq::OM_READWRITE: + fprintf(output, "Open read and write"); + break; + default: + fprintf(output, "Open mode unknown!"); + } + + if (flags & FsOpenReq::OM_CREATE) + fprintf(output, ", Create new file"); + if (flags & FsOpenReq::OM_TRUNCATE) + fprintf(output, ", Truncate existing file"); + if (flags & FsOpenReq::OM_APPEND) + fprintf(output, ", Append"); + + fprintf(output, "\n"); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp b/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp new file mode 100644 index 00000000000..ad9cb623c17 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp @@ -0,0 +1,85 @@ +/* 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 <signaldata/FsReadWriteReq.hpp> + +bool +printFSREADWRITEREQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + bool ret = true; + + const FsReadWriteReq * const sig = (FsReadWriteReq *) theData; + + fprintf(output, " UserPointer: %d\n", sig->userPointer); + fprintf(output, " FilePointer: %d\n", sig->filePointer); + fprintf(output, " UserReference: H\'%.8x", sig->userReference); + + fprintf(output, " Operation flag: H\'%.8x (", sig->operationFlag); + if (sig->getSyncFlag(sig->operationFlag) == true) + fprintf(output, "Sync,"); + else + fprintf(output, "No sync,"); + + fprintf(output, " Format="); + switch(sig->getFormatFlag(sig->operationFlag)){ + case FsReadWriteReq::fsFormatListOfPairs: + fprintf(output, "List of pairs)\n"); + break; + case FsReadWriteReq::fsFormatArrayOfPages: + fprintf(output, "Array of pages)\n"); + break; + case FsReadWriteReq::fsFormatListOfMemPages: + fprintf(output, "List of mem pages)\n"); + break; + default: + fprintf(output, "fsFormatMax not handled\n"); + ret = false; + break; + } + + fprintf(output, " varIndex: %d\n", + sig->varIndex); + fprintf(output, " numberOfPages: %d\n", + sig->numberOfPages); + fprintf(output, " pageData: "); + + + switch(sig->getFormatFlag(sig->operationFlag)){ + case FsReadWriteReq::fsFormatListOfPairs: + for (unsigned int i = 0; i < sig->numberOfPages*2; i += 2){ + fprintf(output, " H\'%.8x, H\'%.8x\n", sig->data.pageData[i], + sig->data.pageData[i + 1]); + } + break; + case FsReadWriteReq::fsFormatArrayOfPages: + fprintf(output, " H\'%.8x, H\'%.8x\n", sig->data.pageData[0], + sig->data.pageData[1]); + break; + case FsReadWriteReq::fsFormatListOfMemPages: + for (unsigned int i = 0; i < (sig->numberOfPages + 1); i++){ + fprintf(output, " H\'%.8x, ", sig->data.pageData[i]); + } + break; + default: + fprintf(output, "Impossible event\n"); + } + + fprintf(output, "\n"); + return ret; +} diff --git a/ndb/src/common/debugger/signaldata/FsRef.cpp b/ndb/src/common/debugger/signaldata/FsRef.cpp new file mode 100644 index 00000000000..ccf3d6da9c8 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/FsRef.cpp @@ -0,0 +1,75 @@ +/* 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 <signaldata/FsRef.hpp> + +bool +printFSREF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + bool ret = true; + + const FsRef * const sig = (FsRef *) theData; + + fprintf(output, " UserPointer: %d\n", + sig->userPointer); + + fprintf(output, " ErrorCode: %d, ", sig->errorCode); + switch (sig->getErrorCode(sig->errorCode)){ + case FsRef::fsErrNone: + fprintf(output, "No error"); + break; + case FsRef::fsErrHardwareFailed: + fprintf(output, "Hardware failure!"); + break; + case FsRef::fsErrUserError: + fprintf(output, "User error!"); + break; + case FsRef::fsErrEnvironmentError: + fprintf(output, "Environment error!"); + break; + case FsRef::fsErrTemporaryNotAccessible: + fprintf(output, "Temporary not accesible!"); + break; + case FsRef::fsErrNoSpaceLeftOnDevice: + fprintf(output, "No space left on device!"); + break; + case FsRef::fsErrPermissionDenied: + fprintf(output, "Permission denied!"); + break; + case FsRef::fsErrInvalidParameters: + fprintf(output, "Invalid parameters!"); + break; + case FsRef::fsErrNoMoreResources: + fprintf(output, "No more resources!"); + break; + case FsRef::fsErrFileDoesNotExist: + fprintf(output, "File does not exist!"); + break; + + case FsRef::fsErrUnknown: + default: + fprintf(output, "Unknown!"); + ret = false; + break; + } + fprintf(output, "\n"); + fprintf(output, " OS ErrorCode: %d \n", sig->osErrorCode); + + return ret; +} diff --git a/ndb/src/common/debugger/signaldata/GCPSave.cpp b/ndb/src/common/debugger/signaldata/GCPSave.cpp new file mode 100644 index 00000000000..7566f004bfd --- /dev/null +++ b/ndb/src/common/debugger/signaldata/GCPSave.cpp @@ -0,0 +1,78 @@ +/* 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 <signaldata/GCPSave.hpp> +#include <RefConvert.hpp> + +bool +printGCPSaveReq(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 receiverBlockNo){ + + GCPSaveReq * sr = (GCPSaveReq*)theData; + + fprintf(output, " dihBlockRef = (%d, %d) dihPtr = %d gci = %d\n", + refToBlock(sr->dihBlockRef), refToNode(sr->dihBlockRef), + sr->dihPtr, sr->gci); + + return true; +} + +bool +printGCPSaveRef(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 receiverBlockNo){ + + GCPSaveRef * sr = (GCPSaveRef*)theData; + + fprintf(output, " nodeId = %d dihPtr = %d gci = %d reason: ", + sr->nodeId, + sr->dihPtr, sr->gci); + + switch(sr->errorCode){ + case GCPSaveRef::NodeShutdownInProgress: + fprintf(output, "NodeShutdownInProgress\n"); + break; + case GCPSaveRef::FakedSignalDueToNodeFailure: + fprintf(output, "FakedSignalDueToNodeFailure\n"); + break; + default: + fprintf(output, "Unknown reason: %d\n", sr->errorCode); + return false; + } + + return true; +} + +bool +printGCPSaveConf(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 receiverBlockNo){ + + GCPSaveConf * sr = (GCPSaveConf*)theData; + + fprintf(output, " nodeId = %d dihPtr = %d gci = %d\n", + sr->nodeId, + sr->dihPtr, sr->gci); + + return true; +} + + diff --git a/ndb/src/common/debugger/signaldata/IndxAttrInfo.cpp b/ndb/src/common/debugger/signaldata/IndxAttrInfo.cpp new file mode 100755 index 00000000000..2ef5feaada7 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/IndxAttrInfo.cpp @@ -0,0 +1,31 @@ +/* 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 <signaldata/IndxAttrInfo.hpp> + +bool +printINDXATTRINFO(FILE * output, const Uint32 * theData, Uint32 len, + Uint16 receiverBlockNo) +{ +// const IndxAttrInfo * const sig = (IndxAttrInfo *) theData; + + Uint32 i = 0; + while (i < len) + fprintf(output, " H\'%.8x", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/IndxKeyInfo.cpp b/ndb/src/common/debugger/signaldata/IndxKeyInfo.cpp new file mode 100755 index 00000000000..6fe5567188d --- /dev/null +++ b/ndb/src/common/debugger/signaldata/IndxKeyInfo.cpp @@ -0,0 +1,31 @@ +/* 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 <signaldata/IndxKeyInfo.hpp> + +bool +printINDXKEYINFO(FILE * output, const Uint32 * theData, Uint32 len, + Uint16 receiverBlockNo) +{ +// const IndxKeyInfo * const sig = (IndxKeyInfo *) theData; + + Uint32 i = 0; + while (i < len) + fprintf(output, " H\'%.8x", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/LCP.cpp b/ndb/src/common/debugger/signaldata/LCP.cpp new file mode 100644 index 00000000000..825659d13b3 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/LCP.cpp @@ -0,0 +1,88 @@ +/* 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 <RefConvert.hpp> +#include <signaldata/LCP.hpp> +#include <DebuggerNames.hpp> + +bool +printSTART_LCP_REQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + const StartLcpReq * const sig = (StartLcpReq *) theData; + + char buf1[sig->participatingDIH.TextLength+1], buf2[sig->participatingLQH.TextLength+1]; + fprintf(output, + " Sender: %d LcpId: %d\n" + " ParticipatingDIH = %s\n" + " ParticipatingLQH = %s\n", + refToNode(sig->senderRef), sig->lcpId, + sig->participatingDIH.getText(buf1), + sig->participatingLQH.getText(buf2)); + + return true; +} + +bool +printSTART_LCP_CONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + const StartLcpConf * const sig = (StartLcpConf *) theData; + + fprintf(output, " Sender: %d LcpId: %d\n", + refToNode(sig->senderRef), sig->lcpId); + + return true; +} + +bool +printLCP_FRAG_ORD(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + const LcpFragOrd * const sig = (LcpFragOrd *) theData; + + fprintf(output, " LcpId: %d LcpNo: %d Table: %d Fragment: %d\n", + sig->lcpId, sig->lcpNo, sig->tableId, sig->fragmentId); + + fprintf(output, " KeepGCI: %d LastFragmentFlag: %d\n", + sig->keepGci, sig->lastFragmentFlag); + return true; +} + +bool +printLCP_FRAG_REP(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + const LcpFragRep * const sig = (LcpFragRep *) theData; + + fprintf(output, " LcpId: %d LcpNo: %d NodeId: %d Table: %d Fragment: %d\n", + sig->lcpId, sig->lcpNo, sig->nodeId, sig->tableId, sig->fragId); + fprintf(output, " Max GCI Started: %d Max GCI Completed: %d\n", + sig->maxGciStarted, sig->maxGciCompleted); + return true; +} + +bool +printLCP_COMPLETE_REP(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo){ + + const LcpCompleteRep * const sig = (LcpCompleteRep *) theData; + + fprintf(output, " LcpId: %d NodeId: %d Block: %s\n", + sig->lcpId, sig->nodeId, getBlockName(sig->blockNo)); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/LqhFrag.cpp b/ndb/src/common/debugger/signaldata/LqhFrag.cpp new file mode 100644 index 00000000000..6d727959a67 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/LqhFrag.cpp @@ -0,0 +1,61 @@ +/* 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 <signaldata/LqhFrag.hpp> + +bool +printLQH_FRAG_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 recB){ + LqhFragReq* sig = (LqhFragReq*)theData; + + fprintf(output, " senderData: %d senderRef: %x", + sig->senderData, sig->senderRef); + fprintf(output, " tableId: %d fragmentId: %d tableType: %d", + sig->tableId, sig->fragmentId, sig->tableType); + if (sig->primaryTableId == RNIL) + fprintf(output, " primaryTableId: RNIL\n"); + else + fprintf(output, " primaryTableId: %d\n", sig->primaryTableId); + fprintf(output, " localKeyLength: %d maxLoadFactor: %d minLoadFactor: %d\n", + sig->localKeyLength, sig->maxLoadFactor, sig->minLoadFactor); + fprintf(output, " kValue: %d lh3DistrBits: %d lh3PageBits: %d\n", + sig->kValue, sig->lh3DistrBits, sig->lh3PageBits); + + fprintf(output, " noOfAttributes: %d noOfNullAttributes: %d keyLength: %d\n", + sig->noOfAttributes, sig->noOfNullAttributes, sig->keyLength); + + fprintf(output, " noOfPagesToPreAllocate: %d schemaVersion: %d nextLCP: %d\n", + sig->noOfPagesToPreAllocate, sig->schemaVersion, sig->nextLCP); + + return true; +} +bool +printLQH_FRAG_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 rec){ + LqhFragConf* sig = (LqhFragConf*)theData; + + fprintf(output, " senderData: %d lqhFragPtr: %d\n", + sig->senderData, sig->lqhFragPtr); + return true; +} + +bool +printLQH_FRAG_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 rec){ + LqhFragRef* sig = (LqhFragRef*)theData; + + fprintf(output, " senderData: %d errorCode: %d\n", + sig->senderData, sig->errorCode); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/LqhKey.cpp b/ndb/src/common/debugger/signaldata/LqhKey.cpp new file mode 100644 index 00000000000..2796437fd8b --- /dev/null +++ b/ndb/src/common/debugger/signaldata/LqhKey.cpp @@ -0,0 +1,161 @@ +/* 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 <signaldata/LqhKey.hpp> + +bool +printLQHKEYREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const LqhKeyReq * const sig = (LqhKeyReq *) theData; + + fprintf(output, + " ClientPtr = H\'%.8x hashValue = H\'%.8x tcBlockRef = H\'%.8x\n" + " transId1 = H\'%.8x transId2 = H\'%.8x savePointId = H\'%.8x\n", + sig->clientConnectPtr, // DATA 0 + sig->hashValue, // DATA 2 + sig->tcBlockref, // DATA 4 + sig->transId1, // DATA 7 + sig->transId2, // DATA 8 + sig->savePointId // DATA 9 + ); + + const Uint32 reqInfo = sig->requestInfo; + const Uint32 attrLen = sig->attrLen; + + fprintf(output, + " Op: %d Lock: %d Flags: ", + LqhKeyReq::getOperation(reqInfo), + LqhKeyReq::getLockType(reqInfo)); + if(LqhKeyReq::getSimpleFlag(reqInfo)) + fprintf(output, "Simple "); + if(LqhKeyReq::getDirtyFlag(reqInfo)) + fprintf(output, "Dirty "); + if(LqhKeyReq::getInterpretedFlag(reqInfo)) + fprintf(output, "Interpreted "); + if(LqhKeyReq::getScanTakeOverFlag(attrLen)) + fprintf(output, "ScanTakeOver "); + if(LqhKeyReq::getMarkerFlag(reqInfo)) + fprintf(output, "CommitAckMarker "); + + fprintf(output, "ScanInfo/noFiredTriggers: H\'%x\n", sig->scanInfo); + + fprintf(output, + " AttrLen: %d (%d in this) KeyLen: %d TableId: %d SchemaVer: %d\n", + LqhKeyReq::getAttrLen(attrLen), + LqhKeyReq::getAIInLqhKeyReq(reqInfo), + LqhKeyReq::getKeyLen(reqInfo), + LqhKeyReq::getTableId(sig->tableSchemaVersion), + LqhKeyReq::getSchemaVersion(sig->tableSchemaVersion)); + + fprintf(output, + " FragId: %d ReplicaNo: %d LastReplica: %d NextNodeId: %d\n", + LqhKeyReq::getFragmentId(sig->fragmentData), + LqhKeyReq::getSeqNoReplica(reqInfo), + LqhKeyReq::getLastReplicaNo(reqInfo), + LqhKeyReq::getNextReplicaNodeId(sig->fragmentData)); + + bool printed = false; + Uint32 nextPos = LqhKeyReq::getApplicationAddressFlag(reqInfo) << 1; + if(nextPos != 0){ + fprintf(output, + " ApiRef: H\'%.8x ApiOpRef: H\'%.8x", + sig->variableData[0], + sig->variableData[1]); + printed = true; + } + + if(LqhKeyReq::getSameClientAndTcFlag(reqInfo)){ + fprintf(output, " TcOpRec: H\'%.8x", sig->variableData[nextPos]); + nextPos++; + printed = true; + } + + Uint32 tmp = LqhKeyReq::getLastReplicaNo(reqInfo) - + LqhKeyReq::getSeqNoReplica(reqInfo); + if(tmp > 1){ + NodeId node2 = sig->variableData[nextPos] & 0xffff; + NodeId node3 = sig->variableData[nextPos] >> 16; + fprintf(output, " NextNodeId2: %d NextNodeId3: %d", + node2, node3); + nextPos ++; + printed = true; + } + if(printed) + fprintf(output, "\n"); + + printed = false; + if(LqhKeyReq::getStoredProcFlag(attrLen)){ + fprintf(output, " StoredProcId: %d", sig->variableData[nextPos]); + nextPos++; + printed = true; + } + + if(LqhKeyReq::getReturnedReadLenAIFlag(reqInfo)){ + fprintf(output, " ReturnedReadLenAI: %d", + sig->variableData[nextPos]); + nextPos++; + printed = true; + } + + const UintR keyLen = LqhKeyReq::getKeyLen(reqInfo); + if(keyLen > 0){ + fprintf(output, " KeyInfo: "); + for(UintR i = 0; i<keyLen && i<4; i++, nextPos++) + fprintf(output, "H\'%.8x ", sig->variableData[nextPos]); + fprintf(output, "\n"); + } + + if(!LqhKeyReq::getInterpretedFlag(reqInfo)){ + fprintf(output, " AttrInfo: "); + for(int i = 0; i<LqhKeyReq::getAIInLqhKeyReq(reqInfo); i++, nextPos++) + fprintf(output, "H\'%.8x ", sig->variableData[nextPos]); + fprintf(output, "\n"); + } else { + fprintf(output, " InitialReadSize: %d InterpretedSize: %d " + "FinalUpdateSize: %d FinalReadSize: %d SubroutineSize: %d\n", + sig->variableData[nextPos+0], sig->variableData[nextPos+1], + sig->variableData[nextPos+2], sig->variableData[nextPos+3], + sig->variableData[nextPos+4]); + nextPos += 5; + } + return true; +} + +bool +printLQHKEYCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ +// const LqhKeyConf * const sig = (LqhKeyConf *) theData; + + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} + +bool +printLQHKEYREF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ +// const LqhKeyRef * const sig = (LqhKeyRef *) theData; + + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/LqhTrans.cpp b/ndb/src/common/debugger/signaldata/LqhTrans.cpp new file mode 100644 index 00000000000..8282530cae6 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/LqhTrans.cpp @@ -0,0 +1,40 @@ +/* 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 <signaldata/LqhTransConf.hpp> + +bool +printLQH_TRANSCONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const LqhTransConf * const sig = (LqhTransConf *)theData; + fprintf(output, " tcRef: %x\n", sig->tcRef); + fprintf(output, " lqhNodeId: %x\n", sig->lqhNodeId); + fprintf(output, " operationStatus: %x\n", sig->operationStatus); + fprintf(output, " transId1: %x\n", sig->transId1); + fprintf(output, " transId2: %x\n", sig->transId2); + fprintf(output, " apiRef: %x\n", sig->apiRef); + fprintf(output, " apiOpRec: %x\n", sig->apiOpRec); + fprintf(output, " lqhConnectPtr: %x\n", sig->lqhConnectPtr); + fprintf(output, " oldTcOpRec: %x\n", sig->oldTcOpRec); + fprintf(output, " requestInfo: %x\n", sig->requestInfo); + fprintf(output, " gci: %x\n", sig->gci); + fprintf(output, " nextNodeId1: %x\n", sig->nextNodeId1); + fprintf(output, " nextNodeId2: %x\n", sig->nextNodeId2); + fprintf(output, " nextNodeId3: %x\n", sig->nextNodeId3); + fprintf(output, " tableId: %x\n", sig->tableId); + return true; +} + diff --git a/ndb/src/common/debugger/signaldata/Makefile b/ndb/src/common/debugger/signaldata/Makefile new file mode 100644 index 00000000000..5e86aaf97c0 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/Makefile @@ -0,0 +1,32 @@ +include .defs.mk + +TYPE := ndbapi + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := signaldataprint + +SOURCES = TcKeyReq.cpp TcKeyConf.cpp TcKeyRef.cpp \ + TcRollbackRep.cpp \ + TupKey.cpp TupCommit.cpp LqhKey.cpp \ + FsOpenReq.cpp FsCloseReq.cpp FsRef.cpp FsConf.cpp FsReadWriteReq.cpp\ + SignalDataPrint.cpp SignalNames.cpp \ + ContinueB.cpp DihContinueB.cpp NdbfsContinueB.cpp \ + CloseComReqConf.cpp PackedSignal.cpp PrepFailReqRef.cpp \ + GCPSave.cpp DictTabInfo.cpp \ + AlterTable.cpp AlterTab.cpp \ + CreateTrig.cpp AlterTrig.cpp DropTrig.cpp \ + FireTrigOrd.cpp TrigAttrInfo.cpp \ + CreateIndx.cpp AlterIndx.cpp DropIndx.cpp TcIndx.cpp \ + IndxKeyInfo.cpp IndxAttrInfo.cpp \ + FsAppendReq.cpp ScanTab.cpp \ + BackupImpl.cpp BackupSignalData.cpp \ + UtilSequence.cpp UtilPrepare.cpp UtilDelete.cpp UtilExecute.cpp \ + LqhFrag.cpp DropTab.cpp PrepDropTab.cpp LCP.cpp MasterLCP.cpp \ + CopyGCI.cpp SystemError.cpp StartRec.cpp NFCompleteRep.cpp \ + FailRep.cpp DisconnectRep.cpp SignalDroppedRep.cpp \ + SumaImpl.cpp NdbSttor.cpp CreateFragmentation.cpp \ + UtilLock.cpp TuxMaint.cpp TupAccess.cpp AccLock.cpp \ + LqhTrans.cpp + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/src/common/debugger/signaldata/MasterLCP.cpp b/ndb/src/common/debugger/signaldata/MasterLCP.cpp new file mode 100644 index 00000000000..aa30404524f --- /dev/null +++ b/ndb/src/common/debugger/signaldata/MasterLCP.cpp @@ -0,0 +1,87 @@ +/* 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 <signaldata/MasterLCP.hpp> +#include <RefConvert.hpp> + +static +void +print(char *buf, size_t buf_len, MasterLCPConf::State s){ + switch(s){ + case MasterLCPConf::LCP_STATUS_IDLE: + snprintf(buf, buf_len, "LCP_STATUS_IDLE"); + break; + case MasterLCPConf::LCP_STATUS_ACTIVE: + snprintf(buf, buf_len, "LCP_STATUS_ACTIVE"); + break; + case MasterLCPConf::LCP_TAB_COMPLETED: + snprintf(buf, buf_len, "LCP_TAB_COMPLETED"); + break; + case MasterLCPConf::LCP_TAB_SAVED: + snprintf(buf, buf_len, "LCP_TAB_SAVED"); + break; + } +} + +NdbOut & +operator<<(NdbOut& out, const MasterLCPConf::State& s){ + static char buf[255]; + print(buf, sizeof(buf), s); + out << buf; + return out; +} + +bool +printMASTER_LCP_CONF(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + + MasterLCPConf * sig = (MasterLCPConf *)&theData[0]; + + static char buf[255]; + print(buf, sizeof(buf), (MasterLCPConf::State)sig->lcpState); + fprintf(output, " senderNode=%d failedNode=%d SenderState=%s\n", + sig->senderNodeId, sig->failedNodeId, buf); + return true; +} + +bool +printMASTER_LCP_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + + MasterLCPReq * sig = (MasterLCPReq *)&theData[0]; + + fprintf(output, " masterRef=(node=%d, block=%d), failedNode=%d\n", + refToNode(sig->masterRef), refToBlock(sig->masterRef), + sig->failedNodeId); + return true; +} + +bool +printMASTER_LCP_REF(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + + MasterLCPRef * sig = (MasterLCPRef *)&theData[0]; + fprintf(output, " senderNode=%d failedNode=%d\n", + sig->senderNodeId, sig->failedNodeId); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/NFCompleteRep.cpp b/ndb/src/common/debugger/signaldata/NFCompleteRep.cpp new file mode 100644 index 00000000000..20f7ea99871 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/NFCompleteRep.cpp @@ -0,0 +1,44 @@ +/* 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 <DebuggerNames.hpp> +#include <signaldata/NFCompleteRep.hpp> + +bool +printNF_COMPLETE_REP(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + + NFCompleteRep * sig = (NFCompleteRep*)theData; + const char * who = getBlockName(sig->blockNo, 0); + + if(who == 0){ + fprintf(output, + " Node: %d has completed failure of node %d\n", + sig->nodeId, sig->failedNodeId); + } else { + fprintf(output, + " Node: %d block: %s has completed failure of node %d\n", + sig->nodeId, who, sig->failedNodeId); + } + + fprintf(output, "Sent from line: %d\n", + sig->from); + + return true; +}; diff --git a/ndb/src/common/debugger/signaldata/NdbSttor.cpp b/ndb/src/common/debugger/signaldata/NdbSttor.cpp new file mode 100644 index 00000000000..9fd081313be --- /dev/null +++ b/ndb/src/common/debugger/signaldata/NdbSttor.cpp @@ -0,0 +1,50 @@ +/* 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 <signaldata/NdbSttor.hpp> + +bool +printNDB_STTOR(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const NdbSttor * const sig = (NdbSttor *)theData; + fprintf(output, " senderRef: %x\n", sig->senderRef); + fprintf(output, " nodeId: %x\n", sig->nodeId); + fprintf(output, " internalStartPhase: %x\n", sig->internalStartPhase); + fprintf(output, " typeOfStart: %x\n", sig->typeOfStart); + fprintf(output, " masterNodeId: %x\n", sig->masterNodeId); + + int left = len - NdbSttor::SignalLength; + if(left > 0){ + fprintf(output, " config: "); + for(int i = 0; i<left; i++){ + fprintf(output, "%x ", sig->config[i]); + if(((i + 1) % 7) == 0 && (i+1) < left){ + fprintf(output, "\n config: "); + } + } + fprintf(output, "\n"); + } + return true; +} + +bool +printNDB_STTORRY(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const NdbSttorry * const sig = (NdbSttorry *)theData; + fprintf(output, " senderRef: %x\n", sig->senderRef); + return true; +} + diff --git a/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp b/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp new file mode 100644 index 00000000000..b3c7a61136e --- /dev/null +++ b/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp @@ -0,0 +1,38 @@ +/* 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 <signaldata/NdbfsContinueB.hpp> + +bool +printCONTINUEB_NDBFS(FILE * output, const Uint32 * theData, Uint32 len){ + + switch (theData[0]) { + case NdbfsContinueB::ZSCAN_MEMORYCHANNEL_10MS_DELAY: + fprintf(output, " Scanning the memory channel every 10ms\n"); + return true; + break; + case NdbfsContinueB::ZSCAN_MEMORYCHANNEL_NO_DELAY: + fprintf(output, " Scanning the memory channel again with no delay\n"); + return true; + break; + default: + fprintf(output, " Default system error lab...\n"); + return false; + break; + }//switch + return false; +} diff --git a/ndb/src/common/debugger/signaldata/PackedSignal.cpp b/ndb/src/common/debugger/signaldata/PackedSignal.cpp new file mode 100644 index 00000000000..f0f7aee74e4 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/PackedSignal.cpp @@ -0,0 +1,104 @@ +/* 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 <signaldata/PackedSignal.hpp> +#include <signaldata/LqhKey.hpp> +#include <debugger/DebuggerNames.hpp> + +bool +printPACKED_SIGNAL(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + fprintf(output, "--------- Begin Packed Signals --------\n"); + // Print each signal separately + for (i = 0; i < len;) { + switch (PackedSignal::getSignalType(theData[i])) { + case ZCOMMIT: { + Uint32 signalLength = 4; + fprintf(output, "--------------- Signal ----------------\n"); + fprintf(output, "r.bn: %u \"%s\", length: %u \"COMMIT\"\n", + receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength); + fprintf(output, "Signal data: "); + for(Uint32 j = 0; j < signalLength; j++) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + break; + } + case ZCOMPLETE: { + Uint32 signalLength = 3; + fprintf(output, "--------------- Signal ----------------\n"); + fprintf(output, "r.bn: %u \"%s\", length: %u \"COMPLETE\"\n", + receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength); + fprintf(output, "Signal data: "); + for(Uint32 j = 0; j < signalLength; j++) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + break; + } + case ZCOMMITTED: { + Uint32 signalLength = 3; + fprintf(output, "--------------- Signal ----------------\n"); + fprintf(output, "r.bn: %u \"%s\", length: %u \"COMMITTED\"\n", + receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength); + fprintf(output, "Signal data: "); + for(Uint32 j = 0; j < signalLength; j++) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + break; + } + case ZCOMPLETED: { + Uint32 signalLength = 3; + fprintf(output, "--------------- Signal ----------------\n"); + fprintf(output, "r.bn: %u \"%s\", length: %u \"COMPLETED\"\n", + receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength); + fprintf(output, "Signal data: "); + for(Uint32 j = 0; j < signalLength; j++) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + break; + } + case ZLQHKEYCONF: { + Uint32 signalLength = LqhKeyConf::SignalLength; + + fprintf(output, "--------------- Signal ----------------\n"); + fprintf(output, "r.bn: %u \"%s\", length: %u \"LQHKEYCONF\"\n", + receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength); + printLQHKEYCONF(output, theData + i, signalLength, receiverBlockNo); + i += signalLength; + break; + } + case ZREMOVE_MARKER: { + Uint32 signalLength = 2; + fprintf(output, "--------------- Signal ----------------\n"); + fprintf(output, "r.bn: %u \"%s\", length: %u \"REMOVE_MARKER\"\n", + receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength); + fprintf(output, "Signal data: "); + i++; // Skip first word! + for(Uint32 j = 0; j < signalLength; j++) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + break; + } + default: + fprintf(output, "Unknown signal type\n"); + } + }//for + fprintf(output, "--------- End Packed Signals ----------\n"); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/PrepDropTab.cpp b/ndb/src/common/debugger/signaldata/PrepDropTab.cpp new file mode 100644 index 00000000000..59001bcd6f6 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/PrepDropTab.cpp @@ -0,0 +1,50 @@ +/* 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 <signaldata/PrepDropTab.hpp> + +bool +printPREP_DROP_TAB_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const PrepDropTabReq * const sig = (PrepDropTabReq *) theData; + + fprintf(output, + " senderRef: %x senderData: %d TableId: %d\n", + sig->senderRef, sig->senderData, sig->tableId); + return true; +} + +bool printPREP_DROP_TAB_CONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const PrepDropTabConf * const sig = (PrepDropTabConf *) theData; + + fprintf(output, + " senderRef: %x senderData: %d TableId: %d\n", + sig->senderRef, sig->senderData, sig->tableId); + + return true; +} + +bool printPREP_DROP_TAB_REF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo) +{ + const PrepDropTabRef * const sig = (PrepDropTabRef *) theData; + + fprintf(output, + " senderRef: %x senderData: %d TableId: %d errorCode: %d\n", + sig->senderRef, sig->senderData, sig->tableId, sig->errorCode); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/PrepFailReqRef.cpp b/ndb/src/common/debugger/signaldata/PrepFailReqRef.cpp new file mode 100644 index 00000000000..f3b4b97f0fd --- /dev/null +++ b/ndb/src/common/debugger/signaldata/PrepFailReqRef.cpp @@ -0,0 +1,53 @@ +/* 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 <NdbStdio.h> +#include <kernel_types.h> +#include <BlockNumbers.h> +#include <signaldata/PrepFailReqRef.hpp> + +bool +printPREPFAILREQREF(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 receiverBlockNo){ + + PrepFailReqRef * cc = (PrepFailReqRef*)theData; + + fprintf(output, " xxxBlockRef = (%d, %d) failNo = %d noOfNodes = %d\n", + refToBlock(cc->xxxBlockRef), refToNode(cc->xxxBlockRef), + cc->failNo, cc->noOfNodes); + + int hits = 0; + fprintf(output, " Nodes: "); + for(int i = 0; i<MAX_NODES; i++){ + if(NodeBitmask::get(cc->theNodes, i)){ + hits++; + fprintf(output, " %d", i); + } + if(hits == 16){ + fprintf(output, "\n Nodes: "); + hits = 0; + } + } + if(hits != 0) + fprintf(output, "\n"); + + return true; +} + + diff --git a/ndb/src/common/debugger/signaldata/ScanTab.cpp b/ndb/src/common/debugger/signaldata/ScanTab.cpp new file mode 100644 index 00000000000..b4246059f6a --- /dev/null +++ b/ndb/src/common/debugger/signaldata/ScanTab.cpp @@ -0,0 +1,163 @@ +/* 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 <BlockNumbers.h> +#include <signaldata/ScanTab.hpp> +#include <signaldata/ScanFrag.hpp> + +bool +printSCANTABREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const ScanTabReq * const sig = (ScanTabReq *) theData; + + const UintR requestInfo = sig->requestInfo; + + fprintf(output, " apiConnectPtr: H\'%.8x\n", + sig->apiConnectPtr); + fprintf(output, " requestInfo: H\'%.8x:\n", requestInfo); + fprintf(output, " Parallellism: %u, LockMode: %u, Holdlock: %u, RangeScan: %u\n", + sig->getParallelism(requestInfo), sig->getLockMode(requestInfo), sig->getHoldLockFlag(requestInfo), sig->getRangeScanFlag(requestInfo)); + + fprintf(output, " attrLen: %d, tableId: %d, tableSchemaVer: %d\n", + sig->attrLen, sig->tableId, sig->tableSchemaVersion); + + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x) storedProcId: H\'%.8x\n", + sig->transId1, sig->transId2, sig->storedProcId); + + fprintf(output, " OperationPtr(s):\n"); + for(int i = 0; i<16; i=i+4){ + fprintf(output, " H\'%.8x, H\'%.8x, H\'%.8x, H\'%.8x\n", + sig->apiOperationPtr[i], sig->apiOperationPtr[i+1], + sig->apiOperationPtr[i+2], sig->apiOperationPtr[i+3]); + } + return false; +} + +bool +printSCANTABCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const ScanTabConf * const sig = (ScanTabConf *) theData; + + const UintR requestInfo = sig->requestInfo; + + fprintf(output, " apiConnectPtr: H\'%.8x\n", + sig->apiConnectPtr); + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n", + sig->transId1, sig->transId2); + + fprintf(output, " requestInfo: H\'%.8x(Operations: %u, ScanStatus: %u(\"", + requestInfo, sig->getOperations(requestInfo), sig->getScanStatus(requestInfo)); + switch(sig->getScanStatus(requestInfo)){ + case 0: + fprintf(output, "ZFALSE"); + break; + case 1: + fprintf(output, "ZTRUE"); + break; + case 2: + fprintf(output, "ZCLOSED"); + break; + default: + fprintf(output, "UNKNOWN"); + break; + } + fprintf(output, "\"))\n"); +#if 0 + fprintf(output, " Operation(s):\n"); + for(int i = 0; i<16; i++){ + fprintf(output, " [%.2u]ix=%d l=%.2d,", + i, sig->getIdx(sig->operLenAndIdx[i]), sig->getLen(sig->operLenAndIdx[i])); + if (((i+1) % 4) == 0) + fprintf(output, "\n"); + } +#endif + return false; +} + +bool +printSCANTABINFO(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const ScanTabInfo * const sig = (ScanTabInfo *) theData; + + fprintf(output, " apiConnectPtr: H\'%.8x\n", + sig->apiConnectPtr); + + fprintf(output, " Operation(s):\n"); + for(int i = 0; i<16; i++){ + fprintf(output, " [%.2u]ix=%d l=%.2d,", + i, sig->getIdx(sig->operLenAndIdx[i]), sig->getLen(sig->operLenAndIdx[i])); + if (((i+1) % 4) == 0) + fprintf(output, "\n"); + } + + return false; +} + +bool +printSCANTABREF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const ScanTabRef * const sig = (ScanTabRef *) theData; + + fprintf(output, " apiConnectPtr: H\'%.8x\n", + sig->apiConnectPtr); + + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n", + sig->transId1, sig->transId2); + + fprintf(output, " Errorcode: %u\n", sig->errorCode); + + // fprintf(output, " sendScanNextReqWithClose: %u\n", sig->sendScanNextReqWithClose); + return false; +} + + +bool +printSCANFRAGNEXTREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + const ScanFragNextReq * const sig = (ScanFragNextReq *) theData; + + fprintf(output, " senderData: H\'%.8x\n", + sig->senderData); + + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n", + sig->transId1, sig->transId2); + + fprintf(output, " Close scan: %u\n", sig->closeFlag); + + return false; +} + +bool +printSCANNEXTREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + if(receiverBlockNo == DBTC){ + const ScanNextReq * const sig = (ScanNextReq *) theData; + + fprintf(output, " aipConnectPtr: H\'%.8x\n", + sig->apiConnectPtr); + + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n", + sig->transId1, sig->transId2); + + fprintf(output, " Stop this scan: %u\n", sig->stopScan); + } + if (receiverBlockNo == DBLQH){ + return printSCANFRAGNEXTREQ(output, theData, len, receiverBlockNo); + } + return false; +} + diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp new file mode 100644 index 00000000000..2236d0c0af1 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp @@ -0,0 +1,254 @@ +/* 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 "GlobalSignalNumbers.h" +#include "signaldata/SignalDataPrint.hpp" +#include "signaldata/TcKeyReq.hpp" +#include "signaldata/TcKeyConf.hpp" +#include "signaldata/TcKeyRef.hpp" +#include "signaldata/LqhKey.hpp" +#include "signaldata/TupKey.hpp" +#include "signaldata/TupCommit.hpp" +#include "signaldata/FsOpenReq.hpp" +#include "signaldata/FsCloseReq.hpp" +#include "signaldata/FsReadWriteReq.hpp" +#include "signaldata/FsRef.hpp" +#include "signaldata/FsConf.hpp" +#include "signaldata/CloseComReqConf.hpp" +#include "signaldata/PackedSignal.hpp" +#include "signaldata/PrepFailReqRef.hpp" +#include "signaldata/DictTabInfo.hpp" +#include "signaldata/AlterTable.hpp" +#include "signaldata/AlterTab.hpp" +#include "signaldata/CreateTrig.hpp" +#include "signaldata/AlterTrig.hpp" +#include "signaldata/DropTrig.hpp" +#include "signaldata/FireTrigOrd.hpp" +#include "signaldata/TrigAttrInfo.hpp" +#include "signaldata/CreateIndx.hpp" +#include "signaldata/AlterIndx.hpp" +#include "signaldata/DropIndx.hpp" +#include "signaldata/TcIndx.hpp" +#include "signaldata/IndxKeyInfo.hpp" +#include "signaldata/IndxAttrInfo.hpp" +#include <signaldata/FsAppendReq.hpp> +#include <signaldata/BackupSignalData.hpp> +#include <signaldata/BackupImpl.hpp> +#include <signaldata/UtilSequence.hpp> +#include <signaldata/UtilPrepare.hpp> +#include <signaldata/UtilExecute.hpp> +#include <signaldata/ScanTab.hpp> +#include <signaldata/LqhFrag.hpp> +#include <signaldata/LqhTransConf.hpp> +#include <signaldata/DropTab.hpp> +#include <signaldata/PrepDropTab.hpp> +#include <signaldata/LCP.hpp> +#include <signaldata/MasterLCP.hpp> +#include <signaldata/CopyGCIReq.hpp> +#include <signaldata/SystemError.hpp> +#include <signaldata/StartRec.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/SignalDroppedRep.hpp> +#include <signaldata/FailRep.hpp> +#include <signaldata/DisconnectRep.hpp> +#include <signaldata/SumaImpl.hpp> +#include <signaldata/NdbSttor.hpp> +#include <signaldata/CreateFragmentation.hpp> +#include <signaldata/UtilLock.hpp> +#include <signaldata/TuxMaint.hpp> +#include <signaldata/TupAccess.hpp> +#include <signaldata/AccLock.hpp> + +bool printCONTINUEB(FILE *, const Uint32 *, Uint32, Uint16); + +/** + * This is the register + */ +const NameFunctionPair +SignalDataPrintFunctions[] = { + { GSN_TCKEYREQ, printTCKEYREQ }, + { GSN_TCKEYCONF, printTCKEYCONF }, + { GSN_TCKEYREF, printTCKEYREF }, + { GSN_LQHKEYREQ, printLQHKEYREQ }, + { GSN_LQHKEYCONF, printLQHKEYCONF }, + { GSN_LQHKEYREF, printLQHKEYREF }, + { GSN_TUPKEYREQ, printTUPKEYREQ }, + { GSN_TUPKEYCONF, printTUPKEYCONF }, + { GSN_TUPKEYREF, printTUPKEYREF }, + { GSN_TUP_COMMITREQ, printTUPCOMMITREQ }, + { GSN_CONTINUEB, printCONTINUEB }, + { GSN_FSOPENREQ, printFSOPENREQ }, + { GSN_FSCLOSEREQ, printFSCLOSEREQ }, + { GSN_FSREADREQ, printFSREADWRITEREQ }, + { GSN_FSWRITEREQ, printFSREADWRITEREQ }, + { GSN_FSCLOSEREF, printFSREF }, + { GSN_FSOPENREF, printFSREF }, + { GSN_FSWRITEREF, printFSREF }, + { GSN_FSREADREF, printFSREF }, + { GSN_FSSYNCREF, printFSREF }, + { GSN_FSCLOSECONF, printFSCONF }, + { GSN_FSOPENCONF, printFSCONF }, + { GSN_FSWRITECONF, printFSCONF }, + { GSN_FSREADCONF, printFSCONF }, + { GSN_FSSYNCCONF, printFSCONF }, + { GSN_CLOSE_COMREQ, printCLOSECOMREQCONF }, + { GSN_CLOSE_COMCONF, printCLOSECOMREQCONF }, + { GSN_PACKED_SIGNAL, printPACKED_SIGNAL }, + { GSN_PREP_FAILREQ, printPREPFAILREQREF }, + { GSN_PREP_FAILREF, printPREPFAILREQREF }, + { GSN_ALTER_TABLE_REQ, printALTER_TABLE_REQ }, + { GSN_ALTER_TABLE_CONF, printALTER_TABLE_CONF }, + { GSN_ALTER_TABLE_REF, printALTER_TABLE_REF }, + { GSN_ALTER_TAB_REQ, printALTER_TAB_REQ }, + { GSN_ALTER_TAB_CONF, printALTER_TAB_CONF }, + { GSN_ALTER_TAB_REF, printALTER_TAB_REF }, + { GSN_CREATE_TRIG_REQ, printCREATE_TRIG_REQ }, + { GSN_CREATE_TRIG_CONF, printCREATE_TRIG_CONF }, + { GSN_CREATE_TRIG_REF, printCREATE_TRIG_REF }, + { GSN_ALTER_TRIG_REQ, printALTER_TRIG_REQ }, + { GSN_ALTER_TRIG_CONF, printALTER_TRIG_CONF }, + { GSN_ALTER_TRIG_REF, printALTER_TRIG_REF }, + { GSN_DROP_TRIG_REQ, printDROP_TRIG_REQ }, + { GSN_DROP_TRIG_CONF, printDROP_TRIG_CONF }, + { GSN_DROP_TRIG_REF, printDROP_TRIG_REF }, + { GSN_FIRE_TRIG_ORD, printFIRE_TRIG_ORD }, + { GSN_TRIG_ATTRINFO, printTRIG_ATTRINFO }, + { GSN_CREATE_INDX_REQ, printCREATE_INDX_REQ }, + { GSN_CREATE_INDX_CONF, printCREATE_INDX_CONF }, + { GSN_CREATE_INDX_REF, printCREATE_INDX_REF }, + { GSN_DROP_INDX_REQ, printDROP_INDX_REQ }, + { GSN_DROP_INDX_CONF, printDROP_INDX_CONF }, + { GSN_DROP_INDX_REF, printDROP_INDX_REF }, + { GSN_ALTER_INDX_REQ, printALTER_INDX_REQ }, + { GSN_ALTER_INDX_CONF, printALTER_INDX_CONF }, + { GSN_ALTER_INDX_REF, printALTER_INDX_REF }, + { GSN_TCINDXREQ, printTCINDXREQ }, + { GSN_TCINDXCONF, printTCINDXCONF }, + { GSN_TCINDXREF, printTCINDXREF }, + { GSN_INDXKEYINFO, printINDXKEYINFO }, + { GSN_INDXATTRINFO, printINDXATTRINFO }, + //{ GSN_TCINDXNEXTREQ, printTCINDXNEXTREQ }, + //{ GSN_TCINDEXNEXTCONF, printTCINDEXNEXTCONF }, + //{ GSN_TCINDEXNEXREF, printTCINDEXNEXREF }, + { GSN_FSAPPENDREQ, printFSAPPENDREQ }, + { GSN_BACKUP_REQ, printBACKUP_REQ }, + { GSN_BACKUP_DATA, printBACKUP_DATA }, + { GSN_BACKUP_REF, printBACKUP_REF }, + { GSN_BACKUP_CONF, printBACKUP_CONF }, + { GSN_ABORT_BACKUP_ORD, printABORT_BACKUP_ORD }, + { GSN_BACKUP_ABORT_REP, printBACKUP_ABORT_REP }, + { GSN_BACKUP_COMPLETE_REP, printBACKUP_COMPLETE_REP }, + { GSN_BACKUP_NF_COMPLETE_REP, printBACKUP_NF_COMPLETE_REP }, + { GSN_DEFINE_BACKUP_REQ, printDEFINE_BACKUP_REQ }, + { GSN_DEFINE_BACKUP_REF, printDEFINE_BACKUP_REF }, + { GSN_DEFINE_BACKUP_CONF, printDEFINE_BACKUP_CONF }, + { GSN_START_BACKUP_REQ, printSTART_BACKUP_REQ }, + { GSN_START_BACKUP_REF, printSTART_BACKUP_REF }, + { GSN_START_BACKUP_CONF, printSTART_BACKUP_CONF }, + { GSN_BACKUP_FRAGMENT_REQ, printBACKUP_FRAGMENT_REQ }, + { GSN_BACKUP_FRAGMENT_REF, printBACKUP_FRAGMENT_REF }, + { GSN_BACKUP_FRAGMENT_CONF, printBACKUP_FRAGMENT_CONF }, + { GSN_STOP_BACKUP_REQ, printSTOP_BACKUP_REQ }, + { GSN_STOP_BACKUP_REF, printSTOP_BACKUP_REF }, + { GSN_STOP_BACKUP_CONF, printSTOP_BACKUP_CONF }, + { GSN_BACKUP_STATUS_REQ, printBACKUP_STATUS_REQ }, + //{ GSN_BACKUP_STATUS_REF, printBACKUP_STATUS_REF }, + { GSN_BACKUP_STATUS_CONF, printBACKUP_STATUS_CONF }, + { GSN_UTIL_SEQUENCE_REQ, printUTIL_SEQUENCE_REQ }, + { GSN_UTIL_SEQUENCE_REF, printUTIL_SEQUENCE_REF }, + { GSN_UTIL_SEQUENCE_CONF, printUTIL_SEQUENCE_CONF }, + { GSN_UTIL_PREPARE_REQ, printUTIL_PREPARE_REQ }, + { GSN_UTIL_PREPARE_REF, printUTIL_PREPARE_REF }, + { GSN_UTIL_PREPARE_CONF, printUTIL_PREPARE_CONF }, + { GSN_UTIL_EXECUTE_REQ, printUTIL_EXECUTE_REQ }, + { GSN_UTIL_EXECUTE_REF, printUTIL_EXECUTE_REF }, + { GSN_UTIL_EXECUTE_CONF, printUTIL_EXECUTE_CONF }, + { GSN_SCAN_TABREQ, printSCANTABREQ }, + { GSN_SCAN_TABCONF, printSCANTABCONF }, + { GSN_SCAN_TABREF, printSCANTABREF }, + { GSN_SCAN_NEXTREQ, printSCANNEXTREQ }, + { GSN_LQHFRAGREQ, printLQH_FRAG_REQ }, + { GSN_LQHFRAGREF, printLQH_FRAG_REF }, + { GSN_LQHFRAGCONF, printLQH_FRAG_CONF }, + { GSN_PREP_DROP_TAB_REQ, printPREP_DROP_TAB_REQ }, + { GSN_PREP_DROP_TAB_REF, printPREP_DROP_TAB_REF }, + { GSN_PREP_DROP_TAB_CONF, printPREP_DROP_TAB_CONF }, + { GSN_DROP_TAB_REQ, printDROP_TAB_REQ }, + { GSN_DROP_TAB_REF, printDROP_TAB_REF }, + { GSN_DROP_TAB_CONF, printDROP_TAB_CONF }, + { GSN_LCP_FRAG_ORD, printLCP_FRAG_ORD }, + { GSN_LCP_FRAG_REP, printLCP_FRAG_REP }, + { GSN_LCP_COMPLETE_REP, printLCP_COMPLETE_REP }, + { GSN_START_LCP_REQ, printSTART_LCP_REQ }, + { GSN_START_LCP_CONF, printSTART_LCP_CONF }, + { GSN_MASTER_LCPREQ, printMASTER_LCP_REQ }, + { GSN_MASTER_LCPREF, printMASTER_LCP_REF }, + { GSN_MASTER_LCPCONF, printMASTER_LCP_CONF }, + { GSN_COPY_GCIREQ, printCOPY_GCI_REQ }, + { GSN_SYSTEM_ERROR, printSYSTEM_ERROR }, + { GSN_START_RECREQ, printSTART_REC_REQ }, + { GSN_START_RECCONF, printSTART_REC_CONF }, + { GSN_NF_COMPLETEREP, printNF_COMPLETE_REP }, + { GSN_SIGNAL_DROPPED_REP, printSIGNAL_DROPPED_REP }, + { GSN_FAIL_REP, printFAIL_REP }, + { GSN_DISCONNECT_REP, printDISCONNECT_REP }, + + { GSN_SUB_CREATE_REQ, printSUB_CREATE_REQ }, + //{ GSN_SUB_CREATE_REF, printSUB_CREATE_REF }, + { GSN_SUB_CREATE_CONF, printSUB_CREATE_CONF }, + { GSN_SUB_START_REQ, printSUB_START_REQ }, + { GSN_SUB_START_REF, printSUB_START_REF }, + { GSN_SUB_START_CONF, printSUB_START_CONF }, + { GSN_SUB_SYNC_REQ, printSUB_SYNC_REQ }, + { GSN_SUB_SYNC_REF, printSUB_SYNC_REF }, + { GSN_SUB_SYNC_CONF, printSUB_SYNC_CONF }, + { GSN_SUB_META_DATA, printSUB_META_DATA }, + { GSN_SUB_TABLE_DATA, printSUB_TABLE_DATA }, + { GSN_SUB_SYNC_CONTINUE_REQ, printSUB_SYNC_CONTINUE_REQ }, + { GSN_SUB_SYNC_CONTINUE_REF, printSUB_SYNC_CONTINUE_REF }, + { GSN_SUB_SYNC_CONTINUE_CONF, printSUB_SYNC_CONTINUE_CONF }, + { GSN_SUB_GCP_COMPLETE_REP, printSUB_GCP_COMPLETE_REP } + + ,{ GSN_CREATE_FRAGMENTATION_REQ, printCREATE_FRAGMENTATION_REQ } + ,{ GSN_CREATE_FRAGMENTATION_REF, printCREATE_FRAGMENTATION_REF } + ,{ GSN_CREATE_FRAGMENTATION_CONF, printCREATE_FRAGMENTATION_CONF } + + ,{ GSN_UTIL_CREATE_LOCK_REQ, printUTIL_CREATE_LOCK_REQ } + ,{ GSN_UTIL_CREATE_LOCK_REF, printUTIL_CREATE_LOCK_REF } + ,{ GSN_UTIL_CREATE_LOCK_CONF, printUTIL_CREATE_LOCK_CONF } + ,{ GSN_UTIL_DESTROY_LOCK_REQ, printUTIL_DESTROY_LOCK_REQ } + ,{ GSN_UTIL_DESTROY_LOCK_REF, printUTIL_DESTROY_LOCK_REF } + ,{ GSN_UTIL_DESTROY_LOCK_CONF, printUTIL_DESTROY_LOCK_CONF } + ,{ GSN_UTIL_LOCK_REQ, printUTIL_LOCK_REQ } + ,{ GSN_UTIL_LOCK_REF, printUTIL_LOCK_REF } + ,{ GSN_UTIL_LOCK_CONF, printUTIL_LOCK_CONF } + ,{ GSN_UTIL_UNLOCK_REQ, printUTIL_UNLOCK_REQ } + ,{ GSN_UTIL_UNLOCK_REF, printUTIL_UNLOCK_REF } + ,{ GSN_UTIL_UNLOCK_CONF, printUTIL_UNLOCK_CONF } + ,{ GSN_TUX_MAINT_REQ, printTUX_MAINT_REQ } + ,{ GSN_TUP_READ_ATTRS, printTUP_READ_ATTRS } + ,{ GSN_TUP_QUERY_TH, printTUP_QUERY_TH } + ,{ GSN_TUP_STORE_TH, printTUP_STORE_TH } + ,{ GSN_ACC_LOCKREQ, printACC_LOCKREQ } + ,{ GSN_LQH_TRANSCONF, printLQH_TRANSCONF } +}; + +const unsigned short NO_OF_PRINT_FUNCTIONS = sizeof(SignalDataPrintFunctions)/sizeof(NameFunctionPair); + + + diff --git a/ndb/src/common/debugger/signaldata/SignalDroppedRep.cpp b/ndb/src/common/debugger/signaldata/SignalDroppedRep.cpp new file mode 100644 index 00000000000..be31b4edb22 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/SignalDroppedRep.cpp @@ -0,0 +1,34 @@ +/* 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 <DebuggerNames.hpp> +#include <signaldata/SignalDroppedRep.hpp> + +bool +printSIGNAL_DROPPED_REP(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + SignalDroppedRep * sig = (SignalDroppedRep*)theData; + + fprintf(output, " originalGsn: %s(%d) Length: %d SectionCount: %d\n", + getSignalName(sig->originalGsn), + sig->originalGsn, + sig->originalLength, + sig->originalSectionCount); + return false; +} diff --git a/ndb/src/common/debugger/signaldata/SignalNames.cpp b/ndb/src/common/debugger/signaldata/SignalNames.cpp new file mode 100644 index 00000000000..4e5c8603db1 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/SignalNames.cpp @@ -0,0 +1,673 @@ +/* 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 "GlobalSignalNumbers.h" + +const GsnName SignalNames [] = { + { GSN_API_REGCONF, "API_REGCONF" } + ,{ GSN_API_REGREF, "API_REGREF" } + ,{ GSN_API_REGREQ, "API_REGREQ" } + ,{ GSN_ATTRINFO, "ATTRINFO" } + ,{ GSN_SCHEMA_INFO, "SCHEMA_INFO" } + ,{ GSN_SCHEMA_INFOCONF, "SCHEMA_INFOCONF" } + ,{ GSN_GET_SCHEMA_INFOREQ, "GET_SCHEMA_INFOREQ" } + ,{ GSN_DIHNDBTAMPER, "DIHNDBTAMPER" } + ,{ GSN_KEYINFO, "KEYINFO" } + ,{ GSN_KEYINFO20, "KEYINFO20" } + ,{ GSN_KEYINFO20_R, "KEYINFO20_R" } + ,{ GSN_NODE_FAILREP, "NODE_FAILREP" } + ,{ GSN_READCONF, "READCONF" } + ,{ GSN_SCAN_NEXTREQ, "SCAN_NEXTREQ" } + ,{ GSN_SCAN_TABCONF, "SCAN_TABCONF" } + ,{ GSN_SCAN_TABINFO, "SCAN_TABINFO" } + ,{ GSN_SCAN_TABREF, "SCAN_TABREF" } + ,{ GSN_SCAN_TABREQ, "SCAN_TABREQ" } + ,{ GSN_TC_COMMITCONF, "TC_COMMITCONF" } + ,{ GSN_TC_COMMITREF, "TC_COMMITREF" } + ,{ GSN_TC_COMMITREQ, "TC_COMMITREQ" } + ,{ GSN_TCKEY_FAILCONF, "TCKEY_FAILCONF" } + ,{ GSN_TCKEY_FAILREF, "TCKEY_FAILREF" } + ,{ GSN_TCKEYCONF, "TCKEYCONF" } + ,{ GSN_TCKEYREF, "TCKEYREF" } + ,{ GSN_TCKEYREQ, "TCKEYREQ" } + ,{ GSN_TCRELEASECONF, "TCRELEASECONF" } + ,{ GSN_TCRELEASEREF, "TCRELEASEREF" } + ,{ GSN_TCRELEASEREQ, "TCRELEASEREQ" } + ,{ GSN_TCROLLBACKCONF, "TCROLLBACKCONF" } + ,{ GSN_TCROLLBACKREF, "TCROLLBACKREF" } + ,{ GSN_TCROLLBACKREQ, "TCROLLBACKREQ" } + ,{ GSN_TCROLLBACKREP, "TCROLLBACKREP" } + ,{ GSN_TCSEIZECONF, "TCSEIZECONF" } + ,{ GSN_TCSEIZEREF, "TCSEIZEREF" } + ,{ GSN_TCSEIZEREQ, "TCSEIZEREQ" } + ,{ GSN_TRANSID_AI, "TRANSID_AI" } + ,{ GSN_TRANSID_AI_R, "TRANSID_AI_R" } + ,{ GSN_ABORT, "ABORT" } + ,{ GSN_ABORTCONF, "ABORTCONF" } + ,{ GSN_ABORTED, "ABORTED" } + ,{ GSN_ABORTREQ, "ABORTREQ" } + ,{ GSN_ACC_ABORTCONF, "ACC_ABORTCONF" } + ,{ GSN_ACC_ABORTREQ, "ACC_ABORTREQ" } + ,{ GSN_ACC_CHECK_SCAN, "ACC_CHECK_SCAN" } + ,{ GSN_ACC_COMMITCONF, "ACC_COMMITCONF" } + ,{ GSN_ACC_COMMITREQ, "ACC_COMMITREQ" } + ,{ GSN_ACC_CONTOPCONF, "ACC_CONTOPCONF" } + ,{ GSN_ACC_CONTOPREQ, "ACC_CONTOPREQ" } + ,{ GSN_ACC_LCPCONF, "ACC_LCPCONF" } + ,{ GSN_ACC_LCPREF, "ACC_LCPREF" } + ,{ GSN_ACC_LCPREQ, "ACC_LCPREQ" } + ,{ GSN_ACC_LCPSTARTED, "ACC_LCPSTARTED" } + ,{ GSN_ACC_OVER_REC, "ACC_OVER_REC" } + ,{ GSN_ACC_SAVE_PAGES, "ACC_SAVE_PAGES" } + ,{ GSN_ACC_SCAN_INFO, "ACC_SCAN_INFO" } + ,{ GSN_ACC_SCAN_INFO24, "ACC_SCAN_INFO24" } + ,{ GSN_ACC_SCANCONF, "ACC_SCANCONF" } + ,{ GSN_ACC_SCANREF, "ACC_SCANREF" } + ,{ GSN_ACC_SCANREQ, "ACC_SCANREQ" } + ,{ GSN_ACC_SRCONF, "ACC_SRCONF" } + ,{ GSN_ACC_SRREF, "ACC_SRREF" } + ,{ GSN_ACC_SRREQ, "ACC_SRREQ" } + ,{ GSN_ACC_TO_CONF, "ACC_TO_CONF" } + ,{ GSN_ACC_TO_REF, "ACC_TO_REF" } + ,{ GSN_ACC_TO_REQ, "ACC_TO_REQ" } + ,{ GSN_ACCFRAGCONF, "ACCFRAGCONF" } + ,{ GSN_ACCFRAGREF, "ACCFRAGREF" } + ,{ GSN_ACCFRAGREQ, "ACCFRAGREQ" } + ,{ GSN_ACCKEYCONF, "ACCKEYCONF" } + ,{ GSN_ACCKEYREF, "ACCKEYREF" } + ,{ GSN_ACCKEYREQ, "ACCKEYREQ" } + ,{ GSN_ACCMINUPDATE, "ACCMINUPDATE" } + ,{ GSN_ACCSEIZECONF, "ACCSEIZECONF" } + ,{ GSN_ACCSEIZEREF, "ACCSEIZEREF" } + ,{ GSN_ACCSEIZEREQ, "ACCSEIZEREQ" } + ,{ GSN_ACCUPDATECONF, "ACCUPDATECONF" } + ,{ GSN_ACCUPDATEKEY, "ACCUPDATEKEY" } + ,{ GSN_ACCUPDATEREF, "ACCUPDATEREF" } + ,{ GSN_ADD_FRAGCONF, "ADD_FRAGCONF" } + ,{ GSN_ADD_FRAGREF, "ADD_FRAGREF" } + ,{ GSN_ADD_FRAGREQ, "ADD_FRAGREQ" } + ,{ GSN_API_FAILCONF, "API_FAILCONF" } + ,{ GSN_API_FAILREQ, "API_FAILREQ" } + ,{ GSN_APPL_CHANGEREP, "APPL_CHANGEREP" } + // ,{ GSN_APPL_ERROR, "APPL_ERROR" } + ,{ GSN_APPL_HB, "APPL_HB" } + ,{ GSN_APPL_HBREQ, "APPL_HBREQ" } + ,{ GSN_APPL_REGCONF, "APPL_REGCONF" } + ,{ GSN_APPL_REGREF, "APPL_REGREF" } + ,{ GSN_APPL_REGREQ, "APPL_REGREQ" } + ,{ GSN_APPL_RUN, "APPL_RUN" } + ,{ GSN_APPL_STARTCONF, "APPL_STARTCONF" } + ,{ GSN_APPL_STARTREG, "APPL_STARTREG" } + ,{ GSN_CHECK_LCP_STOP, "CHECK_LCP_STOP" } + ,{ GSN_CLOSE_COMCONF, "CLOSE_COMCONF" } + ,{ GSN_CLOSE_COMREQ, "CLOSE_COMREQ" } + ,{ GSN_CM_ACKADD, "CM_ACKADD" } + ,{ GSN_CM_ACKALARM, "CM_ACKALARM" } + ,{ GSN_CM_ADD, "CM_ADD" } + ,{ GSN_CM_APPCHG, "CM_APPCHG" } + ,{ GSN_CM_HEARTBEAT, "CM_HEARTBEAT" } + ,{ GSN_CM_INFOCONF, "CM_INFOCONF" } + ,{ GSN_CM_INFOREQ, "CM_INFOREQ" } + ,{ GSN_CM_INIT, "CM_INIT" } + ,{ GSN_CM_NODEINFOCONF, "CM_NODEINFOCONF" } + ,{ GSN_CM_NODEINFOREF, "CM_NODEINFOREF" } + ,{ GSN_CM_NODEINFOREQ, "CM_NODEINFOREQ" } + ,{ GSN_CM_REGCONF, "CM_REGCONF" } + ,{ GSN_CM_REGREF, "CM_REGREF" } + ,{ GSN_CM_REGREQ, "CM_REGREQ" } + ,{ GSN_CM_RUN, "CM_RUN" } + ,{ GSN_CMVMI_CFGCONF, "CMVMI_CFGCONF" } + ,{ GSN_CMVMI_CFGREQ, "CMVMI_CFGREQ" } + ,{ GSN_CNTR_CHANGEREP, "CNTR_CHANGEREP" } + ,{ GSN_CNTR_MASTERCONF, "CNTR_MASTERCONF" } + ,{ GSN_CNTR_MASTERREF, "CNTR_MASTERREF" } + ,{ GSN_CNTR_MASTERREQ, "CNTR_MASTERREQ" } + ,{ GSN_CNTR_WAITREP, "CNTR_WAITREP" } + ,{ GSN_COMMIT, "COMMIT" } + ,{ GSN_COMMIT_FAILCONF, "COMMIT_FAILCONF" } + ,{ GSN_COMMIT_FAILREQ, "COMMIT_FAILREQ" } + ,{ GSN_COMMITCONF, "COMMITCONF" } + ,{ GSN_COMMITREQ, "COMMITREQ" } + ,{ GSN_COMMITTED, "COMMITTED" } + ,{ GSN_LCP_FRAG_ORD, "LCP_FRAG_ORD" } + ,{ GSN_LCP_FRAG_REP, "LCP_FRAG_REP" } + ,{ GSN_LCP_COMPLETE_REP, "LCP_COMPLETE_REP" } + ,{ GSN_START_LCP_REQ, "START_LCP_REQ" } + ,{ GSN_START_LCP_CONF, "START_LCP_CONF" } + ,{ GSN_COMPLETE, "COMPLETE" } + ,{ GSN_COMPLETECONF, "COMPLETECONF" } + ,{ GSN_COMPLETED, "COMPLETED" } + ,{ GSN_COMPLETEREQ, "COMPLETEREQ" } + ,{ GSN_CONNECT_REP, "CONNECT_REP" } + ,{ GSN_CONTINUEB, "CONTINUEB" } + ,{ GSN_COPY_ACTIVECONF, "COPY_ACTIVECONF" } + ,{ GSN_COPY_ACTIVEREF, "COPY_ACTIVEREF" } + ,{ GSN_COPY_ACTIVEREQ, "COPY_ACTIVEREQ" } + ,{ GSN_COPY_FRAGCONF, "COPY_FRAGCONF" } + ,{ GSN_COPY_FRAGREF, "COPY_FRAGREF" } + ,{ GSN_COPY_FRAGREQ, "COPY_FRAGREQ" } + ,{ GSN_COPY_GCICONF, "COPY_GCICONF" } + ,{ GSN_COPY_GCIREQ, "COPY_GCIREQ" } + ,{ GSN_COPY_STATECONF, "COPY_STATECONF" } + ,{ GSN_COPY_STATEREQ, "COPY_STATEREQ" } + ,{ GSN_COPY_TABCONF, "COPY_TABCONF" } + ,{ GSN_COPY_TABREQ, "COPY_TABREQ" } + ,{ GSN_CREATE_FRAGCONF, "CREATE_FRAGCONF" } + ,{ GSN_CREATE_FRAGREF, "CREATE_FRAGREF" } + ,{ GSN_CREATE_FRAGREQ, "CREATE_FRAGREQ" } + ,{ GSN_DEBUG_SIG, "DEBUG_SIG" } + ,{ GSN_DI_FCOUNTCONF, "DI_FCOUNTCONF" } + ,{ GSN_DI_FCOUNTREF, "DI_FCOUNTREF" } + ,{ GSN_DI_FCOUNTREQ, "DI_FCOUNTREQ" } + ,{ GSN_DIADDTABCONF, "DIADDTABCONF" } + ,{ GSN_DIADDTABREF, "DIADDTABREF" } + ,{ GSN_DIADDTABREQ, "DIADDTABREQ" } + ,{ GSN_DICTSTARTCONF, "DICTSTARTCONF" } + ,{ GSN_DICTSTARTREQ, "DICTSTARTREQ" } + ,{ GSN_LIST_TABLES_REQ, "LIST_TABLES_REQ" } + ,{ GSN_LIST_TABLES_CONF, "LIST_TABLES_CONF" } + ,{ GSN_DIGETNODESCONF, "DIGETNODESCONF" } + ,{ GSN_DIGETNODESREF, "DIGETNODESREF" } + ,{ GSN_DIGETNODESREQ, "DIGETNODESREQ" } + ,{ GSN_DIGETPRIMCONF, "DIGETPRIMCONF" } + ,{ GSN_DIGETPRIMREF, "DIGETPRIMREF" } + ,{ GSN_DIGETPRIMREQ, "DIGETPRIMREQ" } + ,{ GSN_DIH_RESTARTCONF, "DIH_RESTARTCONF" } + ,{ GSN_DIH_RESTARTREF, "DIH_RESTARTREF" } + ,{ GSN_DIH_RESTARTREQ, "DIH_RESTARTREQ" } + + ,{ GSN_DIRELEASECONF, "DIRELEASECONF" } + ,{ GSN_DIRELEASEREF, "DIRELEASEREF" } + ,{ GSN_DIRELEASEREQ, "DIRELEASEREQ" } + ,{ GSN_DISCONNECT_REP, "DISCONNECT_REP" } + ,{ GSN_DISEIZECONF, "DISEIZECONF" } + ,{ GSN_DISEIZEREF, "DISEIZEREF" } + ,{ GSN_DISEIZEREQ, "DISEIZEREQ" } + ,{ GSN_DIVERIFYCONF, "DIVERIFYCONF" } + ,{ GSN_DIVERIFYREF, "DIVERIFYREF" } + ,{ GSN_DIVERIFYREQ, "DIVERIFYREQ" } + ,{ GSN_EMPTY_LCP_REQ, "EMPTY_LCP_REQ" } + ,{ GSN_EMPTY_LCP_CONF, "EMPTY_LCP_CONF" } + ,{ GSN_ENABLE_COMORD, "ENABLE_COMORD" } + ,{ GSN_END_LCPCONF, "END_LCPCONF" } + ,{ GSN_END_LCPREQ, "END_LCPREQ" } + ,{ GSN_END_TOCONF, "END_TOCONF" } + ,{ GSN_END_TOREQ, "END_TOREQ" } + ,{ GSN_EVENT_REP, "EVENT_REP" } + ,{ GSN_EXEC_FRAGCONF, "EXEC_FRAGCONF" } + ,{ GSN_EXEC_FRAGREF, "EXEC_FRAGREF" } + ,{ GSN_EXEC_FRAGREQ, "EXEC_FRAGREQ" } + ,{ GSN_EXEC_SRCONF, "EXEC_SRCONF" } + ,{ GSN_EXEC_SRREQ, "EXEC_SRREQ" } + ,{ GSN_EXPANDCHECK2, "EXPANDCHECK2" } + ,{ GSN_FAIL_REP, "FAIL_REP" } + ,{ GSN_FSCLOSECONF, "FSCLOSECONF" } + ,{ GSN_FSCLOSEREF, "FSCLOSEREF" } + ,{ GSN_FSCLOSEREQ, "FSCLOSEREQ" } + ,{ GSN_FSOPENCONF, "FSOPENCONF" } + ,{ GSN_FSOPENREF, "FSOPENREF" } + ,{ GSN_FSOPENREQ, "FSOPENREQ" } + ,{ GSN_FSREADCONF, "FSREADCONF" } + ,{ GSN_FSREADREF, "FSREADREF" } + ,{ GSN_FSREADREQ, "FSREADREQ" } + ,{ GSN_FSSYNCCONF, "FSSYNCCONF" } + ,{ GSN_FSSYNCREF, "FSSYNCREF" } + ,{ GSN_FSSYNCREQ, "FSSYNCREQ" } + ,{ GSN_FSWRITECONF, "FSWRITECONF" } + ,{ GSN_FSWRITEREF, "FSWRITEREF" } + ,{ GSN_FSWRITEREQ, "FSWRITEREQ" } + ,{ GSN_FSAPPENDCONF, "FSAPPENDCONF" } + ,{ GSN_FSAPPENDREF, "FSAPPENDREF" } + ,{ GSN_FSAPPENDREQ, "FSAPPENDREQ" } + ,{ GSN_FSREMOVECONF, "FSREMOVECONF" } + ,{ GSN_FSREMOVEREF, "FSREMOVEREF" } + ,{ GSN_FSREMOVEREQ, "FSREMOVEREQ" } + ,{ GSN_GCP_ABORT, "GCP_ABORT" } + ,{ GSN_GCP_ABORTED, "GCP_ABORTED" } + ,{ GSN_GCP_COMMIT, "GCP_COMMIT" } + ,{ GSN_GCP_NODEFINISH, "GCP_NODEFINISH" } + ,{ GSN_GCP_NOMORETRANS, "GCP_NOMORETRANS" } + ,{ GSN_GCP_PREPARE, "GCP_PREPARE" } + ,{ GSN_GCP_PREPARECONF, "GCP_PREPARECONF" } + ,{ GSN_GCP_PREPAREREF, "GCP_PREPAREREF" } + ,{ GSN_GCP_SAVECONF, "GCP_SAVECONF" } + ,{ GSN_GCP_SAVEREF, "GCP_SAVEREF" } + ,{ GSN_GCP_SAVEREQ, "GCP_SAVEREQ" } + ,{ GSN_GCP_TCFINISHED, "GCP_TCFINISHED" } + ,{ GSN_GET_TABINFOREF, "GET_TABINFOREF" } + ,{ GSN_GET_TABINFOREQ, "GET_TABINFOREQ" } + ,{ GSN_GET_TABINFO_CONF, "GET_TABINFO_CONF" } + ,{ GSN_GETGCICONF, "GETGCICONF" } + ,{ GSN_GETGCIREQ, "GETGCIREQ" } + ,{ GSN_HOT_SPAREREP, "HOT_SPAREREP" } + ,{ GSN_INCL_NODECONF, "INCL_NODECONF" } + ,{ GSN_INCL_NODEREF, "INCL_NODEREF" } + ,{ GSN_INCL_NODEREQ, "INCL_NODEREQ" } + ,{ GSN_LCP_FRAGIDCONF, "LCP_FRAGIDCONF" } + ,{ GSN_LCP_FRAGIDREF, "LCP_FRAGIDREF" } + ,{ GSN_LCP_FRAGIDREQ, "LCP_FRAGIDREQ" } + ,{ GSN_LCP_HOLDOPCONF, "LCP_HOLDOPCONF" } + ,{ GSN_LCP_HOLDOPREF, "LCP_HOLDOPREF" } + ,{ GSN_LCP_HOLDOPREQ, "LCP_HOLDOPREQ" } + ,{ GSN_LQH_RESTART_OP, "LQH_RESTART_OP" } + ,{ GSN_LQH_TRANSCONF, "LQH_TRANSCONF" } + ,{ GSN_LQH_TRANSREQ, "LQH_TRANSREQ" } + ,{ GSN_LQHADDATTCONF, "LQHADDATTCONF" } + ,{ GSN_LQHADDATTREF, "LQHADDATTREF" } + ,{ GSN_LQHADDATTREQ, "LQHADDATTREQ" } + ,{ GSN_LQHFRAGCONF, "LQHFRAGCONF" } + ,{ GSN_LQHFRAGREF, "LQHFRAGREF" } + ,{ GSN_LQHFRAGREQ, "LQHFRAGREQ" } + ,{ GSN_LQHKEYCONF, "LQHKEYCONF" } + ,{ GSN_LQHKEYREF, "LQHKEYREF" } + ,{ GSN_LQHKEYREQ, "LQHKEYREQ" } + ,{ GSN_MASTER_GCPCONF, "MASTER_GCPCONF" } + ,{ GSN_MASTER_GCPREF, "MASTER_GCPREF" } + ,{ GSN_MASTER_GCPREQ, "MASTER_GCPREQ" } + ,{ GSN_MASTER_LCPCONF, "MASTER_LCPCONF" } + ,{ GSN_MASTER_LCPREF, "MASTER_LCPREF" } + ,{ GSN_MASTER_LCPREQ, "MASTER_LCPREQ" } + ,{ GSN_MEMCHECKCONF, "MEMCHECKCONF" } + ,{ GSN_MEMCHECKREQ, "MEMCHECKREQ" } + ,{ GSN_NDB_FAILCONF, "NDB_FAILCONF" } + ,{ GSN_NDB_STARTCONF, "NDB_STARTCONF" } + ,{ GSN_NDB_STARTREF, "NDB_STARTREF" } + ,{ GSN_NDB_STARTREQ, "NDB_STARTREQ" } + ,{ GSN_NDB_STTOR, "NDB_STTOR" } + ,{ GSN_NDB_STTORRY, "NDB_STTORRY" } + ,{ GSN_NDB_TAMPER, "NDB_TAMPER" } + ,{ GSN_NEXT_SCANCONF, "NEXT_SCANCONF" } + ,{ GSN_NEXT_SCANREF, "NEXT_SCANREF" } + ,{ GSN_NEXT_SCANREQ, "NEXT_SCANREQ" } + ,{ GSN_NEXTOPERATION, "NEXTOPERATION" } + ,{ GSN_NF_COMPLETEREP, "NF_COMPLETEREP" } + ,{ GSN_NODE_STATESCONF, "NODE_STATESCONF" } + ,{ GSN_NODE_STATESREF, "NODE_STATESREF" } + ,{ GSN_NODE_STATESREQ, "NODE_STATESREQ" } + ,{ GSN_OPEN_COMCONF, "OPEN_COMCONF" } + ,{ GSN_OPEN_COMREF, "OPEN_COMREF" } + ,{ GSN_OPEN_COMREQ, "OPEN_COMREQ" } + ,{ GSN_PACKED_SIGNAL, "PACKED_SIGNAL" } + ,{ GSN_PREP_FAILCONF, "PREP_FAILCONF" } + ,{ GSN_PREP_FAILREF, "PREP_FAILREF" } + ,{ GSN_PREP_FAILREQ, "PREP_FAILREQ" } + ,{ GSN_PRES_TOCONF, "PRES_TOCONF" } + ,{ GSN_PRES_TOREQ, "PRES_TOREQ" } + ,{ GSN_READ_NODESCONF, "READ_NODESCONF" } + ,{ GSN_READ_NODESREF, "READ_NODESREF" } + ,{ GSN_READ_NODESREQ, "READ_NODESREQ" } + ,{ GSN_SCAN_FRAGCONF, "SCAN_FRAGCONF" } + ,{ GSN_SCAN_FRAGREF, "SCAN_FRAGREF" } + ,{ GSN_SCAN_FRAGREQ, "SCAN_FRAGREQ" } + ,{ GSN_SCAN_HBREP, "SCAN_HBREP" } + ,{ GSN_SCAN_PROCCONF, "SCAN_PROCCONF" } + ,{ GSN_SCAN_PROCREQ, "SCAN_PROCREQ" } + ,{ GSN_SEND_PACKED, "SEND_PACKED" } + ,{ GSN_SET_LOGLEVELORD, "SET_LOGLEVELORD" } + ,{ GSN_SHRINKCHECK2, "SHRINKCHECK2" } + ,{ GSN_SIZEALT_ACK, "SIZEALT_ACK" } + ,{ GSN_SIZEALT_REP, "SIZEALT_REP" } + ,{ GSN_SR_FRAGIDCONF, "SR_FRAGIDCONF" } + ,{ GSN_SR_FRAGIDREF, "SR_FRAGIDREF" } + ,{ GSN_SR_FRAGIDREQ, "SR_FRAGIDREQ" } + ,{ GSN_START_COPYCONF, "START_COPYCONF" } + ,{ GSN_START_COPYREF, "START_COPYREF" } + ,{ GSN_START_COPYREQ, "START_COPYREQ" } + ,{ GSN_START_EXEC_SR, "START_EXEC_SR" } + ,{ GSN_START_FRAGCONF, "START_FRAGCONF" } + ,{ GSN_START_FRAGREF, "START_FRAGREF" } + ,{ GSN_START_FRAGREQ, "START_FRAGREQ" } + ,{ GSN_START_LCP_REF, "START_LCP_REF" } + ,{ GSN_START_LCP_ROUND, "START_LCP_ROUND" } + ,{ GSN_START_MECONF, "START_MECONF" } + ,{ GSN_START_MEREF, "START_MEREF" } + ,{ GSN_START_MEREQ, "START_MEREQ" } + ,{ GSN_START_PERMCONF, "START_PERMCONF" } + ,{ GSN_START_PERMREF, "START_PERMREF" } + ,{ GSN_START_PERMREQ, "START_PERMREQ" } + ,{ GSN_START_RECCONF, "START_RECCONF" } + ,{ GSN_START_RECREF, "START_RECREF" } + ,{ GSN_START_RECREQ, "START_RECREQ" } + ,{ GSN_START_TOCONF, "START_TOCONF" } + ,{ GSN_START_TOREQ, "START_TOREQ" } + ,{ GSN_STORED_PROCCONF, "STORED_PROCCONF" } + ,{ GSN_STORED_PROCREF, "STORED_PROCREF" } + ,{ GSN_STORED_PROCREQ, "STORED_PROCREQ" } + ,{ GSN_STTOR, "STTOR" } + ,{ GSN_STTORRY, "STTORRY" } + ,{ GSN_SYSTEM_ERROR, "SYSTEM_ERROR" } + ,{ GSN_TAB_COMMITCONF, "TAB_COMMITCONF" } + ,{ GSN_TAB_COMMITREF, "TAB_COMMITREF" } + ,{ GSN_TAB_COMMITREQ, "TAB_COMMITREQ" } + ,{ GSN_TAKE_OVERTCCONF, "TAKE_OVERTCCONF" } + ,{ GSN_TAKE_OVERTCREQ, "TAKE_OVERTCREQ" } + ,{ GSN_TC_CLOPSIZECONF, "TC_CLOPSIZECONF" } + ,{ GSN_TC_CLOPSIZEREQ, "TC_CLOPSIZEREQ" } + ,{ GSN_TC_SCHVERCONF, "TC_SCHVERCONF" } + ,{ GSN_TC_SCHVERREQ, "TC_SCHVERREQ" } + ,{ GSN_TCGETOPSIZECONF, "TCGETOPSIZECONF" } + ,{ GSN_TCGETOPSIZEREQ, "TCGETOPSIZEREQ" } + ,{ GSN_TEST_ORD, "TEST_ORD" } + ,{ GSN_TESTSIG, "TESTSIG" } + ,{ GSN_TIME_SIGNAL, "TIME_SIGNAL" } + ,{ GSN_TUP_ABORTREQ, "TUP_ABORTREQ" } + ,{ GSN_TUP_ADD_ATTCONF, "TUP_ADD_ATTCONF" } + ,{ GSN_TUP_ADD_ATTRREF, "TUP_ADD_ATTRREF" } + ,{ GSN_TUP_ADD_ATTRREQ, "TUP_ADD_ATTRREQ" } + ,{ GSN_TUP_ATTRINFO, "TUP_ATTRINFO" } + ,{ GSN_TUP_COMMITREQ, "TUP_COMMITREQ" } + ,{ GSN_TUP_LCPCONF, "TUP_LCPCONF" } + ,{ GSN_TUP_LCPREF, "TUP_LCPREF" } + ,{ GSN_TUP_LCPREQ, "TUP_LCPREQ" } + ,{ GSN_TUP_LCPSTARTED, "TUP_LCPSTARTED" } + ,{ GSN_TUP_PREPLCPCONF, "TUP_PREPLCPCONF" } + ,{ GSN_TUP_PREPLCPREF, "TUP_PREPLCPREF" } + ,{ GSN_TUP_PREPLCPREQ, "TUP_PREPLCPREQ" } + ,{ GSN_TUP_SRCONF, "TUP_SRCONF" } + ,{ GSN_TUP_SRREF, "TUP_SRREF" } + ,{ GSN_TUP_SRREQ, "TUP_SRREQ" } + ,{ GSN_TUPFRAGCONF, "TUPFRAGCONF" } + ,{ GSN_TUPFRAGREF, "TUPFRAGREF" } + ,{ GSN_TUPFRAGREQ, "TUPFRAGREQ" } + ,{ GSN_TUPKEYCONF, "TUPKEYCONF" } + ,{ GSN_TUPKEYREF, "TUPKEYREF" } + ,{ GSN_TUPKEYREQ, "TUPKEYREQ" } + ,{ GSN_TUPRELEASECONF, "TUPRELEASECONF" } + ,{ GSN_TUPRELEASEREF, "TUPRELEASEREF" } + ,{ GSN_TUPRELEASEREQ, "TUPRELEASEREQ" } + ,{ GSN_TUPSEIZECONF, "TUPSEIZECONF" } + ,{ GSN_TUPSEIZEREF, "TUPSEIZEREF" } + ,{ GSN_TUPSEIZEREQ, "TUPSEIZEREQ" } + ,{ GSN_UNBLO_DICTCONF, "UNBLO_DICTCONF" } + ,{ GSN_UNBLO_DICTREQ, "UNBLO_DICTREQ" } + ,{ GSN_UPDATE_TOCONF, "UPDATE_TOCONF" } + ,{ GSN_UPDATE_TOREF, "UPDATE_TOREF" } + ,{ GSN_UPDATE_TOREQ, "UPDATE_TOREQ" } + ,{ GSN_VOTE_MASTERORD, "VOTE_MASTERORD" } + ,{ GSN_TUP_ALLOCREQ, "TUP_ALLOCREQ" } + ,{ GSN_LQH_ALLOCREQ, "LQH_ALLOCREQ" } + ,{ GSN_TUP_DEALLOCREQ, "TUP_DEALLOCREQ" } + ,{ GSN_TUP_WRITELOG_REQ, "TUP_WRITELOG_REQ" } + ,{ GSN_LQH_WRITELOG_REQ, "LQH_WRITELOG_REQ" } + + ,{ GSN_STATISTICS_REQ, "STATISTICS_REQ" } + ,{ GSN_START_ORD, "START_ORD" } + ,{ GSN_STOP_ORD, "STOP_ORD" } + ,{ GSN_TAMPER_ORD, "TAMPER_ORD" } + ,{ GSN_SET_VAR_REQ, "SET_VAR_REQ" } + ,{ GSN_SET_VAR_CONF, "SET_VAR_CONF" } + ,{ GSN_SET_VAR_REF, "SET_VAR_REF" } + ,{ GSN_STATISTICS_CONF, "STATISTICS_CONF" } + + ,{ GSN_EVENT_SUBSCRIBE_REQ, "EVENT_SUBSCRIBE_REQ" } + ,{ GSN_EVENT_SUBSCRIBE_CONF, "EVENT_SUBSCRIBE_CONF" } + ,{ GSN_EVENT_SUBSCRIBE_REF, "EVENT_SUBSCRIBE_REF" } + ,{ GSN_ACC_COM_BLOCK, "ACC_COM_BLOCK" } + ,{ GSN_ACC_COM_UNBLOCK, "ACC_COM_UNBLOCK" } + ,{ GSN_TUP_COM_BLOCK, "TUP_COM_BLOCK" } + ,{ GSN_TUP_COM_UNBLOCK, "TUP_COM_UNBLOCK" } + ,{ GSN_DUMP_STATE_ORD, "DUMP_STATE_ORD" } + + ,{ GSN_START_INFOREQ, "START_INFOREQ" } + ,{ GSN_START_INFOREF, "START_INFOREF" } + ,{ GSN_START_INFOCONF, "START_INFOCONF" } + + ,{ GSN_CHECKNODEGROUPSREQ, "CHECKNODEGROUPSREQ" } + ,{ GSN_CHECKNODEGROUPSCONF, "CHECKNODEGROUPSCONF" } + + ,{ GSN_ARBIT_CFG, "ARBIT_CFG" } + ,{ GSN_ARBIT_PREPREQ, "ARBIT_PREPREQ" } + ,{ GSN_ARBIT_PREPCONF, "ARBIT_PREPCONF" } + ,{ GSN_ARBIT_PREPREF, "ARBIT_PREPREF" } + ,{ GSN_ARBIT_STARTREQ, "ARBIT_STARTREQ" } + ,{ GSN_ARBIT_STARTCONF, "ARBIT_STARTCONF" } + ,{ GSN_ARBIT_STARTREF, "ARBIT_STARTREF" } + ,{ GSN_ARBIT_CHOOSEREQ, "ARBIT_CHOOSEREQ" } + ,{ GSN_ARBIT_CHOOSECONF, "ARBIT_CHOOSECONF" } + ,{ GSN_ARBIT_CHOOSEREF, "ARBIT_CHOOSEREF" } + ,{ GSN_ARBIT_STOPORD, "ARBIT_STOPORD" } + ,{ GSN_ARBIT_STOPREP, "ARBIT_STOPREP" } + + ,{ GSN_TC_COMMIT_ACK, "TC_COMMIT_ACK" } + ,{ GSN_REMOVE_MARKER_ORD, "REMOVE_MARKER_ORD" } + + ,{ GSN_NODE_STATE_REP, "NODE_STATE_REP" } + ,{ GSN_CHANGE_NODE_STATE_REQ, "CHANGE_NODE_STATE_REQ" } + ,{ GSN_CHANGE_NODE_STATE_CONF, "CHANGE_NODE_STATE_CONF" } + + ,{ GSN_BLOCK_COMMIT_ORD, "BLOCK_COMMIT_ORD" } + ,{ GSN_UNBLOCK_COMMIT_ORD, "UNBLOCK_COMMIT_ORD" } + + ,{ GSN_DIH_SWITCH_REPLICA_REQ, "DIH_SWITCH_REPLICA_REQ" } + ,{ GSN_DIH_SWITCH_REPLICA_REF, "DIH_SWITCH_REPLICA_REF" } + ,{ GSN_DIH_SWITCH_REPLICA_CONF, "DIH_SWITCH_REPLICA_CONF" } + + ,{ GSN_STOP_PERM_REQ, "STOP_PERM_REQ" } + ,{ GSN_STOP_PERM_REF, "STOP_PERM_REF" } + ,{ GSN_STOP_PERM_CONF, "STOP_PERM_CONF" } + + ,{ GSN_STOP_ME_REQ, "STOP_ME_REQ" } + ,{ GSN_STOP_ME_REF, "STOP_ME_REF" } + ,{ GSN_STOP_ME_CONF, "STOP_ME_CONF" } + + ,{ GSN_WAIT_GCP_REQ, "WAIT_GCP_REQ" } + ,{ GSN_WAIT_GCP_REF, "WAIT_GCP_REF" } + ,{ GSN_WAIT_GCP_CONF, "WAIT_GCP_CONF" } + + ,{ GSN_STOP_REQ, "STOP_REQ" } + ,{ GSN_STOP_REF, "STOP_REF" } + + ,{ GSN_ABORT_ALL_REQ, "ABORT_ALL_REQ" } + ,{ GSN_ABORT_ALL_REF, "ABORT_ALL_REF" } + ,{ GSN_ABORT_ALL_CONF, "ABORT_ALL_CONF" } + + ,{ GSN_DROP_TABLE_REQ, "DROP_TABLE_REQ" } + ,{ GSN_DROP_TABLE_REF, "DROP_TABLE_REF" } + ,{ GSN_DROP_TABLE_CONF, "DROP_TABLE_CONF" } + + ,{ GSN_DROP_TAB_REQ, "DROP_TAB_REQ" } + ,{ GSN_DROP_TAB_REF, "DROP_TAB_REF" } + ,{ GSN_DROP_TAB_CONF, "DROP_TAB_CONF" } + + ,{ GSN_PREP_DROP_TAB_REQ, "PREP_DROP_TAB_REQ" } + ,{ GSN_PREP_DROP_TAB_REF, "PREP_DROP_TAB_REF" } + ,{ GSN_PREP_DROP_TAB_CONF, "PREP_DROP_TAB_CONF" } + + ,{ GSN_WAIT_DROP_TAB_REQ, "WAIT_DROP_TAB_REQ" } + ,{ GSN_WAIT_DROP_TAB_REF, "WAIT_DROP_TAB_REF" } + ,{ GSN_WAIT_DROP_TAB_CONF, "WAIT_DROP_TAB_CONF" } + + ,{ GSN_CREATE_TRIG_REQ, "CREATE_TRIG_REQ" } + ,{ GSN_CREATE_TRIG_CONF, "CREATE_TRIG_CONF" } + ,{ GSN_CREATE_TRIG_REF, "CREATE_TRIG_REF" } + ,{ GSN_ALTER_TRIG_REQ, "ALTER_TRIG_REQ" } + ,{ GSN_ALTER_TRIG_CONF, "ALTER_TRIG_CONF" } + ,{ GSN_ALTER_TRIG_REF, "ALTER_TRIG_REF" } + ,{ GSN_DROP_TRIG_REQ, "DROP_TRIG_REQ" } + ,{ GSN_DROP_TRIG_CONF, "DROP_TRIG_CONF" } + ,{ GSN_DROP_TRIG_REF, "DROP_TRIG_REF" } + ,{ GSN_FIRE_TRIG_ORD, "FIRE_TRIG_ORD" } + ,{ GSN_TRIG_ATTRINFO, "TRIG_ATTRINFO" } + + ,{ GSN_CREATE_INDX_REQ, "CREATE_INDX_REQ" } + ,{ GSN_CREATE_INDX_CONF, "CREATE_INDX_CONF" } + ,{ GSN_CREATE_INDX_REF, "CREATE_INDX_REF" } + ,{ GSN_DROP_INDX_REQ, "DROP_INDX_REQ" } + ,{ GSN_DROP_INDX_CONF, "DROP_INDX_CONF" } + ,{ GSN_DROP_INDX_REF, "DROP_INDX_REF" } + ,{ GSN_ALTER_INDX_REQ, "ALTER_INDX_REQ" } + ,{ GSN_ALTER_INDX_CONF, "ALTER_INDX_CONF" } + ,{ GSN_ALTER_INDX_REF, "ALTER_INDX_REF" } + ,{ GSN_TCINDXREQ, "TCINDXREQ" } + ,{ GSN_TCINDXCONF, "TCINDXCONF" } + ,{ GSN_TCINDXREF, "TCINDXREF" } + ,{ GSN_INDXKEYINFO, "INDXKEYINFO" } + ,{ GSN_INDXATTRINFO, "INDXATTRINFO" } + ,{ GSN_BUILDINDXREQ, "BUILDINDXREQ" } + ,{ GSN_BUILDINDXCONF, "BUILDINDXCONF" } + ,{ GSN_BUILDINDXREF, "BUILDINDXREF" } + //,{ GSN_TCINDXNEXTREQ, "TCINDXNEXTREQ" } + //,{ GSN_TCINDEXNEXTCONF, "TCINDEXNEXTCONF" } + //,{ GSN_TCINDEXNEXREF, "TCINDEXNEXREF" } + + ,{ GSN_CREATE_EVNT_REQ, "CREATE_EVNT_REQ" } + ,{ GSN_CREATE_EVNT_CONF, "CREATE_EVNT_CONF" } + ,{ GSN_CREATE_EVNT_REF, "CREATE_EVNT_REF" } + + ,{ GSN_SUMA_START_ME, "SUMA_START_ME" } + ,{ GSN_SUMA_HANDOVER_REQ, "SUMA_HANDOVER_REQ"} + ,{ GSN_SUMA_HANDOVER_CONF, "SUMA_HANDOVER_CONF"} + + ,{ GSN_DROP_EVNT_REQ, "DROP_EVNT_REQ" } + ,{ GSN_DROP_EVNT_CONF, "DROP_EVNT_CONF" } + ,{ GSN_DROP_EVNT_REF, "DROP_EVNT_REF" } + + ,{ GSN_BACKUP_TRIG_REQ, "BACKUP_TRIG_REQ" } + ,{ GSN_BACKUP_REQ, "BACKUP_REQ" } + ,{ GSN_BACKUP_DATA, "BACKUP_DATA" } + ,{ GSN_BACKUP_REF, "BACKUP_REF" } + ,{ GSN_BACKUP_CONF, "BACKUP_CONF" } + ,{ GSN_ABORT_BACKUP_ORD, "ABORT_BACKUP_ORD" } + ,{ GSN_BACKUP_ABORT_REP, "BACKUP_ABORT_REP" } + ,{ GSN_BACKUP_COMPLETE_REP, "BACKUP_COMPLETE_REP" } + ,{ GSN_BACKUP_NF_COMPLETE_REP, "BACKUP_NF_COMPLETE_REP" } + ,{ GSN_DEFINE_BACKUP_REQ, "DEFINE_BACKUP_REQ" } + ,{ GSN_DEFINE_BACKUP_REF, "DEFINE_BACKUP_REF" } + ,{ GSN_DEFINE_BACKUP_CONF, "DEFINE_BACKUP_CONF" } + ,{ GSN_START_BACKUP_REQ, "START_BACKUP_REQ" } + ,{ GSN_START_BACKUP_REF, "START_BACKUP_REF" } + ,{ GSN_START_BACKUP_CONF, "START_BACKUP_CONF" } + ,{ GSN_BACKUP_FRAGMENT_REQ, "BACKUP_FRAGMENT_REQ" } + ,{ GSN_BACKUP_FRAGMENT_REF, "BACKUP_FRAGMENT_REF" } + ,{ GSN_BACKUP_FRAGMENT_CONF, "BACKUP_FRAGMENT_CONF" } + ,{ GSN_STOP_BACKUP_REQ, "STOP_BACKUP_REQ" } + ,{ GSN_STOP_BACKUP_REF, "STOP_BACKUP_REF" } + ,{ GSN_STOP_BACKUP_CONF, "STOP_BACKUP_CONF" } + ,{ GSN_BACKUP_STATUS_REQ, "BACKUP_STATUS_REQ" } + ,{ GSN_BACKUP_STATUS_REF, "BACKUP_STATUS_REF" } + ,{ GSN_BACKUP_STATUS_CONF, "BACKUP_STATUS_CONF" } + ,{ GSN_SIGNAL_DROPPED_REP, "SIGNAL_DROPPED_REP" } + ,{ GSN_CONTINUE_FRAGMENTED, "CONTINUE_FRAGMENTED" } + + /** Util Block Services **/ + ,{ GSN_UTIL_SEQUENCE_REQ, "UTIL_SEQUENCE_REQ" } + ,{ GSN_UTIL_SEQUENCE_REF, "UTIL_SEQUENCE_REF" } + ,{ GSN_UTIL_SEQUENCE_CONF, "UTIL_SEQUENCE_CONF" } + ,{ GSN_UTIL_PREPARE_REQ, "UTIL_PREPARE_REQ" } + ,{ GSN_UTIL_PREPARE_CONF, "UTIL_PREPARE_CONF" } + ,{ GSN_UTIL_PREPARE_REF, "UTIL_PREPARE_REF" } + ,{ GSN_UTIL_EXECUTE_REQ, "UTIL_EXECUTE_REQ" } + ,{ GSN_UTIL_EXECUTE_CONF, "UTIL_EXECUTE_CONF" } + ,{ GSN_UTIL_EXECUTE_REF, "UTIL_EXECUTE_REF" } + ,{ GSN_UTIL_RELEASE_REQ, "UTIL_RELEASE_REQ" } + ,{ GSN_UTIL_RELEASE_CONF, "UTIL_RELEASE_CONF" } + ,{ GSN_UTIL_RELEASE_REF, "UTIL_RELASE_REF" } + + ,{ GSN_GREP_CREATE_REQ, "GREP_CREATE_REQ" }, + { GSN_GREP_CREATE_REF, "GREP_CREATE_REF" }, + { GSN_GREP_CREATE_CONF, "GREP_CREATE_CONF" }, + { GSN_GREP_START_REQ, "GREP_START_REQ" }, + { GSN_GREP_START_REF, "GREP_START_REF" }, + { GSN_GREP_START_CONF, "GREP_START_CONF" }, + { GSN_GREP_SYNC_REQ, "GREP_SYNC_REQ" }, + { GSN_GREP_SYNC_REF, "GREP_SYNC_REF" }, + { GSN_GREP_SYNC_CONF, "GREP_SYNC_CONF" }, + //{ GSN_REP_CONNECT_REQ, "REP_CONNECT_REQ" }, Not used + //{ GSN_REP_CONNECT_REF, "REP_CONNECT_REF" }, Not used + //{ GSN_REP_CONNECT_CONF, "REP_CONNECT_CONF" }, Not used + { GSN_REP_WAITGCP_REQ, "REP_WAIT_GCP_REQ" }, + { GSN_REP_WAITGCP_REF, "REP_WAIT_GCP_REF" }, + { GSN_REP_WAITGCP_CONF, "REP_WAIT_GCP_CONF" }, + { GSN_GREP_WAITGCP_REQ, "GREP_WAIT_GCP_REQ" }, + { GSN_GREP_WAITGCP_REF, "GREP_WAIT_GCP_REF" }, + { GSN_GREP_WAITGCP_CONF, "GREP_WAIT_GCP_CONF" } + + /* Suma Block Services **/ + ,{ GSN_SUB_CREATE_REQ, "SUB_CREATE_REQ" } + ,{ GSN_SUB_CREATE_REF, "SUB_CREATE_REF" } + ,{ GSN_SUB_CREATE_CONF, "SUB_CREATE_CONF" } + ,{ GSN_SUB_START_REQ, "SUB_START_REQ" } + ,{ GSN_SUB_START_REF, "SUB_START_REF" } + ,{ GSN_SUB_START_CONF, "SUB_START_CONF" } + ,{ GSN_SUB_STOP_REQ, "SUB_STOP_REQ" } + ,{ GSN_SUB_STOP_REF, "SUB_STOP_REF" } + ,{ GSN_SUB_STOP_CONF, "SUB_STOP_CONF" } + ,{ GSN_SUB_SYNC_REQ, "SUB_SYNC_REQ" } + ,{ GSN_SUB_SYNC_REF, "SUB_SYNC_REF" } + ,{ GSN_SUB_SYNC_CONF, "SUB_SYNC_CONF" } + ,{ GSN_SUB_META_DATA, "SUB_META_DATA" } + ,{ GSN_SUB_TABLE_DATA, "SUB_TABLE_DATA" } + ,{ GSN_SUB_SYNC_CONTINUE_REQ, "SUB_SYNC_CONTINUE_REQ" } + ,{ GSN_SUB_SYNC_CONTINUE_REF, "SUB_SYNC_CONTINUE_REF" } + ,{ GSN_SUB_SYNC_CONTINUE_CONF, "SUB_SYNC_CONTINUE_CONF" } + ,{ GSN_SUB_GCP_COMPLETE_REP, "SUB_GCP_COMPLETE_REP" } + ,{ GSN_SUB_GCP_COMPLETE_ACC, "SUB_GCP_COMPLETE_ACC" } + + ,{ GSN_CREATE_SUBID_REQ, "CREATE_SUBID_REQ" } + ,{ GSN_CREATE_SUBID_REF, "CREATE_SUBID_REF" } + ,{ GSN_CREATE_SUBID_CONF, "CREATE_SUBID_CONF" } + + ,{ GSN_CREATE_TABLE_REQ, "CREATE_TABLE_REQ" } + ,{ GSN_CREATE_TABLE_REF, "CREATE_TABLE_REF" } + ,{ GSN_CREATE_TABLE_CONF, "CREATE_TABLE_CONF" } + + ,{ GSN_CREATE_TAB_REQ, "CREATE_TAB_REQ" } + ,{ GSN_CREATE_TAB_REF, "CREATE_TAB_REF" } + ,{ GSN_CREATE_TAB_CONF, "CREATE_TAB_CONF" } + + ,{ GSN_ALTER_TABLE_REQ, "ALTER_TABLE_REQ" } + ,{ GSN_ALTER_TABLE_REF, "ALTER_TABLE_REF" } + ,{ GSN_ALTER_TABLE_CONF, "ALTER_TABLE_CONF" } + + ,{ GSN_ALTER_TAB_REQ, "ALTER_TAB_REQ" } + ,{ GSN_ALTER_TAB_REF, "ALTER_TAB_REF" } + ,{ GSN_ALTER_TAB_CONF, "ALTER_TAB_CONF" } + + ,{ GSN_CREATE_FRAGMENTATION_REQ, "CREATE_FRAGMENTATION_REQ" } + ,{ GSN_CREATE_FRAGMENTATION_REF, "CREATE_FRAGMENTATION_REF" } + ,{ GSN_CREATE_FRAGMENTATION_CONF, "CREATE_FRAGMENTATION_CONF" } + + ,{ GSN_UTIL_CREATE_LOCK_REQ, "UTIL_CREATE_LOCK_REQ" } + ,{ GSN_UTIL_CREATE_LOCK_REF, "UTIL_CREATE_LOCK_REF" } + ,{ GSN_UTIL_CREATE_LOCK_CONF, "UTIL_CREATE_LOCK_CONF" } + ,{ GSN_UTIL_DESTROY_LOCK_REQ, "UTIL_DESTROY_LOCK_REQ" } + ,{ GSN_UTIL_DESTROY_LOCK_REF, "UTIL_DESTROY_LOCK_REF" } + ,{ GSN_UTIL_DESTROY_LOCK_CONF, "UTIL_DESTROY_LOCK_CONF" } + ,{ GSN_UTIL_LOCK_REQ, "UTIL_LOCK_REQ" } + ,{ GSN_UTIL_LOCK_REF, "UTIL_LOCK_REF" } + ,{ GSN_UTIL_LOCK_CONF, "UTIL_LOCK_CONF" } + ,{ GSN_UTIL_UNLOCK_REQ, "UTIL_UNLOCK_REQ" } + ,{ GSN_UTIL_UNLOCK_REF, "UTIL_UNLOCK_REF" } + ,{ GSN_UTIL_UNLOCK_CONF, "UTIL_UNLOCK_CONF" } + + /* TUX */ + ,{ GSN_TUXFRAGREQ, "TUXFRAGREQ" } + ,{ GSN_TUXFRAGCONF, "TUXFRAGCONF" } + ,{ GSN_TUXFRAGREF, "TUXFRAGREF" } + ,{ GSN_TUX_ADD_ATTRREQ, "TUX_ADD_ATTRREQ" } + ,{ GSN_TUX_ADD_ATTRCONF, "TUX_ADD_ATTRCONF" } + ,{ GSN_TUX_ADD_ATTRREF, "TUX_ADD_ATTRREF" } + ,{ GSN_TUX_MAINT_REQ, "TUX_MAINT_REQ" } + ,{ GSN_TUX_MAINT_CONF, "TUX_MAINT_CONF" } + ,{ GSN_TUX_MAINT_REF, "TUX_MAINT_REF" } + ,{ GSN_TUP_READ_ATTRS, "TUP_READ_ATTRS" } + ,{ GSN_TUP_QUERY_TH, "TUP_QUERY_TH" } + ,{ GSN_TUP_STORE_TH, "TUP_STORE_TH" } + ,{ GSN_TUX_BOUND_INFO, "TUX_BOUND_INFO" } + ,{ GSN_ACC_LOCKREQ, "ACC_LOCKREQ" } + +}; +const unsigned short NO_OF_SIGNAL_NAMES = sizeof(SignalNames)/sizeof(GsnName); diff --git a/ndb/src/common/debugger/signaldata/StartRec.cpp b/ndb/src/common/debugger/signaldata/StartRec.cpp new file mode 100644 index 00000000000..482e3cb0728 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/StartRec.cpp @@ -0,0 +1,52 @@ +/* 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 <RefConvert.hpp> +#include <signaldata/StartRec.hpp> + +bool +printSTART_REC_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + StartRecReq * sig = (StartRecReq *) theData; + + fprintf(output, " receivingNodeId: %d senderRef: (%d, %d)\n", + sig->receivingNodeId, + refToNode(sig->senderRef), + refToBlock(sig->senderRef)); + + fprintf(output, " keepGci: %d lastCompletedGci: %d newestGci: %d\n", + sig->keepGci, + sig->lastCompletedGci, + sig->newestGci); + + return true; +} + +bool +printSTART_REC_CONF(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo){ + StartRecConf * sig = (StartRecConf *) theData; + + fprintf(output, " startingNodeId: %d\n", + sig->startingNodeId); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/SumaImpl.cpp b/ndb/src/common/debugger/signaldata/SumaImpl.cpp new file mode 100644 index 00000000000..558842ed2ba --- /dev/null +++ b/ndb/src/common/debugger/signaldata/SumaImpl.cpp @@ -0,0 +1,167 @@ +/* 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 <signaldata/SumaImpl.hpp> + +bool +printSUB_CREATE_REQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubCreateReq * const sig = (SubCreateReq *)theData; + fprintf(output, " subscriberRef: %x\n", sig->subscriberRef); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " subscriptionType: %x\n", sig->subscriptionType); + fprintf(output, " tableId: %x\n", sig->tableId); + return false; +} + +bool +printSUB_CREATE_CONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubCreateConf * const sig = (SubCreateConf *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + return false; +} + +bool +printSUB_START_REQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubStartReq * const sig = (SubStartReq *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " startPart: %x\n", sig->part); + return false; +} + +bool +printSUB_START_REF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubStartRef * const sig = (SubStartRef *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " startPart: %x\n", sig->part); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + fprintf(output, " err: %x\n", sig->err); + return false; +} + +bool +printSUB_START_CONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubStartConf * const sig = (SubStartConf *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " startPart: %x\n", sig->part); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + return false; +} + +bool +printSUB_SYNC_REQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubSyncReq * const sig = (SubSyncReq *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " syncPart: %x\n", sig->part); + return false; +} + +bool +printSUB_SYNC_REF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubSyncRef * const sig = (SubSyncRef *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " syncPart: %x\n", sig->part); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + fprintf(output, " err: %x\n", sig->err); + return false; +} + +bool +printSUB_SYNC_CONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubSyncConf * const sig = (SubSyncConf *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + fprintf(output, " syncPart: %x\n", sig->part); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + return false; +} + +bool +printSUB_META_DATA(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubMetaData * const sig = (SubMetaData *)theData; + fprintf(output, " gci: %x\n", sig->gci); + fprintf(output, " senderData: %x\n", sig->senderData); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + fprintf(output, " tableId: %x\n", sig->tableId); + return false; +} + +bool +printSUB_TABLE_DATA(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubTableData * const sig = (SubTableData *)theData; + fprintf(output, " senderData: %x\n", sig->senderData); + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + fprintf(output, " gci: %x\n", sig->gci); + fprintf(output, " tableId: %x\n", sig->tableId); + fprintf(output, " operation: %x\n", sig->operation); + fprintf(output, " noOfAttributes: %x\n", sig->noOfAttributes); + fprintf(output, " dataSize: %x\n", sig->dataSize); + return false; +} + +bool +printSUB_SYNC_CONTINUE_REQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubSyncContinueReq * const sig = (SubSyncContinueReq *)theData; + fprintf(output, " subscriberData: %x\n", sig->subscriberData); + fprintf(output, " noOfRowsSent: %x\n", sig->noOfRowsSent); + return false; +} + +bool +printSUB_SYNC_CONTINUE_REF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubSyncContinueRef * const sig = (SubSyncContinueRef *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + return false; +} + +bool +printSUB_SYNC_CONTINUE_CONF(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubSyncContinueConf * const sig = (SubSyncContinueConf *)theData; + fprintf(output, " subscriptionId: %x\n", sig->subscriptionId); + fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey); + return false; +} + +bool +printSUB_GCP_COMPLETE_REP(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const SubGcpCompleteRep * const sig = (SubGcpCompleteRep *)theData; + fprintf(output, " gci: %x\n", sig->gci); + return false; +} + diff --git a/ndb/src/common/debugger/signaldata/SystemError.cpp b/ndb/src/common/debugger/signaldata/SystemError.cpp new file mode 100644 index 00000000000..5ed7dc6b18d --- /dev/null +++ b/ndb/src/common/debugger/signaldata/SystemError.cpp @@ -0,0 +1,41 @@ +/* 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 <NdbStdio.h> +#include <kernel_types.h> +#include <BlockNumbers.h> +#include <signaldata/SystemError.hpp> + +bool +printSYSTEM_ERROR(FILE * output, const Uint32 * theData, Uint32 len, + Uint16 receiverBlockNo){ + + const SystemError * const sig = (SystemError *) theData; + + fprintf(output, "errorRef: H\'%.8x\n", + sig->errorRef); + fprintf(output, "errorCode: %d\n", + sig->errorCode); + fprintf(output, "data1: H\'%.8x\n", + sig->data1); + fprintf(output, "data2: H\'%.8x\n", + sig->data2); + + return true; +} + + diff --git a/ndb/src/common/debugger/signaldata/TcIndx.cpp b/ndb/src/common/debugger/signaldata/TcIndx.cpp new file mode 100644 index 00000000000..6bfa29eff15 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TcIndx.cpp @@ -0,0 +1,159 @@ +/* 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 <signaldata/TcIndx.hpp> +#include <signaldata/TcKeyReq.hpp> +#include <BlockNumbers.h> + +bool +printTCINDXREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const TcIndxReq * const sig = (TcIndxReq *) theData; + + UintR requestInfo = sig->requestInfo; + UintR scanInfo = sig->scanInfo; + + fprintf(output, " apiConnectPtr: H\'%.8x, senderData: H\'%.8x\n", + sig->apiConnectPtr, sig->senderData); + + fprintf(output, " Operation: %s, Flags: ", + sig->getOperationType(requestInfo) == ZREAD ? "Read" : + sig->getOperationType(requestInfo) == ZREAD_EX ? "Read-Ex" : + sig->getOperationType(requestInfo) == ZUPDATE ? "Update" : + sig->getOperationType(requestInfo) == ZINSERT ? "Insert" : + sig->getOperationType(requestInfo) == ZDELETE ? "Delete" : + sig->getOperationType(requestInfo) == ZWRITE ? "Write" : + "Unknown"); + + { + if(sig->getDirtyFlag(requestInfo)){ + fprintf(output, "Dirty "); + } + if(sig->getStartFlag(requestInfo)){ + fprintf(output, "Start "); + } + if (TcKeyReq::getExecuteFlag(sig->requestInfo)) { + fprintf(output, "Execute "); + } + if(sig->getCommitFlag(requestInfo)){ + fprintf(output, "Commit, Type = "); + UintR TcommitType = sig->getCommitType(requestInfo); + if (TcommitType == TcIndxReq::CommitIfFailFree) { + fprintf(output, "FailFree "); + } else if (TcommitType == TcIndxReq::TryCommit) { + fprintf(output, "TryCommit "); + } else if (TcommitType == TcIndxReq::CommitAsMuchAsPossible) { + fprintf(output, "Always "); + }//if + } + if(sig->getSimpleFlag(requestInfo)){ + fprintf(output, "Simple "); + } + if(sig->getInterpretedFlag(requestInfo)){ + fprintf(output, "Interpreted "); + } + if(sig->getDistributionGroupFlag(requestInfo)){ + fprintf(output, "DGroup = %d ", sig->distrGroupHashValue); + } + if(sig->getDistributionKeyFlag(sig->requestInfo)){ + fprintf(output, "DKey = %d ", sig->distributionKeySize); + } + fprintf(output, "\n"); + } + + const int indexLen = sig->getIndexLength(requestInfo); + const int attrInThis = sig->getAIInTcIndxReq(requestInfo); + fprintf(output, + " indexLen: %d, attrLen: %d, AI in this: %d, indexId: %d, " + "indexSchemaVer: %d, API Ver: %d\n", + indexLen, sig->attrLen, attrInThis, + sig->indexId, sig->indexSchemaVersion, sig->getAPIVersion(scanInfo)); + + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n -- Variable Data --\n", + sig->transId1, sig->transId2); + + Uint32 restLen = (len - 8); + const Uint32 * rest = &sig->scanInfo; + while(restLen >= 7){ + fprintf(output, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + rest[0], rest[1], rest[2], rest[3], + rest[4], rest[5], rest[6]); + restLen -= 7; + rest += 7; + } + if(restLen > 0){ + for(Uint32 i = 0; i<restLen; i++) + fprintf(output, " H\'%.8x", rest[i]); + fprintf(output, "\n"); + } + + return true; +} + +bool +printTCINDXCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + if (receiverBlockNo == API_PACKED) { + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + } + else { + const TcIndxConf * const sig = (TcIndxConf *) theData; + + fprintf(output, "Signal data: "); + Uint32 i = 0; + Uint32 confInfo = sig->confInfo; + Uint32 noOfOp = TcIndxConf::getNoOfOperations(confInfo); + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + fprintf(output, "apiConnectPtr: H'%.8x, gci: %u, transId:(H'%.8x, H'%.8x)\n", + sig->apiConnectPtr, sig->gci, sig->transId1, sig->transId2); + + fprintf(output, "noOfOperations: %u, commitFlag: %s, markerFlag: %s\n", + noOfOp, + (TcIndxConf::getCommitFlag(confInfo) == 0)?"false":"true", + (TcIndxConf::getMarkerFlag(confInfo) == 0)?"false":"true"); + fprintf(output, "Operations:\n"); + for(i = 0; i < noOfOp; i++) { + fprintf(output, + "apiOperationPtr: H'%.8x, attrInfoLen: %u\n", + sig->operations[i].apiOperationPtr, + sig->operations[i].attrInfoLen); + } + } + + return true; +} + +bool +printTCINDXREF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + +// const TcIndxRef * const sig = (TcIndxRef *) theData; + + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} + diff --git a/ndb/src/common/debugger/signaldata/TcKeyConf.cpp b/ndb/src/common/debugger/signaldata/TcKeyConf.cpp new file mode 100644 index 00000000000..727e097a464 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TcKeyConf.cpp @@ -0,0 +1,59 @@ +/* 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 <signaldata/TcKeyConf.hpp> +#include <BlockNumbers.h> + +bool +printTCKEYCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + + if (receiverBlockNo == API_PACKED) { + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + } + else { + const TcKeyConf * const sig = (TcKeyConf *) theData; + + fprintf(output, "Signal data: "); + Uint32 i = 0; + Uint32 confInfo = sig->confInfo; + Uint32 noOfOp = TcKeyConf::getNoOfOperations(confInfo); + if (noOfOp > 10) noOfOp = 10; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + fprintf(output, "apiConnectPtr: H'%.8x, gci: %u, transId:(H'%.8x, H'%.8x)\n", + sig->apiConnectPtr, sig->gci, sig->transId1, sig->transId2); + + fprintf(output, "noOfOperations: %u, commitFlag: %s, markerFlag: %s\n", + noOfOp, + (TcKeyConf::getCommitFlag(confInfo) == 0)?"false":"true", + (TcKeyConf::getMarkerFlag(confInfo) == 0)?"false":"true"); + fprintf(output, "Operations:\n"); + for(i = 0; i < noOfOp; i++) { + fprintf(output, + "apiOperationPtr: H'%.8x, attrInfoLen: %u\n", + sig->operations[i].apiOperationPtr, + sig->operations[i].attrInfoLen); + } + } + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/TcKeyRef.cpp b/ndb/src/common/debugger/signaldata/TcKeyRef.cpp new file mode 100644 index 00000000000..0dba9909caf --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TcKeyRef.cpp @@ -0,0 +1,28 @@ +/* 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 <signaldata/TcKeyRef.hpp> + +bool +printTCKEYREF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/TcKeyReq.cpp b/ndb/src/common/debugger/signaldata/TcKeyReq.cpp new file mode 100644 index 00000000000..7304872ff9c --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TcKeyReq.cpp @@ -0,0 +1,114 @@ +/* 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 <signaldata/TcKeyReq.hpp> + +bool +printTCKEYREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + + const TcKeyReq * const sig = (TcKeyReq *) theData; + + UintR requestInfo = sig->requestInfo; + + fprintf(output, " apiConnectPtr: H\'%.8x, apiOperationPtr: H\'%.8x\n", + sig->apiConnectPtr, sig->apiOperationPtr); + fprintf(output, " Operation: %s, Flags: ", + sig->getOperationType(requestInfo) == ZREAD ? "Read" : + sig->getOperationType(requestInfo) == ZREAD_EX ? "Read-Ex" : + sig->getOperationType(requestInfo) == ZUPDATE ? "Update" : + sig->getOperationType(requestInfo) == ZINSERT ? "Insert" : + sig->getOperationType(requestInfo) == ZDELETE ? "Delete" : + sig->getOperationType(requestInfo) == ZWRITE ? "Write" : + "Unknown"); + { + if(sig->getDirtyFlag(requestInfo)){ + fprintf(output, "Dirty "); + } + if(sig->getStartFlag(requestInfo)){ + fprintf(output, "Start "); + } + if(sig->getExecuteFlag(requestInfo)){ + fprintf(output, "Execute "); + } + if(sig->getCommitFlag(requestInfo)){ + fprintf(output, "Commit "); + } + if (sig->getExecutingTrigger(requestInfo)) { + fprintf(output, "Trigger "); + } + + UintR TcommitType = sig->getAbortOption(requestInfo); + if (TcommitType == TcKeyReq::AbortOnError) { + fprintf(output, "AbortOnError "); + } else if (TcommitType == TcKeyReq::IgnoreError) { + fprintf(output, "IgnoreError "); + }//if + + if(sig->getSimpleFlag(requestInfo)){ + fprintf(output, "Simple "); + } + if(sig->getScanIndFlag(requestInfo)){ + fprintf(output, "ScanInd "); + } + if(sig->getInterpretedFlag(requestInfo)){ + fprintf(output, "Interpreted "); + } + if(sig->getDistributionGroupFlag(requestInfo)){ + fprintf(output, "DGroup = %d ", sig->distrGroupHashValue); + } + if(sig->getDistributionKeyFlag(sig->requestInfo)){ + fprintf(output, "DKey = %d ", sig->distributionKeySize); + } + fprintf(output, "\n"); + } + + const int keyLen = sig->getKeyLength(requestInfo); + const int attrInThis = sig->getAIInTcKeyReq(requestInfo); + const int attrLen = sig->getAttrinfoLen(sig->attrLen); + const int apiVer = sig->getAPIVersion(sig->attrLen); + fprintf(output, + " keyLen: %d, attrLen: %d, AI in this: %d, tableId: %d, " + "tableSchemaVer: %d, API Ver: %d\n", + keyLen, attrLen, attrInThis, + sig->tableId, sig->tableSchemaVersion, apiVer); + + fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n -- Variable Data --\n", + sig->transId1, sig->transId2); + + if (len >= TcKeyReq::StaticLength) { + Uint32 restLen = (len - TcKeyReq::StaticLength); + const Uint32 * rest = &sig->scanInfo; + while(restLen >= 7){ + fprintf(output, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + rest[0], rest[1], rest[2], rest[3], + rest[4], rest[5], rest[6]); + restLen -= 7; + rest += 7; + } + if(restLen > 0){ + for(Uint32 i = 0; i<restLen; i++) + fprintf(output, " H\'%.8x", rest[i]); + fprintf(output, "\n"); + } + } else { + fprintf(output, "*** invalid len %u ***\n", len); + } + return true; +} + diff --git a/ndb/src/common/debugger/signaldata/TcRollbackRep.cpp b/ndb/src/common/debugger/signaldata/TcRollbackRep.cpp new file mode 100644 index 00000000000..961f0c3619d --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TcRollbackRep.cpp @@ -0,0 +1,28 @@ +/* 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 <signaldata/TcRollbackRep.hpp> + +bool +printTCROLLBACKREP(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/TrigAttrInfo.cpp b/ndb/src/common/debugger/signaldata/TrigAttrInfo.cpp new file mode 100644 index 00000000000..7a8d176ec61 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TrigAttrInfo.cpp @@ -0,0 +1,53 @@ +/* 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 <signaldata/TrigAttrInfo.hpp> + +static +const char * +tatype(Uint32 i){ + switch(i){ + case TrigAttrInfo::PRIMARY_KEY: + return "PK"; + break; + case TrigAttrInfo::BEFORE_VALUES: + return "BEFORE"; + break; + case TrigAttrInfo::AFTER_VALUES: + return "AFTER"; + break; + } + return "UNKNOWN"; +} + +bool +printTRIG_ATTRINFO(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const TrigAttrInfo * const sig = (TrigAttrInfo *) theData; + + fprintf(output, " TriggerId: %d Type: %s ConnectPtr: %x\n", + sig->getTriggerId(), + tatype(sig->getAttrInfoType()), + sig->getConnectionPtr()); + + Uint32 i = 0; + while (i < len - TrigAttrInfo::StaticLength) + fprintf(output, " H\'%.8x", sig->getData()[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/TupAccess.cpp b/ndb/src/common/debugger/signaldata/TupAccess.cpp new file mode 100644 index 00000000000..e94d4636cf5 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TupAccess.cpp @@ -0,0 +1,131 @@ +/* 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 <signaldata/TupAccess.hpp> +#include <SignalLoggerManager.hpp> +#include <AttributeHeader.hpp> + +bool +printTUP_READ_ATTRS(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn) +{ + const TupReadAttrs* const sig = (const TupReadAttrs*)theData; + if (sig->errorCode == RNIL) + fprintf(output, " errorCode=RNIL flags=%x\n", sig->requestInfo); + else + fprintf(output, " errorCode=%u flags=%x\n", sig->errorCode, sig->requestInfo); + fprintf(output, " table: id=%u", sig->tableId); + fprintf(output, " fragment: id=%u ptr=0x%x\n", sig->fragId, sig->fragPtrI); + fprintf(output, " tuple: addr=0x%x version=%u", sig->tupAddr, sig->tupVersion); + fprintf(output, " realPage=0x%x offset=%u\n", sig->pageId, sig->pageOffset); + const Uint32* buffer = (const Uint32*)sig + TupReadAttrs::SignalLength; + Uint32 attrCount = buffer[0]; + bool readKeys = (sig->requestInfo & TupReadAttrs::ReadKeys); + if (sig->errorCode == RNIL && ! readKeys || + sig->errorCode == 0 && readKeys) { + fprintf(output, " input: attrCount=%u\n", attrCount); + for (unsigned i = 0; i < attrCount; i++) { + AttributeHeader ah(buffer[1 + i]); + fprintf(output, " %u: attrId=%u\n", i, ah.getAttributeId()); + } + } + if (sig->errorCode == 0) { + fprintf(output, " output: attrCount=%u\n", attrCount); + Uint32 pos = 1 + attrCount; + for (unsigned i = 0; i < attrCount; i++) { + AttributeHeader ah(buffer[pos++]); + fprintf(output, " %u: attrId=%u dataSize=%u\n", i, ah.getAttributeId(), ah.getDataSize()); + Uint32 next = pos + ah.getDataSize(); + Uint32 printpos = 0; + while (pos < next) { + SignalLoggerManager::printDataWord(output, printpos, buffer[pos]); + pos++; + } + if (ah.getDataSize() > 0) + fprintf(output, "\n"); + } + } + return true; +} + +bool +printTUP_QUERY_TH(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn) +{ + const TupQueryTh* const sig = (const TupQueryTh*)theData; + fprintf(output, "tableId = %u, fragId = %u ", sig->tableId, sig->fragId); + fprintf(output, "tuple: addr = 0x%x version = %u\n", sig->tupAddr, + sig->tupVersion); + fprintf(output, "transId1 = 0x%x, transId2 = 0x%x, savePointId = %u\n", + sig->transId1, sig->transId2, sig->savePointId); + return true; +} + +bool +printTUP_STORE_TH(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn) +{ + const TupStoreTh* const sig = (const TupStoreTh*)theData; + if (sig->errorCode == RNIL) + fprintf(output, " errorCode=RNIL\n"); + else + fprintf(output, " errorCode=%u\n", sig->errorCode); + fprintf(output, " table: id=%u", sig->tableId); + fprintf(output, " fragment: id=%u ptr=0x%x\n", sig->fragId, sig->fragPtrI); + fprintf(output, " tuple: addr=0x%x", sig->tupAddr); + if ((sig->tupAddr & 0x1) == 0) { + fprintf(output, " fragPage=0x%x index=%u", + sig->tupAddr >> MAX_TUPLES_BITS, + (sig->tupAddr & ((1 <<MAX_TUPLES_BITS) - 1)) >> 1); + fprintf(output, " realPage=0x%x offset=%u\n", sig->pageId, sig->pageOffset); + } else { + fprintf(output, " cacheId=%u\n", + sig->tupAddr >> 1); + } + if (sig->tupVersion != 0) { + fprintf(output, " version=%u ***invalid***\n", sig->tupVersion); + } + bool showdata = true; + switch (sig->opCode) { + case TupStoreTh::OpRead: + fprintf(output, " operation=Read\n"); + showdata = false; + break; + case TupStoreTh::OpInsert: + fprintf(output, " operation=Insert\n"); + break; + case TupStoreTh::OpUpdate: + fprintf(output, " operation=Update\n"); + break; + case TupStoreTh::OpDelete: + fprintf(output, " operation=Delete\n"); + showdata = false; + break; + default: + fprintf(output, " operation=%u ***invalid***\n", sig->opCode); + break; + } + fprintf(output, " data: offset=%u size=%u", sig->dataOffset, sig->dataSize); + if (! showdata) { + fprintf(output, " [not printed]\n"); + } else { + fprintf(output, "\n"); + const Uint32* buffer = (const Uint32*)sig + TupStoreTh::SignalLength; + Uint32 pos = 0; + while (pos < sig->dataSize) + SignalLoggerManager::printDataWord(output, pos, buffer[sig->dataOffset + pos]); + if (sig->dataSize > 0) + fprintf(output, "\n"); + } + return true; +}; diff --git a/ndb/src/common/debugger/signaldata/TupCommit.cpp b/ndb/src/common/debugger/signaldata/TupCommit.cpp new file mode 100644 index 00000000000..d0391b2a8e6 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TupCommit.cpp @@ -0,0 +1,28 @@ +/* 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 <signaldata/TupCommit.hpp> + +bool +printTUPCOMMITREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/TupKey.cpp b/ndb/src/common/debugger/signaldata/TupKey.cpp new file mode 100644 index 00000000000..134b5fde8bc --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TupKey.cpp @@ -0,0 +1,50 @@ +/* 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 <signaldata/TupKey.hpp> + +bool +printTUPKEYREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} + +bool +printTUPKEYCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} + +bool +printTUPKEYREF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ + fprintf(output, "Signal data: "); + Uint32 i = 0; + while (i < len) + fprintf(output, "H\'%.8x ", theData[i++]); + fprintf(output,"\n"); + + return true; +} diff --git a/ndb/src/common/debugger/signaldata/TuxMaint.cpp b/ndb/src/common/debugger/signaldata/TuxMaint.cpp new file mode 100644 index 00000000000..06ac475382c --- /dev/null +++ b/ndb/src/common/debugger/signaldata/TuxMaint.cpp @@ -0,0 +1,45 @@ +/* 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 <signaldata/TuxMaint.hpp> +#include <SignalLoggerManager.hpp> +#include <AttributeHeader.hpp> + +bool +printTUX_MAINT_REQ(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn) +{ + //const bool inOut = rbn & (1 << 15); + const TuxMaintReq* const sig = (const TuxMaintReq*)theData; + fprintf(output, " errorCode=%d\n", sig->errorCode); + fprintf(output, " table: id=%d", sig->tableId); + fprintf(output, " index: id=%d", sig->indexId); + fprintf(output, " fragment: id=%d\n", sig->fragId); + fprintf(output, " tuple: addr=0x%x version=%d\n", sig->tupAddr, sig->tupVersion); + const Uint32 opCode = sig->opInfo & 0xFF; + const Uint32 opFlag = sig->opInfo >> 8; + switch (opCode ) { + case TuxMaintReq::OpAdd: + fprintf(output, " opCode=Add opFlag=%u\n", opFlag); + break; + case TuxMaintReq::OpRemove: + fprintf(output, " opCode=Remove opFlag=%u\n", opFlag); + break; + default: + fprintf(output, " opInfo=%x ***invalid***\n", sig->opInfo); + break; + } + return true; +} diff --git a/ndb/src/common/debugger/signaldata/UtilDelete.cpp b/ndb/src/common/debugger/signaldata/UtilDelete.cpp new file mode 100644 index 00000000000..b6ba53559ac --- /dev/null +++ b/ndb/src/common/debugger/signaldata/UtilDelete.cpp @@ -0,0 +1,65 @@ +/* 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 <signaldata/UtilDelete.hpp> + +bool +printUTIL_DELETE_REQ(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + (void)l; // Don't want compiler warning + (void)b; // Don't want compiler warning + + UtilDeleteReq* sig = (UtilDeleteReq*)data; + fprintf(out, " senderData: %d prepareId: %d totalDataLen: %d\n", + sig->senderData, + sig->prepareId, + sig->totalDataLen); + fprintf(out, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n" + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n" + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + sig->attrData[0], sig->attrData[1], sig->attrData[2], + sig->attrData[3], sig->attrData[4], sig->attrData[5], + sig->attrData[6], sig->attrData[7], sig->attrData[8], + sig->attrData[9], sig->attrData[10], sig->attrData[11], + sig->attrData[12], sig->attrData[13], sig->attrData[14], + sig->attrData[15], sig->attrData[16], sig->attrData[17], + sig->attrData[18], sig->attrData[19], sig->attrData[20], + sig->attrData[21] + ); + + return true; +} + +bool +printUTIL_DELETE_CONF(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + (void)l; // Don't want compiler warning + (void)b; // Don't want compiler warning + + UtilDeleteConf* sig = (UtilDeleteConf*)data; + fprintf(out, " senderData: %d\n", sig->senderData); + return true; +} + +bool +printUTIL_DELETE_REF(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + (void)l; // Don't want compiler warning + (void)b; // Don't want compiler warning + + UtilDeleteRef* sig = (UtilDeleteRef*)data; + fprintf(out, " senderData: %d\n", sig->senderData); + fprintf(out, " errorCode: %d\n", sig->errorCode); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/UtilExecute.cpp b/ndb/src/common/debugger/signaldata/UtilExecute.cpp new file mode 100644 index 00000000000..2c88fa174d4 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/UtilExecute.cpp @@ -0,0 +1,59 @@ +/* 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 <signaldata/UtilExecute.hpp> + +bool +printUTIL_EXECUTE_REQ(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) +{ + const UtilExecuteReq* const sig = (UtilExecuteReq*)data; + fprintf(out, " senderRef: H'%.8x, senderData: H'%.8x prepareId: %d\n", + sig->senderRef, + sig->senderData, + sig->prepareId); + return true; +} + +bool +printUTIL_EXECUTE_CONF(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) +{ + UtilExecuteConf* sig = (UtilExecuteConf*)data; + fprintf(out, " senderData: H'%.8x\n", + sig->senderData); + return true; +} + +bool +printUTIL_EXECUTE_REF(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) +{ + UtilExecuteRef* sig = (UtilExecuteRef*)data; + fprintf(out, " senderData: H'%.8x, ", sig->senderData); + fprintf(out, " errorCode: %s, ", + sig->errorCode == UtilExecuteRef::IllegalKeyNumber ? + "IllegalKeyNumber" : + sig->errorCode == UtilExecuteRef::IllegalAttrNumber ? + "IllegalAttrNumber" : + sig->errorCode == UtilExecuteRef::TCError ? + "TCError" : + sig->errorCode == UtilExecuteRef::IllegalPrepareId ? + "IllegalPrepareId" : + sig->errorCode == UtilExecuteRef::AllocationError ? + "AllocationError" : + "Unknown"); + fprintf(out, " TCErrorCode: %d\n", + sig->TCErrorCode); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/UtilLock.cpp b/ndb/src/common/debugger/signaldata/UtilLock.cpp new file mode 100644 index 00000000000..34e37c3e2d8 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/UtilLock.cpp @@ -0,0 +1,158 @@ +/* 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 <signaldata/UtilLock.hpp> + +bool +printUTIL_LOCK_REQ (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilLockReq *const sig = (UtilLockReq *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " requestInfo: %x\n", sig->requestInfo); + return true; +} + +bool +printUTIL_LOCK_CONF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilLockConf *const sig = (UtilLockConf *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " lockKey: %x\n", sig->lockKey); + return true; +} + +bool +printUTIL_LOCK_REF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilLockRef *const sig = (UtilLockRef *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " errorCode: %x\n", sig->errorCode); + return true; +} + +bool +printUTIL_UNLOCK_REQ (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilUnlockReq *const sig = (UtilUnlockReq *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " lockKey: %x\n", sig->lockKey); + return true; +} + +bool +printUTIL_UNLOCK_CONF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilUnlockConf *const sig = (UtilUnlockConf *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + return true; +} + +bool +printUTIL_UNLOCK_REF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilUnlockRef *const sig = (UtilUnlockRef *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " errorCode: %x\n", sig->errorCode); + return true; +} + +bool +printUTIL_CREATE_LOCK_REQ (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilCreateLockReq *const sig = (UtilCreateLockReq *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " lockType: %x\n", sig->lockType); + return true; +} + +bool +printUTIL_CREATE_LOCK_REF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilCreateLockRef *const sig = (UtilCreateLockRef *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " errorCode: %x\n", sig->errorCode); + return true; +} + +bool +printUTIL_CREATE_LOCK_CONF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilCreateLockConf *const sig = (UtilCreateLockConf *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + return true; +} + +bool +printUTIL_DESTROY_LOCK_REQ (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilDestroyLockReq *const sig = (UtilDestroyLockReq *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " lockKey: %x\n", sig->lockKey); + return true; +} + +bool +printUTIL_DESTROY_LOCK_REF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilDestroyLockRef *const sig = (UtilDestroyLockRef *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + fprintf (output, " errorCode: %x\n", sig->errorCode); + return true; +} + +bool +printUTIL_DESTROY_LOCK_CONF (FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) +{ + const UtilDestroyLockConf *const sig = (UtilDestroyLockConf *) theData; + fprintf (output, " senderData: %x\n", sig->senderData); + fprintf (output, " senderRef: %x\n", sig->senderRef); + fprintf (output, " lockId: %x\n", sig->lockId); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/UtilPrepare.cpp b/ndb/src/common/debugger/signaldata/UtilPrepare.cpp new file mode 100644 index 00000000000..adc2e299380 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/UtilPrepare.cpp @@ -0,0 +1,64 @@ +/* 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 <signaldata/UtilPrepare.hpp> + +bool +printUTIL_PREPARE_REQ(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) +{ + UtilPrepareReq* sig = (UtilPrepareReq*)data; + fprintf(out, " senderRef: H'%.8x senderData: H'%.8x\n", + sig->senderRef, + sig->senderData); + + return true; +} + +bool +printUTIL_PREPARE_CONF(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) +{ + UtilPrepareConf* sig = (UtilPrepareConf*)data; + fprintf(out, " senderData: H'%.8x prepareId: %d\n", + sig->senderData, + sig->prepareId); + return true; +} + +bool +printUTIL_PREPARE_REF(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) +{ + UtilPrepareRef* sig = (UtilPrepareRef*)data; + fprintf(out, " senderData: H'%.8x, ", sig->senderData); + fprintf(out, " error: %d, ", sig->errorCode); + + fprintf(out, " errorMsg: "); + switch(sig->errorCode) { + case UtilPrepareRef::NO_ERROR: + fprintf(out, "No error"); + break; + case UtilPrepareRef::PREPARE_SEIZE_ERROR: + fprintf(out, "Failed to seize Prepare record"); + break; + case UtilPrepareRef::PREPARED_OPERATION_SEIZE_ERROR: + fprintf(out, "Failed to seize PreparedOperation record"); + break; + case UtilPrepareRef::DICT_TAB_INFO_ERROR: + fprintf(out, "Failed to get table info from DICT"); + break; + } + fprintf(out, "\n"); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/UtilSequence.cpp b/ndb/src/common/debugger/signaldata/UtilSequence.cpp new file mode 100644 index 00000000000..e91999d9abf --- /dev/null +++ b/ndb/src/common/debugger/signaldata/UtilSequence.cpp @@ -0,0 +1,67 @@ +/* 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 <signaldata/UtilSequence.hpp> + +inline +const char * +type2string(UtilSequenceReq::RequestType type){ + switch(type){ + case UtilSequenceReq::NextVal: + return "NextVal"; + case UtilSequenceReq::CurrVal: + return "CurrVal"; + case UtilSequenceReq::Create: + return "Create"; + default: + return "Unknown"; + } +} + +bool +printUTIL_SEQUENCE_REQ(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + UtilSequenceReq* sig = (UtilSequenceReq*)data; + fprintf(out, " senderData: %d sequenceId: %d RequestType: %s\n", + sig->senderData, + sig->sequenceId, + type2string((UtilSequenceReq::RequestType)sig->requestType)); + return true; +} + +bool +printUTIL_SEQUENCE_CONF(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + UtilSequenceConf* sig = (UtilSequenceConf*)data; + fprintf(out, " senderData: %d sequenceId: %d RequestType: %s\n", + sig->senderData, + sig->sequenceId, + type2string((UtilSequenceReq::RequestType)sig->requestType)); + fprintf(out, " val: [ %d %d ]\n", + sig->sequenceValue[0], + sig->sequenceValue[1]); + return true; +} + +bool +printUTIL_SEQUENCE_REF(FILE * out, const Uint32 * data, Uint32 l, Uint16 b){ + UtilSequenceRef* sig = (UtilSequenceRef*)data; + fprintf(out, " senderData: %d sequenceId: %d RequestType: %s\n", + sig->senderData, + sig->sequenceId, + type2string((UtilSequenceReq::RequestType)sig->requestType)); + fprintf(out, " errorCode: %d, TCErrorCode: %d\n", + sig->errorCode, sig->TCErrorCode); + return true; +} diff --git a/ndb/src/common/debugger/signaldata/print.awk b/ndb/src/common/debugger/signaldata/print.awk new file mode 100644 index 00000000000..9730fb4a236 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/print.awk @@ -0,0 +1,55 @@ +BEGIN { + m_curr=""; + m_count=0; + m_level=0; +} +/^[ ]*class[ ]+.*{/ { + if(m_curr != ""){ + print; + print "ERROR: " m_curr; + exit; + } + m_curr = $2; +} +/{/ { + m_level++; +} +/bool print/{ + m_print=$3; + i=index($3, "("); + if(i > 0){ + m_print=substr($3, 0, i-1); + } +} + +/[ ]+Uint32[ ]+[^)]*;/ { + if(m_level >= 0){ + m=$2; + i=index($2, ";"); + if(i > 0){ + m=substr($2, 0, i-1); + } + m_members[m_count]=m; + m_count++; + } +} +/^[ ]*}[ ]*;/ { + m_level--; + if(m_level == 0){ + if(m_count > 0 && m_print != ""){ + print "bool"; + print m_print "(FILE * output, const Uint32 * theData, "; + print "Uint32 len, Uint16 receiverBlockNo) {"; + print "const " m_curr " * const sig = (" m_curr " *)theData;"; + for(i = 0; i<m_count; i++){ + print "fprintf(output, \" " m_members[i] ": %x\\n\", sig->" m_members[i] ");"; + } + print "return true;"; + print "}"; + print ""; + } + m_curr=""; + m_print=""; + m_count=0; + } +} diff --git a/ndb/src/common/editline/MANIFEST b/ndb/src/common/editline/MANIFEST new file mode 100644 index 00000000000..dc8b4b36f88 --- /dev/null +++ b/ndb/src/common/editline/MANIFEST @@ -0,0 +1,15 @@ +File Name Description +-------------------------------------------------------- +README Release notes and copyright +MANIFEST This shipping list +Make.os9 OS-9 makefile +Makefile Unix makefile +complete.c Filename completion routines +editline.3 Manual page for editline library +editline.c Line-editing routines +editline_internal.h Internal library header file +os9.h OS-9-specific declarations +sysos9.c OS-9-specific routines +sysunix.c Unix-specific routines +testit.c Test driver +unix.h Unix-specific declarations diff --git a/ndb/src/common/editline/Makefile b/ndb/src/common/editline/Makefile new file mode 100644 index 00000000000..800df8f0f31 --- /dev/null +++ b/ndb/src/common/editline/Makefile @@ -0,0 +1,18 @@ +include .defs.mk + +TYPE := + +ARCHIVE_TARGET := editline + +CFLAGS += -DANSI_ARROWS -DHAVE_TCGETATTR -DSYS_UNIX + +ifeq ($(NDB_OS), WIN32) +SOURCES = editline_win32.c +else +SOURCES = complete.c editline.c sysunix.c +endif + +DIRS := test + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/src/common/editline/README b/ndb/src/common/editline/README new file mode 100644 index 00000000000..537c7bd8611 --- /dev/null +++ b/ndb/src/common/editline/README @@ -0,0 +1,53 @@ +-- +NOTE: This version has been modified by Ericsson/Alzato. Please +see the cvs changelog for more details. +-- + +$Revision: 1.2 $ + +This is a line-editing library. It can be linked into almost any +program to provide command-line editing and recall. + +It is call-compatible with the FSF readline library, but it is a +fraction of the size (and offers fewer features). It does not use +standard I/O. It is distributed under a "C News-like" copyright. + +Configuration is done in the Makefile. Type "make testit" to get +a small slow shell for testing. + +This contains some changes since the posting to comp.sources.misc: + - Bugfix for completion on absolute pathnames. + - Better handling of M-n versus showing raw 8bit chars. + - Better signal handling. + - Now supports termios/termio/sgttyb ioctl's. + - Add M-m command to toggle how 8bit data is displayed. +The following changes, made since the last public release, come from +J.G. Vons <vons@cesar.crbca1.sinet.slb.com>: + - History-searching no longer redraws the line wrong + - Added ESC-ESC as synonym for ESC-? + - SIGQUIT (normally ^\) now sends a signal, not indicating EOF. + - Fixed some typo's and unclear wording in the manpage. + - Fixed completion when all entries shared a common prefix. + - Fixed some meta-char line-redrawing bugs. + +Enjoy, + Rich $alz + <rsalz@osf.org> + + Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + + This software is not subject to any license of the American Telephone + and Telegraph Company or of the Regents of the University of California. + + Permission is granted to anyone to use this software for any purpose on + any computer system, and to alter it and redistribute it freely, subject + to the following restrictions: + 1. The authors are not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + 2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + 3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + 4. This notice may not be removed or altered. diff --git a/ndb/src/common/editline/complete.c b/ndb/src/common/editline/complete.c new file mode 100644 index 00000000000..d1f8b1d3ff4 --- /dev/null +++ b/ndb/src/common/editline/complete.c @@ -0,0 +1,211 @@ +/* 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 */ + +/* -*- c-basic-offset: 4; -*- +** $Revision: 1.8 $ +** +** History and file completion functions for editline library. +*/ +#include "editline_internal.h" + + +/* +** strcmp-like sorting predicate for qsort. +*/ +static int +compare(const void *p1, const void *p2) +{ + const char **v1; + const char **v2; + + v1 = (const char **)p1; + v2 = (const char **)p2; + return strcmp(*v1, *v2); +} + +/* +** Fill in *avp with an array of names that match file, up to its length. +** Ignore . and .. . +*/ +static int +FindMatches(char *dir, char *file, char ***avp) +{ + char **av; + char **new; + char *p; + DIR *dp; + struct dirent *ep; + size_t ac; + size_t len; + + if ((dp = opendir(dir)) == NULL) + return 0; + + av = NULL; + ac = 0; + len = strlen(file); + while ((ep = readdir(dp)) != NULL) { + p = ep->d_name; + if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))) + continue; + if (len && strncmp(p, file, len) != 0) + continue; + + if ((ac % MEM_INC) == 0) { + if ((new = malloc(sizeof(char*) * (ac + MEM_INC))) == NULL) + break; + if (ac) { + memcpy(new, av, ac * sizeof (char **)); + free(av); + } + *avp = av = new; + } + + if ((av[ac] = strdup(p)) == NULL) { + if (ac == 0) + free(av); + break; + } + ac++; + } + + /* Clean up and return. */ + (void)closedir(dp); + if (ac) + qsort(av, ac, sizeof (char **), compare); + return ac; +} + +/* +** Split a pathname into allocated directory and trailing filename parts. +*/ +static int +SplitPath(char *path, char **dirpart, char ** filepart) +{ + static char DOT[] = "."; + char *dpart; + char *fpart; + + if ((fpart = strrchr(path, '/')) == NULL) { + if ((dpart = strdup(DOT)) == NULL) + return -1; + if ((fpart = strdup(path)) == NULL) { + free(dpart); + return -1; + } + } + else { + if ((dpart = strdup(path)) == NULL) + return -1; + dpart[fpart - path + 1] = '\0'; + if ((fpart = strdup(++fpart)) == NULL) { + free(dpart); + return -1; + } + } + *dirpart = dpart; + *filepart = fpart; + return 0; +} + +/* +** Attempt to complete the pathname, returning an allocated copy. +** Fill in *unique if we completed it, or set it to 0 if ambiguous. +*/ +char * +rl_complete(char *pathname,int *unique) +{ + char **av; + char *dir; + char *file; + char *new; + char *p; + size_t ac; + size_t end; + size_t i; + size_t j; + size_t len; + size_t new_len; + size_t p_len; + + if (SplitPath(pathname, &dir, &file) < 0) + return NULL; + if ((ac = FindMatches(dir, file, &av)) == 0) { + free(dir); + free(file); + return NULL; + } + + p = NULL; + len = strlen(file); + if (ac == 1) { + /* Exactly one match -- finish it off. */ + *unique = 1; + j = strlen(av[0]) - len + 2; + p_len = sizeof(char) * (j + 1); + if ((p = malloc(p_len)) != NULL) { + memcpy(p, av[0] + len, j); + new_len = sizeof(char) * (strlen(dir) + strlen(av[0]) + 2); + new = malloc(new_len); + if(new != NULL) { + snprintf(new, new_len, "%s/%s", dir, av[0]); + rl_add_slash(new, p, p_len); + free(new); + } + } + } + else { + /* Find largest matching substring. */ + for (*unique = 0, i = len, end = strlen(av[0]); i < end; i++) + for (j = 1; j < ac; j++) + if (av[0][i] != av[j][i]) + goto breakout; +breakout: + if (i > len) { + j = i - len + 1; + if ((p = malloc(sizeof(char) * j)) != NULL) { + memcpy(p, av[0] + len, j); + p[j - 1] = '\0'; + } + } + } + + /* Clean up and return. */ + free(dir); + free(file); + for (i = 0; i < ac; i++) + free(av[i]); + free(av); + return p; +} + +/* +** Return all possible completions. +*/ +int +rl_list_possib(char *pathname, char ***avp) +{ + char *dir; + char *file; + int ac; + + if (SplitPath(pathname, &dir, &file) < 0) + return 0; + ac = FindMatches(dir, file, avp); + free(dir); + free(file); + return ac; +} diff --git a/ndb/src/common/editline/editline.3 b/ndb/src/common/editline/editline.3 new file mode 100644 index 00000000000..159cc7f87bb --- /dev/null +++ b/ndb/src/common/editline/editline.3 @@ -0,0 +1,178 @@ +.\" $Revision: 1.1 $ +.TH EDITLINE 3 +.SH NAME +editline \- command-line editing library with history +.SH SYNOPSIS +.nf +.B "char *" +.B "readline(prompt)" +.B " char *prompt;" + +.B "void" +.B "add_history(line)" +.B " char *line;" +.fi +.SH DESCRIPTION +.I Editline +is a library that provides an line-editing interface with text recall. +It is intended to be compatible with the +.I readline +library provided by the Free Software Foundation, but much smaller. +The bulk of this manual page describes the user interface. +.PP +The +.I readline +routine returns a line of text with the trailing newline removed. +The data is returned in a buffer allocated with +.IR malloc (3), +so the space should be released with +.IR free (3) +when the calling program is done with it. +Before accepting input from the user, the specified +.I prompt +is displayed on the terminal. +.PP +The +.I add_history +routine makes a copy of the specified +.I line +and adds it to the internal history list. +.SS "User Interface" +A program that uses this library provides a simple emacs-like editing +interface to its users. +A line may be edited before it is sent to the calling program by typing either +control characters or escape sequences. +A control character, shown as a caret followed by a letter, is typed by +holding down the ``control'' key while the letter is typed. +For example, ``^A'' is a control-A. +An escape sequence is entered by typing the ``escape'' key followed by one or +more characters. +The escape key is abbreviated as ``ESC''. +Note that unlike control keys, case matters in escape sequences; ``ESC\ F'' +is not the same as ``ESC\ f''. +.PP +An editing command may be typed anywhere on the line, not just at the +beginning. +In addition, a return may also be typed anywhere on the line, not just at +the end. +.PP +Most editing commands may be given a repeat count, +.IR n , +where +.I n +is a number. +To enter a repeat count, type the escape key, the number, and then +the command to execute. +For example, ``ESC\ 4\ ^f'' moves forward four characters. +If a command may be given a repeat count then the text ``[n]'' is given at the +end of its description. +.PP +The following control characters are accepted: +.RS +.nf +.ta \w'ESC DEL 'u +^A Move to the beginning of the line +^B Move left (backwards) [n] +^D Delete character [n] +^E Move to end of line +^F Move right (forwards) [n] +^G Ring the bell +^H Delete character before cursor (backspace key) [n] +^I Complete filename (tab key); see below +^J Done with line (return key) +^K Kill to end of line (or column [n]) +^L Redisplay line +^M Done with line (alternate return key) +^N Get next line from history [n] +^P Get previous line from history [n] +^R Search backward (forward if [n]) through history for text; +\& prefixing the string with a caret (^) forces it to +\& match only at the beginning of a history line +^T Transpose characters +^V Insert next character, even if it is an edit command +^W Wipe to the mark +^X^X Exchange current location and mark +^Y Yank back last killed text +^[ Start an escape sequence (escape key) +^]c Move forward to next character ``c'' +^? Delete character before cursor (delete key) [n] +.fi +.RE +.PP +The following escape sequences are provided. +.RS +.nf +.ta \w'ESC DEL 'u +ESC\ ^H Delete previous word (backspace key) [n] +ESC\ DEL Delete previous word (delete key) [n] +ESC\ ESC Show possible completions; see below +ESC\ SP Set the mark (space key); see ^X^X and ^Y above +ESC\ . Get the last (or [n]'th) word from previous line +ESC\ ? Show possible completions; see below +ESC\ < Move to start of history +ESC\ > Move to end of history +ESC\ b Move backward a word [n] +ESC\ d Delete word under cursor [n] +ESC\ f Move forward a word [n] +ESC\ l Make word lowercase [n] +ESC\ m Toggle if 8bit chars display as themselves or with +\& an ``M\-'' prefix +ESC\ u Make word uppercase [n] +ESC\ y Yank back last killed text +ESC\ w Make area up to mark yankable +ESC\ nn Set repeat count to the number nn +ESC\ C Read from environment variable ``_C_'', where C is +\& an uppercase letter +.fi +.RE +.PP +The +.I editline +library has a small macro facility. +If you type the escape key followed by an uppercase letter, +.IR C , +then the contents of the environment variable +.I _C_ +are read in as if you had typed them at the keyboard. +For example, if the variable +.I _L_ +contains the following: +.RS +^A^Kecho '^V^[[H^V^[[2J'^M +.RE +Then typing ``ESC L'' will move to the beginning of the line, kill the +entire line, enter the echo command needed to clear the terminal (if your +terminal is like a VT-100), and send the line back to the shell. +.PP +The +.I editline +library also does filename completion. +Suppose the root directory has the following files in it: +.RS +.nf +.ta \w'core 'u +bin vmunix +core vmunix.old +.fi +.RE +If you type ``rm\ /v'' and then the tab key. +.I Editline +will then finish off as much of the name as possible by adding ``munix''. +Because the name is not unique, it will then beep. +If you type the escape key followed by either a question mark or another +escape, it will display the two choices. +If you then type a period and a tab, the library will finish off the filename +for you: +.RS +.nf +.RI "rm /v[TAB]" munix ".[TAB]" old +.fi +.RE +The tab key is shown by ``[TAB]'' and the automatically-entered text +is shown in italics. +.SH "BUGS AND LIMITATIONS" +Cannot handle lines more than 80 columns. +.SH AUTHORS +Simmule R. Turner <uunet.uu.net!capitol!sysgo!simmy> +and Rich $alz <rsalz@osf.org>. +Original manual page by DaviD W. Sanderson <dws@ssec.wisc.edu>. diff --git a/ndb/src/common/editline/editline.c b/ndb/src/common/editline/editline.c new file mode 100644 index 00000000000..0529d18b952 --- /dev/null +++ b/ndb/src/common/editline/editline.c @@ -0,0 +1,1514 @@ +/* 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 */ + +/* -*- c-basic-offset: 4; -*- +** $Revision: 1.6 $ +** +** Main editing routines for editline library. +*/ +#include "editline_internal.h" +#include <signal.h> +#include <ctype.h> +#include <unistd.h> + +/* +** Manifest constants. +*/ +#define SCREEN_WIDTH 80 +#define SCREEN_ROWS 24 +#define NO_ARG (-1) +#define DEL 127 +#define TAB '\t' +#define CTL(x) ((x) & 0x1F) +#define ISCTL(x) ((x) && (x) < ' ') +#define UNCTL(x) ((x) + 64) +#define META(x) ((x) | 0x80) +#define ISMETA(x) ((x) & 0x80) +#define UNMETA(x) ((x) & 0x7F) +#define MAPSIZE 32 +#define METAMAPSIZE 16 +#if !defined(HIST_SIZE) +#define HIST_SIZE 20 +#endif /* !defined(HIST_SIZE) */ + +/* +** Command status codes. +*/ +typedef enum _STATUS { + CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal +} STATUS; + +/* +** The type of case-changing to perform. +*/ +typedef enum _CASE { + TOupper, TOlower +} CASE; + +/* +** Key to command mapping. +*/ +typedef struct _KEYMAP { + char Key; + char Active; + STATUS (*Function)(); +} KEYMAP; + +/* +** Command history structure. +*/ +typedef struct _HISTORY { + int Size; + int Pos; + char *Lines[HIST_SIZE]; +} HISTORY; + +/* +** Globals. +*/ +int rl_eof; +int rl_erase; +int rl_intr; +int rl_kill; +int rl_quit; +#if defined(DO_SIGTSTP) +int rl_susp; +#endif /* defined(DO_SIGTSTP) */ + +static char NIL[] = ""; +static const char *Input = NIL; +static char *Line; +static const char *Prompt; +static char *Yanked; +static char *Screen; +static char NEWLINE[]= CRLF; +static HISTORY H; +static int Repeat; +static int End; +static int Mark; +static int OldPoint; +static int Point; +static int PushBack; +static int Pushed; +static int Signal; +static KEYMAP Map[MAPSIZE]; +static KEYMAP MetaMap[METAMAPSIZE]; +static size_t Length; +static size_t ScreenCount; +static size_t ScreenSize; +static char *backspace; +static int TTYwidth; +static int TTYrows; + +/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ +int rl_meta_chars = 1; + +/* +** Declarations. +*/ +static char *editinput(); + +#if defined(USE_TERMCAP) +extern char *getenv(); +extern char *tgetstr(); +extern int tgetent(); +extern int tgetnum(); +#endif /* defined(USE_TERMCAP) */ + +/* +** TTY input/output functions. +*/ + +static void +TTYflush() +{ + if (ScreenCount) { + (void)write(1, Screen, ScreenCount); + ScreenCount = 0; + } +} + +static void +TTYput(const char c) +{ + Screen[ScreenCount] = c; + if (++ScreenCount >= ScreenSize - 1) { + ScreenSize += SCREEN_INC; + Screen = realloc(Screen, sizeof(char) * ScreenSize); + /* XXX what to do if realloc failes? */ + } +} + +static void +TTYputs(const char *p) +{ + while (*p) + TTYput(*p++); +} + +static void +TTYshow(char c) +{ + if (c == DEL) { + TTYput('^'); + TTYput('?'); + } + else if (c == TAB) { + /* XXX */ + } + else if (ISCTL(c)) { + TTYput('^'); + TTYput(UNCTL(c)); + } + else if (rl_meta_chars && ISMETA(c)) { + TTYput('M'); + TTYput('-'); + TTYput(UNMETA(c)); + } + else + TTYput(c); +} + +static void +TTYstring(char *p) +{ + while (*p) + TTYshow(*p++); +} + +static int +TTYget() +{ + char c; + + TTYflush(); + if (Pushed) { + Pushed = 0; + return PushBack; + } + if (*Input) + return *Input++; + return read(0, &c, (size_t)1) == 1 ? c : EOF; +} + +#define TTYback() (backspace ? TTYputs((const char *)backspace) : TTYput('\b')) + +static void +TTYbackn(int n) +{ + while (--n >= 0) + TTYback(); +} + +static void +TTYinfo() +{ + static int init; +#if defined(USE_TERMCAP) + char *term; + char buff[2048]; + char *bp; + char *p; +#endif /* defined(USE_TERMCAP) */ +#if defined(TIOCGWINSZ) + struct winsize W; +#endif /* defined(TIOCGWINSZ) */ + + if (init) { +#if defined(TIOCGWINSZ) + /* Perhaps we got resized. */ + if (ioctl(0, TIOCGWINSZ, &W) >= 0 + && W.ws_col > 0 && W.ws_row > 0) { + TTYwidth = (int)W.ws_col; + TTYrows = (int)W.ws_row; + } +#endif /* defined(TIOCGWINSZ) */ + return; + } + init++; + + TTYwidth = TTYrows = 0; +#if defined(USE_TERMCAP) + bp = &buff[0]; + if ((term = getenv("TERM")) == NULL) + term = "dumb"; + if (tgetent(buff, term) < 0) { + TTYwidth = SCREEN_WIDTH; + TTYrows = SCREEN_ROWS; + return; + } + p = tgetstr("le", &bp); + backspace = p ? strdup(p) : NULL; + TTYwidth = tgetnum("co"); + TTYrows = tgetnum("li"); +#endif /* defined(USE_TERMCAP) */ + +#if defined(TIOCGWINSZ) + if (ioctl(0, TIOCGWINSZ, &W) >= 0) { + TTYwidth = (int)W.ws_col; + TTYrows = (int)W.ws_row; + } +#endif /* defined(TIOCGWINSZ) */ + + if (TTYwidth <= 0 || TTYrows <= 0) { + TTYwidth = SCREEN_WIDTH; + TTYrows = SCREEN_ROWS; + } +} + + +/* +** Print an array of words in columns. +*/ +static void +columns(int ac, char **av) +{ + char *p; + int i; + int j; + int k; + int len; + int skip; + int longest; + int cols; + + /* Find longest name, determine column count from that. */ + for (longest = 0, i = 0; i < ac; i++) + if ((j = strlen((char *)av[i])) > longest) + longest = j; + cols = TTYwidth / (longest + 3); + + TTYputs((const char *)NEWLINE); + for (skip = ac / cols + 1, i = 0; i < skip; i++) { + for (j = i; j < ac; j += skip) { + for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++) + TTYput(*p); + if (j + skip < ac) + while (++len < longest + 3) + TTYput(' '); + } + TTYputs((const char *)NEWLINE); + } +} + +static void +reposition() +{ + int i; + char *p; + + TTYput('\r'); + TTYputs((const char *)Prompt); + for (i = Point, p = Line; --i >= 0; p++) + TTYshow(*p); +} + +static void +left(STATUS Change) +{ + char c; + + TTYback(); + if (Point) { + c = Line[Point - 1]; + if (c == TAB) { + /* XXX */ + } + else if (ISCTL(c)) + TTYback(); + else if (rl_meta_chars && ISMETA(c)) { + TTYback(); + TTYback(); + } + } + if (Change == CSmove) + Point--; +} + +static void +right(STATUS Change) +{ + TTYshow(Line[Point]); + if (Change == CSmove) + Point++; +} + +static STATUS +ring_bell() +{ + TTYput('\07'); + TTYflush(); + return CSstay; +} + +static STATUS +do_macro(int c) +{ + char name[4]; + + name[0] = '_'; + name[1] = c; + name[2] = '_'; + name[3] = '\0'; + + if ((Input = (char *)getenv((char *)name)) == NULL) { + Input = NIL; + return ring_bell(); + } + return CSstay; +} + +static STATUS +do_forward(STATUS move) +{ + int i; + char *p; + + i = 0; + do { + p = &Line[Point]; + for ( ; Point < End && (*p == ' ' || !isalnum((int)*p)); Point++, p++) + if (move == CSmove) + right(CSstay); + + for (; Point < End && isalnum((int)*p); Point++, p++) + if (move == CSmove) + right(CSstay); + + if (Point == End) + break; + } while (++i < Repeat); + + return CSstay; +} + +static STATUS +do_case(CASE type) +{ + int i; + int end; + int count; + char *p; + + (void)do_forward(CSstay); + if (OldPoint != Point) { + if ((count = Point - OldPoint) < 0) + count = -count; + Point = OldPoint; + if ((end = Point + count) > End) + end = End; + for (i = Point, p = &Line[i]; i < end; i++, p++) { + if (type == TOupper) { + if (islower((int)*p)) + *p = toupper((int)*p); + } + else if (isupper((int)*p)) + *p = tolower((int)*p); + right(CSmove); + } + } + return CSstay; +} + +static STATUS +case_down_word() +{ + return do_case(TOlower); +} + +static STATUS +case_up_word() +{ + return do_case(TOupper); +} + +static void +ceol() +{ + int extras; + int i; + char *p; + + for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { + TTYput(' '); + if (*p == TAB) { + /* XXX */ + } + else if (ISCTL(*p)) { + TTYput(' '); + extras++; + } + else if (rl_meta_chars && ISMETA(*p)) { + TTYput(' '); + TTYput(' '); + extras += 2; + } + } + + for (i += extras; i > Point; i--) + TTYback(); +} + +static void +clear_line() +{ + Point = -strlen(Prompt); + TTYput('\r'); + ceol(); + Point = 0; + End = 0; + Line[0] = '\0'; +} + +static STATUS +insert_string(char *p) +{ + size_t len; + int i; + char *new; + char *q; + + len = strlen((char *)p); + if (End + len >= Length) { + if ((new = malloc(sizeof(char) * (Length + len + MEM_INC))) == NULL) + return CSstay; + if (Length) { + memcpy(new, Line, Length); + free(Line); + } + Line = new; + Length += len + MEM_INC; + } + + for (q = &Line[Point], i = End - Point; --i >= 0; ) + q[len + i] = q[i]; + memcpy(&Line[Point], p, len); + End += len; + Line[End] = '\0'; + TTYstring(&Line[Point]); + Point += len; + + return Point == End ? CSstay : CSmove; +} + +static STATUS +redisplay() +{ + TTYputs((const char *)NEWLINE); + TTYputs((const char *)Prompt); + TTYstring(Line); + return CSmove; +} + +static STATUS +redisplay_no_nl() +{ + TTYput('\r'); + TTYputs((const char *)Prompt); + TTYstring(Line); + return CSmove; +} + +static STATUS +toggle_meta_mode() +{ + rl_meta_chars = !rl_meta_chars; + return redisplay(); +} + + +static char * +next_hist() +{ + return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos]; +} + +static char * +prev_hist() +{ + return H.Pos == 0 ? NULL : H.Lines[--H.Pos]; +} + +static STATUS +do_insert_hist(char *p) +{ + if (p == NULL) + return ring_bell(); + Point = 0; + reposition(); + ceol(); + End = 0; + return insert_string(p); +} + +static STATUS +do_hist(char *(*move)()) +{ + char *p; + int i; + + i = 0; + do { + if ((p = (*move)()) == NULL) + return ring_bell(); + } while (++i < Repeat); + return do_insert_hist(p); +} + +static STATUS +h_next() +{ + return do_hist(next_hist); +} + +static STATUS +h_prev() +{ + return do_hist(prev_hist); +} + +static STATUS +h_first() +{ + return do_insert_hist(H.Lines[H.Pos = 0]); +} + +static STATUS +h_last() +{ + return do_insert_hist(H.Lines[H.Pos = H.Size - 1]); +} + +/* +** Return zero if pat appears as a substring in text. +*/ +static int +substrcmp(char *text, char *pat,int len) +{ + char c; + + if ((c = *pat) == '\0') + return *text == '\0'; + for ( ; *text; text++) + if (*text == c && strncmp(text, pat, len) == 0) + return 0; + return 1; +} + +static char * +search_hist(char *search,char *(*move)()) +{ + static char *old_search; + int len; + int pos; + int (*match)(); + char *pat; + + /* Save or get remembered search pattern. */ + if (search && *search) { + if (old_search) + free(old_search); + old_search = strdup(search); + } + else { + if (old_search == NULL || *old_search == '\0') + return NULL; + search = old_search; + } + + /* Set up pattern-finder. */ + if (*search == '^') { + match = strncmp; + pat = (char *)(search + 1); + } + else { + match = substrcmp; + pat = (char *)search; + } + len = strlen(pat); + + for (pos = H.Pos; (*move)() != NULL; ) + if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) + return H.Lines[H.Pos]; + H.Pos = pos; + return NULL; +} + +static STATUS +h_search() +{ + static int Searching; + const char *old_prompt; + char *(*move)(); + char *p; + + if (Searching) + return ring_bell(); + Searching = 1; + + clear_line(); + old_prompt = Prompt; + Prompt = "Search: "; + TTYputs((const char *)Prompt); + move = Repeat == NO_ARG ? prev_hist : next_hist; + p = editinput(); + Searching = 0; + if (p == NULL && Signal > 0) { + Signal = 0; + clear_line(); + Prompt = old_prompt; + return redisplay_no_nl(); + } + p = search_hist(p, move); + clear_line(); + Prompt = old_prompt; + if (p == NULL) { + (void)ring_bell(); + return redisplay_no_nl(); + } + return do_insert_hist(p); +} + +static STATUS +fd_char() +{ + int i; + + i = 0; + do { + if (Point >= End) + break; + right(CSmove); + } while (++i < Repeat); + return CSstay; +} + +static void +save_yank(int begin, int i) +{ + if (Yanked) { + free(Yanked); + Yanked = NULL; + } + + if (i < 1) + return; + + if ((Yanked = malloc(sizeof(char) * (i + 1))) != NULL) { + memcpy(Yanked, &Line[begin], i); + Yanked[i] = '\0'; + } +} + +static STATUS +delete_string(int count) +{ + int i; + char *p; + + if (count <= 0 || End == Point) + return ring_bell(); + + if (count == 1 && Point == End - 1) { + /* Optimize common case of delete at end of line. */ + End--; + p = &Line[Point]; + i = 1; + TTYput(' '); + if (*p == TAB) { + /* XXX */ + } + else if (ISCTL(*p)) { + i = 2; + TTYput(' '); + } + else if (rl_meta_chars && ISMETA(*p)) { + i = 3; + TTYput(' '); + TTYput(' '); + } + TTYbackn(i); + *p = '\0'; + return CSmove; + } + if (Point + count > End && (count = End - Point) <= 0) + return CSstay; + + if (count > 1) + save_yank(Point, count); + + ceol(); + for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++) + p[0] = p[count]; + End -= count; + TTYstring(&Line[Point]); + return CSmove; +} + +static STATUS +bk_char() +{ + int i; + + i = 0; + do { + if (Point == 0) + break; + left(CSmove); + } while (++i < Repeat); + + return CSstay; +} + +static STATUS +bk_del_char() +{ + int i; + + i = 0; + do { + if (Point == 0) + break; + left(CSmove); + } while (++i < Repeat); + + return delete_string(i); +} + +static STATUS +kill_line() +{ + int i; + + if (Repeat != NO_ARG) { + if (Repeat < Point) { + i = Point; + Point = Repeat; + reposition(); + (void)delete_string(i - Point); + } + else if (Repeat > Point) { + right(CSmove); + (void)delete_string(Repeat - Point - 1); + } + return CSmove; + } + + save_yank(Point, End - Point); + ceol(); + Line[Point] = '\0'; + End = Point; + return CSstay; +} + +static STATUS +insert_char(int c) +{ + STATUS s; + char buff[2]; + char *p; + char *q; + int i; + + if (Repeat == NO_ARG || Repeat < 2) { + buff[0] = c; + buff[1] = '\0'; + return insert_string(buff); + } + + if ((p = malloc(sizeof(char) * (Repeat + 1))) == NULL) + return CSstay; + for (i = Repeat, q = p; --i >= 0; ) + *q++ = c; + *q = '\0'; + Repeat = 0; + s = insert_string(p); + free(p); + return s; +} + +static STATUS +meta() +{ + int c; + KEYMAP *kp; + + if ((c = TTYget()) == EOF) + return CSeof; +#if defined(ANSI_ARROWS) + /* Also include VT-100 arrows. */ + if (c == '[' || c == 'O') + switch ((int)(c = TTYget())) { + default: return ring_bell(); + case EOF: return CSeof; + case 'A': return h_prev(); + case 'B': return h_next(); + case 'C': return fd_char(); + case 'D': return bk_char(); + } +#endif /* defined(ANSI_ARROWS) */ + + if (isdigit(c)) { + for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); ) + Repeat = Repeat * 10 + c - '0'; + Pushed = 1; + PushBack = c; + return CSstay; + } + + if (isupper(c)) + return do_macro(c); + for (OldPoint = Point, kp = MetaMap; kp < &MetaMap[METAMAPSIZE]; kp++) + if (kp->Key == c && kp->Active) + return (*kp->Function)(); + + return ring_bell(); +} + +static STATUS +emacs(int c) +{ + STATUS s; + KEYMAP *kp; + +#if 0 + /* This test makes it impossible to enter eight-bit characters when + * meta-char mode is enabled. */ + if (rl_meta_chars && ISMETA(c)) { + Pushed = 1; + PushBack = UNMETA(c); + return meta(); + } +#endif /* 0 */ + for (kp = Map; kp < &Map[MAPSIZE]; kp++) + if (kp->Key == c && kp->Active) + break; + s = kp < &Map[MAPSIZE] ? (*kp->Function)() : insert_char((int)c); + if (!Pushed) + /* No pushback means no repeat count; hacky, but true. */ + Repeat = NO_ARG; + return s; +} + +static STATUS +TTYspecial(int c) +{ + if (rl_meta_chars && ISMETA(c)) + return CSdispatch; + + if (c == rl_erase || c == DEL) + return bk_del_char(); + if (c == rl_kill) { + if (Point != 0) { + Point = 0; + reposition(); + } + Repeat = NO_ARG; + return kill_line(); + } + if (c == rl_eof && Point == 0 && End == 0) + return CSeof; + if (c == rl_intr) { + Signal = SIGINT; + return CSsignal; + } + if (c == rl_quit) { + Signal = SIGQUIT; + return CSsignal; + } +#if defined(DO_SIGTSTP) + if (c == rl_susp) { + Signal = SIGTSTP; + return CSsignal; + } +#endif /* defined(DO_SIGTSTP) */ + + return CSdispatch; +} + +static char * +editinput() +{ + int c; + + Repeat = NO_ARG; + OldPoint = Point = Mark = End = 0; + Line[0] = '\0'; + + Signal = -1; + while ((c = TTYget()) != EOF) + switch (TTYspecial(c)) { + case CSdone: + return Line; + case CSeof: + return NULL; + case CSsignal: + return (char *)""; + case CSmove: + reposition(); + break; + case CSdispatch: + switch (emacs(c)) { + case CSdone: + return Line; + case CSeof: + return NULL; + case CSsignal: + return (char *)""; + case CSmove: + reposition(); + break; + case CSdispatch: + case CSstay: + break; + } + break; + case CSstay: + break; + } + return NULL; +} + +static void +hist_add(char *p) +{ + int i; + + if ((p = strdup(p)) == NULL) + return; + if (H.Size < HIST_SIZE) + H.Lines[H.Size++] = p; + else { + free(H.Lines[0]); + for (i = 0; i < HIST_SIZE - 1; i++) + H.Lines[i] = H.Lines[i + 1]; + H.Lines[i] = p; + } + H.Pos = H.Size - 1; +} + +static char * +read_redirected() +{ + int size; + char *p; + char *line; + char *end; + + for (size = MEM_INC, p = line = malloc(sizeof(char) * size), end = p + size; ; p++) { + if (p == end) { + size += MEM_INC; + p = line = realloc(line, size); + end = p + size; + } + if (read(0, p, 1) <= 0) { + /* Ignore "incomplete" lines at EOF, just like we do for a tty. */ + free(line); + return NULL; + } + if (*p == '\n') + break; + } + *p = '\0'; + return line; +} + +/* +** For compatibility with FSF readline. +*/ +/* ARGSUSED0 */ +void +rl_reset_terminal(char *p) +{ + (void)p; /* Suppress warning */ +} + +void +rl_initialize() +{ +} + +int +rl_insert(int count, int c) +{ + if (count > 0) { + Repeat = count; + (void)insert_char(c); + (void)redisplay_no_nl(); + } + return 0; +} + +int (*rl_event_hook)(); + +int +rl_key_action(int c, char flag) +{ + KEYMAP *kp; + int size; + + (void)flag; /* Suppress warning */ + + if (ISMETA(c)) { + kp = MetaMap; + size = METAMAPSIZE; + } + else { + kp = Map; + size = MAPSIZE; + } + for ( ; --size >= 0; kp++) + if (kp->Key == c) { + kp->Active = c ? 1 : 0; + return 1; + } + return -1; +} + +char * +readline(const char *prompt) +{ + char *line; + int s; + + if (!isatty(0)) { + TTYflush(); + return read_redirected(); + } + + if (Line == NULL) { + Length = MEM_INC; + if ((Line = malloc(sizeof(char) * Length)) == NULL) + return NULL; + } + + TTYinfo(); + rl_ttyset(0); + hist_add(NIL); + ScreenSize = SCREEN_INC; + Screen = malloc(sizeof(char) * ScreenSize); + Prompt = prompt ? prompt : (char *)NIL; + TTYputs((const char *)Prompt); + if ((line = editinput()) != NULL) { + line = strdup(line); + TTYputs((const char *)NEWLINE); + TTYflush(); + } + rl_ttyset(1); + free(Screen); + free(H.Lines[--H.Size]); + if (Signal > 0) { + s = Signal; + Signal = 0; + (void)kill(getpid(), s); + } + return (char *)line; +} + +void +add_history(char *p) +{ + if (p == NULL || *p == '\0') + return; + +#if defined(UNIQUE_HISTORY) + if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0) + return; +#endif /* defined(UNIQUE_HISTORY) */ + hist_add((char *)p); +} + + +static STATUS +beg_line() +{ + if (Point) { + Point = 0; + return CSmove; + } + return CSstay; +} + +static STATUS +del_char() +{ + return delete_string(Repeat == NO_ARG ? 1 : Repeat); +} + +static STATUS +end_line() +{ + if (Point != End) { + Point = End; + return CSmove; + } + return CSstay; +} + +/* +** Return allocated copy of word under cursor, moving cursor after the +** word. +*/ +static char * +find_word() +{ + static char SEPS[] = "\"#;&|^$=`'{}()<>\n\t "; + char *p; + char *new; + size_t len; + + /* Move forward to end of word. */ + p = &Line[Point]; + for ( ; Point < End && strchr(SEPS, (char)*p) == NULL; Point++, p++) + right(CSstay); + + /* Back up to beginning of word. */ + for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--) + continue; + len = Point - (p - Line) + 1; + if ((new = malloc(sizeof(char) * len)) == NULL) + return NULL; + memcpy(new, p, len); + new[len - 1] = '\0'; + return new; +} + +static STATUS +c_complete() +{ + char *p; + char *word; + int unique; + + word = find_word(); + p = (char *)rl_complete((char *)word, &unique); + if (word) + free(word); + if (p && *p) { + (void)insert_string(p); + if (!unique) + (void)ring_bell(); + free(p); + return redisplay_no_nl(); + } + return ring_bell(); +} + +static STATUS +c_possible() +{ + char **av; + char *word; + int ac; + + word = find_word(); + ac = rl_list_possib((char *)word, (char ***)&av); + if (word) + free(word); + if (ac) { + columns(ac, av); + while (--ac >= 0) + free(av[ac]); + free(av); + return redisplay_no_nl(); + } + return ring_bell(); +} + +static STATUS +accept_line() +{ + Line[End] = '\0'; + return CSdone; +} + +static STATUS +transpose() +{ + char c; + + if (Point) { + if (Point == End) + left(CSmove); + c = Line[Point - 1]; + left(CSstay); + Line[Point - 1] = Line[Point]; + TTYshow(Line[Point - 1]); + Line[Point++] = c; + TTYshow(c); + } + return CSstay; +} + +static STATUS +quote() +{ + int c; + + return (c = TTYget()) == EOF ? CSeof : insert_char((int)c); +} + +static STATUS +wipe() +{ + int i; + + if (Mark > End) + return ring_bell(); + + if (Point > Mark) { + i = Point; + Point = Mark; + Mark = i; + reposition(); + } + + return delete_string(Mark - Point); +} + +static STATUS +mk_set() +{ + Mark = Point; + return CSstay; +} + +static STATUS +exchange() +{ + int c; + + if ((c = TTYget()) != CTL('X')) + return c == EOF ? CSeof : ring_bell(); + + if ((c = Mark) <= End) { + Mark = Point; + Point = c; + return CSmove; + } + return CSstay; +} + +static STATUS +yank() +{ + if (Yanked && *Yanked) + return insert_string(Yanked); + return CSstay; +} + +static STATUS +copy_region() +{ + if (Mark > End) + return ring_bell(); + + if (Point > Mark) + save_yank(Mark, Point - Mark); + else + save_yank(Point, Mark - Point); + + return CSstay; +} + +static STATUS +move_to_char() +{ + int c; + int i; + char *p; + + if ((c = TTYget()) == EOF) + return CSeof; + for (i = Point + 1, p = &Line[i]; i < End; i++, p++) + if (*p == c) { + Point = i; + return CSmove; + } + return CSstay; +} + +static STATUS +fd_word() +{ + return do_forward(CSmove); +} + +static STATUS +fd_kill_word() +{ + int i; + + (void)do_forward(CSstay); + if (OldPoint != Point) { + i = Point - OldPoint; + Point = OldPoint; + return delete_string(i); + } + return CSstay; +} + +static STATUS +bk_word() +{ + int i; + char *p; + + i = 0; + do { + for (p = &Line[Point]; p > Line && !isalnum((int)p[-1]); p--) + left(CSmove); + + for (; p > Line && p[-1] != ' ' && isalnum((int)p[-1]); p--) + left(CSmove); + + if (Point == 0) + break; + } while (++i < Repeat); + + return CSstay; +} + +static STATUS +bk_kill_word() +{ + (void)bk_word(); + if (OldPoint != Point) + return delete_string(OldPoint - Point); + return CSstay; +} + +static int +argify(char *line, char ***avp) +{ + char *c; + char **p; + char **new; + int ac; + int i; + + i = MEM_INC; + if ((*avp = p = malloc(sizeof(char*) * i))== NULL) + return 0; + + for (c = line; isspace((int)*c); c++) + continue; + if (*c == '\n' || *c == '\0') + return 0; + + for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { + if (isspace((int)*c)) { + *c++ = '\0'; + if (*c && *c != '\n') { + if (ac + 1 == i) { + new = malloc(sizeof(char*) * (i + MEM_INC)); + if (new == NULL) { + p[ac] = NULL; + return ac; + } + memcpy(new, p, i * sizeof (char **)); + i += MEM_INC; + free(p); + *avp = p = new; + } + p[ac++] = c; + } + } + else + c++; + } + *c = '\0'; + p[ac] = NULL; + return ac; +} + +static STATUS +last_argument() +{ + char **av; + char *p; + STATUS s; + int ac; + + if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL) + return ring_bell(); + + if ((p = strdup(p)) == NULL) + return CSstay; + ac = argify(p, &av); + + if (Repeat != NO_ARG) + s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); + else + s = ac ? insert_string(av[ac - 1]) : CSstay; + + if (ac) + free(av); + free(p); + return s; +} + +static KEYMAP Map[MAPSIZE] = { + { CTL('@'), 1, ring_bell }, + { CTL('A'), 1, beg_line }, + { CTL('B'), 1, bk_char }, + { CTL('D'), 1, del_char }, + { CTL('E'), 1, end_line }, + { CTL('F'), 1, fd_char }, + { CTL('G'), 1, ring_bell }, + { CTL('H'), 1, bk_del_char }, + { CTL('I'), 1, c_complete }, + { CTL('J'), 1, accept_line }, + { CTL('K'), 1, kill_line }, + { CTL('L'), 1, redisplay }, + { CTL('M'), 1, accept_line }, + { CTL('N'), 1, h_next }, + { CTL('O'), 1, ring_bell }, + { CTL('P'), 1, h_prev }, + { CTL('Q'), 1, ring_bell }, + { CTL('R'), 1, h_search }, + { CTL('S'), 1, ring_bell }, + { CTL('T'), 1, transpose }, + { CTL('U'), 1, ring_bell }, + { CTL('V'), 1, quote }, + { CTL('W'), 1, wipe }, + { CTL('X'), 1, exchange }, + { CTL('Y'), 1, yank }, + { CTL('Z'), 1, ring_bell }, + { CTL('['), 1, meta }, + { CTL(']'), 1, move_to_char }, + { CTL('^'), 1, ring_bell }, + { CTL('_'), 1, ring_bell }, +}; + +static KEYMAP MetaMap[16]= { + { CTL('H'), 1, bk_kill_word }, + { CTL('['), 1, c_possible }, + { DEL, 1, bk_kill_word }, + { ' ', 1, mk_set }, + { '.', 1, last_argument }, + { '<', 1, h_first }, + { '>', 1, h_last }, + { '?', 1, c_possible }, + { 'b', 1, bk_word }, + { 'd', 1, fd_kill_word }, + { 'f', 1, fd_word }, + { 'l', 1, case_down_word }, + { 'm', 1, toggle_meta_mode}, + { 'u', 1, case_up_word }, + { 'y', 1, yank }, + { 'w', 1, copy_region }, +}; diff --git a/ndb/src/common/editline/editline_internal.h b/ndb/src/common/editline/editline_internal.h new file mode 100644 index 00000000000..93c13e55edc --- /dev/null +++ b/ndb/src/common/editline/editline_internal.h @@ -0,0 +1,47 @@ +/* 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 */ + +/* $Revision: 1.2 $ +** +** Internal header file for editline library. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(SYS_UNIX) +#include "unix.h" +#endif /* defined(SYS_UNIX) */ + +#define MEM_INC 64 +#define SCREEN_INC 256 + +/* +** Variables and routines internal to this package. +*/ +extern int rl_eof; +extern int rl_erase; +extern int rl_intr; +extern int rl_kill; +extern int rl_quit; +#if defined(DO_SIGTSTP) +extern int rl_susp; +#endif /* defined(DO_SIGTSTP) */ +extern char *rl_complete(); +extern int rl_list_possib(); +extern void rl_ttyset(); +extern void rl_add_slash(); + diff --git a/ndb/src/common/editline/editline_win32.c b/ndb/src/common/editline/editline_win32.c new file mode 100644 index 00000000000..feef0108523 --- /dev/null +++ b/ndb/src/common/editline/editline_win32.c @@ -0,0 +1,33 @@ +/* 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 <stdio.h> +#include <malloc.h> + + +char* readline(const char* prompt) +{ + char* szBuf; + printf(prompt); + szBuf = (char*)malloc(256); + return gets(szBuf); +} + +void add_history(char* pch) +{ +} + diff --git a/ndb/src/common/editline/sysunix.c b/ndb/src/common/editline/sysunix.c new file mode 100644 index 00000000000..000bca78dfc --- /dev/null +++ b/ndb/src/common/editline/sysunix.c @@ -0,0 +1,143 @@ +/* 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 */ + +/* $Revision: 1.4 $ +** +** Unix system-dependant routines for editline library. +*/ +#include "editline_internal.h" + +#if defined(HAVE_TCGETATTR) +#include <termios.h> + +void +rl_ttyset(int Reset) +{ + static struct termios old; + struct termios new; + + if (Reset == 0) { + if (tcgetattr(0, &old) < 0) perror("tcgetattr"); + rl_erase = old.c_cc[VERASE]; + rl_kill = old.c_cc[VKILL]; + rl_eof = old.c_cc[VEOF]; + rl_intr = old.c_cc[VINTR]; + rl_quit = old.c_cc[VQUIT]; +#if defined(DO_SIGTSTP) + rl_susp = old.c_cc[VSUSP]; +#endif /* defined(DO_SIGTSTP) */ + + new = old; + new.c_lflag &= ~(ECHO | ICANON | ISIG); + new.c_iflag &= ~(ISTRIP | INPCK); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + if (tcsetattr(0, TCSADRAIN, &new) < 0) perror("tcsetattr"); + } + else + (void)tcsetattr(0, TCSADRAIN, &old); +} + +#else +#if defined(HAVE_TERMIO) +#include <termio.h> + +void +rl_ttyset(int Reset) +{ + static struct termio old; + struct termio new; + + if (Reset == 0) { + (void)ioctl(0, TCGETA, &old); + rl_erase = old.c_cc[VERASE]; + rl_kill = old.c_cc[VKILL]; + rl_eof = old.c_cc[VEOF]; + rl_intr = old.c_cc[VINTR]; + rl_quit = old.c_cc[VQUIT]; +#if defined(DO_SIGTSTP) + rl_susp = old.c_cc[VSUSP]; +#endif /* defined(DO_SIGTSTP) */ + + new = old; + new.c_lflag &= ~(ECHO | ICANON | ISIG); + new.c_iflag &= ~(ISTRIP | INPCK); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + (void)ioctl(0, TCSETAW, &new); + } + else + (void)ioctl(0, TCSETAW, &old); +} + +#else +#include <sgtty.h> + +void +rl_ttyset(int Reset) +{ + static struct sgttyb old_sgttyb; + static struct tchars old_tchars; + struct sgttyb new_sgttyb; + struct tchars new_tchars; +#if defined(DO_SIGTSTP) + struct ltchars old_ltchars; +#endif /* defined(DO_SIGTSTP) */ + + if (Reset == 0) { + (void)ioctl(0, TIOCGETP, &old_sgttyb); + rl_erase = old_sgttyb.sg_erase; + rl_kill = old_sgttyb.sg_kill; + + (void)ioctl(0, TIOCGETC, &old_tchars); + rl_eof = old_tchars.t_eofc; + rl_intr = old_tchars.t_intrc; + rl_quit = old_tchars.t_quitc; + +#if defined(DO_SIGTSTP) + (void)ioctl(0, TIOCGLTC, &old_ltchars); + rl_susp = old_ltchars.t_suspc; +#endif /* defined(DO_SIGTSTP) */ + + new_sgttyb = old_sgttyb; + new_sgttyb.sg_flags &= ~ECHO; + new_sgttyb.sg_flags |= RAW; +#if defined(PASS8) + new_sgttyb.sg_flags |= PASS8; +#endif /* defined(PASS8) */ + (void)ioctl(0, TIOCSETP, &new_sgttyb); + + new_tchars = old_tchars; + new_tchars.t_intrc = -1; + new_tchars.t_quitc = -1; + (void)ioctl(0, TIOCSETC, &new_tchars); + } + else { + (void)ioctl(0, TIOCSETP, &old_sgttyb); + (void)ioctl(0, TIOCSETC, &old_tchars); + } +} +#endif /* defined(HAVE_TERMIO) */ +#endif /* defined(HAVE_TCGETATTR) */ + +void +rl_add_slash(char *path, char *p, size_t p_len) +{ + struct stat Sb; + + if (stat(path, &Sb) >= 0) + (void)strlcat(p, S_ISDIR(Sb.st_mode) ? "/" : " ", p_len); +} diff --git a/ndb/src/common/editline/test/Makefile b/ndb/src/common/editline/test/Makefile new file mode 100644 index 00000000000..20229d0aa62 --- /dev/null +++ b/ndb/src/common/editline/test/Makefile @@ -0,0 +1,10 @@ +include .defs.mk + +TYPE := util + +BIN_TARGET := editline_test +BIN_TARGET_ARCHIVES := editline + +SOURCES = testit.c + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/editline/test/testit.c b/ndb/src/common/editline/test/testit.c new file mode 100644 index 00000000000..9a7dfb7bbdf --- /dev/null +++ b/ndb/src/common/editline/test/testit.c @@ -0,0 +1,59 @@ +/* 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 */ + +/* -*- c-basic-offset: 4; -*- +** $Revision: 1.5 $ +** +** A "micro-shell" to test editline library. +** If given any arguments, commands aren't executed. +*/ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <NdbString.h> +#include <editline/editline.h> + +int +main(int argc, char **argv) +{ + char *prompt; + char *p; + int doit; + + (void)argv; /* Suppress warning */ + + doit = argc == 1; + if ((prompt = getenv("TESTPROMPT")) == NULL) + prompt = "testit> "; + + while ((p = readline(prompt)) != NULL) { + (void)printf("\t\t\t|%s|\n", p); + if (doit) { + if (strncmp(p, "cd ", 3) == 0) { + if (chdir(&p[3]) < 0) + perror(&p[3]); + } else { + if (system(p) != 0) + perror(p); + } + } + add_history(p); + free(p); + } + + return 0; +} diff --git a/ndb/src/common/editline/unix.h b/ndb/src/common/editline/unix.h new file mode 100644 index 00000000000..582c4888856 --- /dev/null +++ b/ndb/src/common/editline/unix.h @@ -0,0 +1,26 @@ +/* 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 */ + +/* $Revision: 1.3 $ +** +** Editline system header file for Unix. +*/ + +#define CRLF "\r\n" + +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> diff --git a/ndb/src/common/logger/ConsoleLogHandler.cpp b/ndb/src/common/logger/ConsoleLogHandler.cpp new file mode 100644 index 00000000000..8f6a45fe5dd --- /dev/null +++ b/ndb/src/common/logger/ConsoleLogHandler.cpp @@ -0,0 +1,68 @@ +/* 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 "ConsoleLogHandler.hpp" + +#include <NdbOut.hpp> + +ConsoleLogHandler::ConsoleLogHandler() : LogHandler() +{ +} + +ConsoleLogHandler::~ConsoleLogHandler() +{ + +} + +bool +ConsoleLogHandler::open() +{ + return true; +} + +bool +ConsoleLogHandler::close() +{ + return true; +} + +// +// PROTECTED +// +void +ConsoleLogHandler::writeHeader(const char* pCategory, Logger::LoggerLevel level) +{ + char str[LogHandler::MAX_HEADER_LENGTH]; + ndbout << getDefaultHeader(str, pCategory, level); +} + +void +ConsoleLogHandler::writeMessage(const char* pMsg) +{ + ndbout << pMsg; +} + +void +ConsoleLogHandler::writeFooter() +{ + ndbout << getDefaultFooter(); +} + + +bool +ConsoleLogHandler::setParam(const BaseString ¶m, const BaseString &value) { + return false; +} diff --git a/ndb/src/common/logger/FileLogHandler.cpp b/ndb/src/common/logger/FileLogHandler.cpp new file mode 100644 index 00000000000..f3d547b4fe7 --- /dev/null +++ b/ndb/src/common/logger/FileLogHandler.cpp @@ -0,0 +1,241 @@ +/* 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 "FileLogHandler.hpp" + +#include <File.hpp> + +#include <NdbStdio.h> +#include <sys/param.h> + +#include <errno.h> +#include <string.h> + +// +// PUBLIC +// + +FileLogHandler::FileLogHandler() : + LogHandler(), + m_maxNoFiles(MAX_NO_FILES), + m_maxFileSize(MAX_FILE_SIZE), + m_maxLogEntries(MAX_LOG_ENTRIES) + +{ + m_pLogFile = new File("logger.log", "a+"); +} + +FileLogHandler::FileLogHandler(const char* aFileName, + int maxNoFiles, + long maxFileSize, + unsigned int maxLogEntries) : + LogHandler(), + m_maxNoFiles(maxNoFiles), + m_maxFileSize(maxFileSize), + m_maxLogEntries(maxLogEntries) +{ + m_pLogFile = new File(aFileName, "a+"); +} + +FileLogHandler::~FileLogHandler() +{ + delete m_pLogFile; +} + +bool +FileLogHandler::open() +{ + bool rc = true; + + if (m_pLogFile->open()) + { + if (isTimeForNewFile()) + { + if (!createNewFile()) + { + setErrorCode(errno); + rc = false; + } + } + } + else + { + setErrorCode(errno); + rc = false; + } + + return rc; +} + +bool +FileLogHandler::close() +{ + bool rc = true; + if (!m_pLogFile->close()) + { + setErrorCode(errno); + rc = false; + } + + return rc; +} + +void +FileLogHandler::writeHeader(const char* pCategory, Logger::LoggerLevel level) +{ + char str[LogHandler::MAX_HEADER_LENGTH]; + m_pLogFile->writeChar(getDefaultHeader(str, pCategory, level)); +} + +void +FileLogHandler::writeMessage(const char* pMsg) +{ + m_pLogFile->writeChar(pMsg); +} + +void +FileLogHandler::writeFooter() +{ + static int callCount = 0; + m_pLogFile->writeChar(getDefaultFooter()); + /** + * The reason I also check the number of log entries instead of + * only the log size, is that I do not want to check the file size + * after each log entry which requires system calls and is quite slow. + * TODO: Any better way? + */ + if (callCount % m_maxLogEntries != 0) // Check every m_maxLogEntries + { + if (isTimeForNewFile()) + { + if (!createNewFile()) + { + // Baby one more time... + createNewFile(); + } + } + callCount = 0; + } + callCount++; + + // Needed on Cello since writes to the flash disk does not happen until + // we flush and fsync. + m_pLogFile->flush(); +} + + +// +// PRIVATE +// + +bool +FileLogHandler::isTimeForNewFile() +{ + return (m_pLogFile->size() >= m_maxFileSize); +} + +bool +FileLogHandler::createNewFile() +{ + bool rc = true; + int fileNo = 1; + char newName[MAXPATHLEN]; + + do + { + if (fileNo >= m_maxNoFiles) + { + fileNo = 1; + ::snprintf(newName, sizeof(newName), + "%s.%d", m_pLogFile->getName(), fileNo); + break; + } + ::snprintf(newName, sizeof(newName), + "%s.%d", m_pLogFile->getName(), fileNo++); + + } while (File::exists(newName)); + + m_pLogFile->close(); + if (!File::rename(m_pLogFile->getName(), newName)) + { + setErrorCode(errno); + rc = false; + } + + // Open again + if (!m_pLogFile->open()) + { + setErrorCode(errno); + rc = false; + } + + return rc; +} + +bool +FileLogHandler::setParam(const BaseString ¶m, const BaseString &value){ + if(param == "filename") + return setFilename(value); + if(param == "maxsize") + return setMaxSize(value); + if(param == "maxfiles") + return setMaxFiles(value); + return false; +} + +bool +FileLogHandler::setFilename(const BaseString &filename) { + close(); + if(m_pLogFile) + delete m_pLogFile; + m_pLogFile = new File(filename.c_str(), "a+"); + open(); + return true; +}; + +bool +FileLogHandler::setMaxSize(const BaseString &size) { + char *end; + long val = strtol(size.c_str(), &end, 0); /* XXX */ + if(size.c_str() == end) + return false; + if(strncasecmp("M", end, 1) == 0) + val *= 1024*1024; + if(strncasecmp("k", end, 1) == 0) + val *= 1024; + + m_maxFileSize = val; + + return true; +}; + +bool +FileLogHandler::setMaxFiles(const BaseString &files) { + char *end; + long val = strtol(files.c_str(), &end, 0); + if(files.c_str() == end) + return false; + m_maxNoFiles = val; + + return true; +}; + +bool +FileLogHandler::checkParams() { + if(m_pLogFile == NULL) + return false; + return true; +} diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp new file mode 100644 index 00000000000..d1445555e87 --- /dev/null +++ b/ndb/src/common/logger/LogHandler.cpp @@ -0,0 +1,142 @@ +/* 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 "LogHandler.hpp" + +#include <NdbTick.h> +#include <NdbString.h> + +#include <time.h> + +// +// PUBLIC +// +LogHandler::LogHandler() : + m_pDateTimeFormat("%d-%.2d-%.2d %.2d:%.2d:%.2d"), + m_errorCode(0) +{ +} + +LogHandler::~LogHandler() +{ +} + +void +LogHandler::append(const char* pCategory, Logger::LoggerLevel level, + const char* pMsg) +{ + writeHeader(pCategory, level); + writeMessage(pMsg); + writeFooter(); +} + +const char* +LogHandler::getDefaultHeader(char* pStr, const char* pCategory, + Logger::LoggerLevel level) const +{ + char time[MAX_DATE_TIME_HEADER_LENGTH]; + ::snprintf(pStr, MAX_HEADER_LENGTH, "%s [%s] %s -- ", + getTimeAsString((char*)time), + pCategory, + Logger::LoggerLevelNames[level]); + + return pStr; +} + + +const char* +LogHandler::getDefaultFooter() const +{ + return "\n"; +} + +const char* +LogHandler::getDateTimeFormat() const +{ + return m_pDateTimeFormat; +} + +void +LogHandler::setDateTimeFormat(const char* pFormat) +{ + m_pDateTimeFormat = (char*)pFormat; +} + +char* +LogHandler::getTimeAsString(char* pStr) const +{ + struct tm* tm_now; + time_t now; + now = ::time((time_t*)NULL); +#ifdef NDB_WIN32 + tm_now = localtime(&now); +#else + tm_now = ::localtime(&now); //uses the "current" timezone +#endif + + ::snprintf(pStr, MAX_DATE_TIME_HEADER_LENGTH, + m_pDateTimeFormat, + tm_now->tm_year + 1900, + tm_now->tm_mon + 1, //month is [0,11]. +1 -> [1,12] + tm_now->tm_mday, + tm_now->tm_hour, + tm_now->tm_min, + tm_now->tm_sec); + + return pStr; +} + +int +LogHandler::getErrorCode() const +{ + return m_errorCode; +} + +void +LogHandler::setErrorCode(int code) +{ + m_errorCode = code; +} + +bool +LogHandler::parseParams(const BaseString &_params) { + Vector<BaseString> v_args; + + bool ret = true; + + _params.split(v_args, ","); + for(size_t i=0; i < v_args.size(); i++) { + Vector<BaseString> v_param_value; + + v_args[i].split(v_param_value, "=", 2); + if(v_param_value.size() == 2 && + !setParam(v_param_value[0], v_param_value[1])) + ret = false; + } + + if(!checkParams()) + ret = false; + return ret; +} + +bool +LogHandler::checkParams() { + return true; +} + +// +// PRIVATE +// diff --git a/ndb/src/common/logger/LogHandlerList.cpp b/ndb/src/common/logger/LogHandlerList.cpp new file mode 100644 index 00000000000..f020ad23e56 --- /dev/null +++ b/ndb/src/common/logger/LogHandlerList.cpp @@ -0,0 +1,183 @@ +/* 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 "LogHandlerList.hpp" + +#include <LogHandler.hpp> +#include <NdbStdio.h> +#include <ndb_types.h> + +// +// PUBLIC +// + +LogHandlerList::LogHandlerList() : + m_size(0), + m_pHeadNode(NULL), + m_pTailNode(NULL), + m_pCurrNode(NULL) +{ +} + +LogHandlerList::~LogHandlerList() +{ + removeAll(); +} + +void +LogHandlerList::add(LogHandler* pNewHandler) +{ + LogHandlerNode* pNode = new LogHandlerNode(); + + if (m_pHeadNode == NULL) + { + m_pHeadNode = pNode; + pNode->pPrev = NULL; + } + else + { + m_pTailNode->pNext = pNode; + pNode->pPrev = m_pTailNode; + } + m_pTailNode = pNode; + pNode->pNext = NULL; + pNode->pHandler = pNewHandler; + + m_size++; +} + +bool +LogHandlerList::remove(LogHandler* pRemoveHandler) +{ + LogHandlerNode* pNode = m_pHeadNode; + bool removed = false; + do + { + if (pNode->pHandler == pRemoveHandler) + { + removeNode(pNode); + removed = true; + break; + } + } while ( (pNode = next(pNode)) != NULL); + + return removed; +} + +void +LogHandlerList::removeAll() +{ + while (m_pHeadNode != NULL) + { + removeNode(m_pHeadNode); + } +} + +LogHandler* +LogHandlerList::next() +{ + LogHandler* pHandler = NULL; + if (m_pCurrNode == NULL) + { + m_pCurrNode = m_pHeadNode; + if (m_pCurrNode != NULL) + { + pHandler = m_pCurrNode->pHandler; + } + } + else + { + m_pCurrNode = next(m_pCurrNode); // Next node + if (m_pCurrNode != NULL) + { + pHandler = m_pCurrNode->pHandler; + } + } + + return pHandler; +} + +int +LogHandlerList::size() const +{ + return m_size; +} + +// +// PRIVATE +// + +LogHandlerList::LogHandlerNode* +LogHandlerList::next(LogHandlerNode* pNode) +{ + LogHandlerNode* pCurr = pNode; + if (pNode->pNext != NULL) + { + pCurr = pNode->pNext; + } + else + { + // Tail + pCurr = NULL; + } + return pCurr; +} + +LogHandlerList::LogHandlerNode* +LogHandlerList::prev(LogHandlerNode* pNode) +{ + LogHandlerNode* pCurr = pNode; + if (pNode->pPrev != NULL) // head + { + pCurr = pNode->pPrev; + } + else + { + // Head + pCurr = NULL; + } + + return pCurr; +} + +void +LogHandlerList::removeNode(LogHandlerNode* pNode) +{ + if (pNode->pPrev == NULL) // If head + { + m_pHeadNode = pNode->pNext; + } + else + { + pNode->pPrev->pNext = pNode->pNext; + } + + if (pNode->pNext == NULL) // if tail + { + m_pTailNode = pNode->pPrev; + } + else + { + pNode->pNext->pPrev = pNode->pPrev; + } + + pNode->pNext = NULL; + pNode->pPrev = NULL; + delete pNode->pHandler; // Delete log handler + delete pNode; + + m_size--; +} diff --git a/ndb/src/common/logger/LogHandlerList.hpp b/ndb/src/common/logger/LogHandlerList.hpp new file mode 100644 index 00000000000..7c001a28a76 --- /dev/null +++ b/ndb/src/common/logger/LogHandlerList.hpp @@ -0,0 +1,93 @@ +/* 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 */ + +#ifndef LOGHANDLERLIST_H +#define LOGHANDLERLIST_H + +class LogHandler; + +/** + * Provides a simple linked list of log handlers. + * + * @see LogHandler + * @version #@ $Id: LogHandlerList.hpp,v 1.2 2002/03/14 13:07:21 eyualex Exp $ + */ +class LogHandlerList +{ +public: + /** + * Default Constructor. + */ + LogHandlerList(); + + /** + * Destructor. + */ + ~LogHandlerList(); + + /** + * Adds a new log handler. + * + * @param pNewHandler log handler. + */ + void add(LogHandler* pNewHandler); + + /** + * Removes a log handler from the list and call its destructor. + * + * @param pRemoveHandler the handler to remove + */ + bool remove(LogHandler* pRemoveHandler); + + /** + * Removes all log handlers. + */ + void removeAll(); + + /** + * Returns the next log handler in the list. + * returns a log handler or NULL. + */ + LogHandler* next(); + + /** + * Returns the size of the list. + */ + int size() const; +private: + /** List node */ + struct LogHandlerNode + { + LogHandlerNode* pPrev; + LogHandlerNode* pNext; + LogHandler* pHandler; + }; + + LogHandlerNode* next(LogHandlerNode* pNode); + LogHandlerNode* prev(LogHandlerNode* pNode); + + void removeNode(LogHandlerNode* pNode); + + int m_size; + + LogHandlerNode* m_pHeadNode; + LogHandlerNode* m_pTailNode; + LogHandlerNode* m_pCurrNode; +}; + +#endif + + diff --git a/ndb/src/common/logger/Logger.cpp b/ndb/src/common/logger/Logger.cpp new file mode 100644 index 00000000000..6eaafd91854 --- /dev/null +++ b/ndb/src/common/logger/Logger.cpp @@ -0,0 +1,358 @@ +/* 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 <stdarg.h> + +#include "Logger.hpp" + +#include <LogHandler.hpp> +#include <ConsoleLogHandler.hpp> +#include <FileLogHandler.hpp> +#include "LogHandlerList.hpp" + +#if !defined NDB_OSE || !defined NDB_SOFTOSE || !defined NDB_WIN32 +#include <SysLogHandler.hpp> +#endif + +#include <NdbStdio.h> +#include <ndb_types.h> +#include <NdbString.h> + +#include <assert.h> + +// +// PUBLIC +// +const char* Logger::LoggerLevelNames[] = { "OFF ", + "DEBUG ", + "INFO ", + "WARNING ", + "ERROR ", + "CRITICAL", + "ALERT ", + "ALL " + }; +Logger::Logger() : + m_pCategory("Logger"), + m_pConsoleHandler(NULL), + m_pFileHandler(NULL), + m_pSyslogHandler(NULL) +{ + m_pHandlerList = new LogHandlerList(); + m_logLevels[LL_INFO] = true; +} + +Logger::~Logger() +{ + removeAllHandlers(); + delete m_pHandlerList; +} + +void +Logger::setCategory(const char* pCategory) +{ + m_pCategory = pCategory; +} + +bool +Logger::createConsoleHandler() +{ + bool rc = true; + if (m_pConsoleHandler == NULL) + { + m_pConsoleHandler = new ConsoleLogHandler(); + if (!addHandler(m_pConsoleHandler)) // TODO: check error code + { + rc = false; + delete m_pConsoleHandler; + m_pConsoleHandler = NULL; + } + } + + return rc; +} + +void +Logger::removeConsoleHandler() +{ + if (removeHandler(m_pConsoleHandler)) + { + m_pConsoleHandler = NULL; + } +} + +bool +Logger::createFileHandler() +{ + bool rc = true; + if (m_pFileHandler == NULL) + { + m_pFileHandler = new FileLogHandler(); + if (!addHandler(m_pFileHandler)) // TODO: check error code + { + rc = false; + delete m_pFileHandler; + m_pFileHandler = NULL; + } + } + + return rc; +} + +void +Logger::removeFileHandler() +{ + if (removeHandler(m_pFileHandler)) + { + m_pFileHandler = NULL; + } +} + +bool +Logger::createSyslogHandler() +{ + bool rc = true; + if (m_pSyslogHandler == NULL) + { +#if defined NDB_OSE || defined NDB_SOFTOSE || defined NDB_WIN32 + m_pSyslogHandler = new ConsoleLogHandler(); +#else + m_pSyslogHandler = new SysLogHandler(); +#endif + if (!addHandler(m_pSyslogHandler)) // TODO: check error code + { + rc = false; + delete m_pSyslogHandler; + m_pSyslogHandler = NULL; + } + } + + return rc; +} + +void +Logger::removeSyslogHandler() +{ + if (removeHandler(m_pSyslogHandler)) + { + m_pSyslogHandler = NULL; + } +} + +bool +Logger::addHandler(LogHandler* pHandler) +{ + assert(pHandler != NULL); + + bool rc = pHandler->open(); + if (rc) + { + m_pHandlerList->add(pHandler); + } + else + { + delete pHandler; + } + + return rc; +} + +bool +Logger::addHandler(const BaseString &logstring) { + size_t i; + Vector<BaseString> logdest; + Vector<LogHandler *>loghandlers; + + logstring.split(logdest, ";"); + + for(i = 0; i < logdest.size(); i++) { + Vector<BaseString> v_type_args; + logdest[i].split(v_type_args, ":", 2); + + BaseString type(v_type_args[0]); + BaseString params; + if(v_type_args.size() >= 2) + params = v_type_args[1]; + + LogHandler *handler = NULL; + + if(type == "SYSLOG") { + handler = new SysLogHandler(); + } else if(type == "FILE") + handler = new FileLogHandler(); + else if(type == "CONSOLE") + handler = new ConsoleLogHandler(); + + if(handler == NULL) + return false; + if(!handler->parseParams(params)) + return false; + loghandlers.push_back(handler); + } + + for(i = 0; i < loghandlers.size(); i++) + addHandler(loghandlers[i]); + + return true; /* @todo handle errors */ +} + +bool +Logger::removeHandler(LogHandler* pHandler) +{ + int rc = false; + if (pHandler != NULL) + { + rc = m_pHandlerList->remove(pHandler); + } + + return rc; +} + +void +Logger::removeAllHandlers() +{ + m_pHandlerList->removeAll(); +} + +bool +Logger::isEnable(LoggerLevel logLevel) const +{ + return m_logLevels[logLevel]; +} + +void +Logger::enable(LoggerLevel logLevel) +{ + if (logLevel == LL_ALL) + { + for (int i = 1; i < MAX_LOG_LEVELS; i++) + { + m_logLevels[i] = true; + } + } + else + { + m_logLevels[logLevel] = true; + } +} + +void +Logger::enable(LoggerLevel fromLogLevel, LoggerLevel toLogLevel) +{ + if (fromLogLevel > toLogLevel) + { + LoggerLevel tmp = toLogLevel; + toLogLevel = fromLogLevel; + fromLogLevel = tmp; + } + + for (int i = fromLogLevel; i <= toLogLevel; i++) + { + m_logLevels[i] = true; + } +} + +void +Logger::disable(LoggerLevel logLevel) +{ + if (logLevel == LL_ALL) + { + for (int i = 0; i < MAX_LOG_LEVELS; i++) + { + m_logLevels[i] = false; + } + } + else + { + m_logLevels[logLevel] = false; + } +} + +void +Logger::alert(const char* pMsg, ...) const +{ + va_list ap; + va_start(ap, pMsg); + log(LL_ALERT, pMsg, ap); + va_end(ap); +} + +void +Logger::critical(const char* pMsg, ...) const +{ + va_list ap; + va_start(ap, pMsg); + log(LL_CRITICAL, pMsg, ap); + va_end(ap); +} +void +Logger::error(const char* pMsg, ...) const +{ + va_list ap; + va_start(ap, pMsg); + log(LL_ERROR, pMsg, ap); + va_end(ap); +} +void +Logger::warning(const char* pMsg, ...) const +{ + va_list ap; + va_start(ap, pMsg); + log(LL_WARNING, pMsg, ap); + va_end(ap); +} + +void +Logger::info(const char* pMsg, ...) const +{ + va_list ap; + va_start(ap, pMsg); + log(LL_INFO, pMsg, ap); + va_end(ap); +} + +void +Logger::debug(const char* pMsg, ...) const +{ + va_list ap; + va_start(ap, pMsg); + log(LL_DEBUG, pMsg, ap); + va_end(ap); +} + +// +// PROTECTED +// + +void +Logger::log(LoggerLevel logLevel, const char* pMsg, va_list ap) const +{ + if (m_logLevels[LL_OFF] == false && m_logLevels[logLevel]) + { + LogHandler* pHandler = NULL; + while ( (pHandler = m_pHandlerList->next()) != NULL) + { + char buf[1024]; + vsnprintf(buf, sizeof(buf), pMsg, ap); + pHandler->append(m_pCategory, logLevel, buf); + } + } +} + +// +// PRIVATE +// + diff --git a/ndb/src/common/logger/Makefile b/ndb/src/common/logger/Makefile new file mode 100644 index 00000000000..994eb86ba35 --- /dev/null +++ b/ndb/src/common/logger/Makefile @@ -0,0 +1,27 @@ +include .defs.mk + +TYPE := ndbapi + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := logger + +DIRS := loggertest + +SOURCES := Logger.cpp LogHandlerList.cpp LogHandler.cpp \ + ConsoleLogHandler.cpp FileLogHandler.cpp + +ifeq ($(NDB_OS), OSE) +NO_SYSLOG := Y +endif + +ifeq ($(NDB_OS), WIN32) +NO_SYSLOG := Y +endif + +ifneq ($(NO_SYSLOG), Y) +SOURCES += SysLogHandler.cpp +endif + +include $(NDB_TOP)/Epilogue.mk + + diff --git a/ndb/src/common/logger/SysLogHandler.cpp b/ndb/src/common/logger/SysLogHandler.cpp new file mode 100644 index 00000000000..f3511bf5638 --- /dev/null +++ b/ndb/src/common/logger/SysLogHandler.cpp @@ -0,0 +1,159 @@ +/* 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 "SysLogHandler.hpp" + +#include <syslog.h> +#include <NdbString.h> + +// +// PUBLIC +// + +SysLogHandler::SysLogHandler() : + m_severity(LOG_INFO), + m_pIdentity("NDB"), + m_facility(LOG_USER) +{ +} + +SysLogHandler::SysLogHandler(const char* pIdentity, int facility) : + m_severity(LOG_INFO), + m_pIdentity(pIdentity), + m_facility(facility) +{ + +} + +SysLogHandler::~SysLogHandler() +{ +} + +bool +SysLogHandler::open() +{ + ::setlogmask(LOG_UPTO(LOG_DEBUG)); // Log from EMERGENCY down to DEBUG + ::openlog(m_pIdentity, LOG_PID|LOG_CONS|LOG_ODELAY, m_facility); // PID, CONSOLE delay openlog + + return true; +} + +bool +SysLogHandler::close() +{ + ::closelog(); + + return true; +} + +void +SysLogHandler::writeHeader(const char* pCategory, Logger::LoggerLevel level) +{ + // Save category to be used by writeMessage... + m_pCategory = pCategory; + // Map LogLevel to syslog severity + switch (level) + { + case Logger::LL_ALERT: + m_severity = LOG_ALERT; + break; + case Logger::LL_CRITICAL: + m_severity = LOG_CRIT; + break; + case Logger::LL_ERROR: + m_severity = LOG_ERR; + break; + case Logger::LL_WARNING: + m_severity = LOG_WARNING; + break; + case Logger::LL_INFO: + m_severity = LOG_INFO; + break; + case Logger::LL_DEBUG: + m_severity = LOG_DEBUG; + break; + default: + m_severity = LOG_INFO; + break; + } + +} + +void +SysLogHandler::writeMessage(const char* pMsg) +{ + ::syslog(m_facility | m_severity, "[%s] %s", m_pCategory, pMsg); +} + +void +SysLogHandler::writeFooter() +{ + // Need to close it everytime? Do we run out of file descriptors? + //::closelog(); +} + +bool +SysLogHandler::setParam(const BaseString ¶m, const BaseString &value) { + if(param == "facility") { + return setFacility(value); + } + return false; +} + +static const struct syslog_facility { + char *name; + int value; +} facilitynames[] = { + { "auth", LOG_AUTH }, +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, +#ifdef LOG_FTP + { "ftp", LOG_FTP }, +#endif + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { NULL, -1 } +}; + +bool +SysLogHandler::setFacility(const BaseString &facility) { + const struct syslog_facility *c; + for(c = facilitynames; c->name != NULL; c++) { + if(facility == c->name) { + m_facility = c->value; + close(); + open(); + return true; + } + } + return false; +} diff --git a/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp b/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp new file mode 100644 index 00000000000..22f67d15659 --- /dev/null +++ b/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp @@ -0,0 +1,165 @@ +/* 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 "LogHandlerListUnitTest.hpp" + +#include <ConsoleLogHandler.hpp> +#include <FileLogHandler.hpp> +#include <SysLogHandler.hpp> + +#include <NdbOut.hpp> + +#include <stdio.h> +#include <assert.h> + +typedef bool (*TESTFUNC)(const char*); +typedef struct +{ + const char* name; + TESTFUNC test; +}Tests; + +static Tests testCases[] = { {"Add", &LogHandlerListUnitTest::testAdd}, + {"Remove", &LogHandlerListUnitTest::testRemove}, + {"Traverse Next", &LogHandlerListUnitTest::testTraverseNext} + }; + + +int testFailed = 0; + +int main(int argc, char* argv[]) +{ + char str[256]; + int testCount = (sizeof(testCases) / sizeof(Tests)); + ndbout << "Starting " << testCount << " tests..." << endl; + for (int i = 0; i < testCount; i++) + { + ndbout << "-- " << " Test " << i + 1 + << " [" << testCases[i].name << "] --" << endl; + snprintf(str, 256, "%s %s %s %d", "Logging ", + testCases[i].name, " message ", i); + if (testCases[i].test(str)) + { + ndbout << "-- Passed --" << endl; + } + else + { + ndbout << "-- Failed -- " << endl; + } + + } + ndbout << endl << "-- " << testCount - testFailed << " passed, " + << testFailed << " failed --" << endl; + + return 0; +} + +bool +LogHandlerListUnitTest::testAdd(const char* msg) +{ + bool rc = true; + LogHandlerList list; + int size = 10; + for (int i = 0; i < size; i++) + { + list.add(new ConsoleLogHandler()); + } + if (list.size() != size) + { + rc = false; + } + ndbout << "List size: " << list.size() << endl; + + + return rc; +} +bool +LogHandlerListUnitTest::testRemove(const char* msg) +{ + bool rc = true; + + LogHandlerList list; + int size = 10; + LogHandler* pHandlers[10]; + for (int i = 0; i < size; i++) + { + pHandlers[i] = new ConsoleLogHandler(); + list.add(pHandlers[i]); + } + + // Remove + + for (int i = 0; i < size; i++) + { + if (!list.remove(pHandlers[i])) + { + ndbout << "Could not remove handler!" << endl; + } + else + { + ndbout << "List size: " << list.size() << endl; + } + } + + return rc; + +} +bool +LogHandlerListUnitTest::testTraverseNext(const char* msg) +{ + bool rc = true; + LogHandlerList list; + int size = 10; + LogHandler* pHandlers[10]; + + for (int i = 0; i < size; i++) + { + char* str = new char[3]; + pHandlers[i] = new ConsoleLogHandler(); + ::snprintf(str, 3, "%d", i); + pHandlers[i]->setDateTimeFormat(str); + list.add(pHandlers[i]); + } + + ndbout << "List size: " << list.size() << endl; + + LogHandler* pHandler = NULL; + int i = 0; + while ((pHandler = list.next()) != NULL) + { + ndbout << "Handler[" << i++ << "]:dateformat = " + << pHandler->getDateTimeFormat() << endl; + } + + list.removeAll(); + + return rc; + +} + +void +LogHandlerListUnitTest::error(const char* msg) +{ + testFailed++; + ndbout << "Test failed: " << msg << endl; +} + +LogHandlerListUnitTest::LogHandlerListUnitTest() +{ +} +LogHandlerListUnitTest::~LogHandlerListUnitTest() +{ +} diff --git a/ndb/src/common/logger/listtest/LogHandlerListUnitTest.hpp b/ndb/src/common/logger/listtest/LogHandlerListUnitTest.hpp new file mode 100644 index 00000000000..e98a2722b8d --- /dev/null +++ b/ndb/src/common/logger/listtest/LogHandlerListUnitTest.hpp @@ -0,0 +1,40 @@ +/* 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 */ + +#ifndef LOGHANDLERLISTUNITTEST_H +#define LOGHANDLERLISTUNITTEST_H + +#include "LogHandlerList.hpp" + +/** + * Unit test of LogHandlerList. + * + * @version #@ $Id: LogHandlerListUnitTest.hpp,v 1.1 2002/03/13 17:59:15 eyualex Exp $ + */ +class LogHandlerListUnitTest +{ +public: + + static bool testAdd(const char* msg); + static bool testRemove(const char* msg); + static bool testTraverseNext(const char* msg); + + void error(const char* msg); + + LogHandlerListUnitTest(); + ~LogHandlerListUnitTest(); +}; +#endif diff --git a/ndb/src/common/logger/listtest/Makefile b/ndb/src/common/logger/listtest/Makefile new file mode 100644 index 00000000000..4688a5e5a2f --- /dev/null +++ b/ndb/src/common/logger/listtest/Makefile @@ -0,0 +1,14 @@ +include .defs.mk + +TYPE := + +BIN_TARGET := listtest +BIN_TARGET_ARCHIVES := portlib logger general + +SOURCES := LogHandlerListUnitTest.cpp + +CCFLAGS_LOC += -I../ -I$(NDB_TOP)/include/logger -I$(NDB_TOP)/include/portlib + +include $(NDB_TOP)/Epilogue.mk + + diff --git a/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp b/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp new file mode 100644 index 00000000000..4b0241a0b03 --- /dev/null +++ b/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp @@ -0,0 +1,201 @@ +/* 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 "LoggerUnitTest.hpp" + +#include <Logger.hpp> +#include <ConsoleLogHandler.hpp> +#include <FileLogHandler.hpp> + +#if !defined NDB_OSE || !defined NDB_SOFTOSE +#include <SysLogHandler.hpp> +#endif + +#include <NdbOut.hpp> +#include <NdbStdio.h> +#include <NdbMain.h> + +#include <string.h> +#include <assert.h> + +typedef bool (*TESTFUNC)(const char*); +typedef struct +{ + const char* name; + TESTFUNC test; +}Tests; + +static Tests testCases[] = { {"Alert", &LoggerUnitTest::testAlert}, + {"Critical", &LoggerUnitTest::testCritical}, + {"Error", &LoggerUnitTest::testError}, + {"Warning", &LoggerUnitTest::testWarning}, + {"Info", &LoggerUnitTest::testInfo}, + {"Debug", &LoggerUnitTest::testDebug}, + {"Info to Critical", &LoggerUnitTest::testInfoCritical}, + {"All", &LoggerUnitTest::testAll}, + {"Off", &LoggerUnitTest::testOff} + }; + +static Logger logger; +int testFailed = 0; + +NDB_COMMAND(loggertest, "loggertest", "loggertest -console | -file", + "loggertest", 16384) +{ + if (argc < 2) + { +#if defined NDB_OSE || defined NDB_SOFTOSE + ndbout << "Usage: loggertest -console | -file" << endl; +#else + ndbout << "Usage: loggertest -console | -file | -syslog" << endl; +#endif + return 0; + } + + if (strcmp(argv[1], "-console") == 0) + { + logger.createConsoleHandler(); + } + else if (strcmp(argv[1], "-file") == 0) + { + logger.createFileHandler(); + //logger.addHandler(new FileLogHandler(argv[2])); + } +#if !defined NDB_OSE || !defined NDB_SOFTOSE + else if (strcmp(argv[1], "-syslog") == 0) + { + logger.createSyslogHandler(); + } +#endif + + logger.disable(Logger::LL_ALL); + + char str[256]; + int testCount = (sizeof(testCases) / sizeof(Tests)); + ndbout << "Starting " << testCount << " tests..." << endl; + for (int i = 0; i < testCount; i++) + { + ndbout << "-- " << " Test " << i + 1 + << " [" << testCases[i].name << "] --" << endl; + ::snprintf(str, 256, "%s %s %s %d", "Logging ", + testCases[i].name, " message ", i); + if (testCases[i].test(str)) + { + ndbout << "-- Passed --" << endl; + } + else + { + ndbout << "-- Failed -- " << endl; + } + + } + ndbout << endl << "-- " << testCount - testFailed << " passed, " + << testFailed << " failed --" << endl; + + logger.removeAllHandlers(); // Need to remove all for OSE, + // because logger is global + return 0; +} + +bool +LoggerUnitTest::logTo(Logger::LoggerLevel from, Logger::LoggerLevel to, const char* msg) +{ + logger.enable(from, to); + return logTo(from, msg); +} + +bool +LoggerUnitTest::logTo(Logger::LoggerLevel level, const char* msg) +{ + logger.enable(level); + logger.alert(msg); + logger.critical(msg); + logger.error(msg); + logger.warning(msg); + logger.info(msg); + logger.debug(msg); + logger.disable(level); + return true; +} + +bool +LoggerUnitTest::testAll(const char* msg) +{ + return logTo(Logger::LL_ALL, msg); +} + +bool +LoggerUnitTest::testOff(const char* msg) +{ + return logTo(Logger::LL_OFF, msg); + +} + +bool +LoggerUnitTest::testAlert(const char* msg) +{ + return logTo(Logger::LL_ALERT, msg); +} + +bool +LoggerUnitTest::testCritical(const char* msg) +{ + return logTo(Logger::LL_CRITICAL, msg); +} + +bool +LoggerUnitTest::testError(const char* msg) +{ + return logTo(Logger::LL_ERROR, msg); +} + +bool +LoggerUnitTest::testWarning(const char* msg) +{ + return logTo(Logger::LL_WARNING, msg); +} + +bool +LoggerUnitTest::testInfo(const char* msg) +{ + return logTo(Logger::LL_INFO, msg); +} + +bool +LoggerUnitTest::testDebug(const char* msg) +{ + return logTo(Logger::LL_DEBUG, msg); +} + +bool +LoggerUnitTest::testInfoCritical(const char* msg) +{ + return logTo(Logger::LL_CRITICAL, Logger::LL_INFO, msg); +} + +void +LoggerUnitTest::error(const char* msg) +{ + testFailed++; + ndbout << "Test failed: " << msg << endl; +} + +LoggerUnitTest::LoggerUnitTest() +{ +} +LoggerUnitTest::~LoggerUnitTest() +{ +} diff --git a/ndb/src/common/logger/loggertest/LoggerUnitTest.hpp b/ndb/src/common/logger/loggertest/LoggerUnitTest.hpp new file mode 100644 index 00000000000..79f560750d5 --- /dev/null +++ b/ndb/src/common/logger/loggertest/LoggerUnitTest.hpp @@ -0,0 +1,49 @@ +/* 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 */ + +#ifndef LOGGERUNITTEST_H +#define LOGGERUNITTEST_H + +#include "Logger.hpp" + +/** + * Unit test of Logger. + * + * @version #@ $Id: LoggerUnitTest.hpp,v 1.1 2002/03/13 17:55:31 eyualex Exp $ + */ +class LoggerUnitTest +{ +public: + + static bool testAll(const char* msg); + static bool testOff(const char* msg); + static bool testAlert(const char* msg); + static bool testCritical(const char* msg); + static bool testError(const char* msg); + static bool testWarning(const char* msg); + static bool testInfo(const char* msg); + static bool testDebug(const char* msg); + static bool testInfoCritical(const char* msg); + + static bool logTo(Logger::LoggerLevel level, const char* msg); + static bool logTo(Logger::LoggerLevel from, Logger::LoggerLevel to, const char* msg); + + void error(const char* msg); + + LoggerUnitTest(); + ~LoggerUnitTest(); +}; +#endif diff --git a/ndb/src/common/logger/loggertest/Makefile b/ndb/src/common/logger/loggertest/Makefile new file mode 100644 index 00000000000..0aef0ca2bce --- /dev/null +++ b/ndb/src/common/logger/loggertest/Makefile @@ -0,0 +1,16 @@ +include .defs.mk + +TYPE := + +BIN_TARGET := loggertest +BIN_TARGET_ARCHIVES := logger portlib general + +SOURCES := LoggerUnitTest.cpp + +CCFLAGS_LOC += -I$(NDB_TOP)/include/logger \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/include/portlib + +include $(NDB_TOP)/Epilogue.mk + + diff --git a/ndb/src/common/mgmcommon/Config.cpp b/ndb/src/common/mgmcommon/Config.cpp new file mode 100644 index 00000000000..5492394ee4a --- /dev/null +++ b/ndb/src/common/mgmcommon/Config.cpp @@ -0,0 +1,255 @@ +/* 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 "Config.hpp" +#include <ctype.h> +#include <string.h> +#include "MgmtErrorReporter.hpp" +#include <Properties.hpp> +#include "ConfigInfo.hpp" + +//***************************************************************************** +// Ctor / Dtor +//***************************************************************************** + +Config::Config() { + m_info = new ConfigInfo(); +} + +Config::Config(const Config & org) : + Properties(org) { + + m_info = new ConfigInfo(); +} + +Config::Config(const Properties & org) : + Properties(org) { + + m_info = new ConfigInfo(); +} + +Config::~Config() { + delete m_info; +} + +/*****************************************************************************/ + +void +Config::printAllNameValuePairs(NdbOut &out, + const Properties *prop, + const char* s) const { + Properties::Iterator it(prop); + const Properties * section = m_info->getInfo(s); + for (const char* n = it.first(); n != NULL; n = it.next()) { + Uint32 int_value; + const char* str_value; + + if (m_info->getStatus(section, n) == ConfigInfo::INTERNAL) + continue; + if (m_info->getStatus(section, n) == ConfigInfo::DEPRICATED) + continue; + if (m_info->getStatus(section, n) == ConfigInfo::NOTIMPLEMENTED) + continue; + + out << n << ": "; + + switch (m_info->getType(section, n)) { + case ConfigInfo::INT: + MGM_REQUIRE(prop->get(n, &int_value)); + out << int_value; + break; + + case ConfigInfo::BOOL: + MGM_REQUIRE(prop->get(n, &int_value)); + if (int_value) { + out << "Y"; + } else { + out << "N"; + } + break; + case ConfigInfo::STRING: + MGM_REQUIRE(prop->get(n, &str_value)); + out << str_value; + break; + } + out << endl; + } +} + +/*****************************************************************************/ + +void Config::printConfigFile(NdbOut &out) const { + Uint32 noOfNodes, noOfConnections, noOfComputers; + MGM_REQUIRE(get("NoOfNodes", &noOfNodes)); + MGM_REQUIRE(get("NoOfConnections", &noOfConnections)); + MGM_REQUIRE(get("NoOfComputers", &noOfComputers)); + + out << + "######################################################################" << + endl << + "#" << endl << + "# NDB Cluster System configuration" << endl << + "#" << endl << + "######################################################################" << + endl << + "# No of nodes (DB, API or MGM): " << noOfNodes << endl << + "# No of connections: " << noOfConnections << endl << + "######################################################################" << + endl; + + /************************** + * Print COMPUTER configs * + **************************/ + const char * name; + Properties::Iterator it(this); + for(name = it.first(); name != NULL; name = it.next()){ + if(strncasecmp("Computer_", name, 9) == 0){ + + const Properties *prop; + out << endl << "[COMPUTER]" << endl; + MGM_REQUIRE(get(name, &prop)); + printAllNameValuePairs(out, prop, "COMPUTER"); + + out << endl << + "###################################################################" << + endl; + + } else if(strncasecmp("Node_", name, 5) == 0){ + /********************** + * Print NODE configs * + **********************/ + const Properties *prop; + const char *s; + + MGM_REQUIRE(get(name, &prop)); + MGM_REQUIRE(prop->get("Type", &s)); + out << endl << "[" << s << "]" << endl; + printAllNameValuePairs(out, prop, s); + + out << endl << + "###################################################################" << + endl; + } else if(strncasecmp("Connection_", name, 11) == 0){ + /**************************** + * Print CONNECTION configs * + ****************************/ + const Properties *prop; + const char *s; + + MGM_REQUIRE(get(name, &prop)); + MGM_REQUIRE(prop->get("Type", &s)); + out << endl << "[" << s << "]" << endl; + printAllNameValuePairs(out, prop, s); + + out << endl << + "###################################################################" << + endl; + } else if(strncasecmp("SYSTEM", name, strlen("SYSTEM")) == 0) { + /************************ + * Print SYSTEM configs * + ************************/ + const Properties *prop; + + MGM_REQUIRE(get(name, &prop)); + out << endl << "[SYSTEM]" << endl; + printAllNameValuePairs(out, prop, "SYSTEM"); + + out << endl << + "###################################################################" << + endl; + } + } +} + +const +ConfigInfo* Config::getConfigInfo() const { + return m_info; +} + +Uint32 +Config::getGenerationNumber() const { + Uint32 ret; + const Properties *prop = NULL; + + get("SYSTEM", &prop); + + if(prop != NULL) + if(prop->get("ConfigGenerationNumber", &ret)) + return ret; + + return 0; +} + +int +Config::setGenerationNumber(Uint32 gen) { + Properties *prop = NULL; + + getCopy("SYSTEM", &prop); + + if(prop != NULL) { + MGM_REQUIRE(prop->put("ConfigGenerationNumber", gen, true)); + MGM_REQUIRE(put("SYSTEM", prop, true)); + return 0; + } + return -1; +} + +bool +Config::change(const BaseString §ion, + const BaseString ¶m, + const BaseString &value) { + const char *name; + Properties::Iterator it(this); + + for(name = it.first(); name != NULL; name = it.next()) { + Properties *prop = NULL; + if(strcasecmp(section.c_str(), name) == 0) { + getCopy(name, &prop); + if(prop == NULL) /* doesn't exist */ + return false; + if(value == "") { + prop->remove(param.c_str()); + put(section.c_str(), prop, true); + } else { + PropertiesType t; + if(!prop->getTypeOf(param.c_str(), &t)) /* doesn't exist */ + return false; + switch(t) { + case PropertiesType_Uint32: + long val; + char *ep; + errno = 0; + val = strtol(value.c_str(), &ep, 0); + if(value.length() == 0 || *ep != '\0') /* not a number */ + return false; + if(errno == ERANGE) + return false; + prop->put(param.c_str(), (unsigned int)val, true); + put(section.c_str(), prop, true); + break; + case PropertiesType_char: + prop->put(param.c_str(), value.c_str(), true); + put(section.c_str(), prop, true); + break; + default: + return false; + } + } + break; + } + } + return true; +} diff --git a/ndb/src/common/mgmcommon/Config.hpp b/ndb/src/common/mgmcommon/Config.hpp new file mode 100644 index 00000000000..1314abe004a --- /dev/null +++ b/ndb/src/common/mgmcommon/Config.hpp @@ -0,0 +1,86 @@ +/* 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 */ + +#ifndef Config_H +#define Config_H + +#include <signaldata/ConfigParamId.hpp> +#include <LogLevel.hpp> + +#include <kernel_types.h> + +#include <NdbOut.hpp> +#include <NdbStdio.h> +#include <ndb_limits.h> +#include <NdbConstant.hpp> +#include <Properties.hpp> + +/** + * @class Config + * @brief Cluster Configuration (corresponds to initial configuration file) + * + * Contains all cluster configuration parameters. + * + * The information includes all configurable parameters for a NDB cluster: + * - DB, API and MGM nodes with all their properties, + * - Connections between nodes and computers the nodes will execute on. + * + * The following categories (sections) of configuration parameters exists: + * - COMPUTER, DB, MGM, API, TCP, SCI, SHM, OSE + */ +class Config : public Properties { +public: + /** + * Constructor which loads the object with an Properties object + */ + Config(const Config & org); + Config(const Properties & org); + Config(); + virtual ~Config(); + + /** + * Prints the configuration in configfile format + */ + void printConfigFile(NdbOut &out = ndbout) const; + void printConfigFile(OutputStream &out) const { + NdbOut ndb(out); + printConfigFile(ndb); + } + + const class ConfigInfo* getConfigInfo() const; + + Uint32 getGenerationNumber() const; + int setGenerationNumber(Uint32); + + /** Change configuration + */ + bool change(const BaseString §ion, + const BaseString ¶m, + const BaseString &value); + +private: + + void printAllNameValuePairs(NdbOut &out, + const Properties *prop, + const char* section) const; + + /** + * Information about parameters (min, max values etc) + */ + const class ConfigInfo* m_info; +}; + +#endif // Config_H diff --git a/ndb/src/common/mgmcommon/ConfigInfo.cpp b/ndb/src/common/mgmcommon/ConfigInfo.cpp new file mode 100644 index 00000000000..da6024d946f --- /dev/null +++ b/ndb/src/common/mgmcommon/ConfigInfo.cpp @@ -0,0 +1,2629 @@ +/* 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 "ConfigInfo.hpp" +#define MAX_LINE_LENGTH 255 + +/**************************************************************************** + * Section names + ****************************************************************************/ +const char* +ConfigInfo::m_sectionNames[]={ + "SYSTEM", + "EXTERNAL SYSTEM", + "COMPUTER", + + "DB", + "MGM", + "API", + "REP", + "EXTERNAL REP", + + "TCP", + "SCI", + "SHM", + "OSE" +}; +const int ConfigInfo::m_noOfSectionNames = +sizeof(m_sectionNames)/sizeof(char*); + + +/**************************************************************************** + * Section Rules declarations + ****************************************************************************/ +bool transformComputer(InitConfigFileParser::Context & ctx, const char *); +bool transformSystem(InitConfigFileParser::Context & ctx, const char *); +bool transformExternalSystem(InitConfigFileParser::Context & ctx, const char *); +bool transformNode(InitConfigFileParser::Context & ctx, const char *); +bool transformExtNode(InitConfigFileParser::Context & ctx, const char *); +bool transformConnection(InitConfigFileParser::Context & ctx, const char *); +bool applyDefaultValues(InitConfigFileParser::Context & ctx, const char *); +bool checkMandatory(InitConfigFileParser::Context & ctx, const char *); +bool fixPortNumber(InitConfigFileParser::Context & ctx, const char *); +bool fixShmkey(InitConfigFileParser::Context & ctx, const char *); +bool checkDbConstraints(InitConfigFileParser::Context & ctx, const char *); +bool checkConnectionConstraints(InitConfigFileParser::Context &, const char *); +bool fixHostname(InitConfigFileParser::Context & ctx, const char * data); +bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data); +bool fixExtConnection(InitConfigFileParser::Context & ctx, const char * data); + +const ConfigInfo::SectionRule +ConfigInfo::m_SectionRules[] = { + { "SYSTEM", transformSystem, 0 }, + { "EXTERNAL SYSTEM", transformExternalSystem, 0 }, + { "COMPUTER", transformComputer, 0 }, + + { "DB", transformNode, 0 }, + { "API", transformNode, 0 }, + { "MGM", transformNode, 0 }, + { "REP", transformNode, 0 }, + { "EXTERNAL REP", transformExtNode, 0 }, + + { "TCP", transformConnection, 0 }, + { "SHM", transformConnection, 0 }, + { "SCI", transformConnection, 0 }, + { "OSE", transformConnection, 0 }, + + { "TCP", fixPortNumber, 0 }, + //{ "SHM", fixShmKey, 0 }, + + { "COMPUTER", applyDefaultValues, 0 }, + + { "DB", applyDefaultValues, 0 }, + { "API", applyDefaultValues, 0 }, + { "MGM", applyDefaultValues, 0 }, + { "REP", applyDefaultValues, 0 }, + { "EXTERNAL REP", applyDefaultValues, 0 }, + + { "TCP", applyDefaultValues, 0 }, + { "SHM", applyDefaultValues, 0 }, + { "SCI", applyDefaultValues, 0 }, + { "OSE", applyDefaultValues, 0 }, + + { "DB", checkDbConstraints, 0 }, + + { "TCP", fixNodeId, "NodeId1" }, + { "TCP", fixNodeId, "NodeId2" }, + { "SHM", fixNodeId, "NodeId1" }, + { "SHM", fixNodeId, "NodeId2" }, + { "SCI", fixNodeId, "NodeId1" }, + { "SCI", fixNodeId, "NodeId2" }, + { "OSE", fixNodeId, "NodeId1" }, + { "OSE", fixNodeId, "NodeId2" }, + + /** + * fixExtConnection must be after fixNodeId + */ + { "TCP", fixExtConnection, 0 }, + { "SHM", fixExtConnection, 0 }, + { "SCI", fixExtConnection, 0 }, + { "OSE", fixExtConnection, 0 }, + + /** + * checkConnectionConstraints must be after fixExtConnection + */ + { "TCP", checkConnectionConstraints, 0 }, + { "SHM", checkConnectionConstraints, 0 }, + { "SCI", checkConnectionConstraints, 0 }, + { "OSE", checkConnectionConstraints, 0 }, + + { "COMPUTER", checkMandatory, 0 }, + + { "DB", checkMandatory, 0 }, + { "API", checkMandatory, 0 }, + { "MGM", checkMandatory, 0 }, + { "REP", checkMandatory, 0 }, + + { "TCP", checkMandatory, 0 }, + { "SHM", checkMandatory, 0 }, + { "SCI", checkMandatory, 0 }, + { "OSE", checkMandatory, 0 }, + + { "TCP", fixHostname, "HostName1" }, + { "TCP", fixHostname, "HostName2" }, + { "OSE", fixHostname, "HostName1" }, + { "OSE", fixHostname, "HostName2" }, +}; +const int ConfigInfo::m_NoOfRules = sizeof(m_SectionRules)/sizeof(SectionRule); + +/** + * The default constructors create objects with suitable values for the + * configuration parameters. + * + * Some are however given the value MANDATORY which means that the value + * must be specified in the configuration file. + * + * Min and max values are also given for some parameters. + * - Attr1: Name in file (initial config file) + * - Attr2: Name in prop (properties object) + * - Attr3: Name of Section (in init config file) + * - Attr4: Updateable + * - Attr5: Type of parameter (INT or BOOL) + * - Attr6: Default Value (number only) + * - Attr7: Min value + * - Attr8: Max value + * + * Parameter constraints are coded in file Config.cpp. + * + * ******************************************************************* + * Parameters used under development should be marked "NOTIMPLEMENTED" + * ******************************************************************* + */ +const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { + + /**************************************************************************** + * COMPUTER + ****************************************************************************/ + + {"Id", + "Id", + "COMPUTER", + "Name of computer", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0}, + + {"HostName", + "HostName", + "COMPUTER", + "Hostname of computer (e.g. mysql.com)", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ByteOrder", + "ByteOrder", + "COMPUTER", + "Not yet implemented", + ConfigInfo::USED, // Actually not used, but since it is MANDATORY, + // we don't want any warning message + false, + ConfigInfo::STRING, + MANDATORY, // Big == 0, Little == 1, NotSet == 2 (?) + 0, + 0x7FFFFFFF}, + + /**************************************************************************** + * DB + ****************************************************************************/ + + {"Id", + "Id", + "DB", + "Number identifying the database node (DB)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 1, + (MAX_NODES - 1)}, + + {"Type", + "Type", + "DB", + "Type of node (Should have value DB)", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0}, + + {"NoOfReplicas", + "NoOfReplicas", + "DB", + "Number of copies of all data in the database (1-4)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 1, + 4}, + + {"MaxNoOfAttributes", + "MaxNoOfAttributes", + "DB", + "Total number of attributes stored in database. I.e. sum over all tables", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1000, + 32, + 4096}, + + {"MaxNoOfTables", + "MaxNoOfTables", + "DB", + "Total number of tables stored in the database", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 32, + 8, + 128}, + + {"MaxNoOfIndexes", + "MaxNoOfIndexes", + "DB", + "Total number of indexes that can be defined in the system", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 128, + 0, + 2048}, + + {"MaxNoOfConcurrentIndexOperations", + "MaxNoOfConcurrentIndexOperations", + "DB", + "Total number of index operations that can execute simultaneously on one DB node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 8192, + 0, + 1000000 + }, + + {"MaxNoOfTriggers", + "MaxNoOfTriggers", + "DB", + "Total number of triggers that can be defined in the system", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 768, + 0, + 2432}, + + {"MaxNoOfFiredTriggers", + "MaxNoOfFiredTriggers", + "DB", + "Total number of triggers that can fire simultaneously in one DB node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1000, + 0, + 1000000}, + + {"ExecuteOnComputer", + "ExecuteOnComputer", + "DB", + "String referencing an earlier defined COMPUTER", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"MaxNoOfSavedMessages", + "MaxNoOfSavedMessages", + "DB", + "Max number of error messages in error log and max number of trace files", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 25, + 0, + 0x7FFFFFFF}, + + {"LockPagesInMainMemory", + "LockPagesInMainMemory", + "DB", + "If set to yes, then NDB Cluster data will not be swapped out to disk", + ConfigInfo::USED, + true, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"SleepWhenIdle", + "SleepWhenIdle", + "DB", + "?", + ConfigInfo::DEPRICATED, + true, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + {"NoOfSignalsToExecuteBetweenCommunicationInterfacePoll", + "NoOfSignalsToExecuteBetweenCommunicationInterfacePoll", + "DB", + "?", + ConfigInfo::DEPRICATED, + true, + ConfigInfo::INT, + 20, + 1, + 0x7FFFFFFF}, + + {"TimeBetweenWatchDogCheck", + "TimeBetweenWatchDogCheck", + "DB", + "Time between execution checks inside a database node", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 4000, + 70, + 0x7FFFFFFF}, + + {"StopOnError", + "StopOnError", + "DB", + "If set to N, the DB automatically restarts/recovers in case of node failure", + ConfigInfo::USED, + true, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + { "RestartOnErrorInsert", + "RestartOnErrorInsert", + "DB", + "See src/kernel/vm/Emulator.hpp NdbRestartType for details", + ConfigInfo::INTERNAL, + true, + ConfigInfo::INT, + 2, + 0, + 4 }, + + {"MaxNoOfConcurrentOperations", + "MaxNoOfConcurrentOperations", + "DB", + "Max no of op:s on DB (op:s within a transaction are concurrently executed)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 8192, + 32, + 1000000}, + + {"MaxNoOfConcurrentTransactions", + "MaxNoOfConcurrentTransactions", + "DB", + "Max number of transaction executing concurrently on the DB node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 4096, + 32, + 1000000}, + + {"MaxNoOfConcurrentScans", + "MaxNoOfConcurrentScans", + "DB", + "Max number of scans executing concurrently on the DB node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 25, + 2, + 500}, + + {"TransactionBufferMemory", + "TransactionBufferMemory", + "DB", + "Dynamic buffer space (in bytes) for key and attribute data allocated for each DB node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1024000, + 1024, + 0x7FFFFFFF}, + + {"NoOfIndexPages", + "NoOfIndexPages", + "DB", + "Number of 8k byte pages on each DB node for storing indexes", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 3000, + 128, + 192000}, + + {"MemorySpaceIndexes", + "NoOfIndexPages", + "DB", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 128, + 192000}, + + {"NoOfDataPages", + "NoOfDataPages", + "DB", + "Number of 8k byte pages on each DB node for storing data", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 10000, + 128, + 400000}, + + {"MemorySpaceTuples", + "NoOfDataPages", + "DB", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 128, + 400000}, + + {"NoOfDiskBufferPages", + "NoOfDiskBufferPages", + "DB", + "?", + ConfigInfo::NOTIMPLEMENTED, + false, + ConfigInfo::INT, + 0, + 0, + 0}, + + {"MemoryDiskPages", + "NoOfDiskBufferPages", + "DB", + "?", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0}, + + {"NoOfFreeDiskClusters", + "NoOfFreeDiskClusters", + "DB", + "?", + ConfigInfo::NOTIMPLEMENTED, + false, + ConfigInfo::INT, + 0, + 0, + 0}, + + {"NoOfDiskClusters", + "NoOfDiskClusters", + "DB", + "?", + ConfigInfo::NOTIMPLEMENTED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + {"TimeToWaitAlive", + "TimeToWaitAlive", + "DB", + "Time to wait for other nodes to become alive during initial system start", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 25, + 2, + 4000}, + + {"HeartbeatIntervalDbDb", + "HeartbeatIntervalDbDb", + "DB", + "Time between DB-to-DB heartbeats. DB considered dead after 3 missed HBs", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 1500, + 10, + 0x7FFFFFFF}, + + {"HeartbeatIntervalDbApi", + "HeartbeatIntervalDbApi", + "DB", + "Time between API-to-DB heartbeats. API connection closed after 3 missed HBs", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 1500, + 100, + 0x7FFFFFFF}, + + {"TimeBetweenLocalCheckpoints", + "TimeBetweenLocalCheckpoints", + "DB", + "Time between taking snapshots of the database (expressed in 2log of bytes)", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 20, + 0, + 31}, + + {"TimeBetweenGlobalCheckpoints", + "TimeBetweenGlobalCheckpoints", + "DB", + "Time between doing group commit of transactions to disk", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 2000, + 10, + 32000}, + + {"NoOfFragmentLogFiles", + "NoOfFragmentLogFiles", + "DB", + "No of 16 Mbyte Redo log files in each of 4 file sets belonging to DB node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 8, + 1, + 0x7FFFFFFF}, + + {"MaxNoOfOpenFiles", + "MaxNoOfOpenFiles", + "DB", + "Max number of files open per DB node.(One thread is created per file)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 40, + 20, + 256}, + + {"NoOfConcurrentCheckpointsDuringRestart", + "NoOfConcurrentCheckpointsDuringRestart", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 1, + 1, + 4}, + + {"TimeBetweenInactiveTransactionAbortCheck", + "TimeBetweenInactiveTransactionAbortCheck", + "DB", + "Time between inactive transaction checks", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 1000, + 1000, + 0x7FFFFFFF}, + + {"TransactionInactiveTimeout", + "TransactionInactiveTimeout", + "DB", + "Time application can wait before executing another transaction part (ms).\n" + "This is the time the transaction coordinator waits for the application\n" + "to execute or send another part (query, statement) of the transaction.\n" + "If the application takes too long time, the transaction gets aborted.\n" + "Timeout set to 0 means that we don't timeout at all on application wait.", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 3000, + 0, + 0x7FFFFFFF}, + + {"TransactionDeadlockDetectionTimeout", + "TransactionDeadlockDetectionTimeout", + "DB", + "Time transaction can be executing in a DB node (ms).\n" + "This is the time the transaction coordinator waits for each database node\n" + "of the transaction to execute a request. If the database node takes too\n" + "long time, the transaction gets aborted.", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 3000, + 50, + 0x7FFFFFFF}, + + {"TransactionInactiveTimeBeforeAbort", + "TransactionInactiveTimeBeforeAbort", + "DB", + "Time a transaction can be inactive before getting aborted (ms)", + ConfigInfo::DEPRICATED, + true, + ConfigInfo::INT, + 3000, + 20, + 0x7FFFFFFF}, + + {"NoOfConcurrentProcessesHandleTakeover", + "NoOfConcurrentProcessesHandleTakeover", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 1, + 1, + 15}, + + {"NoOfConcurrentCheckpointsAfterRestart", + "NoOfConcurrentCheckpointsAfterRestart", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 1, + 1, + 4}, + + {"NoOfDiskPagesToDiskDuringRestartTUP", + "NoOfDiskPagesToDiskDuringRestartTUP", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 50, + 1, + 0x7FFFFFFF}, + + {"NoOfDiskPagesToDiskAfterRestartTUP", + "NoOfDiskPagesToDiskAfterRestartTUP", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 10, + 1, + 0x7FFFFFFF}, + + {"NoOfDiskPagesToDiskDuringRestartACC", + "NoOfDiskPagesToDiskDuringRestartACC", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 25, + 1, + 0x7FFFFFFF}, + + {"NoOfDiskPagesToDiskAfterRestartACC", + "NoOfDiskPagesToDiskAfterRestartACC", + "DB", + "?", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 5, + 1, + 0x7FFFFFFF}, + + {"NoOfDiskClustersPerDiskFile", + "NoOfDiskClustersPerDiskFile", + "DB", + "?", + ConfigInfo::NOTIMPLEMENTED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + {"NoOfDiskFiles", + "NoOfDiskFiles", + "DB", + "?", + ConfigInfo::NOTIMPLEMENTED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + {"ArbitrationTimeout", + "ArbitrationTimeout", + "DB", + "Max time (milliseconds) database partion waits for arbitration signal", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1000, + 10, + 0x7FFFFFFF}, + + {"FileSystemPath", + "FileSystemPath", + "DB", + "Path to directory where the DB node stores its data (directory must exist)", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"LogLevelStartup", + "LogLevelStartup", + "DB", + "Node startup info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1, + 0, + 15}, + + {"LogLevelShutdown", + "LogLevelShutdown", + "DB", + "Node shutdown info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + {"LogLevelStatistic", + "LogLevelStatistic", + "DB", + "Transaction, operation, transporter info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + {"LogLevelCheckpoint", + "LogLevelCheckpoint", + "DB", + "Local and Global checkpoint info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + {"LogLevelNodeRestart", + "LogLevelNodeRestart", + "DB", + "Node restart, node failure info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + {"LogLevelConnection", + "LogLevelConnection", + "DB", + "Node connect/disconnect info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + {"LogLevelError", + "LogLevelError", + "DB", + "Transporter, heartbeat errors printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + {"LogLevelInfo", + "LogLevelInfo", + "DB", + "Heartbeat and log info printed on stdout", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 15}, + + /** + * Backup + */ + { "ParallelBackups", + "ParallelBackups", + "DB", + "Maximum number of parallel backups", + ConfigInfo::NOTIMPLEMENTED, + false, + ConfigInfo::INT, + 1, + 1, + 1 }, + + { "BackupMemory", + "BackupMemory", + "DB", + "Total memory allocated for backups per node (in bytes)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + (2 * 1024 * 1024) + (2 * 1024 * 1024), // sum of BackupDataBufferSize and BackupLogBufferSize + 0, + 0x7FFFFFFF }, + + { "BackupDataBufferSize", + "BackupDataBufferSize", + "DB", + "Default size of databuffer for a backup (in bytes)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + (2 * 1024 * 1024), // remember to change BackupMemory + 0, + 0x7FFFFFFF }, + + { "BackupLogBufferSize", + "BackupLogBufferSize", + "DB", + "Default size of logbuffer for a backup (in bytes)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + (2 * 1024 * 1024), // remember to change BackupMemory + 0, + 0x7FFFFFFF }, + + { "BackupWriteSize", + "BackupWriteSize", + "DB", + "Default size of filesystem writes made by backup (in bytes)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 32768, + 0, + 0x7FFFFFFF }, + + /**************************************************************************** + * REP + ****************************************************************************/ + + {"Id", + "Id", + "REP", + "Number identifying replication node (REP)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 1, + (MAX_NODES - 1)}, + + {"Type", + "Type", + "REP", + "Type of node (Should have value REP)", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0}, + + {"ExecuteOnComputer", + "ExecuteOnComputer", + "REP", + "String referencing an earlier defined COMPUTER", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + /**************************************************************************** + * EXTERNAL REP + ****************************************************************************/ + + {"Id", + "Id", + "EXTERNAL REP", + "Number identifying external (i.e. in another NDB Cluster) replication node (REP)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 1, + (MAX_NODES - 1)}, + + {"Type", + "Type", + "EXTERNAL REP", + "Type of node (Should have value REP)", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0}, + + {"System", + "System", + "EXTERNAL REP", + "System name of system hosting node", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + 0, + 0, + 0}, + + {"HeartbeatIntervalRepRep", + "HeartbeatIntervalRepRep", + "EXTERNAL REP", + "Time between REP-REP heartbeats. Connection closed after 3 missed HBs", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 3000, + 100, + 0x7FFFFFFF}, + + /**************************************************************************** + * API + ****************************************************************************/ + + {"Id", + "Id", + "API", + "Number identifying application node (API)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 1, + (MAX_NODES - 1)}, + + {"Type", + "Type", + "API", + "Type of node (Should have value API)", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0}, + + {"ExecuteOnComputer", + "ExecuteOnComputer", + "API", + "String referencing an earlier defined COMPUTER", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"MaxNoOfSavedMessages", + "MaxNoOfSavedMessages", + "API", + "Max number of error messages in error log and max number of trace files", + ConfigInfo::USED, + true, + ConfigInfo::INT, + 25, + 0, + 0x7FFFFFFF}, + + {"SleepWhenIdle", + "SleepWhenIdle", + "API", + "?", + ConfigInfo::DEPRICATED, + true, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + {"ArbitrationRank", + "ArbitrationRank", + "API", + "If 0, then API is not arbitrator. Kernel selects arbitrators in order 1, 2", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 2, + 0, + 2}, + + {"ArbitrationDelay", + "ArbitrationDelay", + "API", + "When asked to arbitrate, arbitrator waits this long before voting (msec)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + /**************************************************************************** + * MGM + ****************************************************************************/ + + {"Id", + "Id", + "MGM", + "Number identifying the management server node (MGM)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 1, + (MAX_NODES - 1)}, + + {"Type", + "Type", + "MGM", + "Type of node (Should have value MGM)", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0}, + + {"ExecuteOnComputer", + "ExecuteOnComputer", + "MGM", + "String referencing an earlier defined COMPUTER", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + // SHOULD THIS REALLY BE DEFINABLE FOR MGM ??? + {"MaxNoOfSavedMessages", + "MaxNoOfSavedMessages", + "MGM", + "Max number of error messages in error log and max number of trace files", + ConfigInfo::DEPRICATED, + true, + ConfigInfo::INT, + 25, + 0, + 0x7FFFFFFF}, + + {"MaxNoOfSavedEvents", + "MaxNoOfSavedEvents", + "MGM", + "", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 100, + 0, + 0x7FFFFFFF}, + + {"PortNumber", + "PortNumber", + "MGM", + "Port number to give commands to/fetch configurations from management server", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 2200, + 0, + 0x7FFFFFFF}, + + {"PortNumberStats", + "PortNumberStats", + "MGM", + "Port number used to get statistical information from a management server", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 2199, + 0, + 0x7FFFFFFF}, + + {"ArbitrationRank", + "ArbitrationRank", + "MGM", + "If 0, then MGM is not arbitrator. Kernel selects arbitrators in order 1, 2", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 2, + 0, + 2}, + + {"ArbitrationDelay", + "ArbitrationDelay", + "MGM", + "", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + /***************************************************************************** + * SYSTEM + ****************************************************************************/ + + {"Name", + "Name", + "SYSTEM", + "Name of system (NDB Cluster)", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0}, + + {"ReplicationRole", + "ReplicationRole", + "SYSTEM", + "Role in Global Replication (None, Primary, or Standby)", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0}, + + {"LogDestination", + "LogDestination", + "MGM", + "String describing where logmessages are sent", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + 0, + 0, + 0x7FFFFFFF}, + + {"PrimaryMGMNode", + "PrimaryMGMNode", + "SYSTEM", + "Node id of Primary MGM node", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + {"ConfigGenerationNumber", + "ConfigGenerationNumber", + "SYSTEM", + "Configuration generation number", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 0, + 0, + 0x7FFFFFFF}, + + {"Name", + "Name", + "EXTERNAL SYSTEM", + "Name of external system (another NDB Cluster)", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0}, + + /***************************************************************************** + * TCP + ****************************************************************************/ + + {"Type", + "Type", + "TCP", + "", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0x7FFFFFFF}, + + {"HostName1", + "HostName1", + "TCP", + "Name of computer on one side of the connection", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"HostName2", + "HostName2", + "TCP", + "Name of computer on one side of the connection", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"NodeId1", + "NodeId1", + "TCP", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId1", + "NodeId1", + "TCP", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"NodeId2", + "NodeId2", + "TCP", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId2", + "NodeId2", + "TCP", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"IpAddress1", + "HostName1", + "TCP", + "IP address of first node in connection.", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"IpAddress2", + "HostName2", + "TCP", + "IP address of second node in connection.", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0}, + + {"SendSignalId", + "SendSignalId", + "TCP", + "Sends id in each signal. Used in trace files.", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + {"Compression", + "Compression", + "TCP", + "If compression is enabled, then all signals between nodes are compressed", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"Checksum", + "Checksum", + "TCP", + "If checksum is enabled, all signals between nodes are checked for errors", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"PortNumber", + "PortNumber", + "TCP", + "Port used for this transporter", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"SendBufferSize", + "SendBufferSize", + "TCP", + "Size of buffer for signals sent from this node (in no of signals)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 16, + 1, + 0x7FFFFFFF}, + + {"MaxReceiveSize", + "MaxReceiveSize", + "TCP", + "Size of buffer for signals received by this node (in no of signals)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 4, + 1, + 0x7FFFFFFF}, + + {"Proxy", + "Proxy", + "TCP", + "", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0}, + + /***************************************************************************** + * SHM + ****************************************************************************/ + + {"Type", + "Type", + "SHM", + "", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0x7FFFFFFF}, + + {"NodeId1", + "NodeId1", + "SHM", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId1", + "NodeId1", + "SHM", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"NodeId2", + "NodeId2", + "SHM", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId2", + "NodeId2", + "SHM", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"SendSignalId", + "SendSignalId", + "SHM", + "Sends id in each signal. Used in trace files.", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"Compression", + "Compression", + "SHM", + "If compression is enabled, then all signals between nodes are compressed", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"Checksum", + "Checksum", + "SHM", + "If checksum is enabled, all signals between nodes are checked for errors", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + {"ShmKey", + "ShmKey", + "SHM", + "A shared memory key", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF }, + + {"ShmSize", + "ShmSize", + "SHM", + "Size of shared memory segment", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1048576, + 4096, + 0x7FFFFFFF}, + + /***************************************************************************** + * SCI + ****************************************************************************/ + + {"NodeId1", + "NodeId1", + "SCI", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId1", + "NodeId1", + "SCI", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"NodeId2", + "NodeId2", + "SCI", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId2", + "NodeId2", + "SCI", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"SciId0", + "SciId0", + "SCI", + "Local SCI-node id for adapter 0 (a computer can have two adapters)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"SciId1", + "SciId1", + "SCI", + "Local SCI-node id for adapter 1 (a computer can have two adapters)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"SendSignalId", + "SendSignalId", + "SCI", + "Sends id in each signal. Used in trace files.", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + {"Compression", + "Compression", + "SCI", + "If compression is enabled, then all signals between nodes are compressed", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"Checksum", + "Checksum", + "SCI", + "If checksum is enabled, all signals between nodes are checked for errors", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"SendLimit", + "SendLimit", + "SCI", + "Transporter send buffer contents are sent when this no of bytes is buffered", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 2048, + 512, + 0x7FFFFFFF}, + + {"SharedBufferSize", + "SharedBufferSize", + "SCI", + "Size of shared memory segment", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1048576, + 262144, + 0x7FFFFFFF}, + + {"Node1_NoOfAdapters", + "Node1_NoOfAdapters", + "SCI", + "", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"Node2_NoOfAdapters", + "Node2_NoOfAdapters", + "SCI", + "", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"Node1_Adapter", + "Node1_Adapter", + "SCI", + "", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"Node2_Adapter", + "Node2_Adapter", + "SCI", + "", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + /***************************************************************************** + * OSE + ****************************************************************************/ + + {"Type", + "Type", + "OSE", + "", + ConfigInfo::INTERNAL, + false, + ConfigInfo::STRING, + 0, + 0, + 0x7FFFFFFF}, + + {"HostName1", + "HostName1", + "OSE", + "Name of computer on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"HostName2", + "HostName2", + "OSE", + "Name of computer on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::STRING, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"NodeId1", + "NodeId1", + "OSE", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"ProcessId1", + "NodeId1", + "OSE", + "Depricated", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"NodeId2", + "NodeId2", + "OSE", + "Id of node (DB, API or MGM) on one side of the connection", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 0, + 0x7FFFFFFF}, + + {"ProcessId2", + "NodeId2", + "OSE", + "Depricated", + ConfigInfo::USED, + false, + ConfigInfo::INT, + MANDATORY, + 0, + 0x7FFFFFFF}, + + {"SendSignalId", + "SendSignalId", + "OSE", + "Sends id in each signal. Used in trace files.", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + true, + 0, + 0x7FFFFFFF}, + + {"Compression", + "Compression", + "OSE", + "If compression is enabled, then all signals between nodes are compressed", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + {"Checksum", + "Checksum", + "OSE", + "If checksum is enabled, all signals between nodes are checked for errors", + ConfigInfo::USED, + false, + ConfigInfo::BOOL, + false, + 0, + 0x7FFFFFFF}, + + // Should not be part of OSE ? + {"SharedBufferSize", + "SharedBufferSize", + "OSE", + "?", + ConfigInfo::DEPRICATED, + false, + ConfigInfo::INT, + UNDEFINED, + 2000, + 0x7FFFFFFF}, + + {"PrioASignalSize", + "PrioASignalSize", + "OSE", + "Size of priority A signals (in bytes)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1000, + 0, + 0x7FFFFFFF}, + + {"PrioBSignalSize", + "PrioBSignalSize", + "OSE", + "Size of priority B signals (in bytes)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 1000, + 0, + 0x7FFFFFFF}, + + {"ReceiveArraySize", + "ReceiveArraySize", + "OSE", + "Number of OSE signals checked for correct ordering (in no of OSE signals)", + ConfigInfo::USED, + false, + ConfigInfo::INT, + 10, + 0, + 0x7FFFFFFF} +}; + +const int ConfigInfo::m_NoOfParams = sizeof(m_ParamInfo) / sizeof(ParamInfo); + + +/**************************************************************************** + * Ctor + ****************************************************************************/ +inline void require(bool v) { if(!v) abort();} + +ConfigInfo::ConfigInfo() { + Properties *section; + const Properties *oldpinfo; + + m_info.setCaseInsensitiveNames(true); + m_systemDefaults.setCaseInsensitiveNames(true); + + for (int i=0; i<m_NoOfParams; i++) { + const ParamInfo & param = m_ParamInfo[i]; + + // Create new section if it did not exist + if (!m_info.getCopy(param._section, §ion)) { + Properties newsection; + newsection.setCaseInsensitiveNames(true); + m_info.put(param._section, &newsection); + } + + // Get copy of section + m_info.getCopy(param._section, §ion); + + // Create pinfo (parameter info) entry + Properties pinfo; + pinfo.put("Fname", param._fname); + pinfo.put("Pname", param._pname); + pinfo.put("Description", param._description); + pinfo.put("Updateable", param._updateable); + pinfo.put("Type", param._type); + pinfo.put("Status", param._status); + pinfo.put("Default", param._default); + pinfo.put("Min", param._min); + pinfo.put("Max", param._max); + + // Check that pinfo is really new + if (section->get(param._fname, &oldpinfo)) { + ndbout << "Error: Parameter " << param._fname + << " defined twice in section " << param._section + << "." << endl; + exit(-1); + } + + // Add new pinfo to section + section->put(param._fname, &pinfo); + + // Replace section with modified section + m_info.put(param._section, section, true); + + { + Properties * p; + if(!m_systemDefaults.getCopy(param._section, &p)){ + p = new Properties(); + p->setCaseInsensitiveNames(true); + } + if(param._type != STRING && + param._default != UNDEFINED && + param._default != MANDATORY){ + require(p->put(param._pname, param._default)); + } + require(m_systemDefaults.put(param._section, p, true)); + delete p; + } + } + + for (int i=0; i<m_NoOfParams; i++) { + if(m_ParamInfo[i]._section == NULL){ + ndbout << "Check that each pname has an fname failed." << endl; + ndbout << "Parameter \"" << m_ParamInfo[i]._pname + << "\" does not exist in section \"" + << m_ParamInfo[i]._section << "\"." << endl; + ndbout << "Edit file " << __FILE__ << "." << endl; + exit(-1); + } + const Properties * p = getInfo(m_ParamInfo[i]._section); + if (!p || !p->contains(m_ParamInfo[i]._pname)) { + ndbout << "Check that each pname has an fname failed." << endl; + ndbout << "Parameter \"" << m_ParamInfo[i]._pname + << "\" does not exist in section \"" + << m_ParamInfo[i]._section << "\"." << endl; + ndbout << "Edit file " << __FILE__ << "." << endl; + exit(-1); + } + } +} + +/**************************************************************************** + * Getters + ****************************************************************************/ +inline void warning(const char * src, const char * arg){ + ndbout << "Illegal call to ConfigInfo::" << src << "() - " << arg << endl; + abort(); +} + +const Properties * +ConfigInfo::getInfo(const char * section) const { + const Properties * p; + if(!m_info.get(section, &p)){ + warning("getInfo", section); + } + return p; +} + +const Properties * +ConfigInfo::getDefaults(const char * section) const { + const Properties * p; + if(!m_systemDefaults.get(section, &p)){ + warning("getDefaults", section); + } + return p; +} + +static +Uint32 +getInfoInt(const Properties * section, + const char* fname, const char * type){ + Uint32 val; + const Properties * p; + if (section->get(fname, &p) && p->get(type, &val)) { + return val; + } + warning(type, fname); + return val; +} + +static +const char * +getInfoString(const Properties * section, + const char* fname, const char * type){ + const char* val; + const Properties * p; + if (section->get(fname, &p) && p->get(type, &val)) { + return val; + } + warning(type, fname); + return val; +} + +Uint32 +ConfigInfo::getMax(const Properties * section, const char* fname) const { + return getInfoInt(section, fname, "Max"); +} + +Uint32 +ConfigInfo::getMin(const Properties * section, const char* fname) const { + return getInfoInt(section, fname, "Min"); +} + +Uint32 +ConfigInfo::getDefault(const Properties * section, const char* fname) const { + return getInfoInt(section, fname, "Default"); +} + +const char* +ConfigInfo::getPName(const Properties * section, const char* fname) const { + return getInfoString(section, fname, "Pname"); +} + +const char* +ConfigInfo::getDescription(const Properties * section, + const char* fname) const { + return getInfoString(section, fname, "Description"); +} + +bool +ConfigInfo::isSection(const char * section) const { + for (int i = 0; i<m_noOfSectionNames; i++) { + if(!strcmp(section, m_sectionNames[i])) return true; + } + return false; +} + +bool +ConfigInfo::verify(const Properties * section, const char* fname, + Uint32 value) const { + Uint32 min, max; min = max + 1; + + min = getInfoInt(section, fname, "Min"); + max = getInfoInt(section, fname, "Max"); + if(min > max){ + warning("verify", fname); + } + if (value >= min && value <= max) + return true; + else + return false; +} + +ConfigInfo::Type +ConfigInfo::getType(const Properties * section, const char* fname) const { + return (ConfigInfo::Type) getInfoInt(section, fname, "Type"); +} + +ConfigInfo::Status +ConfigInfo::getStatus(const Properties * section, const char* fname) const { + return (ConfigInfo::Status) getInfoInt(section, fname, "Status"); +} + +/**************************************************************************** + * Printers + ****************************************************************************/ + +void ConfigInfo::print() const { + Properties::Iterator it(&m_info); + for (const char* n = it.first(); n != NULL; n = it.next()) { + print(n); + } +} + +void ConfigInfo::print(const char* section) const { + ndbout << "****** " << section << " ******" << endl << endl; + const Properties * sec = getInfo(section); + Properties::Iterator it(sec); + for (const char* n = it.first(); n != NULL; n = it.next()) { + // Skip entries with different F- and P-names + if (strcmp(n, getPName(sec, n))) continue; + if (getStatus(sec, n) == ConfigInfo::INTERNAL) continue; + if (getStatus(sec, n) == ConfigInfo::DEPRICATED) continue; + if (getStatus(sec, n) == ConfigInfo::NOTIMPLEMENTED) continue; + print(sec, n); + } +} + +void ConfigInfo::print(const Properties * section, + const char* parameter) const { + ndbout << getPName(section, parameter); + // ndbout << getDescription(section, parameter) << endl; + switch (getType(section, parameter)) { + case ConfigInfo::BOOL: + ndbout << " (Boolean value)" << endl; + ndbout << getDescription(section, parameter) << endl; + if (getDefault(section, parameter) == false) { + ndbout << "Default: N (Legal values: Y, N)" << endl; + } else if (getDefault(section, parameter) == true) { + ndbout << "Default: Y (Legal values: Y, N)" << endl; + } else if (getDefault(section, parameter) == MANDATORY) { + ndbout << "MANDATORY (Legal values: Y, N)" << endl; + } else { + ndbout << "UNKNOWN" << endl; + } + ndbout << endl; + break; + + case ConfigInfo::INT: + ndbout << " (Non-negative Integer)" << endl; + ndbout << getDescription(section, parameter) << endl; + if (getDefault(section, parameter) == MANDATORY) { + ndbout << "MANDATORY ("; + } else if (getDefault(section, parameter) == UNDEFINED) { + ndbout << "UNDEFINED ("; + } else { + ndbout << "Default: " << getDefault(section, parameter) << " ("; + } + ndbout << "Min: " << getMin(section, parameter) << ", "; + ndbout << "Max: " << getMax(section, parameter) << ")" << endl; + ndbout << endl; + break; + + case ConfigInfo::STRING: + ndbout << " (String)" << endl; + ndbout << getDescription(section, parameter) << endl; + if (getDefault(section, parameter) == MANDATORY) { + ndbout << "MANDATORY" << endl; + } else { + ndbout << "No default value" << endl; + } + ndbout << endl; + break; + } +} + +/**************************************************************************** + * Section Rules + ****************************************************************************/ + +/** + * Node rule: Add "Type" and update "NoOfNodes" + */ +bool +transformNode(InitConfigFileParser::Context & ctx, const char * data){ + + Uint32 id; + if(!ctx.m_currentSection->get("Id", &id)){ + ctx.reportError("Mandatory parameter Id missing from section " + "[%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + snprintf(ctx.pname, sizeof(ctx.pname), "Node_%d", id); + + ctx.m_currentSection->put("Type", ctx.fname); + + Uint32 nodes = 0; + ctx.m_userProperties.get("NoOfNodes", &nodes); + ctx.m_userProperties.put("NoOfNodes", ++nodes, true); + + return true; +} + +bool +transformExtNode(InitConfigFileParser::Context & ctx, const char * data){ + + Uint32 id; + const char * systemName; + + if(!ctx.m_currentSection->get("Id", &id)){ + ctx.reportError("Mandatory parameter 'Id' missing from section " + "[%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + + if(!ctx.m_currentSection->get("System", &systemName)){ + ctx.reportError("Mandatory parameter 'System' missing from section " + "[%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + + ctx.m_currentSection->put("Type", ctx.fname); + + Uint32 nodes = 0; + ctx.m_userProperties.get("ExtNoOfNodes", &nodes); + require(ctx.m_userProperties.put("ExtNoOfNodes",++nodes, true)); + + snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s:Node_%d", + systemName, id); + + return true; +} + +/** + * Connection rule: Update "NoOfConnections" + */ +bool +transformConnection(InitConfigFileParser::Context & ctx, const char * data){ + + Uint32 connections = 0; + ctx.m_userProperties.get("NoOfConnections", &connections); + snprintf(ctx.pname, sizeof(ctx.pname), "Connection_%d", connections); + ctx.m_userProperties.put("NoOfConnections", ++connections, true); + + ctx.m_currentSection->put("Type", ctx.fname); + return true; +} + +/** + * System rule: Just add it + */ +bool +transformSystem(InitConfigFileParser::Context & ctx, const char * data){ + + const char * name; + if(!ctx.m_currentSection->get("Name", &name)){ + ctx.reportError("Mandatory parameter Name missing from section " + "[%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + snprintf(ctx.pname, sizeof(ctx.pname), "SYSTEM_%s", name); + + return true; +} + +/** + * External system rule: Just add it + */ +bool +transformExternalSystem(InitConfigFileParser::Context & ctx, const char * data){ + const char * name; + if(!ctx.m_currentSection->get("Name", &name)){ + ctx.reportError("Mandatory parameter Name missing from section " + "[%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s", name); + + return true; +} + +/** + * Computer rule: Update "NoOfComputers", add "Type" + */ +bool +transformComputer(InitConfigFileParser::Context & ctx, const char * data){ + const char * id; + if(!ctx.m_currentSection->get("Id", &id)){ + ctx.reportError("Mandatory parameter Id missing from section " + "[%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + snprintf(ctx.pname, sizeof(ctx.pname), "Computer_%s", id); + + Uint32 computers = 0; + ctx.m_userProperties.get("NoOfComputers", &computers); + ctx.m_userProperties.put("NoOfComputers", ++computers, true); + + return true; +} + +/** + * Apply default values + */ +void +applyDefaultValues(InitConfigFileParser::Context & ctx, + const Properties * defaults){ + if(defaults != NULL){ + Properties::Iterator it(defaults); + + for(const char * name = it.first(); name != NULL; name = it.next()){ + if(!ctx.m_currentSection->contains(name)){ + switch (ctx.m_info->getType(ctx.m_currentInfo, name)){ + case ConfigInfo::INT: + case ConfigInfo::BOOL:{ + Uint32 val = 0; + ::require(defaults->get(name, &val)); + ctx.m_currentSection->put(name, val); + break; + } + case ConfigInfo::STRING:{ + const char * val; + ::require(defaults->get(name, &val)); + ctx.m_currentSection->put(name, val); + break; + } + } + } + } + } +} + +bool +applyDefaultValues(InitConfigFileParser::Context & ctx, const char * data){ + + applyDefaultValues(ctx, ctx.m_userDefaults); + applyDefaultValues(ctx, ctx.m_systemDefaults); + + return true; +} + +/** + * Check that a section contains all MANDATORY parameters + */ +bool +checkMandatory(InitConfigFileParser::Context & ctx, const char * data){ + + Properties::Iterator it(ctx.m_currentInfo); + for(const char * name = it.first(); name != NULL; name = it.next()){ + const Properties * info = NULL; + ::require(ctx.m_currentInfo->get(name, &info)); + Uint32 val; + if(info->get("Default", &val) && val == MANDATORY){ + const char * pname; + const char * fname; + ::require(info->get("Pname", &pname)); + ::require(info->get("Fname", &fname)); + if(!ctx.m_currentSection->contains(pname)){ + ctx.reportError("Mandatory parameter %s missing from section " + "[%s] starting at line: %d", + fname, ctx.fname, ctx.m_sectionLineno); + return false; + } + } + } + return true; +} + +/** + * Connection rule: Fix node id + * + * Transform a string "NodeidX" (e.g. "uppsala.32") + * into a Uint32 "NodeIdX" (e.g. 32) and a string "SystemX" (e.g. "uppsala"). + */ +bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data){ + + char buf[] = "NodeIdX"; buf[6] = data[sizeof("NodeI")]; + char sysbuf[] = "SystemX"; sysbuf[6] = data[sizeof("NodeI")]; + const char* nodeId; + require(ctx.m_currentSection->get(buf, &nodeId)); + + char tmpLine[MAX_LINE_LENGTH]; + strncpy(tmpLine, nodeId, MAX_LINE_LENGTH); + char* token1 = strtok(tmpLine, "."); + char* token2 = strtok(NULL, "."); + Uint32 id; + + if (token2 == NULL) { // Only a number given + errno = 0; + char* p; + id = strtol(token1, &p, 10); + if (errno != 0) warning("STRTOK1", nodeId); + require(ctx.m_currentSection->put(buf, id, true)); + } else { // A pair given (e.g. "uppsala.32") + errno = 0; + char* p; + id = strtol(token2, &p, 10); + if (errno != 0) warning("STRTOK2", nodeId); + require(ctx.m_currentSection->put(buf, id, true)); + require(ctx.m_currentSection->put(sysbuf, token1)); + } + + return true; +} + +/** + * @returns true if connection is external (one node is external) + * Also returns: + * - name of external system in parameter extSystemName, and + * - nodeId of external node in parameter extSystemNodeId. + */ +bool +isExtConnection(InitConfigFileParser::Context & ctx, + const char **extSystemName, Uint32 * extSystemNodeId){ + + Uint32 nodeId1, nodeId2; + + if (ctx.m_currentSection->contains("System1") && + ctx.m_currentSection->get("System1", extSystemName) && + ctx.m_currentSection->get("NodeId1", &nodeId1)) { + *extSystemNodeId = nodeId1; + return true; + } + + if (ctx.m_currentSection->contains("System2") && + ctx.m_currentSection->get("System2", extSystemName) && + ctx.m_currentSection->get("NodeId2", &nodeId2)) { + *extSystemNodeId = nodeId2; + return true; + } + + return false; +} + +/** + * External Connection Rule: + * If connection is to an external system, then move connection into + * external system configuration (i.e. a sub-property). + */ +bool +fixExtConnection(InitConfigFileParser::Context & ctx, const char * data){ + + const char * extSystemName; + Uint32 extSystemNodeId; + + if (isExtConnection(ctx, &extSystemName, &extSystemNodeId)) { + + Uint32 connections = 0; + ctx.m_userProperties.get("ExtNoOfConnections", &connections); + require(ctx.m_userProperties.put("ExtNoOfConnections",++connections, true)); + + char tmpLine1[MAX_LINE_LENGTH]; + snprintf(tmpLine1, MAX_LINE_LENGTH, "Connection_%d", connections-1); + + /** + * Section: EXTERNAL SYSTEM_<Ext System Name> + */ + char extSystemPropName[MAX_LINE_LENGTH]; + strncpy(extSystemPropName, "EXTERNAL SYSTEM_", MAX_LINE_LENGTH); + strncat(extSystemPropName, extSystemName, MAX_LINE_LENGTH); + strncat(extSystemPropName, ":", MAX_LINE_LENGTH); + strncat(extSystemPropName, tmpLine1, MAX_LINE_LENGTH); + + /** + * Increase number of external connections for the system + * + * @todo Limitation: Only one external system is allowed + */ + require(ctx.m_userProperties.put("ExtSystem", extSystemName, true)); + + /** + * Make sure section is stored in right place + */ + strncpy(ctx.pname, extSystemPropName, MAX_LINE_LENGTH); + + /** + * Since this is an external connection, + * decrease number of internal connections + */ + require(ctx.m_userProperties.get("NoOfConnections", &connections)); + require(ctx.m_userProperties.put("NoOfConnections", --connections, true)); + } + + return true; +} + +/** + * Connection rule: Fix hostname + * + * Unless Hostname is not already specified, do steps: + * -# Via Connection's NodeId lookup Node + * -# Via Node's ExecuteOnComputer lookup Hostname + * -# Add HostName to Connection + */ +bool +fixHostname(InitConfigFileParser::Context & ctx, const char * data){ + + char buf[] = "NodeIdX"; buf[6] = data[sizeof("HostNam")]; + char sysbuf[] = "SystemX"; sysbuf[6] = data[sizeof("HostNam")]; + + if(!ctx.m_currentSection->contains(data)){ + Uint32 id = 0; + require(ctx.m_currentSection->get(buf, &id)); + + const Properties * node; + require(ctx.m_config->get("Node", id, &node)); + + const char * compId; + require(node->get("ExecuteOnComputer", &compId)); + + const Properties * computer; + char tmp[255]; + snprintf(tmp, sizeof(tmp), "Computer_%s", compId); + require(ctx.m_config->get(tmp, &computer)); + + const char * hostname; + require(computer->get("HostName", &hostname)); + require(ctx.m_currentSection->put(data, hostname)); + } + return true; +} + +/** + * Connection rule: Fix port number (using a port number adder) + */ +bool +fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){ + + if(!ctx.m_currentSection->contains("PortNumber")){ + Uint32 adder = 0; + ctx.m_userProperties.get("PortNumberAdder", &adder); + Uint32 base = 0; + if(!ctx.m_userDefaults->get("PortNumber", &base) && + !ctx.m_systemDefaults->get("PortNumber", &base)){ + return true; + } + ctx.m_currentSection->put("PortNumber", base + adder); + adder++; + ctx.m_userProperties.put("PortNumberAdder", adder, true); + } + return true; +} + +/** + * DB Node rule: Check various constraints + */ +bool +checkDbConstraints(InitConfigFileParser::Context & ctx, const char *){ + + Uint32 t1 = 0, t2 = 0; + ctx.m_currentSection->get("MaxNoOfConcurrentOperations", &t1); + ctx.m_currentSection->get("MaxNoOfConcurrentTransactions", &t2); + + if (t1 < t2) { + ctx.reportError("MaxNoOfConcurrentOperations must be greater than " + "MaxNoOfConcurrentTransactions - [%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + + Uint32 replicas = 0, otherReplicas; + ctx.m_currentSection->get("NoOfReplicas", &replicas); + if(ctx.m_userProperties.get("NoOfReplicas", &otherReplicas)){ + if(replicas != otherReplicas){ + ctx.reportError("NoOfReplicas defined differently on different nodes" + " - [%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + } else { + ctx.m_userProperties.put("NoOfReplicas", replicas); + } + + return true; +} + +/** + * Connection rule: Check varius constraints + */ +bool +checkConnectionConstraints(InitConfigFileParser::Context & ctx, const char *){ + + Uint32 id1 = 0, id2 = 0; + ctx.m_currentSection->get("NodeId1", &id1); + ctx.m_currentSection->get("NodeId2", &id2); + + // If external connection, just accept it + if (ctx.m_currentSection->contains("System1") || + ctx.m_currentSection->contains("System2")) + return true; + + if(id1 == id2){ + ctx.reportError("Illegal connection from node to itself" + " - [%s] starting at line: %d", + ctx.fname, ctx.m_sectionLineno); + return false; + } + + const Properties * node1; + if(!ctx.m_config->get("Node", id1, &node1)){ + ctx.reportError("Connection refering to undefined node: %d" + " - [%s] starting at line: %d", + id1, ctx.fname, ctx.m_sectionLineno); + return false; + } + + const Properties * node2; + if(!ctx.m_config->get("Node", id2, &node2)){ + ctx.reportError("Connection refering to undefined node: %d" + " - [%s] starting at line: %d", + id2, ctx.fname, ctx.m_sectionLineno); + return false; + } + + const char * type1; + const char * type2; + require(node1->get("Type", &type1)); + require(node2->get("Type", &type2)); + + /** + * Report error if the following are true + * -# None of the nodes is of type DB + * -# Not both of them are MGMs + * -# None of them contain a "SystemX" name + */ + if((strcmp(type1, "DB") != 0 && strcmp(type2, "DB") != 0) && + !(strcmp(type1, "MGM") == 0 && strcmp(type2, "MGM") == 0) && + !ctx.m_currentSection->contains("System1") && + !ctx.m_currentSection->contains("System2")){ + ctx.reportError("Invalid connection between node %d (%s) and node %d (%s)" + " - [%s] starting at line: %d", + id1, type1, id2, type2, + ctx.fname, ctx.m_sectionLineno); + return false; + } + return true; +} diff --git a/ndb/src/common/mgmcommon/ConfigInfo.hpp b/ndb/src/common/mgmcommon/ConfigInfo.hpp new file mode 100644 index 00000000000..43041a3f772 --- /dev/null +++ b/ndb/src/common/mgmcommon/ConfigInfo.hpp @@ -0,0 +1,120 @@ +/* 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 */ + +#ifndef ConfigInfo_H +#define ConfigInfo_H + +#include <kernel_types.h> +#include <Properties.hpp> +#include <ndb_limits.h> +#include <NdbOut.hpp> +#include "InitConfigFileParser.hpp" + +/** + * A MANDATORY parameters must be specified in the config file + * An UNDEFINED parameter may or may not be specified in the config file + */ +static const Uint32 MANDATORY = ~0; // Default value for mandatory params. +static const Uint32 UNDEFINED = (~0)-1; // Default value for undefined params. + +/** + * @class ConfigInfo + * @brief Metainformation about ALL cluster configuration parameters + * + * Use the getters to find out metainformation about parameters. + */ +class ConfigInfo { +public: + enum Type {BOOL, INT, STRING}; + enum Status {USED, ///< Active + DEPRICATED, ///< Can be, but should not be used anymore + NOTIMPLEMENTED, ///< Can not be used currently. Is ignored. + INTERNAL ///< Not configurable by the user + }; + + /** + * Entry for one configuration parameter + */ + struct ParamInfo { + const char* _fname; + const char* _pname; + const char* _section; + const char* _description; + Status _status; + bool _updateable; + Type _type; + Uint32 _default; + Uint32 _min; + Uint32 _max; + }; + + /** + * Entry for one section rule + */ + struct SectionRule { + const char * m_section; + bool (* m_sectionRule)(struct InitConfigFileParser::Context &, + const char * m_ruleData); + const char * m_ruleData; + }; + + ConfigInfo(); + + /** + * Checks if the suggested value is valid for the suggested parameter + * (i.e. if it is >= than min and <= than max). + * + * @param section Init Config file section name + * @param fname Name of parameter + * @param value Value to check + * @return true if parameter value is valid. + * + * @note Result is not defined if section/name are wrong! + */ + bool verify(const Properties* section, const char* fname, Uint32 value) const; + bool isSection(const char*) const; + + const char* getPName(const Properties * section, const char* fname) const; + const char* getDescription(const Properties * section, const char* fname) const; + Type getType(const Properties * section, const char* fname) const; + Status getStatus(const Properties* section, const char* fname) const; + Uint32 getMin(const Properties * section, const char* fname) const; + Uint32 getMax(const Properties * section, const char* fname) const; + Uint32 getDefault(const Properties * section, const char* fname) const; + + const Properties * getInfo(const char * section) const; + const Properties * getDefaults(const char * section) const; + + void print() const; + void print(const char* section) const; + void print(const Properties * section, const char* parameter) const; + +private: + Properties m_info; + Properties m_systemDefaults; + + static const ParamInfo m_ParamInfo[]; + static const int m_NoOfParams; + + static const char* m_sectionNames[]; + static const int m_noOfSectionNames; + +public: + static const SectionRule m_SectionRules[]; + static const int m_NoOfRules; +}; + +#endif // ConfigInfo_H diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp new file mode 100644 index 00000000000..a3f26454df6 --- /dev/null +++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -0,0 +1,514 @@ +/* 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 <ConfigRetriever.hpp> + +#include "LocalConfig.hpp" +#include <NdbSleep.h> +#include <NdbOut.hpp> + +#include <NdbTCP.h> +#include <string.h> +#include <NdbStdio.h> +#include <NdbEnv.h> +#include "MgmtErrorReporter.hpp" + +#include <uucode.h> +#include <Properties.hpp> + +#include <stdio.h> +#include <NdbString.h> +#include <sys/stat.h> +#include <socket_io.h> +#include <NdbConfig.h> + +#include <ndb_version.h> + +//**************************************************************************** +//**************************************************************************** + +ConfigRetriever::ConfigRetriever() { + + _localConfigFileName = NULL; + m_defaultConnectString = NULL; + + + errorString = 0; + _localConfig = new LocalConfig(); + m_connectString = NULL; +} + +ConfigRetriever::~ConfigRetriever(){ + if(_localConfigFileName != 0) + free(_localConfigFileName); + + if(m_defaultConnectString != 0) + free(m_defaultConnectString); + + if(m_connectString != 0) + free(m_connectString); + + if(errorString != 0) + free(errorString); + + delete _localConfig; +} + + +//**************************************************************************** +//**************************************************************************** + +int +ConfigRetriever::init(bool onlyNodeId) { + if (_localConfig->init(onlyNodeId, m_connectString, _localConfigFileName, m_defaultConnectString)) { + return _ownNodeId = (*_localConfig)._ownNodeId; + } + + setError(CR_ERROR, "error in retrieving contact info for mgmtsrvr"); + _localConfig->printError(); + _localConfig->printUsage(); + + return -1; +} + +//**************************************************************************** +//**************************************************************************** + +Properties * +ConfigRetriever::getConfig(const char * nodeType, int versionId) { + Properties * p = getConfig(versionId); + + if (p == 0) { + char err_buf[255]; + snprintf(err_buf, sizeof(err_buf), + "No configuration retrieved for this %s node ", nodeType); + setError(CR_ERROR, err_buf); + return 0; + } + + const Uint32 nodeId = _ownNodeId; + + if (strcmp(nodeType, "DB") == 0) { + if (!verifyProperties("DB", p, nodeId, versionId)) return 0; + } else if (strcmp(nodeType, "API") == 0) { + if (!verifyProperties("API", p, nodeId, versionId)) return 0; + } else if (strcmp(nodeType, "REP") == 0) { + if (!verifyProperties("REP", p, nodeId, versionId)) return 0; + } else if (strcmp(nodeType, "MGM") == 0) { + if (!verifyProperties("MGM", p, nodeId, versionId)) return 0; + } else { + return 0; + } + + return p; +} + + +//**************************************************************************** +//**************************************************************************** +Properties * +ConfigRetriever::getConfig(int verId) { + + int res = init(); + if (res == -1) { + return 0; + } + + if (_localConfig->items == 0){ + setError(CR_ERROR, "No Management Servers configured in local config file"); + return 0; + } + + int retry = 1; + int retry_max = 12; // Max number of retry attempts + int retry_interval= 5; // Seconds between each retry + do { + Uint32 type = CR_ERROR; + for (int i = 0; i<_localConfig->items; i++){ + MgmtSrvrId * m = _localConfig->ids[i]; + Properties * p = 0; + const Uint32 nodeId = _ownNodeId; + switch(m->type){ + case MgmId_TCP: + p = getConfig(m->data.tcp.remoteHost, m->data.tcp.port, nodeId, verId); + break; + case MgmId_File: + p = getConfig(m->data.file.filename, nodeId, verId); + break; + default: + setError(CR_ERROR, "Unknown error type"); + break; + } + + if (p != 0) { + return p; + } + if(latestErrorType == CR_RETRY) + type = CR_RETRY; + } // for + + if(type == CR_RETRY){ + REPORT_WARNING("Failed to retrieve cluster configuration"); + ndbout << "(Cause of failure: " << getErrorString() << ")" << endl; + ndbout << "Attempt " << retry << " of " << retry_max << ". " + << "Trying again in "<<retry_interval<<" seconds..." << endl << endl; + NdbSleep_SecSleep(retry_interval); + } else { + break; + } + retry++; + + } while (retry <= retry_max); + + return 0; +} + +int global_ndb_check = 0; // set to one in ndb main; +Properties * +ConfigRetriever::getConfig(const char * mgmhost, + unsigned int port, + Uint32 nodeId, + int versionId){ + const int socketTimeout = 10000; + int result; + const NDB_SOCKET_TYPE sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == NDB_INVALID_SOCKET) { + setError(CR_RETRY, "Could not create socket to Management Server"); + return 0; + } + + char err_buf[255]; + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(port); + // Convert ip address presentation format to numeric format + result = Ndb_getInAddr(&servaddr.sin_addr, mgmhost); + if (result != 0) { + snprintf(err_buf, sizeof(err_buf), + "Name lookup failed: host \"%s\"", mgmhost); + setError(CR_ERROR, err_buf); + return 0; + } + + result = connect(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); + if (result == -1) { + snprintf(err_buf, sizeof(err_buf), + "Failed to connect to \"%s:%d\"", mgmhost, port); + setError(CR_RETRY, err_buf); + NDB_CLOSE_SOCKET(sockfd); + return 0; + } + + if(println_socket(sockfd, 1000, "GET CONFIG %d %d" , + versionId, nodeId) != 0){ + NDB_CLOSE_SOCKET(sockfd); + setError(CR_ERROR, "IO error, write"); + return 0; + } + + char buf[255]; + { + const int tmp = readln_socket(sockfd, socketTimeout, buf, 255); + if(tmp == -1){ + NDB_CLOSE_SOCKET(sockfd); + setError(CR_ERROR, "IO error, read"); + return 0; + } + + if(tmp == 0){ + snprintf(err_buf, 256, + "IO error, failed request: " + "GET CONFIG %d %d", versionId, nodeId); + NDB_CLOSE_SOCKET(sockfd); + setError(CR_ERROR, err_buf); + return 0; + } + } + + int status, version, node, bytes, bytesUU; + if(sscanf(buf, "GET CONFIG %d %d %d %d %d", + &status, &version, &node, &bytes, &bytesUU) != 5){ + NDB_CLOSE_SOCKET(sockfd); + snprintf(err_buf, sizeof(err_buf), + "Invalid response: %s", buf); + setError(CR_ERROR, err_buf); + return 0; + } + + if(status != 0){ + NDB_CLOSE_SOCKET(sockfd); + if (status == 1){ + snprintf(err_buf, sizeof(err_buf), + "Management Server: Requested version id is invalid"); + } else if (status == 2){ + snprintf(err_buf, sizeof(err_buf), + "Management Server: Node with id %d has not been specified", + nodeId); + } else if (status == 3){ + snprintf(err_buf, sizeof(err_buf), "Management Server: Internal error"); + } else { + snprintf(err_buf, sizeof(err_buf), + "Management Server returned unknown error: %d", status); + } + setError(CR_ERROR, err_buf); + return 0; + } + + bool compatible; + if (global_ndb_check) + compatible = ndbCompatible_ndb_mgmt(versionId, version); + else + compatible = ndbCompatible_api_mgmt(versionId, version); + + if(!compatible){ // if(version != versionId){ + NDB_CLOSE_SOCKET(sockfd); + snprintf(err_buf, sizeof(err_buf), "Management Server: Invalid version. " + "Version from server: %d Own version: %d", version, versionId); + setError(CR_ERROR, err_buf); + return 0; + } + + if(node != (int)nodeId){ + NDB_CLOSE_SOCKET(sockfd); + snprintf(err_buf, sizeof(err_buf), "Management Server: Invalid node id. " + "Node id from server: %d Own node id: %d", node, nodeId); + setError(CR_ERROR, err_buf); + return 0; + } + + if(readln_socket(sockfd, socketTimeout, buf, 255) == -1){ + NDB_CLOSE_SOCKET(sockfd); + setError(CR_ERROR, "IO error, read"); + return 0; + } + + if(strncmp("begin", buf, strlen("begin")) != 0){ + NDB_CLOSE_SOCKET(sockfd); + snprintf(err_buf, sizeof(err_buf), + "Invalid response: %s", buf); + setError(CR_ERROR, err_buf); + return 0; + } + + char* bufUU = new char[bytesUU]; + int read = 0; + int start = 0; + do { + if((read = read_socket(sockfd, socketTimeout, &bufUU[start], bytesUU-start)) == -1){ + delete[] bufUU; + NDB_CLOSE_SOCKET(sockfd); + setError(CR_ERROR, "IO error, read(bufUU)"); + return 0; + } + start += read; + } while(start < bytesUU); + + Uint32 * buf2 = new Uint32[bytes/4+1]; // Properties byte size + char * dst = (char *)buf2; + int sz = 0; + start = 0; + + for (int i = 0; i < bytesUU; i++) { + if (bufUU[i] == '\n') { + bufUU[i] = 0; + if (bufUU[i-1] == '\r') { + bufUU[i-1] = 0; + } + sz = uudecode_mem(dst, bytes, &bufUU[start]); + dst += sz; + start = i + 1; // Next row + } + } + + delete[] bufUU; + + if(sz < 0){ + delete []buf2; + NDB_CLOSE_SOCKET(sockfd); + setError(CR_ERROR, "IO error, sz < 0"); + return 0; + } + + Properties * p = new Properties(); + if(!p->unpack(buf2, bytes+4)){ + snprintf(buf, sizeof(buf), "Error while unpacking %d,%d", + p->getPropertiesErrno(), + p->getOSErrno()); + setError(CR_ERROR, buf); + delete []buf2; + delete p; + return 0; + } + delete []buf2; + + NDB_CLOSE_SOCKET(sockfd); + + return p; + +} + +Properties * +ConfigRetriever::getConfig(const char * filename, + Uint32 nodeId, + int versionId){ + + struct stat sbuf; + const int res = stat(filename, &sbuf); + if(res != 0){ + char buf[255]; + snprintf(buf, sizeof(buf), "Could not find file: \"%s\"", filename); + setError(CR_ERROR, buf); + return 0; + } + const Uint32 bytes = sbuf.st_size; + + Uint32 * buf2 = new Uint32[bytes/4+1]; + + FILE * f = fopen(filename, "rb"); + if(f == 0){ + setError(CR_ERROR, "Failed to open file"); + delete []buf2; + return 0; + } + Uint32 sz = fread(buf2, 1, bytes, f); + fclose(f); + if(sz != bytes){ + setError(CR_ERROR, "Failed to read file"); + delete []buf2; + return 0; + } + + Properties * p = new Properties(); + if(!p->unpack(buf2, bytes+4)){ + char buf[255]; + snprintf(buf, sizeof(buf), "Error while unpacking %d,%d", + p->getPropertiesErrno(), + p->getOSErrno()); + setError(CR_ERROR, buf); + delete []buf2; + delete p; + return 0; + } + delete [] buf2; + + return p; +} + +bool +ConfigRetriever::verifyProperties(const char* nodeType, Properties * p, + Uint32 nodeId, int versionId){ + + Uint32 t = 0; + const Properties *tmp; + const char *type; + + if (p == 0) return false; + + bool compatible = false; + if (p->get("Version", &t)) + if (global_ndb_check) + compatible = ndbCompatible_ndb_mgmt(versionId, t); + else + compatible = ndbCompatible_api_mgmt(versionId, t); + + if(!compatible){ // if(!p->get("Version", &t) || versionId != (int)t){ + setError(CR_ERROR, "Invalid configuration version"); + delete p; + return false; + } + + if(!p->get("LocalNodeId", &t) || nodeId != t){ + setError(CR_ERROR, "Invalid node identity in configuration"); + delete p; + return false; + } + + if(!p->get("Node", nodeId, &tmp)){ + setError(CR_ERROR, "Internal error while processing configuration"); + ndbout_c("nodeId = %d", nodeId); + p->print(); + delete p; + return false; + } + + if(!tmp->get("Type", &type) || strcmp(type, nodeType)) { + if (!(!strcmp(type, "REP") && !strcmp(nodeType, "API"))) { + char buf[1024]; + snprintf(buf, sizeof(buf), + "Configuration error: Node with id %d is not of type %s.\n" + "Check local config file: %s", nodeId, nodeType, + _localConfigFileName); + setError(CR_ERROR, buf); + return false; + } + } + + return true; +} + +void +ConfigRetriever::setError(ErrorType et, const char * s){ + if(errorString != 0){ + free(errorString); + } + if(s == 0) + errorString = 0; + else + errorString = strdup(s); + latestErrorType = et; +} + + +const char * +ConfigRetriever::getErrorString(){ + return errorString; +} + +void +ConfigRetriever::setLocalConfigFileName(const char * localConfigFileName) { + if(_localConfigFileName != 0) + free(_localConfigFileName); + if(localConfigFileName != 0) + _localConfigFileName = strdup(localConfigFileName); + else + _localConfigFileName = 0; +} + +void +ConfigRetriever::setConnectString(const char * connectString) { + if(m_connectString != 0) + free(m_connectString); + if (connectString != 0) { + m_connectString = strdup(connectString); + } else { + m_connectString = 0; + } +} + +/** + * @note Do not use! Use the one above if possible. /elathal + */ +void +ConfigRetriever::setDefaultConnectString(const char * defaultConnectString) { + if(m_defaultConnectString != 0) + free(m_defaultConnectString); + if (defaultConnectString != 0) { + m_defaultConnectString = strdup(defaultConnectString); + } else { + m_defaultConnectString = 0; + } +} diff --git a/ndb/src/common/mgmcommon/IPCConfig.cpp b/ndb/src/common/mgmcommon/IPCConfig.cpp new file mode 100644 index 00000000000..f75cf806cc0 --- /dev/null +++ b/ndb/src/common/mgmcommon/IPCConfig.cpp @@ -0,0 +1,336 @@ +/* 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 "IPCConfig.hpp" +#include <NdbOut.hpp> +#include <NdbHost.h> +#include <TransporterDefinitions.hpp> +#include <TransporterRegistry.hpp> +#include <Properties.hpp> + +#if defined DEBUG_TRANSPORTER +#define DEBUG(t) ndbout << __FILE__ << ":" << __LINE__ << ":" << t << endl; +#else +#define DEBUG(t) +#endif + +IPCConfig::IPCConfig(Properties * p) +{ + theNoOfRemoteNodes = 0; + the_ownId = 0; + if(p != 0) + props = new Properties(* p); + else + props = 0; +} + + +IPCConfig::~IPCConfig() +{ + if(props != 0){ + delete props; + } +} + +int +IPCConfig::init(){ + Uint32 nodeId; + + if(props == 0) return -1; + if(!props->get("LocalNodeId", &nodeId)) { + DEBUG( "Did not find local node id." ); + return -1; + } + the_ownId = nodeId; + + Uint32 noOfConnections; + if(!props->get("NoOfConnections", &noOfConnections)) { + DEBUG( "Did not find noOfConnections." ); + return -1; + } + + for(Uint32 i = 0; i<noOfConnections; i++){ + const Properties * tmp; + Uint32 node1, node2; + + if(!props->get("Connection", i, &tmp)) { + DEBUG( "Did not find Connection." ); + return -1; + } + if(!tmp->get("NodeId1", &node1)) { + DEBUG( "Did not find NodeId1." ); + return -1; + } + if(!tmp->get("NodeId2", &node2)) { + DEBUG( "Did not find NodeId2." ); + return -1; + } + + if(node1 == the_ownId && node2 != the_ownId) + if(!addRemoteNodeId(node2)) { + DEBUG( "addRemoteNodeId(node2) failed." ); + return -1; + } + + if(node1 != the_ownId && node2 == the_ownId) + if(!addRemoteNodeId(node1)) { + DEBUG( "addRemoteNodeId(node2) failed." ); + return -1; + } + } + return 0; +} + +bool +IPCConfig::addRemoteNodeId(NodeId nodeId){ + for(int i = 0; i<theNoOfRemoteNodes; i++) + if(theRemoteNodeIds[i] == nodeId) + return false; + theRemoteNodeIds[theNoOfRemoteNodes] = nodeId; + theNoOfRemoteNodes++; + return true; +} + +/** + * Returns no of transporters configured + */ +int +IPCConfig::configureTransporters(TransporterRegistry * theTransporterRegistry){ + int noOfTransportersCreated = 0; + + Uint32 noOfConnections; + if(!props->get("NoOfConnections", &noOfConnections)) return -1; + + for (Uint32 i = 0; i < noOfConnections; i++){ + const Properties * tmp; + Uint32 nodeId1, nodeId2; + const char * host1; + const char * host2; + + if(!props->get("Connection", i, &tmp)) continue; + if(!tmp->get("NodeId1", &nodeId1)) continue; + if(!tmp->get("NodeId2", &nodeId2)) continue; + if(nodeId1 != the_ownId && nodeId2 != the_ownId) continue; + + Uint32 sendSignalId; + Uint32 compression; + Uint32 checksum; + if(!tmp->get("SendSignalId", &sendSignalId)) continue; + if(!tmp->get("Compression", &compression)) continue; + if(!tmp->get("Checksum", &checksum)) continue; + + const char * type; + if(!tmp->get("Type", &type)) continue; + + if(strcmp("SHM", type) == 0){ + SHM_TransporterConfiguration conf; + conf.localNodeId = the_ownId; + conf.remoteNodeId = (nodeId1 != the_ownId ? nodeId1 : nodeId2); + conf.byteOrder = 0; + conf.compression = compression; + conf.checksum = checksum; + conf.signalId = sendSignalId; + + if(!tmp->get("ShmKey", &conf.shmKey)) continue; + if(!tmp->get("ShmSize", &conf.shmSize)) continue; + + if(!theTransporterRegistry->createTransporter(&conf)){ + ndbout << "Failed to create SHM Transporter from: " + << conf.localNodeId << " to: " << conf.remoteNodeId << endl; + continue; + } else { + noOfTransportersCreated++; + continue; + } + + } else if(strcmp("SCI", type) == 0){ + SCI_TransporterConfiguration conf; + conf.localNodeId = the_ownId; + conf.remoteNodeId = (nodeId1 != the_ownId ? nodeId1 : nodeId2); + conf.byteOrder = 0; + conf.compression = compression; + conf.checksum = checksum; + conf.signalId = sendSignalId; + + if(!tmp->get("SendLimit", &conf.sendLimit)) continue; + if(!tmp->get("SharedBufferSize", &conf.bufferSize)) continue; + + if(the_ownId == nodeId1){ + if(!tmp->get("Node1_NoOfAdapters", &conf.nLocalAdapters)) continue; + if(!tmp->get("Node2_NoOfAdapters", &conf.nRemoteAdapters)) continue; + if(!tmp->get("Node2_Adapter", 0, &conf.remoteSciNodeId0)) continue; + + if(conf.nRemoteAdapters > 1){ + if(!tmp->get("Node2_Adapter", 1, &conf.remoteSciNodeId1)) continue; + } + } else { + if(!tmp->get("Node2_NoOfAdapters", &conf.nLocalAdapters)) continue; + if(!tmp->get("Node1_NoOfAdapters", &conf.nRemoteAdapters)) continue; + if(!tmp->get("Node1_Adapter", 0, &conf.remoteSciNodeId0)) continue; + + if(conf.nRemoteAdapters > 1){ + if(!tmp->get("Node1_Adapter", 1, &conf.remoteSciNodeId1)) continue; + } + } + + if(!theTransporterRegistry->createTransporter(&conf)){ + ndbout << "Failed to create SCI Transporter from: " + << conf.localNodeId << " to: " << conf.remoteNodeId << endl; + continue; + } else { + noOfTransportersCreated++; + continue; + } + } + + if(!tmp->get("HostName1", &host1)) continue; + if(!tmp->get("HostName2", &host2)) continue; + + Uint32 ownNodeId; + Uint32 remoteNodeId; + const char * ownHostName; + const char * remoteHostName; + + if(nodeId1 == the_ownId){ + ownNodeId = nodeId1; + ownHostName = host1; + remoteNodeId = nodeId2; + remoteHostName = host2; + } else if(nodeId2 == the_ownId){ + ownNodeId = nodeId2; + ownHostName = host2; + remoteNodeId = nodeId1; + remoteHostName = host1; + } else { + continue; + } + + if(strcmp("TCP", type) == 0){ + TCP_TransporterConfiguration conf; + + if(!tmp->get("PortNumber", &conf.port)) continue; + if(!tmp->get("SendBufferSize", &conf.sendBufferSize)) continue; + if(!tmp->get("MaxReceiveSize", &conf.maxReceiveSize)) continue; + + const char * proxy; + if (tmp->get("Proxy", &proxy)) { + if (strlen(proxy) > 0 && nodeId2 == the_ownId) { + // TODO handle host:port + conf.port = atoi(proxy); + } + } + conf.sendBufferSize *= MAX_MESSAGE_SIZE; + conf.maxReceiveSize *= MAX_MESSAGE_SIZE; + + conf.remoteHostName = remoteHostName; + conf.localHostName = ownHostName; + conf.remoteNodeId = remoteNodeId; + conf.localNodeId = ownNodeId; + conf.byteOrder = 0; + conf.compression = compression; + conf.checksum = checksum; + conf.signalId = sendSignalId; + + if(!theTransporterRegistry->createTransporter(&conf)){ + ndbout << "Failed to create TCP Transporter from: " + << ownNodeId << " to: " << remoteNodeId << endl; + } else { + noOfTransportersCreated++; + } + + } else if(strcmp("OSE", type) == 0){ + + OSE_TransporterConfiguration conf; + + if(!tmp->get("PrioASignalSize", &conf.prioASignalSize)) + continue; + if(!tmp->get("PrioBSignalSize", &conf.prioBSignalSize)) + continue; + if(!tmp->get("ReceiveArraySize", &conf.receiveBufferSize)) + continue; + + conf.remoteHostName = remoteHostName; + conf.localHostName = ownHostName; + conf.remoteNodeId = remoteNodeId; + conf.localNodeId = ownNodeId; + conf.byteOrder = 0; + conf.compression = compression; + conf.checksum = checksum; + conf.signalId = sendSignalId; + + if(!theTransporterRegistry->createTransporter(&conf)){ + ndbout << "Failed to create OSE Transporter from: " + << ownNodeId << " to: " << remoteNodeId << endl; + } else { + noOfTransportersCreated++; + } + } else { + continue; + } + } + return noOfTransportersCreated; +} + +/** + * Supply a nodeId, + * and get next higher node id + * Returns false if none found + */ +bool +IPCConfig::getNextRemoteNodeId(NodeId & nodeId) const { + NodeId returnNode = MAX_NODES + 1; + for(int i = 0; i<theNoOfRemoteNodes; i++) + if(theRemoteNodeIds[i] > nodeId){ + if(theRemoteNodeIds[i] < returnNode){ + returnNode = theRemoteNodeIds[i]; + } + } + if(returnNode == (MAX_NODES + 1)) + return false; + nodeId = returnNode; + return true; +} + + +Uint32 +IPCConfig::getREPHBFrequency(NodeId id) const { + const Properties * tmp; + Uint32 out; + + /** + * Todo: Fix correct heartbeat + */ + if (!props->get("Node", id, &tmp) || + !tmp->get("HeartbeatIntervalRepRep", &out)) { + DEBUG("Illegal Node or HeartbeatIntervalRepRep in config."); + out = 10000; + } + + return out; +} + +const char* +IPCConfig::getNodeType(NodeId id) const { + const char * out; + const Properties * tmp; + + if (!props->get("Node", id, &tmp) || !tmp->get("Type", &out)) { + DEBUG("Illegal Node or NodeType in config."); + out = "Unknown"; + } + + return out; +} diff --git a/ndb/src/common/mgmcommon/InitConfigFileParser.cpp b/ndb/src/common/mgmcommon/InitConfigFileParser.cpp new file mode 100644 index 00000000000..33652fa472c --- /dev/null +++ b/ndb/src/common/mgmcommon/InitConfigFileParser.cpp @@ -0,0 +1,544 @@ +/* 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 "InitConfigFileParser.hpp" +#include <string.h> +#include <errno.h> +#include "Config.hpp" +#include "MgmtErrorReporter.hpp" +#include <NdbOut.hpp> +#include "ConfigInfo.hpp" +#include <stdarg.h> +#include <ctype.h> +#include <NdbString.h> + +const int MAX_LINE_LENGTH = 120; // Max length of line of text in config file +static void trim(char *); + +static void require(bool v) { if(!v) abort();} + +//**************************************************************************** +// Ctor / Dtor +//**************************************************************************** +InitConfigFileParser::InitConfigFileParser(const char* initialConfigFileName){ + + m_initConfigStream = fopen(initialConfigFileName, "r"); + + m_info = new ConfigInfo(); + m_config = new Config(); + m_defaults = new Properties(); + m_defaults->setCaseInsensitiveNames(true); +} + +InitConfigFileParser::~InitConfigFileParser() { + if (m_initConfigStream != NULL) fclose(m_initConfigStream); + + delete m_info; + delete m_config; + delete m_defaults; +} + +//**************************************************************************** +// Read Config File +//**************************************************************************** +bool InitConfigFileParser::readConfigFile() { + + char line[MAX_LINE_LENGTH]; + + Context ctx; + ctx.m_lineno = 0; + ctx.m_currentSection = 0; + + ctx.m_info = m_info; + ctx.m_config = m_config; + ctx.m_defaults = m_defaults; + + /************* + * Open file * + *************/ + if (m_initConfigStream == NULL) { + ctx.reportError("Could not open file."); + return false; + } + + /*********************** + * While lines to read * + ***********************/ + while (fgets(line, MAX_LINE_LENGTH, m_initConfigStream)) { + ctx.m_lineno++; + + trim(line); + + if (isEmptyLine(line)) // Skip if line is empty or comment + continue; + + // End with NULL instead of newline + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = '\0'; + + /******************************** + * 1. Parse new default section * + ********************************/ + if (char* section = parseDefaultSectionHeader(line)) { + if(!storeSection(ctx)){ + free(section); + ctx.reportError("Could not store previous default section " + "of configuration file."); + return false; + } + + snprintf(ctx.fname, sizeof(ctx.fname), section); free(section); + ctx.type = InitConfigFileParser::DefaultSection; + ctx.m_sectionLineno = ctx.m_lineno; + ctx.m_currentSection = new Properties(); + ctx.m_userDefaults = NULL; + ctx.m_currentInfo = m_info->getInfo(ctx.fname); + ctx.m_systemDefaults = m_info->getDefaults(ctx.fname); + continue; + } + + /************************ + * 2. Parse new section * + ************************/ + if (char* section = parseSectionHeader(line)) { + if(!storeSection(ctx)){ + free(section); + ctx.reportError("Could not store previous section " + "of configuration file."); + return false; + } + + snprintf(ctx.fname, sizeof(ctx.fname), section); + free(section); + ctx.type = InitConfigFileParser::Section; + ctx.m_sectionLineno = ctx.m_lineno; + ctx.m_currentSection = new Properties(); + ctx.m_userDefaults = getSection(ctx.fname, m_defaults); + ctx.m_currentInfo = m_info->getInfo(ctx.fname); + ctx.m_systemDefaults = m_info->getDefaults(ctx.fname); + continue; + } + + /**************************** + * 3. Parse name-value pair * + ****************************/ + if (!parseNameValuePair(ctx, line)) { + ctx.reportError("Could not parse name-value pair in config file."); + return false; + } + } + + if(!storeSection(ctx)) { + ctx.reportError("Could not store section of configuration file."); + return false; + } + + Uint32 nConnections = 0; + Uint32 nComputers = 0; + Uint32 nNodes = 0; + Uint32 nExtConnections = 0; + const char * system = "?"; + ctx.m_userProperties.get("NoOfConnections", &nConnections); + ctx.m_userProperties.get("NoOfComputers", &nComputers); + ctx.m_userProperties.get("NoOfNodes", &nNodes); + ctx.m_userProperties.get("ExtNoOfConnections", &nExtConnections); + ctx.m_userProperties.get("ExtSystem", &system); + m_config->put("NoOfConnections", nConnections); + m_config->put("NoOfComputers", nComputers); + m_config->put("NoOfNodes", nNodes); + + char tmpLine[MAX_LINE_LENGTH]; + snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_"); + strncat(tmpLine, system, MAX_LINE_LENGTH); + strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH); + m_config->put(tmpLine, nExtConnections); + + if (ferror(m_initConfigStream)) { + ctx.reportError("Failure in reading"); + return false; + } + return true; +} + +//**************************************************************************** +// Parse Name-Value Pair +//**************************************************************************** + +bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) { + + char tmpLine[MAX_LINE_LENGTH]; + char fname[MAX_LINE_LENGTH], rest[MAX_LINE_LENGTH]; + char* t; + + if (ctx.m_currentSection == NULL){ + ctx.reportError("Value specified outside section"); + return false; + } + + strncpy(tmpLine, line, MAX_LINE_LENGTH); + + // ************************************* + // Check if a separator exists in line + // ************************************* + if (!strchr(tmpLine, ':')) { + ctx.reportError("Parse error"); + return false; + } + + // ******************************************* + // Get pointer to substring before separator + // ******************************************* + t = strtok(tmpLine, ":"); + + // ***************************************** + // Count number of tokens before separator + // ***************************************** + if (sscanf(t, "%120s%120s", fname, rest) != 1) { + ctx.reportError("Multiple names before \':\'"); + return false; + } + if (!ctx.m_currentInfo->contains(fname)) { + ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname); + return false; + } + ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname); + if (status == ConfigInfo::NOTIMPLEMENTED) { + ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, fname); + } + if (status == ConfigInfo::DEPRICATED) { + ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname); + } + + // ****************************************** + // Get pointer to substring after separator + // ****************************************** + t = strtok(NULL, "\0"); + if (t == NULL) { + ctx.reportError("No value for parameter"); + return false; + } + + // ****************************************** + // Remove prefix and postfix spaces and tabs + // ******************************************* + trim(t); + + // *********************** + // Store name-value pair + // *********************** + return storeNameValuePair(ctx, fname, t); +} + + +//**************************************************************************** +// STORE NAME-VALUE pair in properties section +//**************************************************************************** + +bool +InitConfigFileParser::storeNameValuePair(Context& ctx, + const char* fname, + const char* value) { + + const char * pname = m_info->getPName(ctx.m_currentInfo, fname); + + if (ctx.m_currentSection->contains(pname)) { + ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname); + return false; + } + + // *********************** + // Store name-value pair + // *********************** + + switch(m_info->getType(ctx.m_currentInfo, fname)){ + case ConfigInfo::BOOL: { + bool value_bool; + if (!convertStringToBool(value, value_bool)) { + ctx.reportError("Illegal boolean value for parameter %s", fname); + return false; + } + MGM_REQUIRE(ctx.m_currentSection->put(pname, value_bool)); + break; + } + case ConfigInfo::INT:{ + Uint32 value_int; + if (!convertStringToUint32(value, value_int)) { + ctx.reportError("Illegal integer value for parameter %s", fname); + return false; + } + if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) { + ctx.reportError("Illegal value %s for parameter %s.\n" + "Legal values are between %d and %d", value, fname, + m_info->getMin(ctx.m_currentInfo, fname), + m_info->getMax(ctx.m_currentInfo, fname)); + return false; + } + MGM_REQUIRE(ctx.m_currentSection->put(pname, value_int)); + break; + } + case ConfigInfo::STRING: + MGM_REQUIRE(ctx.m_currentSection->put(pname, value)); + break; + } + return true; +} + +//**************************************************************************** +// Is Empty Line +//**************************************************************************** + +bool InitConfigFileParser::isEmptyLine(const char* line) const { + int i; + + // Check if it is a comment line + if (line[0] == '#') return true; + + // Check if it is a line with only spaces + for (i = 0; i < MAX_LINE_LENGTH && line[i] != '\n' && line[i] != '\0'; i++) { + if (line[i] != ' ' && line[i] != '\t') return false; + } + return true; +} + +//**************************************************************************** +// Convert String to Int +//**************************************************************************** +bool InitConfigFileParser::convertStringToUint32(const char* s, + Uint32& val, + Uint32 log10base) { + if (s == NULL) + return false; + if (strlen(s) == 0) + return false; + + errno = 0; + char* p; + long v = strtol(s, &p, 10); + if (errno != 0) + return false; + + long mul = 0; + if (p != &s[strlen(s)]){ + char * tmp = strdup(p); + trim(tmp); + switch(tmp[0]){ + case 'k': + case 'K': + mul = 10; + break; + case 'M': + mul = 20; + break; + case 'G': + mul = 30; + break; + default: + free(tmp); + return false; + } + free(tmp); + } + + val = (v << mul); + return true; +} + +bool InitConfigFileParser::convertStringToBool(const char* s, bool& val) { + if (s == NULL) return false; + if (strlen(s) == 0) return false; + + if (!strcmp(s, "Y") || !strcmp(s, "y") || + !strcmp(s, "Yes") || !strcmp(s, "YES") || !strcmp(s, "yes") || + !strcmp(s, "True") || !strcmp(s, "TRUE") || !strcmp(s, "true")) { + val = true; + return true; + } + + if (!strcmp(s, "N") || !strcmp(s, "n") || + !strcmp(s, "No") || !strcmp(s, "NO") || !strcmp(s, "no") || + !strcmp(s, "False") || !strcmp(s, "FALSE") || !strcmp(s, "false")) { + val = false; + return true; + } + + return false; // Failure to convert +} + +//**************************************************************************** +// Get Config +//**************************************************************************** +const Config* InitConfigFileParser::getConfig() { + Uint32 nConnections = 0; + Uint32 nComputers = 0; + Uint32 nNodes = 0; + m_config->get("NoOfConnections", &nConnections); + m_config->get("NoOfComputers", &nComputers); + m_config->get("NoOfNodes", &nNodes); + + return m_config; +} + + +//**************************************************************************** +// Parse Section Header +//**************************************************************************** +static void +trim(char * str){ + int len = strlen(str); + for(len--; + (str[len] == '\r' || str[len] == '\n' || + str[len] == ' ' || str[len] == '\t') && + len > 0; + len--) + str[len] = 0; + + int pos = 0; + while(str[pos] == ' ' || str[pos] == '\t') + pos++; + + if(str[pos] == '\"' && str[len] == '\"') { + pos++; + str[len] = 0; + len--; + } + + memmove(str, &str[pos], len - pos + 2); +} + +char* +InitConfigFileParser::parseSectionHeader(const char* line) const { + char * tmp = strdup(line); + + if(tmp[0] != '['){ + free(tmp); + return NULL; + } + + if(tmp[strlen(tmp)-1] != ']'){ + free(tmp); + return NULL; + } + tmp[strlen(tmp)-1] = 0; + + tmp[0] = ' '; + trim(tmp); + + // Lookup token among sections + if(!m_info->isSection(tmp)) return NULL; + if(m_info->getInfo(tmp)) return tmp; + + free(tmp); + return NULL; +} + +//**************************************************************************** +// Parse Default Section Header +//**************************************************************************** + +char* +InitConfigFileParser::parseDefaultSectionHeader(const char* line) const { + static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH]; + + int no = sscanf(line, "[%120[A-Za-z] %120[A-Za-z]]", token1, token2); + + // Not correct no of tokens + if (no != 2) return NULL; + + // Not correct keyword at end + if (!strcmp(token2, "DEFAULT") == 0) return NULL; + + if(m_info->getInfo(token1)){ + return strdup(token1); + } + + // Did not find section + return NULL; +} + +const Properties * +InitConfigFileParser::getSection(const char * name, const Properties * src){ + const Properties * p; + if(src && src->get(name, &p)) + return p; + + return 0; +} + +//**************************************************************************** +// STORE section +//**************************************************************************** +bool +InitConfigFileParser::storeSection(Context& ctx){ + if(ctx.m_currentSection == NULL) + return true; + + for(int i = strlen(ctx.fname) - 1; i>=0; i--){ + ctx.fname[i] = toupper(ctx.fname[i]); + } + + snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname); + + char buf[255]; + if(ctx.type == InitConfigFileParser::Section) + snprintf(buf, sizeof(buf), "%s", ctx.fname); + if(ctx.type == InitConfigFileParser::DefaultSection) + snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname); + + snprintf(ctx.fname, sizeof(ctx.fname), buf); + for(int i = 0; i<m_info->m_NoOfRules; i++){ + const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i]; + if(strcmp(rule.m_section, ctx.fname) == 0) + if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){ + return false; + } + } + + if(ctx.type == InitConfigFileParser::DefaultSection) + require(m_defaults->put(ctx.pname, ctx.m_currentSection)); + + if(ctx.type == InitConfigFileParser::Section) + require(m_config->put(ctx.pname, ctx.m_currentSection)); + + delete ctx.m_currentSection; ctx.m_currentSection = NULL; + + return true; +} + +void +InitConfigFileParser::Context::reportError(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << "Error line " << m_lineno << ": " << buf << endl; + va_end(ap); + + //m_currentSection->print(); +} + +void +InitConfigFileParser::Context::reportWarning(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << "Warning line " << m_lineno << ": " << buf << endl; + va_end(ap); +} diff --git a/ndb/src/common/mgmcommon/InitConfigFileParser.hpp b/ndb/src/common/mgmcommon/InitConfigFileParser.hpp new file mode 100644 index 00000000000..1e85067396c --- /dev/null +++ b/ndb/src/common/mgmcommon/InitConfigFileParser.hpp @@ -0,0 +1,142 @@ +/* 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 */ + +#ifndef InitConfigFileParser_H +#define InitConfigFileParser_H + +#include <stdio.h> +#include <Properties.hpp> + +class Config; +class ConfigInfo; + +/** + * @class InitConfigFileParser + * @brief Reads initial config file and returns Config object + * + * This class contains one public method InitConfigFileParser::getConfig, + * which reads an initial configuration file and returns a Config + * object if the config file has correct syntax and semantic. + */ +class InitConfigFileParser { +public: + enum ContextSectionType { Undefined, Section, DefaultSection }; + + /** + * Context = Which section in init config file we are currently parsing + */ + struct Context { + ContextSectionType type; ///< Section type (e.g. default section,section) + char fname[256]; ///< Section name occuring in init config file + char pname[256]; ///< Section name stored in properties object + Uint32 m_lineno; ///< Current line no in config file + Uint32 m_sectionLineno; ///< Where did current section start + + const ConfigInfo * m_info; // The config info + const Properties * m_config; // The config object + const Properties * m_defaults; // The user defaults + + Properties * m_currentSection; // The current section I'm in + const Properties * m_userDefaults; // The defaults of this section + const Properties * m_systemDefaults; // The syst. defaults for this section + const Properties * m_currentInfo; // The "info" for this section + + Properties m_userProperties; // User properties (temporary values) + + public: + void reportError(const char * msg, ...); + void reportWarning(const char * msg, ...); + }; + + + /** + * Constructor + * @param initialConfigFileName: Name of the initial configuration file + */ + InitConfigFileParser(const char* initialConfigFileName); + ~InitConfigFileParser(); + + /** + * Reads the initial configuration file, checks syntax and semantic + * and stores internally the values of all parameters. + * + * @returns true if succeeded, o/w false (e.g. incorrect config file) + */ + bool readConfigFile(); + + /** + * Get config. Must execute InitConfigFileParser::readConfigFile first. + * + * @returns Config if succeeded, o/w NULL + */ + const Config* getConfig(); + + +private: + /** + * Check if line only contains space/comments + * @param line: The line to check + * @return true if spaces/comments only, false otherwise + */ + bool isEmptyLine(const char* line) const; + + /** + * Checks if line contains a section header + * @param line: String to search + * @return section header if matching some section header, NULL otherwise + */ + char* parseSectionHeader(const char* line) const; + + /** + * Checks if line contains a default header + * @param line: String to search + * @return section header if matching some section header, NULL otherwise + */ + char* parseDefaultSectionHeader(const char* line) const; + + bool parseNameValuePair(Context&, const char* line); + bool storeNameValuePair(Context&, const char* fname, const char* value); + + bool convertStringToUint32(const char* s, Uint32& val, Uint32 log10base = 0); + bool convertStringToBool(const char* s, bool& val); + + const Properties* getSection(const char * name, const Properties* src); + + /*************************************************************************** + * VARIABLES + ***************************************************************************/ + FILE* m_initConfigStream; + + /** + * Information about parameters (min, max values etc) + */ + const ConfigInfo* m_info; + + /** + * Configuration from initial configuration file + * (returned by InitConfigFileParser::readConfigFile) + */ + Config* m_config; + + /** + * Default values specified in default sections + */ + Properties* m_defaults; + + bool storeSection(Context&); +}; + +#endif // InitConfigFileParser_H diff --git a/ndb/src/common/mgmcommon/LocalConfig.cpp b/ndb/src/common/mgmcommon/LocalConfig.cpp new file mode 100644 index 00000000000..12e685ced34 --- /dev/null +++ b/ndb/src/common/mgmcommon/LocalConfig.cpp @@ -0,0 +1,308 @@ +/* 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 "LocalConfig.hpp" +#include <NdbEnv.h> +#include <NdbConfig.h> + +LocalConfig::LocalConfig(){ + ids = 0; size = 0; items = 0; + error_line = 0; error_msg[0] = 0; +} + +bool +LocalConfig::init(bool onlyNodeId, + const char *connectString, + const char *fileName, + const char *defaultConnectString) { + /** + * Escalation: + * 1. Check connectString + * 2. Check given filename + * 3. Check environment variable NDB_CONNECTSTRING + * 4. Check Ndb.cfg in NDB_HOME + * 5. Check Ndb.cfg in cwd + * 6. Check defaultConnectString + */ + + //1. Check connectString + if(connectString != 0) { + if(readConnectString(connectString, onlyNodeId)){ + return true; + } + return false; + } + + //2. Check given filename + if (fileName && strlen(fileName) > 0) { + bool fopenError; + if(readFile(fileName, fopenError, onlyNodeId)){ + return true; + } + return false; + } + + //3. Check environment variable + char buf[255]; + if(NdbEnv_GetEnv("NDB_CONNECTSTRING", buf, sizeof(buf)) && + strlen(buf) != 0){ + if(readConnectString(buf, onlyNodeId)){ + return true; + } + return false; + } + + //4. Check Ndb.cfg in NDB_HOME + { + bool fopenError; + char buf[256]; + if(readFile(NdbConfig_NdbCfgName(buf, sizeof(buf), 1 /*true*/), fopenError, onlyNodeId)){ + return true; + } + if (!fopenError) + return false; + } + + //5. Check Ndb.cfg in cwd + { + bool fopenError; + char buf[256]; + if(readFile(NdbConfig_NdbCfgName(buf, sizeof(buf), 0 /*false*/), fopenError, onlyNodeId)){ + return true; + } + if (!fopenError) + return false; + } + + //6. Check defaultConnectString + if(defaultConnectString != 0) { + if(readConnectString(defaultConnectString, onlyNodeId)){ + return true; + } + return false; + } + + setError(0, ""); + + return false; +} + +LocalConfig::~LocalConfig(){ + for(int i = 0; i<items; i++){ + if(ids[i]->type == MgmId_TCP) + free(ids[i]->data.tcp.remoteHost); + else if(ids[i]->type == MgmId_File) + free(ids[i]->data.file.filename); + delete ids[i]; + } + if(ids != 0) + delete[] ids; +} + +void LocalConfig::add(MgmtSrvrId * i){ + if(items == size){ + MgmtSrvrId ** tmp = new MgmtSrvrId * [size+10]; + if(ids != 0){ + memcpy(tmp, ids, items*sizeof(MgmtSrvrId *)); + delete []ids; + } + ids = tmp; + } + ids[items] = i; + items++; +} + +void LocalConfig::setError(int lineNumber, const char * _msg) { + error_line = lineNumber; + strncpy(error_msg, _msg, sizeof(error_msg)); +} + +void LocalConfig::printError() const { + ndbout << "Local configuration error"<< endl + << "Line: "<< error_line << ", " << error_msg << endl << endl; +} + +void LocalConfig::printUsage() const { + ndbout << "This node needs information on how to connect"<<endl + << "to the NDB Management Server."<<endl + << "The information can be supplied in one of the following ways:" + << endl; + + ndbout << "1. Put a Ndb.cfg file in the directory where you start"<<endl + << " the node. "<< endl + << " Ex: Ndb.cfg" << endl + << " | nodeid=11;host=localhost:2200"<<endl<<endl; + + ndbout << "2. Use the environment variable NDB_CONNECTSTRING to "<<endl + << " provide this information." <<endl + << " Ex: " << endl + << " >export NDB_CONNECTSTRING=\"nodeid=11;host=localhost:2200\"" + <<endl<<endl; +} + +char *nodeIdTokens[] = { + "OwnProcessId %i", + "nodeid=%i", + 0 +}; + +char *hostNameTokens[] = { + "host://%[^:]:%i", + "host=%[^:]:%i", + "%[^:]:%i", + "%s %i", + 0 +}; + +char *fileNameTokens[] = { + "file://%s", + "file=%s", + 0 +}; + +bool +LocalConfig::parseNodeId(const char * buf){ + for(int i = 0; nodeIdTokens[i] != 0; i++) + if (sscanf(buf, nodeIdTokens[i], &_ownNodeId) == 1) + return true; + return false; +} + +bool +LocalConfig::parseHostName(const char * buf){ + char tempString[100]; + int port; + for(int i = 0; hostNameTokens[i] != 0; i++) { + if (sscanf(buf, hostNameTokens[i], tempString, &port) == 2) { + MgmtSrvrId* mgmtSrvrId = new MgmtSrvrId(); + mgmtSrvrId->type = MgmId_TCP; + mgmtSrvrId->data.tcp.remoteHost = strdup(tempString); + mgmtSrvrId->data.tcp.port = port; + add(mgmtSrvrId); + return true; + } + } + return false; +} + +bool +LocalConfig::parseFileName(const char * buf){ + char tempString[100]; + for(int i = 0; fileNameTokens[i] != 0; i++) { + if (sscanf(buf, fileNameTokens[i], tempString) == 1) { + MgmtSrvrId* mgmtSrvrId = new MgmtSrvrId(); + mgmtSrvrId->type = MgmId_File; + mgmtSrvrId->data.file.filename = strdup(tempString); + add(mgmtSrvrId); + return true; + } + } + return false; +} + +bool +LocalConfig::parseString(const char * connectString, bool onlyNodeId, char *line){ + bool return_value = true; + + char * for_strtok; + char * copy = strdup(connectString); + + bool b_nodeId = false; + bool found_other = false; + + for (char *tok = strtok_r(copy,";",&for_strtok); + tok != 0 && !(onlyNodeId && b_nodeId); + tok = strtok_r(NULL, ";", &for_strtok)) { + + if (tok[0] == '#') continue; + + if (!b_nodeId) // only one nodeid definition allowed + if (b_nodeId = parseNodeId(tok)) + continue; + if (onlyNodeId) + continue; + if (found_other = parseHostName(tok)) + continue; + if (found_other = parseFileName(tok)) + continue; + + snprintf(line, 150, "Unexpected entry: \"%s\"", tok); + return_value = false; + break; + } + + if (return_value && !onlyNodeId && !found_other) { + return_value = false; + snprintf(line, 150, "Missing host/file name extry in \"%s\"", connectString); + } + + free(copy); + return return_value; +} + +bool LocalConfig::readFile(const char * filename, bool &fopenError, bool onlyNodeId) +{ + char line[150], line2[150]; + + fopenError = false; + + FILE * file = fopen(filename, "r"); + if(file == 0){ + snprintf(line, 150, "Unable to open local config file: %s", filename); + setError(0, line); + fopenError = true; + return false; + } + + int sz = 1024; + char* theString = (char*)malloc(sz); + theString[0] = 0; + + fgets(theString, sz, file); + while (fgets(line+1, 100, file)) { + line[0] = ';'; + while (strlen(theString) + strlen(line) >= sz) { + sz = sz*2; + char *newString = (char*)malloc(sz); + strcpy(newString, theString); + free(theString); + theString = newString; + } + strcat(theString, line); + } + + bool return_value = parseString(theString, onlyNodeId, line); + + if (!return_value) { + snprintf(line2, 150, "Reading %s: %s", filename, line); + setError(0,line2); + } + + free(theString); + fclose(file); + return return_value; +} + +bool +LocalConfig::readConnectString(const char * connectString, bool onlyNodeId){ + char line[150], line2[150]; + bool return_value = parseString(connectString, onlyNodeId, line); + if (!return_value) { + snprintf(line2, 150, "Reading NDB_CONNECTSTRING \"%s\": %s", connectString, line); + setError(0,line2); + } + return return_value; +} diff --git a/ndb/src/common/mgmcommon/LocalConfig.hpp b/ndb/src/common/mgmcommon/LocalConfig.hpp new file mode 100644 index 00000000000..ec7b572e92d --- /dev/null +++ b/ndb/src/common/mgmcommon/LocalConfig.hpp @@ -0,0 +1,83 @@ +/* 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 */ + +#ifndef LocalConfig_H +#define LocalConfig_H + +#include <stdlib.h> +#include <string.h> +#include <NdbOut.hpp> +#include <NdbStdio.h> + +//**************************************************************************** +// Description: The class LocalConfig corresponds to the information possible +// to give in the local configuration file. +//***************************************************************************** + +enum MgmtSrvrId_Type { + MgmId_TCP = 0, + MgmId_File = 1 +}; + +struct MgmtSrvrId { + MgmtSrvrId_Type type; + union { + struct { + char * remoteHost; + unsigned int port; + } tcp; + struct { + char * filename; + } file; + } data; +}; + +struct LocalConfig { + + int _ownNodeId; + + int size; + int items; + MgmtSrvrId ** ids; + + int error_line; + char error_msg[256]; + + LocalConfig(); + ~LocalConfig(); + bool init(bool onlyNodeId = false, + const char *connectString = 0, + const char *fileName = 0, + const char *defaultConnectString = 0); + + void add(MgmtSrvrId *i); + + void printError() const; + void printUsage() const; + + void setError(int lineNumber, const char * _msg); + bool readConnectString(const char * connectString, bool onlyNodeId = false); + bool readFile(const char * filename, bool &fopenError, bool onlyNodeId = false); + bool parseLine(char * line, int lineNumber); + + bool parseNodeId(const char *buf); + bool parseHostName(const char *buf); + bool parseFileName(const char *buf); + bool parseString(const char *buf, bool onlyNodeId, char *line); +}; + +#endif // LocalConfig_H + diff --git a/ndb/src/common/mgmcommon/Makefile b/ndb/src/common/mgmcommon/Makefile new file mode 100644 index 00000000000..2db7be01d60 --- /dev/null +++ b/ndb/src/common/mgmcommon/Makefile @@ -0,0 +1,26 @@ +include .defs.mk + +TYPE := ndbapi mgmapiclient + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := mgmsrvcommon + +DIRS := printConfig + +SOURCES = \ + LocalConfig.cpp \ + Config.cpp \ + ConfigInfo.cpp \ + ConfigRetriever.cpp \ + InitConfigFileParser.cpp \ + IPCConfig.cpp + +SOURCES.c = NdbConfig.c + +include $(NDB_TOP)/Epilogue.mk + + + + + + diff --git a/ndb/src/common/mgmcommon/NdbConfig.c b/ndb/src/common/mgmcommon/NdbConfig.c new file mode 100644 index 00000000000..b12d9fcfaf9 --- /dev/null +++ b/ndb/src/common/mgmcommon/NdbConfig.c @@ -0,0 +1,61 @@ +/* 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 <NdbConfig.h> +#include <NdbEnv.h> +#include <stdlib.h> +#include <string.h> + +const char* +NdbConfig_HomePath(char* buf, int buflen){ + const char* p; + p = NdbEnv_GetEnv("NDB_HOME", buf, buflen); + if (p == NULL){ + strlcpy(buf, "", buflen); + p = buf; + } else { + const int len = strlen(buf); + if(len != 0 && buf[len-1] != '/'){ + buf[len] = '/'; + buf[len+1] = 0; + } + } + return p; +} + +const char* +NdbConfig_NdbCfgName(char* buf, int buflen, int with_ndb_home){ + if (with_ndb_home) + NdbConfig_HomePath(buf, buflen); + else + buf[0] = 0; + strlcat(buf, "Ndb.cfg", buflen); + return buf; +} + +const char* +NdbConfig_ErrorFileName(char* buf, int buflen){ + NdbConfig_HomePath(buf, buflen); + strlcat(buf, "error.log", buflen); + return buf; +} + +const char* +NdbConfig_ClusterLogFileName(char* buf, int buflen){ + NdbConfig_HomePath(buf, buflen); + strlcat(buf, "cluster.log", buflen); + return buf; +} diff --git a/ndb/src/common/mgmcommon/printConfig/Makefile b/ndb/src/common/mgmcommon/printConfig/Makefile new file mode 100644 index 00000000000..9194316da87 --- /dev/null +++ b/ndb/src/common/mgmcommon/printConfig/Makefile @@ -0,0 +1,14 @@ +include .defs.mk + +TYPE := ndbapi mgmapiclient + +BIN_TARGET := printConfig +BIN_TARGET_ARCHIVES := general portlib + +CCFLAGS_LOC += -I.. + +SOURCES := printConfig.cpp + +SOURCES.c := ../ConfigRetriever.c ../NdbConfig.c ../LocalConfig.c + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/mgmcommon/printConfig/printConfig.cpp b/ndb/src/common/mgmcommon/printConfig/printConfig.cpp new file mode 100644 index 00000000000..7260a84ce7a --- /dev/null +++ b/ndb/src/common/mgmcommon/printConfig/printConfig.cpp @@ -0,0 +1,89 @@ +/* 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 <NdbMain.h> +#include <ConfigRetriever.hpp> +#include <Properties.hpp> +#include <stdlib.h> +#include <NdbOut.hpp> + +void usage(const char * prg){ + ndbout << "Usage " << prg + << " host <mgm host> <mgm port> <node id> [<ver id>]" << endl; + + char buf[255]; + for(unsigned i = 0; i<strlen(prg); i++) + buf[i] = ' '; + buf[strlen(prg)] = 0; + ndbout << " " << buf << " file <filename> <node id> [<ver id>]" + << endl; +} + +NDB_COMMAND(printConfig, + "printConfig", "printConfig", "Prints configuration", 16384){ + if(argc < 4){ + usage(argv[0]); + return 0; + } + if(strcmp("file", argv[1]) != 0 && strcmp("host", argv[1]) != 0){ + usage(argv[0]); + return 0; + } + + if(strcmp("host", argv[1]) == 0 && argc < 5){ + usage(argv[0]); + return 0; + } + + Properties * p = 0; + ConfigRetriever c; + + if(strcmp("host", argv[1]) == 0){ + int verId = 0; + if(argc > 5) + verId = atoi(argv[5]); + + ndbout << "Getting config from: " << argv[2] << ":" << atoi(argv[3]) + << " NodeId =" << atoi(argv[4]) + << " VersionId = " << verId << endl; + + p = c.getConfig(argv[2], + atoi(argv[3]), + atoi(argv[4]), + verId); + } else if (strcmp("file", argv[1]) == 0){ + int verId = 0; + if(argc > 4) + verId = atoi(argv[4]); + + ndbout << "Getting config from: " << argv[2] + << " NodeId =" << atoi(argv[3]) + << " VersionId = " << verId << endl; + + p = c.getConfig(argv[2], atoi(argv[3]), verId); + } + + if(p != 0){ + p->print(stdout); + } else { + ndbout << "Configuration not found: " << c.getErrorString() << endl; + } + + delete p; + + return 0; +} diff --git a/ndb/src/common/portlib/Makefile b/ndb/src/common/portlib/Makefile new file mode 100644 index 00000000000..a928fc1e6d7 --- /dev/null +++ b/ndb/src/common/portlib/Makefile @@ -0,0 +1,43 @@ +include .defs.mk + +DIRS := + +ifeq ($(NDB_OS), SOFTOSE) +DIRS += ose +endif + +ifeq ($(NDB_OS), OSE) +DIRS += ose +endif + +ifeq ($(NDB_OS), SIMCELLO) +DIRS += ose +endif + +ifeq ($(NDB_OS), LINUX) +DIRS += unix +endif + +ifeq ($(NDB_OS), MACOSX) +DIRS += unix +endif + +ifeq ($(NDB_OS), SOLARIS) +DIRS += unix +endif + +ifeq ($(NDB_OS), SOLARIS6) +DIRS += unix +endif + +ifeq ($(NDB_OS), HPUX) +DIRS += unix +endif + +ifeq ($(NDB_OS), WIN32) +DIRS += win32 +endif + + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/src/common/portlib/memtest/Makefile b/ndb/src/common/portlib/memtest/Makefile new file mode 100644 index 00000000000..716cdbdea82 --- /dev/null +++ b/ndb/src/common/portlib/memtest/Makefile @@ -0,0 +1,12 @@ +CC=gcc +LD=$(CC) +SOURCES=memtest.c +OUTPUT=memtest +all: + $(CC) $(SOURCES) -o $(OUTPUT) + +debug: + $(CC) -g $(SOURCES) -o $(OUTPUT) + +clean: rm -rf *.o + rm -rf core* diff --git a/ndb/src/common/portlib/memtest/memtest.c b/ndb/src/common/portlib/memtest/memtest.c new file mode 100644 index 00000000000..d23235b7aa2 --- /dev/null +++ b/ndb/src/common/portlib/memtest/memtest.c @@ -0,0 +1,245 @@ +/* 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 <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/mman.h> +long long getMilli(); +long long getMicro(); +void malloctest(int loopcount, int memsize, int touch); +void freetest(int loopcount, int memsize); +void mmaptest(int loopcount, int memsize, int touch); +void unmaptest(int loopcount, int memsize); + + +main(int argc, char ** argv) +{ + + int loopcount; + int memsize; + if(argc < 4) { + printf("Usage: memtest X loopcount memsize(MB)\n"); + printf("where X = \n"); + printf("1 : malloc test \n"); + printf("2 : mmap test \n"); + printf("3 : malloc test + touch pages\n"); + printf("4 : mmap test + touch pages\n"); + printf("5 : malloc/free test \n"); + printf("6 : mmap/munmap test \n"); + printf("loopcount - number of loops\n"); + printf("memsize - memory segment size to allocate in MB.\n"); + exit(1); + } + + + loopcount = atoi(argv[2]); + memsize = atoi(argv[3]); + switch(atoi(argv[1])) { + case 1: malloctest(loopcount, memsize , 0 ); + break; + case 2: mmaptest(loopcount, memsize,0); + break; + case 3: malloctest(loopcount, memsize,1); + break; + case 4: mmaptest(loopcount, memsize,1); + break; + case 5: freetest(loopcount, memsize); + break; + case 6: unmaptest(loopcount, memsize); + break; + default: + break; + } +} + +long long getMilli() { + struct timeval tick_time; + gettimeofday(&tick_time, 0); + + return + ((long long)tick_time.tv_sec) * ((long long)1000) + + ((long long)tick_time.tv_usec) / ((long long)1000); +} + +long long getMicro(){ + struct timeval tick_time; + int res = gettimeofday(&tick_time, 0); + + long long secs = tick_time.tv_sec; + long long micros = tick_time.tv_usec; + + micros = secs*1000000+micros; + return micros; +} + +void malloctest(int loopcount, int memsize, int touch) { + long long start=0; + int total=0; + int i=0, j=0; + int size=memsize*1024*1024; //bytes; + float mean; + char * ptr =0; + + printf("Staring malloctest "); + if(touch) + printf("with touch\n"); + else + printf("\n"); + + start=getMicro(); + + for(i=0; i<loopcount; i++){ + ptr=(char *)malloc((size_t)(size)); + if(ptr==0) { + printf("failed to malloc!\n"); + return; + } + if(touch) { + for(j=0; j<size; j=j+4096) + ptr[j]=1; + } + } + total=(int)(getMicro()-start); + + mean=(float)((float)total/(float)loopcount); + printf("Total time malloc %d bytes: %2.3f microsecs loopcount %d touch %d \n", + size, mean,loopcount, touch); +} + + +void mmaptest(int loopcount, int memsize, int touch) { + long long start=0; + int total=0; + int i=0, j=0; + char * ptr; + int size=memsize*1024*1024; //bytes; + float mean; + + printf("Staring mmaptest "); + if(touch) + printf("with touch \n"); + else + printf("\n"); + + start=getMicro(); + for(i=0; i<loopcount; i++){ + ptr = mmap(0, + size, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + 0, + 0); + if(ptr<0) { + printf("failed to mmap!\n"); + return; + } + + if(touch) { + for(j=0; j<size; j=j+4096) + ptr[j]=1; + } + } + total=(int)(getMicro()-start); + mean=(float)((float)total/(float)loopcount); + printf("Total time mmap %d bytes: %2.3f microsecs \n",size, mean); +} + + +void unmaptest(loopcount, memsize) +{ + long long start=0; + int total=0; + int i=0, j=0; + char * ptr; + int size=memsize*1024*1024; //bytes; + float mean; + + printf("Staring munmap test (loopcount = 1 no matter what you prev. set)\n"); + + loopcount = 1; + + + for(i=0; i<loopcount; i++){ + ptr =(char*) mmap(0, + size, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + 0, + 0); + if(ptr<0) { + printf("failed to mmap!\n"); + return; + } + + + for(j=0; j<size; j=j+1) + ptr[j]='1'; + start=getMicro(); + if(munmap(ptr, size)<0) { + printf("failed to munmap!\n"); + return; + } + + total=(int)(getMicro()-start); + /* + for(j=8192; j<size; j=j+4096) { + + *(ptr+j)='1'; + } + + for(j=0; j<4096; j=j+4096) { + *(ptr+j)='1'; + } + + */ + } + mean=(float)((float)total/(float)loopcount); + printf("Total time unmap %d bytes: %2.3f microsecs \n",size, mean); +} + +void freetest(int loopcount, int memsize) { + long long start=0; + int total=0; + int i=0, j=0; + int size=memsize*1024*1024; //bytes; + float mean; + char * ptr =0; + + loopcount = 1; + printf("Staring free test (loopcount = 1 no matter what you prev. set)\n"); + + + for(i=0; i<loopcount; i++){ + ptr=(char*)malloc((size_t)(size)); + if(ptr==0) { + printf("failed to malloc!\n"); + return; + } + for(j=0; j<size; j=j+4096) + ptr[j]='1'; + start=getMicro(); + free(ptr); + total=(int)(getMicro()-start); + } + + + mean=(float)((float)total/(float)loopcount); + printf("Total time free %d bytes: %2.3f microsecs loopcount %d \n", + size, mean,loopcount); +} diff --git a/ndb/src/common/portlib/memtest/munmaptest/Makefile b/ndb/src/common/portlib/memtest/munmaptest/Makefile new file mode 100644 index 00000000000..ea8c5238d1c --- /dev/null +++ b/ndb/src/common/portlib/memtest/munmaptest/Makefile @@ -0,0 +1,14 @@ +include .defs.mk + +TYPE := ndbapitest +BIN_TARGET := munmaptest + + +SOURCES = munmaptest.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/portlib/memtest/munmaptest/munmaptest.cpp b/ndb/src/common/portlib/memtest/munmaptest/munmaptest.cpp new file mode 100644 index 00000000000..9e396cd98ee --- /dev/null +++ b/ndb/src/common/portlib/memtest/munmaptest/munmaptest.cpp @@ -0,0 +1,251 @@ +/* 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 <NdbOut.hpp> +#include <NdbThread.h> +#include <NdbMutex.h> +#include <NdbCondition.h> +#include <NdbSleep.h> +#include <NdbTick.h> +#include <NdbEnv.h> +#include <NdbHost.h> +#include <NdbMain.h> +#include <getarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <sys/mman.h> + + +struct ThreadData +{ + char * mapAddr; + Uint32 mapSize; + Uint32 chunk; + Uint32 idx; + +}; + +long long getMilli(); +long long getMicro(); + + +void* mapSegment(void * arg); +void* unmapSegment(void * arg); + + +void* mapSegment(void * arg) { + + ThreadData * threadArgs; + long long start=0; + int total=0; + int id = *(int *)arg; + threadArgs = new ThreadData [1]; + Uint32 size=5*1024*1024; + struct NdbThread* unmapthread_var; + void *status = 0; + int run = 1; + int max=0, min =100000000, sum=0; + while(run < 1001) { + start=getMicro(); + char * ptr =(char*) mmap(0, + size, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + 0, + 0); + + total=(int)(getMicro()-start); + + ndbout << "T" << id << ": mmap took : " << total << " microsecs. " + << " Run: " << run ; + ndbout_c(" mapped @ %p \n", ptr); + + if(total>max) + max = total; + if(total<min) + min=total; + + sum+=total; + + if(ptr<0) { + ndbout << "failed to mmap!" << endl; + exit(1); + } + + + threadArgs[0].mapAddr = (char *)ptr; + threadArgs[0].mapSize = size; + threadArgs[0].chunk = 4096; + threadArgs[0].idx = 0; + + + for(Uint32 j=0; j<size; j=j+4096) + ptr[j]='1'; + + unmapthread_var = NdbThread_Create(unmapSegment, // Function + (void**)&threadArgs[0],// Arg + 32768, // Stacksize + (char*)"unmapthread", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread prio + + + if(NdbThread_WaitFor(unmapthread_var, &status) != 0) { + ndbout << "test failed - exitting " << endl; + exit(1); + } + run++; + } + + ndbout << "MAX: " << max << " MIN: " << min; + float mean = (float) ((float)sum/(float)run); + ndbout_c(" AVERAGE: %2.5f\n",mean); +} + + + +void* unmapSegment(void * arg) +{ + + char * freeAddr; + char * mapAddr; + ThreadData * threadData = (ThreadData*) arg; + int start=0; + int total=0; + Uint32 mapSize = threadData->mapSize; + Uint32 chunk = threadData->chunk; + mapAddr = threadData->mapAddr; + + + + freeAddr = mapAddr+mapSize-chunk; + NdbSleep_MilliSleep(100); + for(Uint32 i=0;i<mapSize; i = i+chunk) { + start=getMicro(); + if(munmap(freeAddr, chunk) < 0){ + ndbout << "munmap failed" << endl; + exit(1); + } + total=(int)(getMicro()-start); + freeAddr = freeAddr - chunk; + NdbSleep_MilliSleep(10); + ndbout << "unmap 4096 bytes : " << total << "microsecs" << endl; + } + return NULL; +} + + +static int trash; +static int segmentsize=1; + + +static struct getargs args[] = { + { "trash", 't', arg_integer, &trash, + "trash the memory before (1 to trash 0 to not trash)", "trash"}, + { "segment", 's', arg_integer, &segmentsize, + "segment size (in MB)", "segment"}, +}; + + +static const int num_args = sizeof(args) / sizeof(args[0]); + +NDB_MAIN(munmaptest) { + + const char *progname = "munmaptest"; + int optind = 0; + + if(getarg(args, num_args, argc, argv, &optind)) { + arg_printusage(args, num_args, progname, ""); + exit(1); + } + + int size; + char * ptr; + if(trash) { + for(int i=0; i<100; i++) { + size=1+(int) (10.0*rand()/(RAND_MAX+1.0)); + NdbSleep_MilliSleep(10); + ptr =(char*) mmap(0, + size*1024*1024, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + 0, + 0); + for(int i=0;i<(size*1024*1024); i=i+4096) { + *(ptr+i)='1'; + } + NdbSleep_MilliSleep(10); + + munmap(ptr,size); + + } + + + } + + int noThreads = 1; + struct NdbThread* mapthread_var; + int id[noThreads]; + void *status=0; + + ThreadData * threadArgs = new ThreadData[noThreads]; + + + + + for(int i=0; i < noThreads; i++) { + threadArgs[i].mapSize = segmentsize*1024*1024; + threadArgs[i].idx = i; + mapthread_var = NdbThread_Create(mapSegment, // Function + (void**)&threadArgs[i],// Arg + 32768, // Stacksize + (char*)"mapthread", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread prio + + } + + + if(NdbThread_WaitFor(mapthread_var, &status) != 0) { + ndbout << "test failed - exitting " << endl; + exit(1); + } + +} + +long long getMilli() { + struct timeval tick_time; + gettimeofday(&tick_time, 0); + + return + ((long long)tick_time.tv_sec) * ((long long)1000) + + ((long long)tick_time.tv_usec) / ((long long)1000); +} + +long long getMicro(){ + struct timeval tick_time; + int res = gettimeofday(&tick_time, 0); + + long long secs = tick_time.tv_sec; + long long micros = tick_time.tv_usec; + + micros = secs*1000000+micros; + return micros; +} diff --git a/ndb/src/common/portlib/mmstest/mmslist.cpp b/ndb/src/common/portlib/mmstest/mmslist.cpp new file mode 100644 index 00000000000..bd00211445c --- /dev/null +++ b/ndb/src/common/portlib/mmstest/mmslist.cpp @@ -0,0 +1,103 @@ +/* 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 <NdbOut.hpp> +#include <NdbMain.h> + +#include <ose.h> +#include <mms.sig> +#include <mms_err.h> +#include <string.h> +#include <stdio.h> +#include <NdbOut.hpp> + +/** + * NOTE: To use NdbMem from a OSE system ose_mms has to be defined + * as a "Required External Process"(see OSE Kernel User's Guide/R1.1(p. 148)), + * like this: + * EXT_PROC(ose_mms, ose_mms, 50000) + * This will create a global variable ose_mms_ that is used from here. + */ + +union SIGNAL +{ + SIGSELECT sigNo; + struct MmsListDomainRequest mmsListDomainRequest; + struct MmsListDomainReply mmsListDomainReply; +}; /* union SIGNAL */ + +extern PROCESS ose_mms_; + +struct ARegion +{ + unsigned long int address; + unsigned long int size; + char name[32]; + + U32 resident; /* Boolean, nonzero if resident. */ + U32 access; /* See values for AccessType (above) .*/ + U32 type; /* either RAM-mem (1) or Io-mem (2) */ + U32 cache; /* 0-copyback,1-writethrough, 2-CacheInhibit.*/ +}; + +NDB_COMMAND(mmslist, "mmslist", "mmslist", "LIst the MMS memory segments", 4096){ + if (argc == 1){ + + static SIGSELECT allocate_sig[] = {1,MMS_LIST_DOMAIN_REPLY}; + union SIGNAL *sig; + + /* Send request to list all segments and regions. */ + sig = alloc(sizeof(struct MmsListDomainRequest), + MMS_LIST_DOMAIN_REQUEST); + send(&sig, ose_mms_); + + while (true){ + sig = receive(allocate_sig); + if (sig != NIL){ + if (sig->mmsListDomainReply.status == MMS_SUCCESS){ + /* Print domain info */ + ndbout << "=================================" << endl; + ndbout << "domain: " << sig->mmsListDomainReply.domain << endl; + ndbout << "name : " << sig->mmsListDomainReply.name << endl; + ndbout << "used : " << sig->mmsListDomainReply.used << endl; + ndbout << "lock : " << sig->mmsListDomainReply.lock << endl; + ndbout << "numOfRegions:" << sig->mmsListDomainReply.numOfRegions << endl; + struct ARegion * tmp = (struct ARegion*)&sig->mmsListDomainReply.regions[0]; + for (int i = 0; i < sig->mmsListDomainReply.numOfRegions && i < 256; i++){ + ndbout << i << ": adress=" << tmp->address << + ", size=" << tmp->size << + ", name=" << tmp->name << + ", resident=" << tmp->resident << + ", access=" << tmp->access << + ", type=" << tmp->type << + ", cache=" << tmp->cache << endl; + tmp++; + } + + free_buf(&sig); + }else{ + free_buf(&sig); + break; + } + } + + } + + }else{ + ndbout << "Usage: mmslist" << endl; + } + return NULL; +} diff --git a/ndb/src/common/portlib/mmstest/mmstest.cpp b/ndb/src/common/portlib/mmstest/mmstest.cpp new file mode 100644 index 00000000000..6ebb5064aaf --- /dev/null +++ b/ndb/src/common/portlib/mmstest/mmstest.cpp @@ -0,0 +1,76 @@ +/* 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 <NdbOut.hpp> +#include "NdbThread.h" +#include <NdbMem.h> +#include <NdbMain.h> + +#include <stdlib.h> + +NDB_COMMAND(ndbmem, "ndbmem", "ndbmem", "Test the ndbmem functionality", 4096){ + + ndbout << "Starting test of NdbMem" << endl; + ndbout << "=======================" << endl; + + ndbout << "Creating NdbMem" << endl; + NdbMem_Create(); + + + ndbout << "NdbMem - test 1" << endl; + if (argc == 2){ + int size1 = atoi(argv[1]); + ndbout << "Allocate and test "<<size1<<" bytes of memory" << endl; + char* mem1 = (char*)NdbMem_Allocate(size1); + ndbout << "mem1 = " << hex << (int)mem1 << endl; + if (mem1 != NULL){ + char* p1; + + // Write to the memory allocated + p1 = mem1; + for(int i = 0; i < size1; i++){ + *p1 = (char)(i%256); + p1++; + } + + // Read from the memory and check value + char read1; + char* pread1; + pread1 = mem1; + for(int i = 0; i < size1; i++){ + read1 = *pread1; + //ndbout << i << "=" << read1 << endl; + if (read1 != (i%256)) + ndbout << "Byte " << i << " was not correct, read1=" << read1 << endl; + pread1++; + } + + ndbout << "Freeing NdbMem" << endl; + NdbMem_Free(mem1); + } + + ndbout << "Destroying NdbMem" << endl; + NdbMem_Destroy(); + }else{ + ndbout << "Usage: ndbmem <size(bytes)>"<< endl; + } + + return NULL; + +} + + + diff --git a/ndb/src/common/portlib/ose/Makefile b/ndb/src/common/portlib/ose/Makefile new file mode 100644 index 00000000000..4ef93b7824a --- /dev/null +++ b/ndb/src/common/portlib/ose/Makefile @@ -0,0 +1,31 @@ +include .defs.mk + +TYPE := + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := portlib + +SOURCES = NdbOut.cpp + +SOURCES.c = NdbCondition.c \ + NdbMutex.c \ + NdbSleep.c \ + NdbTick.c \ + NdbEnv.c \ + NdbThread.c \ + NdbHost.c \ + NdbTCP.c + +ifeq ($(NDB_OS), SOFTOSE) + SOURCES += NdbMem_SoftOse.cpp +else + SOURCES.c += NdbMem.c +endif + +include $(NDB_TOP)/Epilogue.mk + + + + + + diff --git a/ndb/src/common/portlib/ose/NdbCondition.c b/ndb/src/common/portlib/ose/NdbCondition.c new file mode 100644 index 00000000000..2ab6e49006b --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbCondition.c @@ -0,0 +1,244 @@ +/* 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 "NdbCondition.h" +#include <pthread.h> +#include <assert.h> +#include <sys/types.h> +#include <malloc.h> + +#include <NdbMutex.h> + +#include "NdbConditionOSE.h" +struct NdbCondition +{ + PROCESS condserv_pid; +}; + + +OS_PROCESS(ndbcond_serv){ + + union SIGNAL* sig; + union SIGNAL* sig2; + + static const SIGSELECT sel_signal[] = {2, NDBCOND_SIGNAL, NDBCOND_BROADCAST}; + static const SIGSELECT sel_cond[] = {2, NDBCOND_WAIT, NDBCOND_WAITTIMEOUT}; + + for(;;){ + /* Receive condition wait signal */ + sig = receive((SIGSELECT*)sel_cond); + if (sig != NIL){ + switch (sig->sigNo){ + + case NDBCOND_WAIT: + /* Wait for a SIGNAL or BROADCAST from anyone */ + sig2 = receive((SIGSELECT*)sel_signal); + if (sig2 != NIL){ + switch(sig2->sigNo){ + + case NDBCOND_SIGNAL: + ((struct NdbCondWait*)sig)->status = NDBCOND_SIGNALED; + /* Send signal back to the one waiting for this condition */ + send(&sig, sender(&sig)); + break; + case NDBCOND_BROADCAST: + /* Not handled yet */ + assert(1==0); + break; + default: + assert(1==0); + break; + } + free_buf(&sig2); + } + break; + + case NDBCOND_WAITTIMEOUT: + /* Wait for a SIGNAL or BROADCAST from anyone */ + sig2 = receive_w_tmo(((struct NdbCondWaitTimeout*)sig)->timeout, (SIGSELECT*)sel_signal); + if (sig2 != NIL){ + switch(sig2->sigNo){ + + case NDBCOND_SIGNAL: + ((struct NdbCondWaitTimeout*)sig)->status = NDBCOND_SIGNALED; + /* Send signal back to the one waiting for this condition */ + send(&sig, sender(&sig)); + break; + case NDBCOND_BROADCAST: + /* Not handled yet */ + assert(1==0); + break; + default: + assert(1==0); + break; + } + free_buf(&sig2); + }else{ + ((struct NdbCondWaitTimeout*)sig)->status = NDBCOND_TIMEOUT; + send(&sig, sender(&sig)); + } + break; + + default: + assert(1==0); + break; + + } + } + + } +} + + +struct NdbCondition* +NdbCondition_Create(void) +{ + struct NdbCondition* tmpCond; + + + tmpCond = (struct NdbCondition*)malloc(sizeof(struct NdbCondition)); + + if (tmpCond == NULL) + return NULL; + + /** + * Start this process with a quite high + * priority, we want it to be responsive + */ + tmpCond->condserv_pid = create_process(OS_PRI_PROC, /* Process type */ + "ndbcond_serv", /* Name */ + ndbcond_serv, /* Entry point */ + 2048, /* Stack size */ + 10, /* Priority */ + 0, /* Time slice */ + get_bid(current_process()), /* Block */ + NULL, /* Redir table */ + 0, + 0); + + start(tmpCond->condserv_pid); + + return tmpCond; +} + + +int +NdbCondition_Wait(struct NdbCondition* p_cond, + NdbMutex* p_mutex) +{ + static const SIGSELECT sel_cond[] = {1, NDBCOND_WAIT}; + union SIGNAL* sig; + int result; + if (p_cond == NULL || p_mutex == NULL) + return 0; + + sig = alloc(sizeof(struct NdbCondWait), NDBCOND_WAIT); + send(&sig, p_cond->condserv_pid); + + NdbMutex_Unlock(p_mutex); + + result = 1; + while(NIL == (sig = receive_from((OSTIME)-1, (SIGSELECT*)sel_cond, p_cond->condserv_pid))); + if (sig != NIL){ + if (sig->sigNo == NDBCOND_WAIT){ + /* Condition is signaled */ + result = 0; + }else{ + assert(1==0); + } + free_buf(&sig); + + } + NdbMutex_Lock(p_mutex); + + return result; +} + + +int +NdbCondition_WaitTimeout(struct NdbCondition* p_cond, + NdbMutex* p_mutex, + int msecs){ + static const SIGSELECT sel_cond[] = {1, NDBCOND_WAITTIMEOUT}; + union SIGNAL* sig; + int result; + if (p_cond == NULL || p_mutex == NULL) + return 0; + + sig = alloc(sizeof(struct NdbCondWaitTimeout), NDBCOND_WAITTIMEOUT); + ((struct NdbCondWaitTimeout*)sig)->timeout = msecs; + send(&sig, p_cond->condserv_pid); + + NdbMutex_Unlock(p_mutex); + + result = 1; + while(NIL == (sig = receive_from((OSTIME)-1, (SIGSELECT*)sel_cond, p_cond->condserv_pid))); + if (sig != NIL){ + if (sig->sigNo == NDBCOND_WAITTIMEOUT){ + /* Condition is signaled */ + result = 0; + }else{ + assert(1==0); + } + free_buf(&sig); + + } + + NdbMutex_Lock(p_mutex); + + return result; +} + + +int +NdbCondition_Signal(struct NdbCondition* p_cond){ + + union SIGNAL* sig; + if (p_cond == NULL) + return 1; + + sig = alloc(sizeof(struct NdbCondSignal), NDBCOND_SIGNAL); + send(&sig, p_cond->condserv_pid); + + return 0; +} + + +int NdbCondition_Broadcast(struct NdbCondition* p_cond) +{ + union SIGNAL* sig; + if (p_cond == NULL) + return 1; + + sig = alloc(sizeof(struct NdbCondBroadcast), NDBCOND_BROADCAST); + send(&sig, p_cond->condserv_pid); + + return 0; +} + + +int NdbCondition_Destroy(struct NdbCondition* p_cond) +{ + if (p_cond == NULL) + return 1; + + kill_proc(p_cond->condserv_pid); + free(p_cond); + + return 0; +} + diff --git a/ndb/src/common/portlib/ose/NdbConditionOSE.h b/ndb/src/common/portlib/ose/NdbConditionOSE.h new file mode 100644 index 00000000000..bd0306261cc --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbConditionOSE.h @@ -0,0 +1,103 @@ +/* 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 */ + +#ifndef NDB_CONDITIONOSE_H +#define NDB_CONDITIONOSE_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define NDBCOND_SIGBASE 4000 + +#define NDBCOND_WAIT (NDBCOND_SIGBASE + 1) /* !-SIGNO(struct NdbCondWait)-! */ +#define NDBCOND_WAITTIMEOUT (NDBCOND_SIGBASE + 2) /* !-SIGNO(struct NdbCondWaitTimeOut)-! */ +#define NDBCOND_SIGNAL (NDBCOND_SIGBASE + 3) /* !-SIGNO(struct NdbCondSignal)-! */ +#define NDBCOND_BROADCAST (NDBCOND_SIGBASE + 4) /* !-SIGNO(struct NdbCondBroadcast)-! */ + + +const char * +sigNo2String(SIGSELECT sigNo){ + switch(sigNo){ + case NDBCOND_WAIT: + return "NDBCOND_WAIT"; + break; + case NDBCOND_WAITTIMEOUT: + return "NDBCOND_WAITTIMEOUT"; + break; + case NDBCOND_SIGNAL: + return "NDBCOND_SIGNAL"; + break; + case NDBCOND_BROADCAST: + return "NDBCOND_BROADCAST"; + break; + } + return "UNKNOWN"; +} + +struct NdbCondWait +{ + SIGSELECT sigNo; + int status; +}; + +/** + * Signal received + */ +#define NDBCOND_SIGNALED 1 + +/** + * Timeout occured + */ +#define NDBCOND_TIMEOUT 2 + +struct NdbCondWaitTimeout +{ + SIGSELECT sigNo; + int timeout; + int status; + +}; + +struct NdbCondSignal +{ + SIGSELECT sigNo; +}; + +struct NdbCondBroadcast +{ + SIGSELECT sigNo; +}; + + +union SIGNAL +{ + SIGSELECT sigNo; + struct NdbCondWait condWait; + struct NdbCondWaitTimeout condWaitTimeout; + struct NdbCondSignal condSignal; + struct NdbCondBroadcast condBroadcast; +}; + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ndb/src/common/portlib/ose/NdbEnv.c b/ndb/src/common/portlib/ose/NdbEnv.c new file mode 100644 index 00000000000..e2ac4d879d2 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbEnv.c @@ -0,0 +1,55 @@ +/* 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 "NdbEnv.h" +#include <string.h> +#include <stdlib.h> + +const char* NdbEnv_GetEnv(const char* name, char * buf, int buflen) +{ + /** + * All environment variables are associated with a process + * it's important to read env from the correct process + * for now read from own process, own block and last the "ose_shell" process. + * + * TODO! What process should this be read from in the future? + * + */ + PROCESS proc_; + char* p = NULL; + /* Look in own process */ + p = get_env(current_process(), (char*)name); + if (p == NULL){ + /* Look in block process */ + p = get_env(get_bid(current_process()), (char*)name); + if (p == NULL){ + /* Look in ose_shell process */ + if (hunt("ose_shell", 0, &proc_, NULL)){ + p = get_env(proc_, (char*)name); + } + } + } + + if (p != NULL){ + strncpy(buf, p, buflen); + buf[buflen-1] = 0; + free_buf((union SIGNAL **)&p); + p = buf; + } + return p; +} + diff --git a/ndb/src/common/portlib/ose/NdbHost.c b/ndb/src/common/portlib/ose/NdbHost.c new file mode 100644 index 00000000000..f5e1e511c16 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbHost.c @@ -0,0 +1,55 @@ +/* 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 "NdbHost.h" +#include <unistd.h> + + +#include <inet.sig> +#include <string.h> + +union SIGNAL +{ + SIGSELECT sigNo; + struct InetIfUp inetIfUp; +}; + +int NdbHost_GetHostName(char* buf) +{ +#if 0 + extern PROCESS ose_inet_; + union SIGNAL *signal; + static const SIGSELECT select_if_up_reply[] = { 1, INET_IF_UP_REPLY }; + + signal = alloc(sizeof(struct InetIfUp), INET_IF_UP_REQUEST); + strcpy(signal->inetIfUp.ifName, "*"); + send((union SIGNAL **)&signal, ose_inet_); + signal = receive((SIGSELECT *)select_if_up_reply); + strcpy(buf, signal->inetIfUp.ifName); + free_buf(&signal); + return 0; +#else + return -1; +#endif +} + + +int NdbHost_GetProcessId(void) +{ + return current_process(); +} + diff --git a/ndb/src/common/portlib/ose/NdbMem.c b/ndb/src/common/portlib/ose/NdbMem.c new file mode 100644 index 00000000000..6d922e4c073 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbMem.c @@ -0,0 +1,183 @@ +/* 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 "NdbMem.h" + +#include <assert.h> + +#if defined NDB_OSE +#include <ose.h> +#include <mms.sig> +#include <mms_err.h> +#include <string.h> +#include <stdio.h> +#include <NdbOut.hpp> + +// Page size for mp750 is 4096 bytes. +#define PAGE_SIZE 4096 + +/** + * NOTE: To use NdbMem from a OSE system ose_mms has to be defined + * as a "Required External Process"(see OSE Kernel User's Guide/R1.1(p. 148)), + * like this in osemain.con: + * EXT_PROC(ose_mms, ose_mms, 50000) + * This will create a global variable ose_mms_ that is used from here. + */ + +union SIGNAL +{ + SIGSELECT sigNo; + struct MmsAllocateRegionRequest mmsAllocateRegionRequest; + struct MmsAllocateRegionReply mmsAllocateRegionReply; + struct MmsFreeRegionRequest mmsFreeRegionRequest; + struct MmsFreeRegionReply mmsFreeRegionReply; +}; /* union SIGNAL */ + +extern PROCESS ose_mms_; + +void NdbMem_Create(void) +{ + /* Do nothing */ + return; +} + +void NdbMem_Destroy(void) +{ + /* Do nothing */ + return; +} + +void* NdbMem_Allocate(size_t size) +{ + static SIGSELECT allocate_sig[] = {1,MMS_ALLOCATE_REGION_REPLY}; + union SIGNAL *sig; + U32 allocatedAdress; + + assert(size > 0); + + // Only allowed to allocate multiples of the page size. + if(size % PAGE_SIZE != 0) { + size += PAGE_SIZE - size%PAGE_SIZE; + } + + /* Allocate a new region in the callers memory segment. */ + sig = alloc(sizeof(struct MmsAllocateRegionRequest), + MMS_ALLOCATE_REGION_REQUEST); + /* -1: The callers domain is used */ + sig->mmsAllocateRegionRequest.domain = (MemoryDomain)-1; + sig->mmsAllocateRegionRequest.useAddr = False; + sig->mmsAllocateRegionRequest.size = size; + sig->mmsAllocateRegionRequest.access = SuperRW_UserRW; + sig->mmsAllocateRegionRequest.resident = False; + sig->mmsAllocateRegionRequest.memory = CodeData; + sig->mmsAllocateRegionRequest.cache = CopyBack; + strcpy(sig->mmsAllocateRegionRequest.name, "NDB_DATA"); + send(&sig, ose_mms_); + sig = receive(allocate_sig); + + if (sig->mmsAllocateRegionReply.status != MMS_SUCCESS){ + /* Memory allocation failed, make sure this function returns NULL */ + allocatedAdress = NULL; + } + else{ + allocatedAdress = sig->mmsAllocateRegionReply.address; + } + free_buf(&sig); + return (void*)allocatedAdress; +} + +void* NdbMem_AllocateAlign(size_t size, size_t alignment) +{ + return NdbMem_Allocate(size); +} + + +void NdbMem_Free(void* ptr) +{ + static SIGSELECT free_sig[] = {1,MMS_FREE_REGION_REPLY}; + union SIGNAL *sig; + + /* Free a region in the callers domain. */ + sig = alloc(sizeof(struct MmsFreeRegionRequest), + MMS_FREE_REGION_REQUEST); + sig->mmsFreeRegionRequest.address = (U32)ptr; + send(&sig, ose_mms_); + sig = receive(free_sig); + + if (sig->mmsFreeRegionReply.status != MMS_SUCCESS){ + ndbout_c("The MMS Region could not be deallocated.\r\n"); + error(sig->mmsFreeRegionReply.status); + }; + free_buf(&sig); +} + +int NdbMem_MemLockAll(){ + return -1; +} + +int NdbMem_MemUnlockAll(){ + return -1; +} + +#else +#include <assert.h> +#include <stdlib.h> + + +void NdbMem_Create() +{ + /* Do nothing */ + return; +} + +void NdbMem_Destroy() +{ + /* Do nothing */ + return; +} + +void* NdbMem_Allocate(size_t size) +{ + assert(size > 0); + return (void*)malloc(size); +} + +void* NdbMem_AllocateAlign(size_t size, size_t alignment) +{ + /* + return (void*)memalign(alignment, size); + TEMP fix + */ + return (void*)malloc(size); +} + + +void NdbMem_Free(void* ptr) +{ + free(ptr); +} + + +int NdbMem_MemLockAll(){ + return -1; +} + +int NdbMem_MemUnlockAll(){ + return -1; +} + +#endif diff --git a/ndb/src/common/portlib/ose/NdbMem_SoftOse.cpp b/ndb/src/common/portlib/ose/NdbMem_SoftOse.cpp new file mode 100644 index 00000000000..cad22c0474b --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbMem_SoftOse.cpp @@ -0,0 +1,53 @@ +/* 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 "NdbMem.h" + +extern "C" +void NdbMem_Create() +{ +} +extern "C" +void NdbMem_Destroy() +{ +} + +extern "C" +void* NdbMem_Allocate(size_t size) +{ + return new char[size]; +} + +extern "C" +void* NdbMem_AllocateAlign(size_t size, size_t alignment) +{ + return NdbMem_Allocate(size); +} + +extern "C" +void NdbMem_Free(void* ptr) +{ + delete [] (char *)(ptr); +} + +int NdbMem_MemLockAll(){ + return -1; +} + +int NdbMem_MemUnlockAll(){ + return -1; +} + diff --git a/ndb/src/common/portlib/ose/NdbMutex.c b/ndb/src/common/portlib/ose/NdbMutex.c new file mode 100644 index 00000000000..859ddefd536 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbMutex.c @@ -0,0 +1,86 @@ +/* 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 "NdbMutex.h" + +#include <pthread.h> +#include <stdlib.h> +#include <assert.h> + + +NdbMutex* NdbMutex_Create(void) +{ + NdbMutex* pNdbMutex; + + pNdbMutex = create_sem(1); + + return pNdbMutex; +} + + +int NdbMutex_Destroy(NdbMutex* p_mutex) +{ + + if (p_mutex == NULL) + return -1; + + kill_sem(p_mutex); + + return 0; + +} + + +int NdbMutex_Lock(NdbMutex* p_mutex) +{ + if (p_mutex == NULL) + return -1; + + wait_sem(p_mutex); + + return 0; +} + + +int NdbMutex_Unlock(NdbMutex* p_mutex) +{ + + if (p_mutex == NULL) + return -1; + + signal_sem(p_mutex); + + return 0; +} + + +int NdbMutex_Trylock(NdbMutex* p_mutex) +{ + int result = -1; + + if (p_mutex != NULL) { + OSSEMVAL semvalue = get_sem(p_mutex); + if (semvalue > 0) { + wait_sem(p_mutex); + result = 0; + } + } + + return result; + +} + diff --git a/ndb/src/common/portlib/ose/NdbOut.cpp b/ndb/src/common/portlib/ose/NdbOut.cpp new file mode 100644 index 00000000000..0ee12249ff5 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbOut.cpp @@ -0,0 +1,99 @@ +/* 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 "NdbOut.hpp" +#include <NdbStdio.h> +#include <stdarg.h> +#include <NdbUnistd.h> +#include <string.h> + + +#if defined NDB_SOFTOSE +#include <dbgprintf.h> +#define printfunc dbgprintf +#else +#define printfunc printf +#endif + +static char const* const endlineString = "\r\n"; + +static int CtrlC = 0; +NdbOut ndbout; + + +NdbOut& NdbOut::operator<<(int aVal) +{ + char* format; + char HexFormat[] = "0x%08x"; + char DecFormat[] = "%d"; + if (isHexFormat == 1) + format = HexFormat; + else + format = DecFormat; + + printfunc(format, aVal); + return *this; +} + +NdbOut& NdbOut::operator<<(char* pVal) +{ + printfunc("%s", pVal); + return *this; +} + +NdbOut& NdbOut::endline() +{ + isHexFormat = 0; // Reset hex to normal, if user forgot this + printfunc(endlineString); + return *this; +} + +NdbOut& NdbOut::flushline() +{ + isHexFormat = 0; // Reset hex to normal, if user forgot this + return *this; +} + +NdbOut& NdbOut::setHexFormat(int _format) +{ + isHexFormat = _format; + return *this; +} + +NdbOut::NdbOut() +{ + CtrlC = 0; + isHexFormat = 0; +} + +NdbOut::~NdbOut() +{ +} + + + +extern "C" +void +ndbout_c(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf << endl; + va_end(ap); +} diff --git a/ndb/src/common/portlib/ose/NdbSleep.c b/ndb/src/common/portlib/ose/NdbSleep.c new file mode 100644 index 00000000000..70fd83117ef --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbSleep.c @@ -0,0 +1,36 @@ +/* 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 "NdbSleep.h" + +#include <ose.h> + + +int +NdbSleep_MilliSleep(int milliseconds){ + const OSTIME millisecond_delay = milliseconds; + delay(millisecond_delay); + return 0; +} + +int +NdbSleep_SecSleep(int seconds){ + const OSTIME millisecond_delay = seconds*1000; + delay(millisecond_delay); + return 0; +} + diff --git a/ndb/src/common/portlib/ose/NdbTCP.c b/ndb/src/common/portlib/ose/NdbTCP.c new file mode 100644 index 00000000000..9994697b3f8 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbTCP.c @@ -0,0 +1,38 @@ +/* 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 "NdbTCP.h" + + +int +Ndb_getInAddr(struct in_addr * dst, const char *address) { + struct hostent * host; + host = gethostbyname_r(address); + if(host != 0){ + dst->s_addr = ((struct in_addr *) *host->h_addr_list)->s_addr; + free_buf((union SIGNAL **)&host); + return 0; + } + /* Try it as aaa.bbb.ccc.ddd. */ + dst->s_addr = inet_addr(address); + if (dst->s_addr != INADDR_NONE) { + return 0; + } + return -1; +} + + diff --git a/ndb/src/common/portlib/ose/NdbThread.c b/ndb/src/common/portlib/ose/NdbThread.c new file mode 100644 index 00000000000..41a5f181c40 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbThread.c @@ -0,0 +1,184 @@ +/* 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 "NdbThread.h" +#include <pthread.h> +#include <malloc.h> +#include <assert.h> +#include <string.h> +#include <NdbOut.hpp> + +#define MAX_THREAD_NAME 16 + + +struct NdbThread +{ + PROCESS pid; + char thread_name[MAX_THREAD_NAME]; +}; + +#define NDBTHREAD_SIGBASE 4010 + +#define NDBTHREAD_START (NDBTHREAD_SIGBASE + 1) /* !-SIGNO(struct NdbThreadStart)-! */ + +struct NdbThreadStart +{ + SIGSELECT sigNo; + NDB_THREAD_FUNC* func; + NDB_THREAD_ARG arg; +}; + +struct NdbThreadStopped +{ + SIGSELECT sigNo; +}; + +union SIGNAL +{ + SIGSELECT sigNo; + struct NdbThreadStart threadStart; + struct NdbThreadStopped threadStopped; +}; + +OS_PROCESS(thread_starter){ + static const SIGSELECT sel_start[] = {1, NDBTHREAD_START}; + struct NdbThreadStart* sigstart; + union SIGNAL* sig; + + /* Receive function adress and params */ + sig = receive((SIGSELECT*)sel_start); + if (sig != NIL){ + if (sig->sigNo == NDBTHREAD_START){ + sigstart = ((struct NdbThreadStart*)sig); + /* Execute function with arg */ + (*sigstart->func)(sigstart->arg); + }else{ + assert(1==0); + } + free_buf(&sig); + } +} + +struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC* p_thread_func, + NDB_THREAD_ARG *p_thread_arg, + const NDB_THREAD_STACKSIZE thread_stack_size, + const char* p_thread_name, + NDB_THREAD_PRIO thread_prio) +{ + struct NdbThread* tmpThread; + union SIGNAL* sig; + int ose_prio; + + if (p_thread_func == NULL) + return 0; + + tmpThread = (struct NdbThread*)malloc(sizeof(struct NdbThread)); + if (tmpThread == NULL) + return NULL; + + strncpy((char*)&tmpThread->thread_name, p_thread_name, MAX_THREAD_NAME); + + switch(thread_prio){ + case NDB_THREAD_PRIO_HIGHEST: + ose_prio = 1; + break; + case NDB_THREAD_PRIO_HIGH: + ose_prio = 10; + break; + case NDB_THREAD_PRIO_MEAN: + ose_prio = 16; + break; + case NDB_THREAD_PRIO_LOW: + ose_prio = 23; + break; + case NDB_THREAD_PRIO_LOWEST: + ose_prio = 31; + break; + default: + return NULL; + break; + } + + /* Create process */ + tmpThread->pid = create_process(OS_PRI_PROC, /* Process type */ + (char*)p_thread_name, /* Name */ + thread_starter, /* Entry point */ + thread_stack_size, /* Stack size */ + ose_prio, /* Priority */ + 0, /* Time slice */ + get_bid(current_process()), /* Block */ + NULL, /* Redir table */ + 0, + 0); + + /* Send params to process */ + sig = alloc(sizeof(struct NdbThreadStart), NDBTHREAD_START); + ((struct NdbThreadStart*)sig)->func = p_thread_func; + ((struct NdbThreadStart*)sig)->arg = p_thread_arg; + send(&sig, tmpThread->pid); + + /* Enable NDB_HOME environment variable for the thread */ + { + /* Hardcoded NDB_HOME...*/ + char* ndb_home_env = get_env(current_process(), "NDB_HOME"); + if (ndb_home_env != NULL) + { + /* Set NDB_HOME */ + int rc = set_env(tmpThread->pid, "NDB_HOME", ndb_home_env); + if (rc != 0) + { + /* Not really a problem */ + } + } /* Enable NDB_HOME */ + } + + /* Start process */ + start(tmpThread->pid); + + return tmpThread; +} + + + +void NdbThread_Destroy(struct NdbThread** p_thread) +{ + free(* p_thread); * p_thread = 0; +} + + +int NdbThread_WaitFor(struct NdbThread* p_wait_thread, void** status) +{ + while(hunt(p_wait_thread->thread_name, 0, NULL, NULL) != 0) + delay(1000); + + * status = 0; + + return 0; +} + + +void NdbThread_Exit(int a) +{ + kill_proc(current_process()); +} + + +int NdbThread_SetConcurrencyLevel(int level) +{ + return 0; +} + diff --git a/ndb/src/common/portlib/ose/NdbTick.c b/ndb/src/common/portlib/ose/NdbTick.c new file mode 100644 index 00000000000..c3deae2bec3 --- /dev/null +++ b/ndb/src/common/portlib/ose/NdbTick.c @@ -0,0 +1,64 @@ +/* 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 "NdbTick.h" +#include <time.h> + +#define NANOSEC_PER_SEC 1000000000 +#define MICROSEC_PER_SEC 1000000 +#define MILLISEC_PER_SEC 1000 +#define MICROSEC_PER_MILLISEC 1000 +#define MILLISEC_PER_NANOSEC 1000000 + +#ifdef NDB_OSE +NDB_TICKS NdbTick_CurrentMillisecond(void) +{ + return get_ticks()*4; +} +#include <rtc.h> +int +NdbTick_CurrentMicrosecond(NDB_TICKS * secs, Uint32 * micros){ + struct TimePair tvp; + rtc_get_time(&tvp); + * secs = tvp.seconds; + * micros = tvp.micros; + return 0; +} + +#endif + +#if defined NDB_SOFTOSE +NDB_TICKS NdbTick_CurrentMillisecond(void) +{ + /** + * Depends on the interval counter in solaris + * that means each "tick" in OSE is really 10 milliseconds + */ + return get_ticks()*10; +} + +#include <rtc.h> +int +NdbTick_CurrentMicrosecond(NDB_TICKS * secs, Uint32 * micros){ + struct TimePair tvp; + rtc_get_time(&tvp); + * secs = tvp.seconds; + * micros = tvp.micros; + return 0; +} +#endif + diff --git a/ndb/src/common/portlib/test/Makefile b/ndb/src/common/portlib/test/Makefile new file mode 100644 index 00000000000..4edc98ede75 --- /dev/null +++ b/ndb/src/common/portlib/test/Makefile @@ -0,0 +1,15 @@ +include .defs.mk + +TYPE := kernel + +BIN_TARGET := PortLibTest +BIN_TARGET_ARCHIVES := portlib general + +SOURCES = NdbPortLibTest.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/portlib/test/NdbPortLibTest.cpp b/ndb/src/common/portlib/test/NdbPortLibTest.cpp new file mode 100644 index 00000000000..8a5c8f4a878 --- /dev/null +++ b/ndb/src/common/portlib/test/NdbPortLibTest.cpp @@ -0,0 +1,621 @@ +/* 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 */ + +/** + * NdbPortLibTest.cpp + * Test the functionality of portlib + * TODO - Add tests for NdbMem + */ + + + +#include "NdbOut.hpp" +#include "NdbThread.h" +#include "NdbMutex.h" +#include "NdbCondition.h" +#include "NdbSleep.h" +#include "NdbTick.h" +#include "NdbEnv.h" +#include "NdbHost.h" +#include "NdbMain.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +int TestHasFailed; +int verbose = 0; + +static void fail(const char* test, const char* cause) +{ + TestHasFailed = 1; + ndbout << test << " failed, " << cause << endl; +} + +// test 1 variables and funcs + +extern "C" void* thread1func(void* arg) +{ + int arg1; + int returnvalue = 8; + arg1 = *(int*)arg; + ndbout << "thread1: thread1func called with arg = " << arg1 << endl; + + // delay(1000); + if (arg1 != 7) + fail("TEST1", "Wrong arg"); + + NdbThread_Exit(returnvalue); + + return NULL; + +} + +// test 2 variables and funcs + +NdbMutex* test2mutex; + +extern "C" void* test2func(void* arg) +{ + + int arg1; + arg1 = *(int*)arg; + ndbout << "thread" << arg1 << " started in test2func" << endl; + + if (NdbMutex_Lock(test2mutex) != 0) + fail("TEST2", "Failed to lock mutex"); + + ndbout << "thread" << arg1 << ", test2func " << endl; + + if (NdbMutex_Unlock(test2mutex) != 0) + fail("TEST2", "Failed to unlock mutex"); + + int returnvalue = arg1; + NdbThread_Exit(returnvalue); + + return NULL; + +} + + +// test 3 and 7 variables and funcs + +NdbMutex* testmutex; +NdbCondition* testcond; +int testthreadsdone; + +extern "C" void* testfunc(void* arg) +{ + int tmpVar; + int threadno; + int result; + + threadno = *(int*)arg; + + ndbout << "Thread" << threadno << " started in testfunc" << endl; + do + { + + if ((threadno % 2) == 0) + result = NdbSleep_SecSleep(1); + else + result = NdbSleep_MilliSleep(100); + + if (result != 0) + fail("TEST3", "Wrong result from sleep function"); + + if (NdbMutex_Lock(testmutex) != 0) + fail("TEST3", "Wrong result from NdbMutex_Lock function"); + + ndbout << "thread" << threadno << ", testfunc " << endl; + testthreadsdone++; + tmpVar = testthreadsdone; + + if (NdbCondition_Signal(testcond) != 0) + fail("TEST3", "Wrong result from NdbCondition_Signal function"); + + if (NdbMutex_Unlock(testmutex) != 0) + fail("TEST3", "Wrong result from NdbMutex_Unlock function"); + + } + while(tmpVar<100); + + NdbThread_Exit(0); + return NULL; +} + +extern "C" void* testTryLockfunc(void* arg) +{ + int tmpVar = 0; + int threadno; + int result; + + threadno = *(int*)arg; + + ndbout << "Thread" << threadno << " started" << endl; + do + { + + if ((threadno % 2) == 0) + result = NdbSleep_SecSleep(1); + else + result = NdbSleep_MilliSleep(100); + + if (result != 0) + fail("TEST3", "Wrong result from sleep function"); + + if (NdbMutex_Trylock(testmutex) == 0){ + + ndbout << "thread" << threadno << ", testTryLockfunc locked" << endl; + testthreadsdone++; + tmpVar = testthreadsdone; + + if (NdbCondition_Signal(testcond) != 0) + fail("TEST3", "Wrong result from NdbCondition_Signal function"); + + if (NdbMutex_Unlock(testmutex) != 0) + fail("TEST3", "Wrong result from NdbMutex_Unlock function"); + } + + } + while(tmpVar<100); + + NdbThread_Exit(0); + return NULL; +} + + + +void testMicros(int count); +Uint64 time_diff(Uint64 s1, Uint64 s2, Uint32 m1, Uint32 m2); + +NDB_COMMAND(PortLibTest, "portlibtest", "portlibtest", "Test the portable function layer", 4096){ + + ndbout << "= TESTING ARGUMENT PASSING ============" << endl; + ndbout << "ARGC: " << argc << endl; + for(int i = 1; i < argc; i++){ + ndbout << " ARGV"<<i<<": " << (char*)argv[i] << endl; + } + ndbout << endl << endl; + + + struct NdbThread* thread1var; + void *status = 0; + int arg = 7; + + TestHasFailed = 0; + // create one thread and wait for it to return + ndbout << "= TEST1 ===============================" << endl; + + thread1var = NdbThread_Create(thread1func, // Function + (void**)&arg,// Arg + 2048, // Stacksize + (char*)"thread1", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread priority + + + if(NdbThread_WaitFor(thread1var, &status) != 0) + fail("TEST1", "NdbThread_WaitFor failed"); + // NOTE! thread return value is not yet used in Ndb and thus not tested(does not work) + //ndbout << "thread1 returned, status = " << status << endl; + //if (status != 8) + // fail("TEST1", "Wrong status"); + ndbout << "TEST1 completed" << endl; + + + NdbThread_Destroy(&thread1var); + + // Create 10 threads that will wait for a mutex before printing it's message to screen + ndbout << "= TEST2 ===============================" << endl; +#define T2_THREADS 10 + NdbThread* threads[T2_THREADS]; + int args[T2_THREADS]; + void *status2 = 0; + test2mutex = NdbMutex_Create(); + NdbMutex_Lock(test2mutex); + + for (int i = 0; i < T2_THREADS; i++) + { + args[i] = i; + threads[i] = NdbThread_Create(test2func, // Function + (void**)&args[i],// Arg + 2048, // Stacksize + (char*)"test2thread", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread priority + if (threads[i] == NULL) + fail("TEST2", "NdbThread_Create failed"); + } + + ndbout << "All threads created" << endl; + + NdbMutex_Unlock(test2mutex); + + for (int i = 0; i < T2_THREADS; i++) + { + if (NdbThread_WaitFor(threads[i], &status2)) + fail("TEST2", "NdbThread_WaitFor failed"); + + NdbThread_Destroy(&threads[i]); + // Don't test return values + // ndbout << "thread" << i << " returned, status = " << status2 << endl; + // if (status2 != i) + // fail("TEST2", "Wrong status"); + } + + if (NdbMutex_Lock(test2mutex) != 0) + fail("TEST2", "NdbMutex_Lock failed"); + if (NdbMutex_Unlock(test2mutex) != 0) + fail("TEST2", "NdbMutex_Unlock failed"); + if (NdbMutex_Destroy(test2mutex) != 0) + fail("TEST2", "NdbMutex_Destroy failed"); + ndbout << "TEST2 completed" << endl; + + ndbout << "= TEST3 ===============================" << endl; + // Create 10 threads that will by synchronised by a condition + // When they are awakened and have the mutex they will increment a global variable +#define T3_THREADS 10 + NdbThread* t3threads[T3_THREADS]; + int t3args[T3_THREADS]; + void *status3 = 0; + + testmutex = NdbMutex_Create(); + testcond = NdbCondition_Create(); + testthreadsdone = 0; + + for (int i = 0; i < T3_THREADS; i++) + { + t3args[i] = i; + t3threads[i] = NdbThread_Create(testfunc, // Function + (void**)&t3args[i],// Arg + 2048, // Stacksize + (char*)"test3thread", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread priority + } + + ndbout << "All threads created" << endl; + + if (NdbMutex_Lock(testmutex) != 0) + fail("TEST3", "NdbMutex_Lock failed"); + + while (testthreadsdone < T3_THREADS*10) + { + if(NdbCondition_Wait(testcond, testmutex) != 0) + fail("TEST3", "NdbCondition_Wait failed"); + ndbout << "Condition signaled, there are " << testthreadsdone << " completed threads" << endl; + } + if (NdbMutex_Unlock(testmutex) != 0) + fail("TEST3", "NdbMutex_Unlock failed"); + + for (int i = 0; i < T3_THREADS; i++) + { + if (NdbThread_WaitFor(t3threads[i], &status3) != 0) + fail("TEST3", "NdbThread_WaitFor failed"); + + NdbThread_Destroy(&t3threads[i]); + //ndbout << "thread" << i << " returned, status = " << status3 << endl; + //if (status3 != i) + // fail("TEST3", "Wrong status"); + } + + NdbMutex_Destroy(testmutex); + NdbCondition_Destroy(testcond); + ndbout << "TEST3 completed" << endl; + + ndbout << "= TEST4 ===============================" << endl; + // Check tick functions + + //#if 0 + + int sleeptimes[] = {78, 12, 199, 567, 899}; + + + for (int i = 0; i < 5; i++) + { + ndbout << "*------------------------------- Measure" << i << endl; + + NDB_TICKS millisec_now; + NDB_TICKS millisec_now2; + + millisec_now = NdbTick_CurrentMillisecond(); + NdbSleep_MilliSleep(sleeptimes[i]); + millisec_now2 = NdbTick_CurrentMillisecond(); + + ndbout << " Time before sleep = " << millisec_now << endl; + ndbout << " Time after sleep = " << millisec_now2 << endl; + ndbout << " Tried to sleep "<<sleeptimes[i]<<" milliseconds." << endl; + ndbout << " Sleep time was " << millisec_now2 -millisec_now <<" milliseconds." << endl; + + } + + ndbout << "TEST4 completed" << endl; + + ndbout << "= TEST5 ===============================" << endl; + // Check NdbOut + + ndbout << "Testing hex and dec functions of NdbOut" << endl; + + for (int i = 0; i<= 0xFF; i++) + { + ndbout << i << "=" <<hex << i << "="<<dec << i << ", "; + } + + ndbout << endl<< "Testing that hex is reset to dec by endl" << endl; + ndbout << hex << 67 << endl; + ndbout << 67 << endl; + + ndbout << "TEST5 completed" << endl; + + + ndbout << "= TEST6 ===============================" << endl; + const char* theEnvHostNamePtr; + char buf[255]; + char theHostHostName[256]; + theEnvHostNamePtr = NdbEnv_GetEnv("HOSTNAME", buf, 255); + if(theEnvHostNamePtr == NULL) + fail("TEST6", "Could not get HOSTNAME from env"); + else{ + ndbout << "HOSTNAME from GetEnv" << theEnvHostNamePtr << endl; + + NdbHost_GetHostName(theHostHostName); + + ndbout << "HOSTNAME from GetHostName" <<theHostHostName << endl; + + if (strcmp(theEnvHostNamePtr, theHostHostName) != 0) + fail("TEST6", "NdbHost_GetHostName or NdbEnv_GetEnv failed"); + } + + ndbout << "= TEST7 ===============================" << endl; + + testmutex = NdbMutex_Create(); + testcond = NdbCondition_Create(); + testthreadsdone = 0; + + for (int i = 0; i < T3_THREADS; i++) + { + t3args[i] = i; + t3threads[i] = NdbThread_Create(testfunc, // Function + (void**)&t3args[i],// Arg + 2048, // Stacksize + (char*)"test7thread", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread priority + } + + ndbout << "All threads created" << endl; + + if (NdbMutex_Lock(testmutex) != 0) + fail("TEST7", "NdbMutex_Lock failed"); + + while (testthreadsdone < T3_THREADS*10) + { + // just testing the functionality without timing out, therefor 20 sec. + if(NdbCondition_WaitTimeout(testcond, testmutex, 20000) != 0) + fail("TEST7", "NdbCondition_WaitTimeout failed"); + ndbout << "Condition signaled, there are " << testthreadsdone << " completed threads" << endl; + } + if (NdbMutex_Unlock(testmutex) != 0) + fail("TEST7", "NdbMutex_Unlock failed"); + + for (int i = 0; i < T3_THREADS; i++) + { + if (NdbThread_WaitFor(t3threads[i], &status3) != 0) + fail("TEST7", "NdbThread_WaitFor failed"); + + NdbThread_Destroy(&t3threads[i]); + } + + NdbMutex_Destroy(testmutex); + NdbCondition_Destroy(testcond); + + ndbout << "TEST7 completed" << endl; + + + ndbout << "= TEST8 ===============================" << endl; + ndbout << " NdbCondition_WaitTimeout" << endl; + testmutex = NdbMutex_Create(); + testcond = NdbCondition_Create(); + + for (int i = 0; i < 5; i++) + { + ndbout << "*------------------------------- Measure" << i << endl; + + NDB_TICKS millisec_now; + NDB_TICKS millisec_now2; + + millisec_now = NdbTick_CurrentMillisecond(); + if (NdbCondition_WaitTimeout(testcond, testmutex, sleeptimes[i]) != 0) + fail("TEST8", "NdbCondition_WaitTimeout failed"); + millisec_now2 = NdbTick_CurrentMillisecond(); + + ndbout << " Time before WaitTimeout = " << millisec_now << endl; + ndbout << " Time after WaitTimeout = " << millisec_now2 << endl; + ndbout << " Tried to wait "<<sleeptimes[i]<<" milliseconds." << endl; + ndbout << " Wait time was " << millisec_now2 -millisec_now <<" milliseconds." << endl; + + } + + ndbout << "TEST8 completed" << endl; + + + ndbout << "= TEST9 ===============================" << endl; + ndbout << " NdbTick_CurrentXXXXXsecond compare" << endl; + + for (int i = 0; i < 5; i++) + { + ndbout << "*------------------------------- Measure" << i << endl; + + NDB_TICKS millisec_now; + NDB_TICKS millisec_now2; + Uint32 usec_now, usec_now2; + Uint64 msec_now, msec_now2; + + + millisec_now = NdbTick_CurrentMillisecond(); + NdbTick_CurrentMicrosecond( &msec_now, &usec_now); + + NdbSleep_MilliSleep(sleeptimes[i]); + + millisec_now2 = NdbTick_CurrentMillisecond(); + NdbTick_CurrentMicrosecond( &msec_now2, &usec_now2); + + Uint64 usecdiff = time_diff(msec_now,msec_now2,usec_now,usec_now2); + NDB_TICKS msecdiff = millisec_now2 -millisec_now; + + ndbout << " Slept "<<sleeptimes[i]<<" milliseconds." << endl; + ndbout << " Measured " << msecdiff <<" milliseconds with milli function ." << endl; + ndbout << " Measured " << usecdiff/1000 << "," << usecdiff%1000<<" milliseconds with micro function ." << endl; + } + + ndbout << "TEST9 completed" << endl; + + + const int iter = 20; + ndbout << "Testing microsecond timer - " << iter << " iterations" << endl; + testMicros(iter); + ndbout << "Testing microsecond timer - COMPLETED" << endl; + +#if defined NDB_OSE || defined NDB_SOFTOSE + ndbout << "system_tick() = " << system_tick() << " us per tick" << endl; +#endif + + + ndbout << "= TEST10 ===============================" << endl; + + testmutex = NdbMutex_Create(); + testcond = NdbCondition_Create(); + testthreadsdone = 0; + + for (int i = 0; i < T3_THREADS; i++) + { + t3args[i] = i; + t3threads[i] = NdbThread_Create(testTryLockfunc, // Function + (void**)&t3args[i],// Arg + 2048, // Stacksize + (char*)"test10thread", // Thread name + NDB_THREAD_PRIO_MEAN); // Thread priority + } + + ndbout << "All threads created" << endl; + + if (NdbMutex_Lock(testmutex) != 0) + fail("TEST10", "NdbMutex_Lock failed"); + + while (testthreadsdone < T3_THREADS*10) + { + if(NdbCondition_Wait(testcond, testmutex) != 0) + fail("TEST10", "NdbCondition_WaitTimeout failed"); + ndbout << "Condition signaled, there are " << testthreadsdone << " completed threads" << endl; + } + if (NdbMutex_Unlock(testmutex) != 0) + fail("TEST10", "NdbMutex_Unlock failed"); + + for (int i = 0; i < T3_THREADS; i++) + { + if (NdbThread_WaitFor(t3threads[i], &status3) != 0) + fail("TEST10", "NdbThread_WaitFor failed"); + + NdbThread_Destroy(&t3threads[i]); + } + + NdbMutex_Destroy(testmutex); + NdbCondition_Destroy(testcond); + + ndbout << "TEST10 completed" << endl; + + + // Check total status of test + + if (TestHasFailed == 1) + ndbout << endl << "TEST FAILED!" << endl; + else + ndbout << endl << "TEST PASSED!" << endl; + + return TestHasFailed; + +}; + +Uint64 time_diff(Uint64 s1, Uint64 s2, Uint32 m1, Uint32 m2){ + + Uint64 diff = 0; + diff += (s2 - s1) * 1000000; + if(m2 >= m1) + diff += (m2 - m1); + else { + diff += m2; + diff -= m1; + } + + // if(0) + // ndbout("(s1,m1) = (%d, %d) (s2,m2) = (%d, %d) -> diff = %d\n", + // (Uint32)s1,m1,(Uint32)s2,m2, (Uint32)diff); + + return diff; +}; + +void +testMicros(int count){ + Uint32 avg = 0; + Uint32 sum2 = 0; + + for(int i = 0; i<count; i++){ + Uint64 s1, s2; + Uint32 m1, m2; + if(NdbTick_CurrentMicrosecond(&s1, &m1) != 0){ + ndbout << "Failed to get current micro" << endl; + TestHasFailed = 1; + return; + } + Uint32 r = (rand() % 1000) + 1; + NdbSleep_MilliSleep(r); + if(NdbTick_CurrentMicrosecond(&s2, &m2) != 0){ + ndbout << "Failed to get current micro" << endl; + TestHasFailed = 1; + return; + } + Uint64 m = time_diff(s1,s2,m1,m2); + if(verbose) + ndbout << "Slept for " << r << " ms" + << " - Measured " << m << " us" << endl; + + if(m > (r*1000)){ + avg += (m - (r*1000)); + sum2 += (m - (r*1000)) * (m - (r*1000)); + } else { + avg += ((r*1000) - m); + sum2 += ((r*1000) - m) * ((r*1000) - m); + } +#if 0 + m /= 1000; + if(m > r && ((m - r) > 10)){ + ndbout << "Difference to big: " << (m - r) << " - Test failed" << endl; + TestHasFailed = 1; + } + if(m < r && ((r - m) > 10)){ + ndbout << "Difference to big: " << (r - m) << " - Test failed" << endl; + TestHasFailed = 1; + } +#endif + } + + Uint32 dev = (avg * avg - sum2) / count; dev /= count; + avg /= count; + + Uint32 t = 0; + while((t*t)<dev) t++; + ndbout << "NOTE - measure are compared to NdbSleep_MilliSleep(...)" << endl; + ndbout << "Average error = " << avg << " us" << endl; + ndbout << "Stddev error = " << t << " us" << endl; +} diff --git a/ndb/src/common/portlib/unix/Makefile b/ndb/src/common/portlib/unix/Makefile new file mode 100644 index 00000000000..452196d9f08 --- /dev/null +++ b/ndb/src/common/portlib/unix/Makefile @@ -0,0 +1,27 @@ +include .defs.mk + +TYPE := util + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := portlib + +SOURCES.c = NdbCondition.c \ + NdbMutex.c \ + NdbSleep.c \ + NdbTick.c \ + NdbEnv.c \ + NdbThread.c \ + NdbHost.c \ + NdbTCP.c \ + NdbDaemon.c + +ifeq ($(NDB_OS), SOFTOSE) + SOURCES += NdbMem_SoftOse.cpp +else + SOURCES.c += NdbMem.c +endif + +include $(NDB_TOP)/Epilogue.mk + +testNdbDaemon: NdbDaemon.c + $(CC) -o $@ NdbDaemon.c $(CCFLAGS) -DNDB_DAEMON_TEST -L$(NDB_TOP)/lib diff --git a/ndb/src/common/portlib/unix/NdbCondition.c b/ndb/src/common/portlib/unix/NdbCondition.c new file mode 100644 index 00000000000..35b80821052 --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbCondition.c @@ -0,0 +1,179 @@ +/* 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 <NdbCondition.h> +#include <pthread.h> +#include <assert.h> +#include <sys/types.h> +#if defined NDB_MACOSX +#include <stdlib.h> +#else +#include <malloc.h> +#endif + +#include <NdbMutex.h> + +struct NdbCondition +{ + pthread_cond_t cond; +}; + + + +struct NdbCondition* +NdbCondition_Create(void) +{ + struct NdbCondition* tmpCond; + int result; + + tmpCond = (struct NdbCondition*)malloc(sizeof(struct NdbCondition)); + + if (tmpCond == NULL) + return NULL; + + result = pthread_cond_init(&tmpCond->cond, NULL); + + assert(result==0); + return tmpCond; +} + + + +int +NdbCondition_Wait(struct NdbCondition* p_cond, + NdbMutex* p_mutex) +{ + int result; + + if (p_cond == NULL || p_mutex == NULL) + return 1; + + result = pthread_cond_wait(&p_cond->cond, p_mutex); + + return result; +} + +#if defined NDB_SOLARIS || defined NDB_HPUX +#include <time.h> +int +NdbCondition_WaitTimeout(struct NdbCondition* p_cond, + NdbMutex* p_mutex, + int msecs){ + int result; + struct timespec abstime; + int secs = 0; + + if (p_cond == NULL || p_mutex == NULL) + return 1; + + clock_gettime(CLOCK_REALTIME, &abstime); + + if(msecs >= 1000){ + secs = msecs / 1000; + msecs = msecs % 1000; + } + + abstime.tv_sec += secs; + abstime.tv_nsec += msecs * 1000000; + if (abstime.tv_nsec >= 1000000000) { + abstime.tv_sec += 1; + abstime.tv_nsec -= 1000000000; + } + + result = pthread_cond_timedwait(&p_cond->cond, p_mutex, &abstime); + + return result; +} +#endif + +#if defined NDB_LINUX || defined NDB_MACOSX +#include <unistd.h> +#include <sys/time.h> + +int +NdbCondition_WaitTimeout(struct NdbCondition* p_cond, + NdbMutex* p_mutex, + int msecs){ + int result; + struct timespec abstime; + struct timeval tick_time; + int secs = 0; + + if (p_cond == NULL || p_mutex == NULL) + return 1; + + gettimeofday(&tick_time, 0); + + if(msecs >= 1000){ + secs = msecs / 1000; + msecs = msecs % 1000; + } + + + abstime.tv_sec = tick_time.tv_sec + secs; + abstime.tv_nsec = tick_time.tv_usec * 1000 + msecs * 1000000; + if (abstime.tv_nsec >= 1000000000) { + abstime.tv_sec += 1; + abstime.tv_nsec -= 1000000000; + } + + result = pthread_cond_timedwait(&p_cond->cond, p_mutex, &abstime); + + return result; +} +#endif + + +int +NdbCondition_Signal(struct NdbCondition* p_cond){ + int result; + + if (p_cond == NULL) + return 1; + + result = pthread_cond_signal(&p_cond->cond); + + return result; +} + + +int NdbCondition_Broadcast(struct NdbCondition* p_cond) +{ + int result; + + if (p_cond == NULL) + return 1; + + result = pthread_cond_broadcast(&p_cond->cond); + + return result; +} + + +int NdbCondition_Destroy(struct NdbCondition* p_cond) +{ + int result; + + if (p_cond == NULL) + return 1; + + result = pthread_cond_destroy(&p_cond->cond); + free(p_cond); + + return 0; +} + diff --git a/ndb/src/common/portlib/unix/NdbDaemon.c b/ndb/src/common/portlib/unix/NdbDaemon.c new file mode 100644 index 00000000000..fc114266c9d --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbDaemon.c @@ -0,0 +1,170 @@ +/* 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 "NdbDaemon.h" +#include <assert.h> + +#ifdef NDB_LINUX +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#endif + +#ifdef NDB_SOLARIS +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#endif + +#define NdbDaemon_ErrorSize 500 +#if defined(NDB_LINUX) || defined(NDB_SOLARIS) +long NdbDaemon_DaemonPid; +int NdbDaemon_ErrorCode; +char NdbDaemon_ErrorText[NdbDaemon_ErrorSize]; +#endif +int +NdbDaemon_Make(const char* lockfile, const char* logfile, unsigned flags) +{ + /* XXX fix other unixes */ +#if defined(NDB_LINUX) || defined(NDB_SOLARIS) + int lockfd = -1, logfd = -1, n; + char buf[64]; + + /* Check that we have write access to lock file */ + assert(lockfile != NULL); + lockfd = open(lockfile, O_CREAT|O_RDWR, 0644); + if (lockfd == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: open for write failed: %s", lockfile, strerror(errno)); + return -1; + } + /* Read any old pid from lock file */ + buf[0] = 0; + n = read(lockfd, buf, sizeof(buf)); + if (n < 0) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: read failed: %s", lockfile, strerror(errno)); + return -1; + } + NdbDaemon_DaemonPid = atol(buf); + if (lseek(lockfd, 0, SEEK_SET) == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: lseek failed: %s", lockfile, strerror(errno)); + return -1; + } + /* Test for lock before becoming daemon */ + if (lockf(lockfd, F_TEST, 0) == -1) { + if (errno == EACCES || errno == EAGAIN) { /* results may vary */ + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: already locked by pid=%ld", lockfile, NdbDaemon_DaemonPid); + return -1; + } + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: lock test failed: %s", lockfile, strerror(errno)); + return -1; + } + /* Test open log file before becoming daemon */ + if (logfile != NULL) { + logfd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0644); + if (logfd == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: open for write failed: %s", logfile, strerror(errno)); + return -1; + } + } + /* Fork */ + n = fork(); + if (n == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "fork failed: %s", strerror(errno)); + return -1; + } + /* Exit if we are the parent */ + if (n != 0) { + exit(0); + } + /* Running in child process */ + NdbDaemon_DaemonPid = getpid(); + /* Lock the lock file (likely to succeed due to test above) */ + if (lockf(lockfd, F_LOCK, 0) == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: lock failed: %s", lockfile, strerror(errno)); + return -1; + } + /* Become process group leader */ + if (setsid() == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "setsid failed: %s", strerror(errno)); + return -1; + } + /* Write pid to lock file */ + if (ftruncate(lockfd, 0) == -1) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: ftruncate failed: %s", lockfile, strerror(errno)); + return -1; + } + sprintf(buf, "%ld\n", NdbDaemon_DaemonPid); + n = strlen(buf); + if (write(lockfd, buf, n) != n) { + NdbDaemon_ErrorCode = errno; + snprintf(NdbDaemon_ErrorText, NdbDaemon_ErrorSize, + "%s: write failed: %s", lockfile, strerror(errno)); + return -1; + } + /* Do input/output redirections (assume fd 0,1,2 not in use) */ + close(0); + open("/dev/null", O_RDONLY); + if (logfile != 0) { + dup2(logfd, 1); + dup2(logfd, 2); + close(logfd); + } +#endif + /* Success */ + return 0; +} + +#ifdef NDB_DAEMON_TEST + +int +main() +{ + if (NdbDaemon_Make("test.pid", "test.log", 0) == -1) { + fprintf(stderr, "NdbDaemon_Make: %s\n", NdbDaemon_ErrorText); + return 1; + } + sleep(10); + return 0; +} + +#endif diff --git a/ndb/src/common/portlib/unix/NdbEnv.c b/ndb/src/common/portlib/unix/NdbEnv.c new file mode 100644 index 00000000000..b01e3b239ca --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbEnv.c @@ -0,0 +1,34 @@ +/* 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 "NdbEnv.h" +#include <string.h> +#include <stdlib.h> + +const char* NdbEnv_GetEnv(const char* name, char * buf, int buflen) +{ + char* p = NULL; + p = getenv(name); + + if (p != NULL && buf != NULL){ + strncpy(buf, p, buflen); + buf[buflen-1] = 0; + } + return p; + +} + diff --git a/ndb/src/common/portlib/unix/NdbHost.c b/ndb/src/common/portlib/unix/NdbHost.c new file mode 100644 index 00000000000..8d2a23fccda --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbHost.c @@ -0,0 +1,34 @@ +/* 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 "NdbHost.h" +#include <unistd.h> + +int NdbHost_GetHostName(char* buf) +{ + if (gethostname(buf, MAXHOSTNAMELEN) != 0) + { + return -1; + } + return 0; +} + +int NdbHost_GetProcessId(void) +{ + return getpid(); +} + diff --git a/ndb/src/common/portlib/unix/NdbMem.c b/ndb/src/common/portlib/unix/NdbMem.c new file mode 100644 index 00000000000..a18cf30cc8a --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbMem.c @@ -0,0 +1,76 @@ +/* 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 "NdbMem.h" + +#include <assert.h> +#include <assert.h> +#include <stdlib.h> +#ifndef NDB_MACOSX +#include <sys/mman.h> +#endif + +void NdbMem_Create() +{ + /* Do nothing */ + return; +} + +void NdbMem_Destroy() +{ + /* Do nothing */ + return; +} + +void* NdbMem_Allocate(size_t size) +{ + assert(size > 0); + return (void*)malloc(size); +} + +void* NdbMem_AllocateAlign(size_t size, size_t alignment) +{ + /* + return (void*)memalign(alignment, size); + TEMP fix + */ + return (void*)malloc(size); +} + + +void NdbMem_Free(void* ptr) +{ + free(ptr); +} + + +int NdbMem_MemLockAll(){ +#if defined NDB_MACOSX + return 0; +#else + return mlockall(MCL_CURRENT | MCL_FUTURE); +#endif +} + +int NdbMem_MemUnlockAll(){ +#if defined NDB_MACOSX + return 0; +#else + return munlockall(); +#endif +} + diff --git a/ndb/src/common/portlib/unix/NdbMutex.c b/ndb/src/common/portlib/unix/NdbMutex.c new file mode 100644 index 00000000000..3cadc0667e7 --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbMutex.c @@ -0,0 +1,93 @@ +/* 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 "NdbMutex.h" + +#include <pthread.h> +#include <stdlib.h> +#include <assert.h> + +NdbMutex* NdbMutex_Create(void) +{ + NdbMutex* pNdbMutex; + int result; + + pNdbMutex = (NdbMutex*)malloc(sizeof(NdbMutex)); + + if (pNdbMutex == NULL) + return NULL; + + result = pthread_mutex_init(pNdbMutex, NULL); + assert(result == 0); + + return pNdbMutex; + +} + + +int NdbMutex_Destroy(NdbMutex* p_mutex) +{ + int result; + + if (p_mutex == NULL) + return -1; + + result = pthread_mutex_destroy(p_mutex); + free(p_mutex); + + return result; + +} + + +int NdbMutex_Lock(NdbMutex* p_mutex) +{ + int result; + + if (p_mutex == NULL) + return -1; + + result = pthread_mutex_lock(p_mutex); + + return result; +} + + +int NdbMutex_Unlock(NdbMutex* p_mutex) +{ + int result; + + if (p_mutex == NULL) + return -1; + + result = pthread_mutex_unlock(p_mutex); + + return result; +} + + +int NdbMutex_Trylock(NdbMutex* p_mutex) +{ + int result = -1; + + if (p_mutex != NULL) { + result = pthread_mutex_trylock(p_mutex); + } + + return result; +} + diff --git a/ndb/src/common/portlib/unix/NdbSleep.c b/ndb/src/common/portlib/unix/NdbSleep.c new file mode 100644 index 00000000000..35132d7f9c7 --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbSleep.c @@ -0,0 +1,48 @@ +/* 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 "NdbSleep.h" + + +#ifdef NDB_SOLARIS +#include <sys/types.h> +#include <unistd.h> +#endif + +#if defined NDB_LINUX || defined NDB_HPUX || defined NDB_MACOSX +#include <time.h> +#include <unistd.h> +#endif + +int +NdbSleep_MilliSleep(int milliseconds){ + int result = 0; + struct timespec sleeptime; + sleeptime.tv_sec = milliseconds / 1000; + sleeptime.tv_nsec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000; + result = nanosleep(&sleeptime, NULL); + return result; +} + +int +NdbSleep_SecSleep(int seconds){ + int result = 0; + result = sleep(seconds); + return result; +} + + diff --git a/ndb/src/common/portlib/unix/NdbTCP.c b/ndb/src/common/portlib/unix/NdbTCP.c new file mode 100644 index 00000000000..c2613c211c5 --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbTCP.c @@ -0,0 +1,60 @@ +/* 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 "NdbTCP.h" + + +#ifdef NDB_SOLARIS +int +Ndb_getInAddr(struct in_addr * dst, const char *address) { + struct hostent host, * hostPtr; + char buf[1024]; + int h_errno; + hostPtr = gethostbyname_r(address, &host, &buf[0], 1024, &h_errno); + if (hostPtr != NULL) { + dst->s_addr = ((struct in_addr *) *hostPtr->h_addr_list)->s_addr; + return 0; + } + + /* Try it as aaa.bbb.ccc.ddd. */ + dst->s_addr = inet_addr(address); + if (dst->s_addr != -1) { + return 0; + } + return -1; +} +#endif + +#if defined NDB_LINUX || defined NDB_HPUX || defined NDB_MACOSX +int +Ndb_getInAddr(struct in_addr * dst, const char *address) { + struct hostent * hostPtr; + hostPtr = gethostbyname(address); + if (hostPtr != NULL) { + dst->s_addr = ((struct in_addr *) *hostPtr->h_addr_list)->s_addr; + return 0; + } + + /* Try it as aaa.bbb.ccc.ddd. */ + dst->s_addr = inet_addr(address); + if (dst->s_addr != -1) { + return 0; + } + return -1; +} +#endif + diff --git a/ndb/src/common/portlib/unix/NdbThread.c b/ndb/src/common/portlib/unix/NdbThread.c new file mode 100644 index 00000000000..3665c4c9159 --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbThread.c @@ -0,0 +1,119 @@ +/* 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 "NdbThread.h" +#include <pthread.h> +#ifdef NDB_MACOSX +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <assert.h> +#include <string.h> +#include <NdbStdio.h> + +#define MAX_THREAD_NAME 16 + + +struct NdbThread +{ + pthread_t thread; + char thread_name[MAX_THREAD_NAME]; +}; + + + +struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, + NDB_THREAD_ARG *p_thread_arg, + const NDB_THREAD_STACKSIZE thread_stack_size, + const char* p_thread_name, + NDB_THREAD_PRIO thread_prio) +{ + struct NdbThread* tmpThread; + int result; + pthread_attr_t thread_attr; + + if (p_thread_func == NULL) + return 0; + + tmpThread = (struct NdbThread*)malloc(sizeof(struct NdbThread)); + if (tmpThread == NULL) + return NULL; + + snprintf(tmpThread->thread_name, sizeof(tmpThread->thread_name), + "%s", p_thread_name); + + pthread_attr_init(&thread_attr); + pthread_attr_setstacksize(&thread_attr, thread_stack_size); +#if defined NDB_SOLARIS +#if !defined NDB_SOLARIS6 + /* Guard stack overflow with a 2k databuffer */ + pthread_attr_setguardsize(&thread_attr, 2048); +#endif +#endif + + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); + result = pthread_create(&tmpThread->thread, + &thread_attr, + p_thread_func, + p_thread_arg); + assert(result==0); + + pthread_attr_destroy(&thread_attr); + return tmpThread; +} + + +void NdbThread_Destroy(struct NdbThread** p_thread) +{ + if (*p_thread != NULL){ + free(* p_thread); + * p_thread = 0; + } +} + + +int NdbThread_WaitFor(struct NdbThread* p_wait_thread, void** status) +{ + int result; + + if (p_wait_thread == NULL) + return 0; + + if (p_wait_thread->thread == NULL) + return 0; + + result = pthread_join(p_wait_thread->thread, status); + + return result; +} + + +void NdbThread_Exit(int status) +{ + pthread_exit(&status); +} + + +int NdbThread_SetConcurrencyLevel(int level) +{ +#ifndef NDB_SOLARIS6 + return pthread_setconcurrency(level); +#else + return 0; +#endif +} diff --git a/ndb/src/common/portlib/unix/NdbTick.c b/ndb/src/common/portlib/unix/NdbTick.c new file mode 100644 index 00000000000..5adb4ec80c2 --- /dev/null +++ b/ndb/src/common/portlib/unix/NdbTick.c @@ -0,0 +1,110 @@ +/* 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 "NdbTick.h" +#include <time.h> + +#define NANOSEC_PER_SEC 1000000000 +#define MICROSEC_PER_SEC 1000000 +#define MILLISEC_PER_SEC 1000 +#define MICROSEC_PER_MILLISEC 1000 +#define MILLISEC_PER_NANOSEC 1000000 + + +#if defined NDB_SOLARIS || NDB_HPUX +NDB_TICKS NdbTick_CurrentMillisecond(void) +{ + struct timespec tick_time; + clock_gettime(CLOCK_REALTIME, &tick_time); + + return + ((NDB_TICKS)tick_time.tv_sec) * ((NDB_TICKS)MILLISEC_PER_SEC) + + ((NDB_TICKS)tick_time.tv_nsec) / ((NDB_TICKS)MILLISEC_PER_NANOSEC); +} + +int +NdbTick_CurrentMicrosecond(NDB_TICKS * secs, Uint32 * micros){ + struct timespec t; + int res = clock_gettime(CLOCK_REALTIME, &t); + * secs = t.tv_sec; + * micros = t.tv_nsec / 1000; + return res; +} +#endif + +#if defined NDB_LINUX || NDB_MACOSX +#include <unistd.h> +#include <sys/time.h> +NDB_TICKS NdbTick_CurrentMillisecond(void) +{ + struct timeval tick_time; + gettimeofday(&tick_time, 0); + + return + ((NDB_TICKS)tick_time.tv_sec) * ((NDB_TICKS)MILLISEC_PER_SEC) + + ((NDB_TICKS)tick_time.tv_usec) / ((NDB_TICKS)MICROSEC_PER_MILLISEC); +} + +int +NdbTick_CurrentMicrosecond(NDB_TICKS * secs, Uint32 * micros){ + struct timeval tick_time; + int res = gettimeofday(&tick_time, 0); + + if(secs==0) { + NDB_TICKS secs = tick_time.tv_sec; + *micros = tick_time.tv_usec; + *micros = secs*1000000+*micros; + } else { + * secs = tick_time.tv_sec; + * micros = tick_time.tv_usec; + } + return res; +} + +#endif +#ifdef TIME_MEASUREMENT +int +NdbTick_getMicroTimer(struct MicroSecondTimer* input_timer) +{ + NDB_TICKS secs; + Uint32 mics; + int ret_value; + ret_value = NdbTick_CurrentMicrosecond(&secs, &mics); + input_timer->seconds = secs; + input_timer->micro_seconds = (NDB_TICKS)mics; + return ret_value; +} + +NDB_TICKS +NdbTick_getMicrosPassed(struct MicroSecondTimer start, + struct MicroSecondTimer stop) +{ + NDB_TICKS ret_value = (NDB_TICKS)0; + if (start.seconds < stop.seconds) { + NDB_TICKS sec_passed = stop.seconds - start.seconds; + ret_value = ((NDB_TICKS)MICROSEC_PER_SEC) * sec_passed; + } else if (start.seconds > stop.seconds) { + return ret_value; + }//if + if (start.micro_seconds < stop.micro_seconds) { + ret_value += (stop.micro_seconds - start.micro_seconds); + } else if (ret_value != (NDB_TICKS)0) { + ret_value -= (start.micro_seconds - stop.micro_seconds); + }//if + return ret_value; +} +#endif diff --git a/ndb/src/common/portlib/win32/Makefile b/ndb/src/common/portlib/win32/Makefile new file mode 100644 index 00000000000..bb29ac5547e --- /dev/null +++ b/ndb/src/common/portlib/win32/Makefile @@ -0,0 +1,30 @@ +include .defs.mk + +TYPE := util + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := portlib + +SOURCES.c = NdbCondition.c \ + NdbMutex.c \ + NdbSleep.c \ + NdbTick.c \ + NdbEnv.c \ + NdbThread.c \ + NdbHost.c \ + NdbTCP.c \ + NdbDaemon.c + +ifeq ($(NDB_OS), SOFTOSE) + SOURCES += NdbMem_SoftOse.cpp +else + SOURCES.c += NdbMem.c +endif + +include $(NDB_TOP)/Epilogue.mk + + + + + + diff --git a/ndb/src/common/portlib/win32/NdbCondition.c b/ndb/src/common/portlib/win32/NdbCondition.c new file mode 100644 index 00000000000..12b508cf33b --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbCondition.c @@ -0,0 +1,184 @@ +/* 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 <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#include <assert.h> +#include <sys/types.h> + +#include "NdbCondition.h" +#include <NdbMutex.h> + + +struct NdbCondition +{ + long nWaiters; + NdbMutex* pNdbMutexWaitersLock; + HANDLE hSemaphore; + HANDLE hEventWaitersDone; + int bWasBroadcast; +}; + + +struct NdbCondition* +NdbCondition_Create(void) +{ + int result = 0; + struct NdbCondition* pNdbCondition = (struct NdbCondition*)malloc(sizeof(struct NdbCondition)); + if(!pNdbCondition) + return 0; + + pNdbCondition->nWaiters = 0; + pNdbCondition->bWasBroadcast = 0; + if(!(pNdbCondition->hSemaphore = CreateSemaphore(0, 0, MAXLONG, 0))) + result = -1; + else if(!(pNdbCondition->pNdbMutexWaitersLock = NdbMutex_Create())) + result = -1; + else if(!(pNdbCondition->hEventWaitersDone = CreateEvent(0, 0, 0, 0))) + result = -1; + + assert(!result); + return pNdbCondition; +} + + +int +NdbCondition_Wait(struct NdbCondition* p_cond, + NdbMutex* p_mutex) +{ + int result; + int bLastWaiter; + if(!p_cond || !p_mutex) + return 1; + + NdbMutex_Lock(p_cond->pNdbMutexWaitersLock); + p_cond->nWaiters++; + NdbMutex_Unlock(p_cond->pNdbMutexWaitersLock); + + if(NdbMutex_Unlock(p_mutex)) + return -1; + result = WaitForSingleObject (p_cond->hSemaphore, INFINITE); + + NdbMutex_Lock(p_cond->pNdbMutexWaitersLock); + p_cond->nWaiters--; + bLastWaiter = (p_cond->bWasBroadcast && p_cond->nWaiters==0); + NdbMutex_Unlock(p_cond->pNdbMutexWaitersLock); + + if(result==WAIT_OBJECT_0 && bLastWaiter) + SetEvent(p_cond->hEventWaitersDone); + + NdbMutex_Lock(p_mutex); + return result; +} + + +int +NdbCondition_WaitTimeout(struct NdbCondition* p_cond, + NdbMutex* p_mutex, + int msecs) +{ + int result; + int bLastWaiter; + if (!p_cond || !p_mutex) + return 1; + + NdbMutex_Lock(p_cond->pNdbMutexWaitersLock); + p_cond->nWaiters++; + NdbMutex_Unlock(p_cond->pNdbMutexWaitersLock); + if(msecs<0) + msecs = 0; + + if(NdbMutex_Unlock(p_mutex)) + return -1; + result = WaitForSingleObject(p_cond->hSemaphore, msecs); + + NdbMutex_Lock(p_cond->pNdbMutexWaitersLock); + p_cond->nWaiters--; + bLastWaiter = (p_cond->bWasBroadcast && p_cond->nWaiters==0); + NdbMutex_Unlock(p_cond->pNdbMutexWaitersLock); + + if(result!=WAIT_OBJECT_0) + result = -1; + + if(bLastWaiter) + SetEvent(p_cond->hEventWaitersDone); + + NdbMutex_Lock(p_mutex); + return result; +} + + +int +NdbCondition_Signal(struct NdbCondition* p_cond) +{ + int bHaveWaiters; + if(!p_cond) + return 1; + + NdbMutex_Lock(p_cond->pNdbMutexWaitersLock); + bHaveWaiters = (p_cond->nWaiters > 0); + NdbMutex_Unlock(p_cond->pNdbMutexWaitersLock); + + if(bHaveWaiters) + return (ReleaseSemaphore(p_cond->hSemaphore, 1, 0) ? 0 : -1); + else + return 0; +} + + +int NdbCondition_Broadcast(struct NdbCondition* p_cond) +{ + int bHaveWaiters; + int result = 0; + if(!p_cond) + return 1; + + NdbMutex_Lock(p_cond->pNdbMutexWaitersLock); + bHaveWaiters = 0; + if(p_cond->nWaiters > 0) + { + p_cond->bWasBroadcast = !0; + bHaveWaiters = 1; + } + NdbMutex_Unlock(p_cond->pNdbMutexWaitersLock); + if(bHaveWaiters) + { + if(!ReleaseSemaphore(p_cond->hSemaphore, p_cond->nWaiters, 0)) + result = -1; + else if(WaitForSingleObject (p_cond->hEventWaitersDone, INFINITE) != WAIT_OBJECT_0) + result = -1; + p_cond->bWasBroadcast = 0; + } + return result; +} + + +int NdbCondition_Destroy(struct NdbCondition* p_cond) +{ + int result; + if(!p_cond) + return 1; + + CloseHandle(p_cond->hEventWaitersDone); + NdbMutex_Destroy(p_cond->pNdbMutexWaitersLock); + result = (CloseHandle(p_cond->hSemaphore) ? 0 : -1); + + free(p_cond); + return 0; +} + diff --git a/ndb/src/common/portlib/win32/NdbDaemon.c b/ndb/src/common/portlib/win32/NdbDaemon.c new file mode 100644 index 00000000000..b96d4c20260 --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbDaemon.c @@ -0,0 +1,44 @@ +/* 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 "NdbDaemon.h" + +#define NdbDaemon_ErrorSize 500 +long NdbDaemon_DaemonPid; +int NdbDaemon_ErrorCode; +char NdbDaemon_ErrorText[NdbDaemon_ErrorSize]; + +int +NdbDaemon_Make(const char* lockfile, const char* logfile, unsigned flags) +{ + // XXX do something + return 0; +} + +#ifdef NDB_DAEMON_TEST + +int +main() +{ + if (NdbDaemon_Make("test.pid", "test.log", 0) == -1) { + fprintf(stderr, "NdbDaemon_Make: %s\n", NdbDaemon_ErrorText); + return 1; + } + sleep(10); + return 0; +} + +#endif diff --git a/ndb/src/common/portlib/win32/NdbEnv.c b/ndb/src/common/portlib/win32/NdbEnv.c new file mode 100644 index 00000000000..0df703a5e97 --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbEnv.c @@ -0,0 +1,33 @@ +/* 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 "NdbEnv.h" +#include <string.h> +#include <stdlib.h> + +const char* NdbEnv_GetEnv(const char* name, char * buf, int buflen) +{ + char* p = NULL; + p = getenv(name); + + if (p != NULL && buf != NULL){ + strncpy(buf, p, buflen); + buf[buflen-1] = 0; + } + return p; +} + diff --git a/ndb/src/common/portlib/win32/NdbHost.c b/ndb/src/common/portlib/win32/NdbHost.c new file mode 100644 index 00000000000..f91dd1a531c --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbHost.c @@ -0,0 +1,53 @@ +/* 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 "NdbHost.h" +#include <windows.h> +#include <process.h> + + +int NdbHost_GetHostName(char* buf) +{ + /* We must initialize TCP/IP if we want to call gethostname */ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + /** + * Tell the user that we couldn't find a usable + * WinSock DLL. + */ + return -1; + } + + /* Get host name */ + if(gethostname(buf, MAXHOSTNAMELEN)) + { + return -1; + } + return 0; +} + + +int NdbHost_GetProcessId(void) +{ + return _getpid(); +} + diff --git a/ndb/src/common/portlib/win32/NdbMem.c b/ndb/src/common/portlib/win32/NdbMem.c new file mode 100644 index 00000000000..274dc31353f --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbMem.c @@ -0,0 +1,237 @@ +/* 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 <windows.h> +#include <assert.h> +#include <NdbStdio.h> + +#include "NdbMem.h" + + +struct AWEINFO +{ + SIZE_T dwSizeInBytesRequested; + ULONG_PTR nNumberOfPagesRequested; + ULONG_PTR nNumberOfPagesActual; + ULONG_PTR nNumberOfPagesFreed; + ULONG_PTR* pnPhysicalMemoryPageArray; + void* pRegionReserved; +}; + +const size_t cNdbMem_nMaxAWEinfo = 256; +size_t gNdbMem_nAWEinfo = 0; + +struct AWEINFO* gNdbMem_pAWEinfo = 0; + + +void ShowLastError(const char* szContext, const char* szFunction) +{ + DWORD dwError = GetLastError(); + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR)&lpMsgBuf, + 0, + NULL + ); + printf("%s : %s failed : %lu : %s\n", szContext, szFunction, dwError, (char*)lpMsgBuf); + LocalFree(lpMsgBuf); +} + + + +void NdbMem_Create() +{ + // Address Windowing Extensions + struct PRIVINFO + { + DWORD Count; + LUID_AND_ATTRIBUTES Privilege[1]; + } Info; + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hToken; + if(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + ShowLastError("NdbMem_Create", "OpenProcessToken"); + } + + Info.Count = 1; + Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + if(!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &(Info.Privilege[0].Luid))) + { + ShowLastError("NdbMem_Create", "LookupPrivilegeValue"); + } + + if(!AdjustTokenPrivileges(hToken, FALSE, (PTOKEN_PRIVILEGES)&Info, 0, 0, 0)) + { + ShowLastError("NdbMem_Create", "AdjustTokenPrivileges"); + } + + if(!CloseHandle(hToken)) + { + ShowLastError("NdbMem_Create", "CloseHandle"); + } + + return; +} + +void NdbMem_Destroy() +{ + /* Do nothing */ + return; +} + +void* NdbMem_Allocate(size_t size) +{ + // Address Windowing Extensions + struct AWEINFO* pAWEinfo; + HANDLE hProcess; + SYSTEM_INFO sysinfo; + + if(!gNdbMem_pAWEinfo) + { + gNdbMem_pAWEinfo = VirtualAlloc(0, + sizeof(struct AWEINFO)*cNdbMem_nMaxAWEinfo, + MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + } + + assert(gNdbMem_nAWEinfo < cNdbMem_nMaxAWEinfo); + pAWEinfo = gNdbMem_pAWEinfo+gNdbMem_nAWEinfo++; + + hProcess = GetCurrentProcess(); + GetSystemInfo(&sysinfo); + pAWEinfo->nNumberOfPagesRequested = (size+sysinfo.dwPageSize-1)/sysinfo.dwPageSize; + pAWEinfo->pnPhysicalMemoryPageArray = VirtualAlloc(0, + sizeof(ULONG_PTR)*pAWEinfo->nNumberOfPagesRequested, + MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + pAWEinfo->nNumberOfPagesActual = pAWEinfo->nNumberOfPagesRequested; + if(!AllocateUserPhysicalPages(hProcess, &(pAWEinfo->nNumberOfPagesActual), pAWEinfo->pnPhysicalMemoryPageArray)) + { + ShowLastError("NdbMem_Allocate", "AllocateUserPhysicalPages"); + return 0; + } + if(pAWEinfo->nNumberOfPagesRequested != pAWEinfo->nNumberOfPagesActual) + { + ShowLastError("NdbMem_Allocate", "nNumberOfPagesRequested != nNumberOfPagesActual"); + return 0; + } + + pAWEinfo->dwSizeInBytesRequested = size; + pAWEinfo->pRegionReserved = VirtualAlloc(0, pAWEinfo->dwSizeInBytesRequested, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE); + if(!pAWEinfo->pRegionReserved) + { + ShowLastError("NdbMem_Allocate", "VirtualAlloc"); + return 0; + } + + if(!MapUserPhysicalPages(pAWEinfo->pRegionReserved, pAWEinfo->nNumberOfPagesActual, pAWEinfo->pnPhysicalMemoryPageArray)) + { + ShowLastError("NdbMem_Allocate", "MapUserPhysicalPages"); + return 0; + } + + /* + printf("allocate AWE memory: %lu bytes, %lu pages, address %lx\n", + pAWEinfo->dwSizeInBytesRequested, + pAWEinfo->nNumberOfPagesActual, + pAWEinfo->pRegionReserved); + */ + return pAWEinfo->pRegionReserved; +} + + +void* NdbMem_AllocateAlign(size_t size, size_t alignment) +{ + /* + return (void*)memalign(alignment, size); + TEMP fix + */ + return NdbMem_Allocate(size); +} + + +void NdbMem_Free(void* ptr) +{ + // VirtualFree(ptr, 0, MEM_DECOMMIT|MEM_RELEASE); + + // Address Windowing Extensions + struct AWEINFO* pAWEinfo = 0; + size_t i; + HANDLE hProcess; + + for(i=0; i<gNdbMem_nAWEinfo; ++i) + { + if(ptr==gNdbMem_pAWEinfo[i].pRegionReserved) + { + pAWEinfo = gNdbMem_pAWEinfo+i; + } + } + if(!pAWEinfo) + { + ShowLastError("NdbMem_Free", "ptr is not AWE memory"); + } + + hProcess = GetCurrentProcess(); + if(!MapUserPhysicalPages(ptr, pAWEinfo->nNumberOfPagesActual, 0)) + { + ShowLastError("NdbMem_Free", "MapUserPhysicalPages"); + } + + if(!VirtualFree(ptr, 0, MEM_RELEASE)) + { + ShowLastError("NdbMem_Free", "VirtualFree"); + } + + pAWEinfo->nNumberOfPagesFreed = pAWEinfo->nNumberOfPagesActual; + if(!FreeUserPhysicalPages(hProcess, &(pAWEinfo->nNumberOfPagesFreed), pAWEinfo->pnPhysicalMemoryPageArray)) + { + ShowLastError("NdbMem_Free", "FreeUserPhysicalPages"); + } + + VirtualFree(pAWEinfo->pnPhysicalMemoryPageArray, 0, MEM_DECOMMIT|MEM_RELEASE); +} + + +int NdbMem_MemLockAll() +{ + /* + HANDLE hProcess = GetCurrentProcess(); + SIZE_T nMinimumWorkingSetSize; + SIZE_T nMaximumWorkingSetSize; + GetProcessWorkingSetSize(hProcess, &nMinimumWorkingSetSize, &nMaximumWorkingSetSize); + ndbout << "nMinimumWorkingSetSize=" << nMinimumWorkingSetSize << ", nMaximumWorkingSetSize=" << nMaximumWorkingSetSize << endl; + + SetProcessWorkingSetSize(hProcess, 50000000, 100000000); + + GetProcessWorkingSetSize(hProcess, &nMinimumWorkingSetSize, &nMaximumWorkingSetSize); + ndbout << "nMinimumWorkingSetSize=" << nMinimumWorkingSetSize << ", nMaximumWorkingSetSize=" << nMaximumWorkingSetSize << endl; + */ + return -1; +} + +int NdbMem_MemUnlockAll() +{ + //VirtualUnlock(); + return -1; +} + diff --git a/ndb/src/common/portlib/win32/NdbMutex.c b/ndb/src/common/portlib/win32/NdbMutex.c new file mode 100644 index 00000000000..c93384d91db --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbMutex.c @@ -0,0 +1,78 @@ +/* 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 <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#include <time.h> +#include <assert.h> + +#include "NdbMutex.h" + + +NdbMutex* NdbMutex_Create(void) +{ + NdbMutex* pNdbMutex = (NdbMutex*)malloc(sizeof(NdbMutex)); + if(!pNdbMutex) + return 0; + + InitializeCriticalSection(pNdbMutex); + return pNdbMutex; +} + + +int NdbMutex_Destroy(NdbMutex* p_mutex) +{ + if(!p_mutex) + return -1; + + DeleteCriticalSection(p_mutex); + free(p_mutex); + return 0; +} + + +int NdbMutex_Lock(NdbMutex* p_mutex) +{ + if(!p_mutex) + return -1; + + EnterCriticalSection (p_mutex); + return 0; +} + + +int NdbMutex_Unlock(NdbMutex* p_mutex) +{ + if(!p_mutex) + return -1; + + LeaveCriticalSection(p_mutex); + return 0; +} + + +int NdbMutex_Trylock(NdbMutex* p_mutex) +{ + int result = -1; + if(p_mutex) + { + result = (TryEnterCriticalSection(p_mutex) ? 0 : -1); + } + return result; +} + diff --git a/ndb/src/common/portlib/win32/NdbSleep.c b/ndb/src/common/portlib/win32/NdbSleep.c new file mode 100644 index 00000000000..ac0f44dd07f --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbSleep.c @@ -0,0 +1,35 @@ +/* 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 "NdbSleep.h" + +#include <windows.h> + + +int +NdbSleep_MilliSleep(int milliseconds) +{ + Sleep(milliseconds); + return 0; +} + +int +NdbSleep_SecSleep(int seconds) +{ + return NdbSleep_MilliSleep(seconds*1000); +} + diff --git a/ndb/src/common/portlib/win32/NdbTCP.c b/ndb/src/common/portlib/win32/NdbTCP.c new file mode 100644 index 00000000000..483a53bd606 --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbTCP.c @@ -0,0 +1,39 @@ +/* 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 "NdbTCP.h" + +int +Ndb_getInAddr(struct in_addr * dst, const char *address) +{ + struct hostent * hostPtr; + + /* Try it as aaa.bbb.ccc.ddd. */ + dst->s_addr = inet_addr(address); + if (dst->s_addr != -1) { + return 0; + } + + hostPtr = gethostbyname(address); + if (hostPtr != NULL) { + dst->s_addr = ((struct in_addr *) *hostPtr->h_addr_list)->s_addr; + return 0; + } + + return -1; +} + diff --git a/ndb/src/common/portlib/win32/NdbThread.c b/ndb/src/common/portlib/win32/NdbThread.c new file mode 100644 index 00000000000..ae3c74be70d --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbThread.c @@ -0,0 +1,118 @@ +/* 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 <windows.h> +#include <process.h> +#include <assert.h> + +#include "NdbThread.h" + + +#define MAX_THREAD_NAME 16 + +typedef unsigned (WINAPI* NDB_WIN32_THREAD_FUNC)(void*); + + +struct NdbThread +{ + HANDLE hThread; + unsigned nThreadId; + char thread_name[MAX_THREAD_NAME]; +}; + + +struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, + NDB_THREAD_ARG *p_thread_arg, + const NDB_THREAD_STACKSIZE thread_stack_size, + const char* p_thread_name, + NDB_THREAD_PRIO thread_prio) +{ + struct NdbThread* tmpThread; + unsigned initflag; + int nPriority = 0; + + if(!p_thread_func) + return 0; + + tmpThread = (struct NdbThread*)malloc(sizeof(struct NdbThread)); + if(!tmpThread) + return 0; + + strncpy((char*)&tmpThread->thread_name, p_thread_name, MAX_THREAD_NAME); + + switch(thread_prio) + { + case NDB_THREAD_PRIO_HIGHEST: nPriority=THREAD_PRIORITY_HIGHEST; break; + case NDB_THREAD_PRIO_HIGH: nPriority=THREAD_PRIORITY_ABOVE_NORMAL; break; + case NDB_THREAD_PRIO_MEAN: nPriority=THREAD_PRIORITY_NORMAL; break; + case NDB_THREAD_PRIO_LOW: nPriority=THREAD_PRIORITY_BELOW_NORMAL; break; + case NDB_THREAD_PRIO_LOWEST: nPriority=THREAD_PRIORITY_LOWEST; break; + } + initflag = (nPriority ? CREATE_SUSPENDED : 0); + + tmpThread->hThread = (HANDLE)_beginthreadex(0, thread_stack_size, + (NDB_WIN32_THREAD_FUNC)p_thread_func, p_thread_arg, + initflag, &tmpThread->nThreadId); + + if(nPriority && tmpThread->hThread) + { + SetThreadPriority(tmpThread->hThread, nPriority); + ResumeThread (tmpThread->hThread); + } + + assert(tmpThread->hThread); + return tmpThread; +} + + +void NdbThread_Destroy(struct NdbThread** p_thread) +{ + CloseHandle((*p_thread)->hThread); + (*p_thread)->hThread = 0; + free(*p_thread); + *p_thread = 0; +} + + +int NdbThread_WaitFor(struct NdbThread* p_wait_thread, void** status) +{ + void *local_status = 0; + if (status == 0) + status = &local_status; + + if(WaitForSingleObject(p_wait_thread->hThread, INFINITE) == WAIT_OBJECT_0 + && GetExitCodeThread(p_wait_thread->hThread, (LPDWORD)status)) + { + CloseHandle(p_wait_thread->hThread); + p_wait_thread->hThread = 0; + return 0; + } + return -1; +} + + +void NdbThread_Exit(int status) +{ + _endthreadex((DWORD) status); +} + + +int NdbThread_SetConcurrencyLevel(int level) +{ + return 0; +} + diff --git a/ndb/src/common/portlib/win32/NdbTick.c b/ndb/src/common/portlib/win32/NdbTick.c new file mode 100644 index 00000000000..e3a67d8437d --- /dev/null +++ b/ndb/src/common/portlib/win32/NdbTick.c @@ -0,0 +1,64 @@ +/* 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 <windows.h> +#include "NdbTick.h" + +/* +#define FILETIME_PER_MICROSEC 10 +#define FILETIME_PER_MILLISEC 10000 +#define FILETIME_PER_SEC 10000000 + + +NDB_TICKS NdbTick_CurrentMillisecond(void) +{ + ULONGLONG ullTime; + GetSystemTimeAsFileTime((LPFILETIME)&ullTime); + return (ullTime / FILETIME_PER_MILLISEC); +} + +int +NdbTick_CurrentMicrosecond(NDB_TICKS * secs, Uint32 * micros) +{ + ULONGLONG ullTime; + GetSystemTimeAsFileTime((LPFILETIME)&ullTime); + *secs = (ullTime / FILETIME_PER_SEC); + *micros = (Uint32)((ullTime % FILETIME_PER_SEC) / FILETIME_PER_MICROSEC); + return 0; +} +*/ + + +NDB_TICKS NdbTick_CurrentMillisecond(void) +{ + LARGE_INTEGER liCount, liFreq; + QueryPerformanceCounter(&liCount); + QueryPerformanceFrequency(&liFreq); + return (liCount.QuadPart*1000) / liFreq.QuadPart; +} + +int +NdbTick_CurrentMicrosecond(NDB_TICKS * secs, Uint32 * micros) +{ + LARGE_INTEGER liCount, liFreq; + QueryPerformanceCounter(&liCount); + QueryPerformanceFrequency(&liFreq); + *secs = liCount.QuadPart / liFreq.QuadPart; + liCount.QuadPart -= *secs * liFreq.QuadPart; + *micros = (liCount.QuadPart*1000000) / liFreq.QuadPart; + return 0; +} diff --git a/ndb/src/common/transporter/Makefile b/ndb/src/common/transporter/Makefile new file mode 100644 index 00000000000..3bd23b627d3 --- /dev/null +++ b/ndb/src/common/transporter/Makefile @@ -0,0 +1,62 @@ +include .defs.mk + +TYPE := util + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := transporter +DIRS := basictest perftest + +# Source files of non-templated classes (.cpp files) +SOURCES = \ + Transporter.cpp \ + SendBuffer.cpp \ + SHM_Transporter.cpp \ + TCP_Transporter.cpp \ + TransporterRegistry.cpp \ + Packer.cpp + +DIRS := basictest perftest + +CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/kernel) \ + -I$(call fixpath,$(NDB_TOP)/include/transporter) + +ifeq ($(NDB_OS), WIN32) +SOURCES += SHM_Transporter.win32.cpp +endif + +ifeq ($(NDB_OS), SOLARIS) +SOURCES += SHM_Transporter.unix.cpp +endif + +ifeq ($(NDB_OS), HPUX) +SOURCES += SHM_Transporter.unix.cpp +endif + +ifeq ($(NDB_OS), MACOSX) +SOURCES += SHM_Transporter.unix.cpp +endif + +ifeq ($(NDB_OS), IBMAIX) +SOURCES += SHM_Transporter.unix.cpp +endif + +ifeq ($(NDB_OS), TRU64X) +SOURCES += SHM_Transporter.unix.cpp +endif + +ifeq ($(NDB_OS), LINUX) +SOURCES += SHM_Transporter.unix.cpp +ifeq ($(NDB_SCI), Y) +SOURCES += SCI_Transporter.cpp +endif +endif + + +ifneq ($(findstring OSE, $(NDB_OS)),) + SOURCES += OSE_Transporter.cpp + SOURCES += OSE_Receiver.cpp +endif + + + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/transporter/OSE_Receiver.cpp b/ndb/src/common/transporter/OSE_Receiver.cpp new file mode 100644 index 00000000000..558dee92d8d --- /dev/null +++ b/ndb/src/common/transporter/OSE_Receiver.cpp @@ -0,0 +1,360 @@ +/* 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 <NdbOut.hpp> +#include "OSE_Receiver.hpp" +#include "OSE_Transporter.hpp" +#include "TransporterCallback.hpp" +#include <TransporterRegistry.hpp> +#include "TransporterInternalDefinitions.hpp" +#include <NdbStdio.h> + +OSE_Receiver::OSE_Receiver(TransporterRegistry * tr, + int _recBufSize, + NodeId _localNodeId) { + theTransporterRegistry = tr; + + recBufSize = _recBufSize; + recBufReadIndex = 0; + recBufWriteIndex = 0; + receiveBuffer = new union SIGNAL * [recBufSize]; + + waitStackCount = 0; + waitStackSize = _recBufSize; + waitStack = new union SIGNAL * [waitStackSize]; + + nextSigId = new Uint32[MAX_NTRANSPORTERS]; + for (int i = 0; i < MAX_NTRANSPORTERS; i++) + nextSigId[i] = 0; + + phantomCreated = false; + localNodeId = _localNodeId; + snprintf(localHostName, sizeof(localHostName), + "ndb_node%d", localNodeId); + + DEBUG("localNodeId = " << localNodeId << " -> localHostName = " + << localHostName); +} + +OSE_Receiver::~OSE_Receiver(){ + while(recBufReadIndex != recBufWriteIndex){ + free_buf(&receiveBuffer[recBufReadIndex]); + recBufReadIndex = (recBufReadIndex + 1) % recBufSize; + } + delete [] receiveBuffer; + destroyPhantom(); +} + +PROCESS +OSE_Receiver::createPhantom(){ + redir.sig = 1; + redir.pid = current_process(); + + if(!phantomCreated){ + phantomPid = create_process + (OS_PHANTOM, // Type + localHostName, // Name + NULL, // Entry point + 0, // Stack size + 0, // Prio - Not used + (OSTIME)0, // Timeslice - Not used + 0, // Block - current block + &redir, + (OSVECTOR)0, // vector + (OSUSER)0); // user + phantomCreated = true; + DEBUG("Created phantom pid: " << hex << phantomPid); + } + return phantomPid; +} + +void +OSE_Receiver::destroyPhantom(){ + if(phantomCreated){ + DEBUG("Destroying phantom pid: " << hex << phantomPid); + kill_proc(phantomPid); + phantomCreated = false; + } +} + +static SIGSELECT PRIO_A_SIGNALS[] = { 6, + NDB_TRANSPORTER_PRIO_A, + NDB_TRANSPORTER_HUNT, + NDB_TRANSPORTER_CONNECT_REQ, + NDB_TRANSPORTER_CONNECT_REF, + NDB_TRANSPORTER_CONNECT_CONF, + NDB_TRANSPORTER_DISCONNECT_ORD +}; + +static SIGSELECT PRIO_B_SIGNALS[] = { 1, + NDB_TRANSPORTER_DATA +}; + +/** + * Check waitstack for signals that are next in sequence + * Put any found signal in receive buffer + * Returns true if one signal is found + */ +bool +OSE_Receiver::checkWaitStack(NodeId _nodeId){ + + for(int i = 0; i < waitStackCount; i++){ + if (waitStack[i]->dataSignal.senderNodeId == _nodeId && + waitStack[i]->dataSignal.sigId == nextSigId[_nodeId]){ + + ndbout_c("INFO: signal popped from waitStack, sigId = %d", + waitStack[i]->dataSignal.sigId); + + if(isFull()){ + ndbout_c("ERROR: receiveBuffer is full"); + reportError(callbackObj, _nodeId, TE_RECEIVE_BUFFER_FULL); + return false; + } + + // The next signal was found, put it in the receive buffer + insertReceiveBuffer(waitStack[i]); + + // Increase sequence id, set it to the next expected id + nextSigId[_nodeId]++; + + // Move signals below up one step + for(int j = i; j < waitStackCount-1; j++) + waitStack[j] = waitStack[j+1]; + waitStack[waitStackCount] = NULL; + waitStackCount--; + + // return true since signal was found + return true; + } + } + return false; +} + +/** + * Clear waitstack for signals from node with _nodeId + */ +void +OSE_Receiver::clearWaitStack(NodeId _nodeId){ + + for(int i = 0; i < waitStackCount; i++){ + if (waitStack[i]->dataSignal.senderNodeId == _nodeId){ + + // Free signal buffer + free_buf(&waitStack[i]); + + // Move signals below up one step + for(int j = i; j < waitStackCount-1; j++) + waitStack[j] = waitStack[j+1]; + waitStack[waitStackCount] = NULL; + waitStackCount--; + } + } + nextSigId[_nodeId] = 0; +} + + +inline +void +OSE_Receiver::insertWaitStack(union SIGNAL* _sig){ + if (waitStackCount <= waitStackSize){ + waitStack[waitStackCount] = _sig; + waitStackCount++; + } else { + ndbout_c("ERROR: waitStack is full"); + reportError(callbackObj, localNodeId, TE_WAIT_STACK_FULL); + } +} + +bool +OSE_Receiver::doReceive(Uint32 timeOutMillis) { + if(isFull()) + return false; + + union SIGNAL * sig = receive_w_tmo(0, + PRIO_A_SIGNALS); + if(sig == NIL){ + sig = receive_w_tmo(timeOutMillis, + PRIO_B_SIGNALS); + if(sig == NIL) + return false; + } + + DEBUG("Received signal: " << sig->sigNo << " " + << sigNo2String(sig->sigNo)); + + switch(sig->sigNo){ + case NDB_TRANSPORTER_PRIO_A: + { + OSE_Transporter * t = getTransporter(sig->dataSignal.senderNodeId); + if (t != 0 && t->isConnected()){ + insertReceiveBuffer(sig); + } else { + free_buf(&sig); + } + } + break; + case NDB_TRANSPORTER_DATA: + { + OSE_Transporter * t = getTransporter(sig->dataSignal.senderNodeId); + if (t != 0 && t->isConnected()){ + int nodeId = sig->dataSignal.senderNodeId; + Uint32 currSigId = sig->dataSignal.sigId; + + /** + * Check if signal is the next in sequence + * nextSigId is always set to the next sigId to wait for + */ + if (nextSigId[nodeId] == currSigId){ + + // Insert in receive buffer + insertReceiveBuffer(sig); + + // Increase sequence id, set it to the next expected id + nextSigId[nodeId]++; + + // Check if there are any signal in the wait stack + if (waitStackCount > 0){ + while(checkWaitStack(nodeId)); + } + } else { + // Signal was not received in correct order + // Check values and put it in the waitStack + ndbout_c("WARNING: sigId out of order," + " currSigId = %d, nextSigId = %d", + currSigId, nextSigId[nodeId]); + + if (currSigId < nextSigId[nodeId]){ + // Current recieved sigId was smaller than nextSigId + // There is no use to put it in the waitStack + ndbout_c("ERROR: recieved sigId was smaller than nextSigId"); + reportError(callbackObj, nodeId, TE_TOO_SMALL_SIGID); + return false; + } + + if (currSigId > (nextSigId[nodeId] + waitStackSize)){ + // Current sigId was larger than nextSigId + size of waitStack + // we can never "save" so many signal's on the stack + ndbout_c("ERROR: currSigId > (nextSigId + size of waitStack)"); + reportError(callbackObj, nodeId, TE_TOO_LARGE_SIGID); + return false; + } + + // Insert in wait stack + insertWaitStack(sig); + } + } else { + free_buf(&sig); + } + } + break; + case NDB_TRANSPORTER_HUNT: + { + NdbTransporterHunt * s = (NdbTransporterHunt*)sig; + OSE_Transporter * t = getTransporter(s->remoteNodeId); + if(t != 0) + t->huntReceived(s); + free_buf(&sig); + } + break; + case NDB_TRANSPORTER_CONNECT_REQ: + { + NdbTransporterConnectReq * s = (NdbTransporterConnectReq*)sig; + OSE_Transporter * t = getTransporter(s->senderNodeId); + if(t != 0){ + if(t->connectReq(s)){ + clearWaitStack(s->senderNodeId); + clearRecvBuffer(s->senderNodeId); + } + } + free_buf(&sig); + } + break; + case NDB_TRANSPORTER_CONNECT_REF: + { + NdbTransporterConnectRef * s = (NdbTransporterConnectRef*)sig; + OSE_Transporter * t = getTransporter(s->senderNodeId); + if(t != 0){ + if(t->connectRef(s)){ + clearWaitStack(s->senderNodeId); + clearRecvBuffer(s->senderNodeId); + } + } + free_buf(&sig); + } + break; + case NDB_TRANSPORTER_CONNECT_CONF: + { + NdbTransporterConnectConf * s = (NdbTransporterConnectConf*)sig; + OSE_Transporter * t = getTransporter(s->senderNodeId); + if(t != 0){ + if(t->connectConf(s)){ + clearWaitStack(s->senderNodeId); + clearRecvBuffer(s->senderNodeId); + } + } + free_buf(&sig); + } + break; + case NDB_TRANSPORTER_DISCONNECT_ORD: + { + NdbTransporterDisconnectOrd * s = (NdbTransporterDisconnectOrd*)sig; + OSE_Transporter * t = getTransporter(s->senderNodeId); + if(t != 0){ + if(t->disconnectOrd(s)){ + clearWaitStack(s->senderNodeId); + clearRecvBuffer(s->senderNodeId); + } + } + free_buf(&sig); + } + } + return true; +} + +OSE_Transporter * +OSE_Receiver::getTransporter(NodeId nodeId){ + if(theTransporterRegistry->theTransporterTypes[nodeId] != tt_OSE_TRANSPORTER) + return 0; + return (OSE_Transporter *) + theTransporterRegistry->theTransporters[nodeId]; +} + +void +OSE_Receiver::clearRecvBuffer(NodeId nodeId){ + int tmpIndex = 0; + union SIGNAL** tmp = new union SIGNAL * [recBufSize]; + + /** + * Put all signal that I want to keep into tmp + */ + while(recBufReadIndex != recBufWriteIndex){ + if(receiveBuffer[recBufReadIndex]->dataSignal.senderNodeId != nodeId){ + tmp[tmpIndex] = receiveBuffer[recBufReadIndex]; + tmpIndex++; + } else { + free_buf(&receiveBuffer[recBufReadIndex]); + } + recBufReadIndex = (recBufReadIndex + 1) % recBufSize; + } + + /** + * Put all signals that I kept back into receiveBuffer + */ + for(int i = 0; i<tmpIndex; i++) + insertReceiveBuffer(tmp[i]); + + delete [] tmp; +} diff --git a/ndb/src/common/transporter/OSE_Receiver.hpp b/ndb/src/common/transporter/OSE_Receiver.hpp new file mode 100644 index 00000000000..1812ab51065 --- /dev/null +++ b/ndb/src/common/transporter/OSE_Receiver.hpp @@ -0,0 +1,119 @@ +/* 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 */ + +#ifndef OSE_RECEIVER_HPP +#define OSE_RECEIVER_HPP + +#include "ose.h" +#include "OSE_Signals.hpp" +#include <kernel_types.h> + +class OSE_Receiver { +public: + OSE_Receiver(class TransporterRegistry *, + int recBufSize, + NodeId localNodeId); + + ~OSE_Receiver(); + + bool hasData() const ; + bool isFull() const ; + + Uint32 getReceiveData(NodeId * remoteNodeId, + Uint32 ** readPtr); + + void updateReceiveDataPtr(Uint32 szRead); + + bool doReceive(Uint32 timeOutMillis); + + PROCESS createPhantom(); + void destroyPhantom(); + +private: + class TransporterRegistry * theTransporterRegistry; + + NodeId localNodeId; + char localHostName[255]; + + bool phantomCreated; + PROCESS phantomPid; + struct OS_redir_entry redir; + + int recBufReadIndex; + int recBufWriteIndex; + int recBufSize; + union SIGNAL **receiveBuffer; + + // Stack for signals that are received out of order + int waitStackCount; + int waitStackSize; + union SIGNAL** waitStack; + + // Counters for the next signal id + Uint32* nextSigId; + + class OSE_Transporter * getTransporter(NodeId nodeId); + + void insertReceiveBuffer(union SIGNAL * _sig); + void clearRecvBuffer(NodeId _nodeId); + bool checkWaitStack(NodeId _nodeId); + void clearWaitStack(NodeId _nodeId); + void insertWaitStack(union SIGNAL* _sig); +}; + +inline +bool +OSE_Receiver::hasData () const { + return recBufReadIndex != recBufWriteIndex; +} + +inline +bool +OSE_Receiver::isFull () const { + return ((recBufWriteIndex + 1) % recBufSize) == recBufWriteIndex; +} + +inline +Uint32 +OSE_Receiver::getReceiveData(NodeId * remoteNodeId, + Uint32 ** readPtr){ + NdbTransporterData *s = (NdbTransporterData *)receiveBuffer[recBufReadIndex]; + if(recBufReadIndex != recBufWriteIndex){ + * remoteNodeId = s->senderNodeId; + * readPtr = &s->data[0]; + return s->length; + } + return 0; +} + +inline +void +OSE_Receiver::updateReceiveDataPtr(Uint32 bytesRead){ + if(bytesRead != 0){ + free_buf(&receiveBuffer[recBufReadIndex]); + recBufReadIndex = (recBufReadIndex + 1) % recBufSize; + } +} + +inline +void +OSE_Receiver::insertReceiveBuffer(union SIGNAL * _sig){ + receiveBuffer[recBufWriteIndex] = _sig; + recBufWriteIndex = (recBufWriteIndex + 1) % recBufSize; +} + + +#endif diff --git a/ndb/src/common/transporter/OSE_Signals.hpp b/ndb/src/common/transporter/OSE_Signals.hpp new file mode 100644 index 00000000000..3f6cc07b473 --- /dev/null +++ b/ndb/src/common/transporter/OSE_Signals.hpp @@ -0,0 +1,144 @@ +/* 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 */ + +#ifndef OSE_SIGNALS_HPP +#define OSE_SIGNALS_HPP + +#include <ose.h> +#include <kernel_types.h> + +#define NDB_TRANSPORTER_SIGBASE 3000 + +#define NDB_TRANSPORTER_DATA (NDB_TRANSPORTER_SIGBASE + 1) /* !-SIGNO(struct NdbTransporterData)-! */ +#define NDB_TRANSPORTER_HUNT (NDB_TRANSPORTER_SIGBASE + 2) /* !-SIGNO(struct NdbTransporterHunt)-! */ +#define NDB_TRANSPORTER_CONNECT_REQ (NDB_TRANSPORTER_SIGBASE + 3) /* !-SIGNO(struct NdbTransporterConnectReq)-! */ +#define NDB_TRANSPORTER_CONNECT_REF (NDB_TRANSPORTER_SIGBASE + 4) /* !-SIGNO(struct NdbTransporterConnectRef)-! */ +#define NDB_TRANSPORTER_CONNECT_CONF (NDB_TRANSPORTER_SIGBASE + 5) /* !-SIGNO(struct NdbTransporterConnectConf)-! */ +#define NDB_TRANSPORTER_DISCONNECT_ORD (NDB_TRANSPORTER_SIGBASE + 6) /* !-SIGNO(struct NdbTransporterDisconnectOrd)-! */ +#define NDB_TRANSPORTER_PRIO_A (NDB_TRANSPORTER_SIGBASE + 7) + +inline +const char * +sigNo2String(SIGSELECT sigNo){ + switch(sigNo){ + case NDB_TRANSPORTER_PRIO_A: + return "PRIO_A_DATA"; + break; + case NDB_TRANSPORTER_DATA: + return "PRIO_B_DATA"; + break; + case NDB_TRANSPORTER_HUNT: + return "HUNT"; + break; + case NDB_TRANSPORTER_CONNECT_REQ: + return "CONNECT_REQ"; + break; + case NDB_TRANSPORTER_CONNECT_REF: + return "CONNECT_REF"; + break; + case NDB_TRANSPORTER_CONNECT_CONF: + return "CONNECT_CONF"; + break; + case NDB_TRANSPORTER_DISCONNECT_ORD: + return "DISCONNECT_ORD"; + break; + } + return "UNKNOWN"; +} + +struct NdbTransporterData +{ + SIGSELECT sigNo; + Uint32 sigId; // Sequence number for this signal + Uint32 senderNodeId; + Uint32 length; + Uint32 data[1]; +}; + +struct NdbTransporterData_PrioA +{ + SIGSELECT sigNo; + Uint32 sigId; // Sequence number for this signal + Uint32 senderNodeId; + Uint32 length; + Uint32 data[1]; +}; + +struct NdbTransporterHunt +{ + SIGSELECT sigNo; + NodeId remoteNodeId; +}; + + +struct NdbTransporterConnectReq +{ + SIGSELECT sigNo; + NodeId remoteNodeId; + NodeId senderNodeId; +}; + + +struct NdbTransporterConnectConf +{ + SIGSELECT sigNo; + NodeId remoteNodeId; + NodeId senderNodeId; +}; + +struct NdbTransporterConnectRef +{ + SIGSELECT sigNo; + NodeId remoteNodeId; + NodeId senderNodeId; + Uint32 reason; + + /** + * Node is not accepting connections + */ + static const Uint32 INVALID_STATE = 1; +}; + +struct NdbTransporterDisconnectOrd +{ + SIGSELECT sigNo; + NodeId senderNodeId; + Uint32 reason; + + /** + * Process died + */ + static const Uint32 PROCESS_DIED = 1; + + /** + * Ndb disconnected + */ + static const Uint32 NDB_DISCONNECT = 2; +}; + +union SIGNAL +{ + SIGSELECT sigNo; + struct NdbTransporterData dataSignal; + struct NdbTransporterData prioAData; + struct NdbTransporterHunt ndbHunt; + struct NdbTransporterConnectReq ndbConnectReq; + struct NdbTransporterConnectRef ndbConnectRef; + struct NdbTransporterConnectConf ndbConnectConf; + struct NdbTransporterDisconnectOrd ndbDisconnect; +}; + +#endif diff --git a/ndb/src/common/transporter/OSE_Transporter.cpp b/ndb/src/common/transporter/OSE_Transporter.cpp new file mode 100644 index 00000000000..a7a5ed81ce2 --- /dev/null +++ b/ndb/src/common/transporter/OSE_Transporter.cpp @@ -0,0 +1,487 @@ +/* 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 <ose.h> +#include "OSE_Transporter.hpp" +#include "OSE_Signals.hpp" + +#include <TransporterCallback.hpp> +#include "TransporterInternalDefinitions.hpp" + +#include <NdbMutex.h> + +#include <NdbStdio.h> +#include <NdbHost.h> +#include <NdbOut.hpp> +#include <time.h> +#include <assert.h> + +OSE_Transporter::OSE_Transporter(int _prioASignalSize, + int _prioBSignalSize, + NodeId localNodeId, + const char * lHostName, + NodeId remoteNodeId, + const char * rHostName, + int byteorder, + bool compression, + bool checksum, + bool signalId, + Uint32 reportFreq) : + Transporter(localNodeId, + remoteNodeId, + byteorder, + compression, + checksum, + signalId), + isServer(localNodeId < remoteNodeId) +{ + + signalIdCounter = 0; + prioBSignalSize = _prioBSignalSize; + + if (strcmp(lHostName, rHostName) == 0){ + snprintf(remoteNodeName, sizeof(remoteNodeName), + "ndb_node%d", remoteNodeId); + } else { + snprintf(remoteNodeName, sizeof(remoteNodeName), + "%s/ndb_node%d", rHostName, remoteNodeId); + } + + prioBSignal = NIL; +} + +OSE_Transporter::~OSE_Transporter() { + +#if 0 + /** + * Don't free these buffers since they have already been freed + * when the process allocating them died (wild pointers) + */ + if(prioBSignal != NIL) + free_buf(&prioBSignal); +#endif +} + +bool +OSE_Transporter::initTransporter() { + + struct OS_pcb * pcb = get_pcb(current_process()); + if(pcb != NULL){ + if(pcb->type != OS_ILLEGAL){ + if(prioBSignalSize > pcb->max_sigsize){ + DEBUG("prioBSignalSize(" << prioBSignalSize << ") > max_sigsize(" + << pcb->max_sigsize << ") using max_sigsize"); + prioBSignalSize = pcb->max_sigsize; + } + } + free_buf((union SIGNAL **)&pcb); + } + + maxPrioBDataSize = prioBSignalSize; + maxPrioBDataSize -= (sizeof(NdbTransporterData) + MAX_MESSAGE_SIZE - 4); + + if(maxPrioBDataSize < 0){ + +#ifdef DEBUG_TRANSPORTER + printf("maxPrioBDataSize < 0 %d\n", + maxPrioBDataSize); +#endif + return false; + } + + initSignals(); + + return true; +} + +void +OSE_Transporter::initSignals(){ + if(prioBSignal == NIL){ + prioBSignal = alloc(prioBSignalSize, NDB_TRANSPORTER_DATA); + prioBInsertPtr = &prioBSignal->dataSignal.data[0]; + + prioBSignal->dataSignal.length = 0; + prioBSignal->dataSignal.senderNodeId = localNodeId; + } + dataToSend = 0; +} + +NdbTransporterData * +OSE_Transporter::allocPrioASignal(Uint32 messageLenBytes) const +{ + + const Uint32 lenBytes = messageLenBytes + sizeof(NdbTransporterData) - 4; + + NdbTransporterData * sig = + (NdbTransporterData*)alloc(lenBytes, NDB_TRANSPORTER_PRIO_A); + + sig->length = 0; + sig->senderNodeId = localNodeId; + + return sig; +} + +Uint32 * +OSE_Transporter::getWritePtr(Uint32 lenBytes, Uint32 prio){ + if(prio >= 1){ + prio = 1; + insertPtr = prioBInsertPtr; + signal = (NdbTransporterData*)prioBSignal; + } else { + signal = allocPrioASignal(lenBytes); + insertPtr = &signal->data[0]; + } + return insertPtr; +} + +void +OSE_Transporter::updateWritePtr(Uint32 lenBytes, Uint32 prio){ + + Uint32 bufferSize = signal->length; + bufferSize += lenBytes; + signal->length = bufferSize; + if(prio >= 1){ + prioBInsertPtr += (lenBytes / 4); + if(bufferSize >= maxPrioBDataSize) + doSend(); + } else { + /** + * Prio A signal are sent directly + */ + signal->sigId = 0; + + ::send((union SIGNAL**)&signal, remoteNodePid); + } +} + +#if 0 +int getSeq(int _seq){ + if (_seq > 0){ + switch (_seq % 100){ + case 10: + return _seq - 1; + case 9: + return _seq + 1; + default: + return _seq; + } + }else{ + return _seq; + } +} +int getSeq(int _seq){ + + switch (_seq % 40){ + case 10: + return _seq-4; + case 9: + return _seq-2; + case 8: + return _seq; + case 7: + return _seq+2; + case 6: + return _seq+4; + + + case 30: + return _seq-9; + case 29: + return _seq-7; + case 28: + return _seq-5; + case 27: + return _seq-3; + case 26: + return _seq-1; + case 25: + return _seq+1; + case 24: + return _seq+3; + case 23: + return _seq+5; + case 22: + return _seq+7; + case 21: + return _seq+9; + + default: + return _seq; + + } +} +#endif + +void +OSE_Transporter::doSend() { + /** + * restore is always called to make sure the signal buffer is taken over + * by a process that is alive, this will otherwise lead to that these buffers + * are removed when the process that allocated them dies + */ + restore(prioBSignal); + if(prioBSignal->dataSignal.length > 0){ + + prioBSignal->dataSignal.sigId = signalIdCounter; + signalIdCounter++; + + ::send(&prioBSignal, remoteNodePid); + } + + initSignals(); +} + +void +OSE_Transporter::doConnect() { + + NdbMutex_Lock(theMutexPtr); + if(_connecting || _disconnecting || _connected){ + NdbMutex_Unlock(theMutexPtr); + return; + } + + _connecting = true; + signalIdCounter = 0; + + if(isServer){ + DEBUG("Waiting for connect req: "); + state = WAITING_FOR_CONNECT_REQ; + } else { + state = WAITING_FOR_HUNT; + + DEBUG("Hunting for: " << remoteNodeName); + + union SIGNAL* huntsig; + huntsig = alloc(sizeof(NdbTransporterHunt), NDB_TRANSPORTER_HUNT); + huntsig->ndbHunt.remoteNodeId = remoteNodeId; + hunt(remoteNodeName, 0, NULL, &huntsig); + } + NdbMutex_Unlock(theMutexPtr); +} + +void +OSE_Transporter::doDisconnect() { + NdbMutex_Lock(theMutexPtr); + + switch(state){ + case DISCONNECTED: + case WAITING_FOR_HUNT: + case WAITING_FOR_CONNECT_REQ: + case WAITING_FOR_CONNECT_CONF: + break; + case CONNECTED: + { +#if 0 + /** + * There should not be anything in the buffer that needs to be sent here + */ + DEBUG("Doing send before disconnect"); + doSend(); +#endif + union SIGNAL * sig = alloc(sizeof(NdbTransporterDisconnectOrd), + NDB_TRANSPORTER_DISCONNECT_ORD); + sig->ndbDisconnect.senderNodeId = localNodeId; + sig->ndbDisconnect.reason = NdbTransporterDisconnectOrd::NDB_DISCONNECT; + ::send(&sig, remoteNodePid); + detach(&remoteNodeRef); + + } + break; + } + state = DISCONNECTED; + + _connected = false; + _connecting = false; + _disconnecting = false; + + NdbMutex_Unlock(theMutexPtr); +} + +void +OSE_Transporter::huntReceived(struct NdbTransporterHunt * sig){ + if(isServer){ + WARNING("Hunt received for server: remoteNodeId: " << + sig->remoteNodeId); + return; + } + + if(state != WAITING_FOR_HUNT){ + WARNING("Hunt received while in state: " << state); + return; + } + remoteNodePid = sender((union SIGNAL**)&sig); + union SIGNAL * signal = alloc(sizeof(NdbTransporterConnectReq), + NDB_TRANSPORTER_CONNECT_REQ); + signal->ndbConnectReq.remoteNodeId = remoteNodeId; + signal->ndbConnectReq.senderNodeId = localNodeId; + + DEBUG("Sending connect req to pid: " << hex << remoteNodePid); + + ::send(&signal, remoteNodePid); + state = WAITING_FOR_CONNECT_CONF; + return; +} + +bool +OSE_Transporter::connectReq(struct NdbTransporterConnectReq * sig){ + if(!isServer){ + WARNING("OSE Connect Req received for client: senderNodeId: " << + sig->senderNodeId); + return false; + } + + if(state != WAITING_FOR_CONNECT_REQ){ + PROCESS pid = sender((union SIGNAL**)&sig); + union SIGNAL * signal = alloc(sizeof(NdbTransporterConnectRef), + NDB_TRANSPORTER_CONNECT_REF); + signal->ndbConnectRef.senderNodeId = localNodeId; + signal->ndbConnectRef.reason = NdbTransporterConnectRef::INVALID_STATE; + + DEBUG("Sending connect ref to pid: " << hex << pid); + + ::send(&signal, pid); + return false; + } + + NdbMutex_Lock(theMutexPtr); + + if(prioBSignal != NIL){ + restore(prioBSignal); + free_buf(&prioBSignal); + } + initSignals(); + + remoteNodePid = sender((union SIGNAL**)&sig); + union SIGNAL * signal = alloc(sizeof(NdbTransporterConnectRef), + NDB_TRANSPORTER_CONNECT_CONF); + signal->ndbConnectConf.senderNodeId = localNodeId; + signal->ndbConnectConf.remoteNodeId = remoteNodeId; + + union SIGNAL * discon = alloc(sizeof(NdbTransporterDisconnectOrd), + NDB_TRANSPORTER_DISCONNECT_ORD); + discon->ndbDisconnect.senderNodeId = remoteNodeId; + discon->ndbDisconnect.reason = NdbTransporterDisconnectOrd::PROCESS_DIED; + + DEBUG("Attaching to pid: " << hex << remoteNodePid); + + remoteNodeRef = attach(&discon, remoteNodePid); + + DEBUG("Sending connect conf to pid: " << hex << remoteNodePid); + + ::send(&signal, remoteNodePid); + state = CONNECTED; + + _connected = true; + _connecting = false; + _disconnecting = false; + + NdbMutex_Unlock(theMutexPtr); + + return true; +} + +bool +OSE_Transporter::connectRef(struct NdbTransporterConnectRef * sig){ + if(isServer){ + WARNING("OSE Connect Ref received for server: senderNodeId: " << + sig->senderNodeId); + return false; + } + if(state != WAITING_FOR_CONNECT_CONF){ + WARNING("OSE Connect Ref received for client while in state: " << + state << " senderNodeId: " << sig->senderNodeId); + return false; + } + doDisconnect(); +#if 0 + /** + * Don't call connect directly, wait until the next time + * checkConnections is called which will trigger a new connect attempt + */ + doConnect(); +#endif + return true; +} + + +bool +OSE_Transporter::connectConf(struct NdbTransporterConnectConf * sig){ + if(isServer){ + WARNING("OSE Connect Conf received for server: senderNodeId: " << + sig->senderNodeId); + return false; + } + if(state != WAITING_FOR_CONNECT_CONF){ + WARNING("OSE Connect Conf received while in state: " << + state); + return false; + } + NdbMutex_Lock(theMutexPtr); + + // Free the buffers to get rid of any "junk" that they might contain + if(prioBSignal != NIL){ + restore(prioBSignal); + free_buf(&prioBSignal); + } + initSignals(); + + union SIGNAL * discon = alloc(sizeof(NdbTransporterDisconnectOrd), + NDB_TRANSPORTER_DISCONNECT_ORD); + discon->ndbDisconnect.senderNodeId = remoteNodeId; + discon->ndbDisconnect.reason= NdbTransporterDisconnectOrd::PROCESS_DIED; + + remoteNodeRef = attach(&discon, remoteNodePid); + + state = CONNECTED; + _connected = true; + _connecting = false; + _disconnecting = false; + + // Free the buffers to get rid of any "junk" that they might contain + if(prioBSignal != NIL){ + restore(prioBSignal); + free_buf(&prioBSignal); + } + initSignals(); + + NdbMutex_Unlock(theMutexPtr); + return true; +} + + +bool +OSE_Transporter::disconnectOrd(struct NdbTransporterDisconnectOrd * sig){ + if(state != CONNECTED){ + WARNING("OSE Disconnect Ord received while in state: " << state << + " reason: " << sig->reason); + return false; + } + + if(sig->reason == NdbTransporterDisconnectOrd::PROCESS_DIED){ + state = DISCONNECTED; + } + + doDisconnect(); + reportDisconnect(callbackObj, remoteNodeId,0); + return true; +} + + + + + + + diff --git a/ndb/src/common/transporter/OSE_Transporter.hpp b/ndb/src/common/transporter/OSE_Transporter.hpp new file mode 100644 index 00000000000..4fd06130477 --- /dev/null +++ b/ndb/src/common/transporter/OSE_Transporter.hpp @@ -0,0 +1,158 @@ +/* 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 */ + +//**************************************************************************** +// +// AUTHOR +// Magnus Svensson +// +// NAME +// OSE_Transporter +// +// DESCRIPTION +// A OSE_Transporter instance is created when OSE-signal communication +// shall be used (user specified). It handles connect, disconnect, +// send and receive. +// +// +// +//***************************************************************************/ +#ifndef OSE_Transporter_H +#define OSE_Transporter_H + +#include "Transporter.hpp" + +#include "ose.h" + +class OSE_Transporter : public Transporter { + friend class OSE_Receiver; + friend class TransporterRegistry; +public: + + // Initialize member variables + OSE_Transporter(int prioASignalSize, + int prioBSignalSize, + NodeId localNodeId, + const char * lHostName, + NodeId remoteNodeId, + const char * rHostName, + int byteorder, + bool compression, + bool checksum, + bool signalId, + Uint32 reportFreq = 4096); + + // Disconnect, delete send buffers and receive buffer + ~OSE_Transporter(); + + /** + * Allocate buffers for sending and receiving + */ + bool initTransporter(); + + /** + * Connect + */ + virtual void doConnect(); + + /** + * Disconnect + */ + virtual void doDisconnect(); + + Uint32 * getWritePtr(Uint32 lenBytes, Uint32 prio); + void updateWritePtr(Uint32 lenBytes, Uint32 prio); + + /** + * Retrieves the contents of the send buffers, copies it into + * an OSE signal and sends it. Until the send buffers are empty + */ + void doSend(); + + bool hasDataToSend() const { + return prioBSignal->dataSignal.length > 0; + } + +protected: + /** + * Not implemented + * OSE uses async connect/disconnect + */ + virtual bool connectImpl(Uint32 timeOut){ + return false; + } + + /** + * Not implemented + * OSE uses async connect/disconnect + */ + virtual void disconnectImpl(){ + } + +private: + const bool isServer; + + int maxPrioBDataSize; + + /** + * Remote node name + * On same machine: ndb_node1 + * On remote machine: rhost/ndb_node1 + **/ + PROCESS remoteNodePid; + OSATTREF remoteNodeRef; + char remoteNodeName[256]; + + Uint32 signalIdCounter; + + int prioBSignalSize; + + Uint32 * prioBInsertPtr; + union SIGNAL * prioBSignal; + + struct NdbTransporterData * allocPrioASignal(Uint32 lenBytes) const; + + /** + * Statistics + */ + Uint32 reportFreq; + Uint32 receiveCount; + Uint64 receiveSize; + Uint32 sendCount; + Uint64 sendSize; + + void initSignals(); + + /** + * OSE Receiver callbacks + */ + void huntReceived(struct NdbTransporterHunt * sig); + bool connectReq(struct NdbTransporterConnectReq * sig); + bool connectRef(struct NdbTransporterConnectRef * sig); + bool connectConf(struct NdbTransporterConnectConf * sig); + bool disconnectOrd(struct NdbTransporterDisconnectOrd * sig); + + enum OSETransporterState { + DISCONNECTED = 0, + WAITING_FOR_HUNT = 1, + WAITING_FOR_CONNECT_REQ = 2, + WAITING_FOR_CONNECT_CONF = 3, + CONNECTED = 4 + } state; +}; + +// Define of OSE_Transporter_H +#endif diff --git a/ndb/src/common/transporter/Packer.cpp b/ndb/src/common/transporter/Packer.cpp new file mode 100644 index 00000000000..77bd66d1ba9 --- /dev/null +++ b/ndb/src/common/transporter/Packer.cpp @@ -0,0 +1,502 @@ +/* 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 "Packer.hpp" +#include <TransporterRegistry.hpp> +#include <TransporterCallback.hpp> +#include <RefConvert.hpp> + +#include <stdio.h> + +Uint32 +TransporterRegistry::unpack(Uint32 * readPtr, + Uint32 sizeOfData, + NodeId remoteNodeId, + IOState state) { + SignalHeader signalHeader; + LinearSectionPtr ptr[3]; + + Uint32 usedData = 0; + + if(state == NoHalt || state == HaltOutput){ + while(sizeOfData >= 4 + sizeof(Protocol6)){ + Uint32 word1 = readPtr[0]; + Uint32 word2 = readPtr[1]; + Uint32 word3 = readPtr[2]; + +#if 0 + if(Protocol6::getByteOrder(word1) != MY_OWN_BYTE_ORDER){ + //Do funky stuff + } +#endif + + const Uint16 messageLen32 = Protocol6::getMessageLength(word1); + const Uint32 messageLenBytes = ((Uint32)messageLen32) << 2; + + if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){ + DEBUG("Message Size = " << messageLenBytes); + reportError(callbackObj, remoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return usedData; + }//if + + if (sizeOfData < messageLenBytes) { + break; + }//if + + if(Protocol6::getCheckSumIncluded(word1)){ + const Uint32 tmpLen = messageLen32 - 1; + const Uint32 checkSumSent = readPtr[tmpLen]; + const Uint32 checkSumComputed = computeChecksum(&readPtr[0], tmpLen); + + if(checkSumComputed != checkSumSent){ + reportError(callbackObj, remoteNodeId, TE_INVALID_CHECKSUM); + return usedData; + }//if + }//if + +#if 0 + if(Protocol6::getCompressed(word1)){ + //Do funky stuff + }//if +#endif + + Protocol6::createSignalHeader(&signalHeader, word1, word2, word3); + + Uint32 sBlockNum = signalHeader.theSendersBlockRef; + sBlockNum = numberToRef(sBlockNum, remoteNodeId); + signalHeader.theSendersBlockRef = sBlockNum; + + Uint8 prio = Protocol6::getPrio(word1); + + Uint32 * signalData = &readPtr[3]; + + if(Protocol6::getSignalIdIncluded(word1) == 0){ + signalHeader.theSendersSignalId = ~0; + } else { + signalHeader.theSendersSignalId = * signalData; + signalData ++; + }//if + + Uint32 * sectionPtr = signalData + signalHeader.theLength; + Uint32 * sectionData = sectionPtr + signalHeader.m_noOfSections; + for(Uint32 i = 0; i<signalHeader.m_noOfSections; i++){ + Uint32 sz = * sectionPtr; + ptr[i].sz = sz; + ptr[i].p = sectionData; + + sectionPtr ++; + sectionData += sz; + } + + execute(callbackObj, &signalHeader, prio, signalData, ptr); + + readPtr += messageLen32; + sizeOfData -= messageLenBytes; + usedData += messageLenBytes; + }//while + + return usedData; + } else { + /** state = HaltIO || state == HaltInput */ + + while(sizeOfData >= 4 + sizeof(Protocol6)){ + Uint32 word1 = readPtr[0]; + Uint32 word2 = readPtr[1]; + Uint32 word3 = readPtr[2]; + +#if 0 + if(Protocol6::getByteOrder(word1) != MY_OWN_BYTE_ORDER){ + //Do funky stuff + }//if +#endif + + const Uint16 messageLen32 = Protocol6::getMessageLength(word1); + const Uint32 messageLenBytes = ((Uint32)messageLen32) << 2; + if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){ + DEBUG("Message Size = " << messageLenBytes); + reportError(callbackObj, remoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return usedData; + }//if + + if (sizeOfData < messageLenBytes) { + break; + }//if + + if(Protocol6::getCheckSumIncluded(word1)){ + const Uint32 tmpLen = messageLen32 - 1; + const Uint32 checkSumSent = readPtr[tmpLen]; + const Uint32 checkSumComputed = computeChecksum(&readPtr[0], tmpLen); + + if(checkSumComputed != checkSumSent){ + + //theTransporters[remoteNodeId]->disconnect(); + reportError(callbackObj, remoteNodeId, TE_INVALID_CHECKSUM); + return usedData; + }//if + }//if + +#if 0 + if(Protocol6::getCompressed(word1)){ + //Do funky stuff + }//if +#endif + + Protocol6::createSignalHeader(&signalHeader, word1, word2, word3); + + Uint32 rBlockNum = signalHeader.theReceiversBlockNumber; + + if(rBlockNum == 252){ + Uint32 sBlockNum = signalHeader.theSendersBlockRef; + sBlockNum = numberToRef(sBlockNum, remoteNodeId); + signalHeader.theSendersBlockRef = sBlockNum; + + Uint8 prio = Protocol6::getPrio(word1); + + Uint32 * signalData = &readPtr[3]; + + if(Protocol6::getSignalIdIncluded(word1) == 0){ + signalHeader.theSendersSignalId = ~0; + } else { + signalHeader.theSendersSignalId = * signalData; + signalData ++; + }//if + + Uint32 * sectionPtr = signalData + signalHeader.theLength; + Uint32 * sectionData = sectionPtr + signalHeader.m_noOfSections; + for(Uint32 i = 0; i<signalHeader.m_noOfSections; i++){ + Uint32 sz = * sectionPtr; + ptr[i].sz = sz; + ptr[i].p = sectionData; + + sectionPtr ++; + sectionData += sz; + } + + execute(callbackObj, &signalHeader, prio, signalData, ptr); + } else { + DEBUG("prepareReceive(...) - Discarding message to block: " + << rBlockNum << " from Node: " << remoteNodeId); + }//if + + readPtr += messageLen32; + sizeOfData -= messageLenBytes; + usedData += messageLenBytes; + }//while + + + return usedData; + }//if +} + +Uint32 * +TransporterRegistry::unpack(Uint32 * readPtr, + Uint32 * eodPtr, + NodeId remoteNodeId, + IOState state) { + static SignalHeader signalHeader; + static LinearSectionPtr ptr[3]; + if(state == NoHalt || state == HaltOutput){ + while(readPtr < eodPtr){ + Uint32 word1 = readPtr[0]; + Uint32 word2 = readPtr[1]; + Uint32 word3 = readPtr[2]; + +#if 0 + if(Protocol6::getByteOrder(word1) != MY_OWN_BYTE_ORDER){ + //Do funky stuff + } +#endif + + const Uint16 messageLen32 = Protocol6::getMessageLength(word1); + + if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){ + DEBUG("Message Size(words) = " << messageLen32); + reportError(callbackObj, remoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return readPtr; + }//if + + if(Protocol6::getCheckSumIncluded(word1)){ + const Uint32 tmpLen = messageLen32 - 1; + const Uint32 checkSumSent = readPtr[tmpLen]; + const Uint32 checkSumComputed = computeChecksum(&readPtr[0], tmpLen); + + if(checkSumComputed != checkSumSent){ + reportError(callbackObj, remoteNodeId, TE_INVALID_CHECKSUM); + return readPtr; + }//if + }//if + +#if 0 + if(Protocol6::getCompressed(word1)){ + //Do funky stuff + }//if +#endif + + Protocol6::createSignalHeader(&signalHeader, word1, word2, word3); + + Uint32 sBlockNum = signalHeader.theSendersBlockRef; + sBlockNum = numberToRef(sBlockNum, remoteNodeId); + signalHeader.theSendersBlockRef = sBlockNum; + + Uint8 prio = Protocol6::getPrio(word1); + + Uint32 * signalData = &readPtr[3]; + + if(Protocol6::getSignalIdIncluded(word1) == 0){ + signalHeader.theSendersSignalId = ~0; + } else { + signalHeader.theSendersSignalId = * signalData; + signalData ++; + }//if + + Uint32 * sectionPtr = signalData + signalHeader.theLength; + Uint32 * sectionData = sectionPtr + signalHeader.m_noOfSections; + for(Uint32 i = 0; i<signalHeader.m_noOfSections; i++){ + Uint32 sz = * sectionPtr; + ptr[i].sz = sz; + ptr[i].p = sectionData; + + sectionPtr ++; + sectionData += sz; + } + + execute(callbackObj, &signalHeader, prio, signalData, ptr); + + readPtr += messageLen32; + }//while + } else { + /** state = HaltIO || state == HaltInput */ + + while(readPtr < eodPtr){ + Uint32 word1 = readPtr[0]; + Uint32 word2 = readPtr[1]; + Uint32 word3 = readPtr[2]; + +#if 0 + if(Protocol6::getByteOrder(word1) != MY_OWN_BYTE_ORDER){ + //Do funky stuff + }//if +#endif + + const Uint16 messageLen32 = Protocol6::getMessageLength(word1); + if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){ + DEBUG("Message Size(words) = " << messageLen32); + reportError(callbackObj, remoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return readPtr; + }//if + + if(Protocol6::getCheckSumIncluded(word1)){ + const Uint32 tmpLen = messageLen32 - 1; + const Uint32 checkSumSent = readPtr[tmpLen]; + const Uint32 checkSumComputed = computeChecksum(&readPtr[0], tmpLen); + + if(checkSumComputed != checkSumSent){ + + //theTransporters[remoteNodeId]->disconnect(); + reportError(callbackObj, remoteNodeId, TE_INVALID_CHECKSUM); + return readPtr; + }//if + }//if + +#if 0 + if(Protocol6::getCompressed(word1)){ + //Do funky stuff + }//if +#endif + + Protocol6::createSignalHeader(&signalHeader, word1, word2, word3); + + Uint32 rBlockNum = signalHeader.theReceiversBlockNumber; + + if(rBlockNum == 252){ + Uint32 sBlockNum = signalHeader.theSendersBlockRef; + sBlockNum = numberToRef(sBlockNum, remoteNodeId); + signalHeader.theSendersBlockRef = sBlockNum; + + Uint8 prio = Protocol6::getPrio(word1); + + Uint32 * signalData = &readPtr[3]; + + if(Protocol6::getSignalIdIncluded(word1) == 0){ + signalHeader.theSendersSignalId = ~0; + } else { + signalHeader.theSendersSignalId = * signalData; + signalData ++; + }//if + + Uint32 * sectionPtr = signalData + signalHeader.theLength; + Uint32 * sectionData = sectionPtr + signalHeader.m_noOfSections; + for(Uint32 i = 0; i<signalHeader.m_noOfSections; i++){ + Uint32 sz = * sectionPtr; + ptr[i].sz = sz; + ptr[i].p = sectionData; + + sectionPtr ++; + sectionData += sz; + } + + execute(callbackObj, &signalHeader, prio, signalData, ptr); + } else { + DEBUG("prepareReceive(...) - Discarding message to block: " + << rBlockNum << " from Node: " << remoteNodeId); + }//if + + readPtr += messageLen32; + }//while + }//if + return readPtr; +} + +Packer::Packer(bool signalId, bool checksum) { + + checksumUsed = (checksum ? 1 : 0); + signalIdUsed = (signalId ? 1 : 0); + + // Set the priority + + preComputedWord1 = 0; + Protocol6::setByteOrder(preComputedWord1, 0); + Protocol6::setSignalIdIncluded(preComputedWord1, signalIdUsed); + Protocol6::setCheckSumIncluded(preComputedWord1, checksumUsed); + Protocol6::setCompressed(preComputedWord1, 0); +} + +inline +void +import(Uint32 * & insertPtr, const LinearSectionPtr & ptr){ + const Uint32 sz = ptr.sz; + memcpy(insertPtr, ptr.p, 4 * sz); + insertPtr += sz; +} + +void copy(Uint32 * & insertPtr, + class SectionSegmentPool &, const SegmentedSectionPtr & ptr); + +void +Packer::pack(Uint32 * insertPtr, + Uint32 prio, + const SignalHeader * header, + const Uint32 * theData, + const LinearSectionPtr ptr[3]) const { + + Uint32 dataLen32 = header->theLength; + Uint32 no_segs = header->m_noOfSections; + + Uint32 len32 = + dataLen32 + no_segs + + checksumUsed + signalIdUsed + (sizeof(Protocol6)/4); + + + for(Uint32 i = 0; i<no_segs; i++){ + len32 += ptr[i].sz; + } + + /** + * Do insert of data + */ + Uint32 word1 = preComputedWord1; + Uint32 word2 = 0; + Uint32 word3 = 0; + + Protocol6::setPrio(word1, prio); + Protocol6::setMessageLength(word1, len32); + Protocol6::createProtocol6Header(word1, word2, word3, header); + + insertPtr[0] = word1; + insertPtr[1] = word2; + insertPtr[2] = word3; + + Uint32 * tmpInserPtr = &insertPtr[3]; + + if(signalIdUsed){ + * tmpInserPtr = header->theSignalId; + tmpInserPtr++; + } + + memcpy(tmpInserPtr, theData, 4 * dataLen32); + + tmpInserPtr += dataLen32; + for(Uint32 i = 0; i<no_segs; i++){ + tmpInserPtr[i] = ptr[i].sz; + } + + tmpInserPtr += no_segs; + for(Uint32 i = 0; i<no_segs; i++){ + import(tmpInserPtr, ptr[i]); + } + + if(checksumUsed){ + * tmpInserPtr = computeChecksum(&insertPtr[0], len32-1); + } +} + +void +Packer::pack(Uint32 * insertPtr, + Uint32 prio, + const SignalHeader * header, + const Uint32 * theData, + class SectionSegmentPool & thePool, + const SegmentedSectionPtr ptr[3]) const { + + Uint32 dataLen32 = header->theLength; + Uint32 no_segs = header->m_noOfSections; + + Uint32 len32 = + dataLen32 + no_segs + + checksumUsed + signalIdUsed + (sizeof(Protocol6)/4); + + for(Uint32 i = 0; i<no_segs; i++){ + len32 += ptr[i].sz; + } + + /** + * Do insert of data + */ + Uint32 word1 = preComputedWord1; + Uint32 word2 = 0; + Uint32 word3 = 0; + + Protocol6::setPrio(word1, prio); + Protocol6::setMessageLength(word1, len32); + Protocol6::createProtocol6Header(word1, word2, word3, header); + + insertPtr[0] = word1; + insertPtr[1] = word2; + insertPtr[2] = word3; + + Uint32 * tmpInserPtr = &insertPtr[3]; + + if(signalIdUsed){ + * tmpInserPtr = header->theSignalId; + tmpInserPtr++; + } + + memcpy(tmpInserPtr, theData, 4 * dataLen32); + + tmpInserPtr += dataLen32; + for(Uint32 i = 0; i<no_segs; i++){ + tmpInserPtr[i] = ptr[i].sz; + } + + tmpInserPtr += no_segs; + for(Uint32 i = 0; i<no_segs; i++){ + copy(tmpInserPtr, thePool, ptr[i]); + } + + if(checksumUsed){ + * tmpInserPtr = computeChecksum(&insertPtr[0], len32-1); + } +} diff --git a/ndb/src/common/transporter/Packer.hpp b/ndb/src/common/transporter/Packer.hpp new file mode 100644 index 00000000000..5c191203201 --- /dev/null +++ b/ndb/src/common/transporter/Packer.hpp @@ -0,0 +1,85 @@ +/* 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 */ + +#ifndef PACKER_HPP +#define PACKER_HPP + +#include <TransporterDefinitions.hpp> +#include "TransporterInternalDefinitions.hpp" + +class Packer { + Uint32 preComputedWord1; + Uint32 checksumUsed; // Checksum shall be included in the message + Uint32 signalIdUsed; // Senders signal id shall be included in the message +public: + Packer(bool signalId, bool checksum); + + Uint32 getMessageLength(const SignalHeader* header, + const LinearSectionPtr ptr[3]) const ; + + + Uint32 getMessageLength(const SignalHeader* header, + const SegmentedSectionPtr ptr[3]) const ; + + void pack(Uint32 * insertPtr, + Uint32 prio, + const SignalHeader* header, + const Uint32* data, + const LinearSectionPtr ptr[3]) const ; + + void pack(Uint32 * insertPtr, + Uint32 prio, + const SignalHeader* header, + const Uint32* data, + class SectionSegmentPool & thePool, + const SegmentedSectionPtr ptr[3]) const ; +}; + +inline +Uint32 +Packer::getMessageLength(const SignalHeader* header, + const LinearSectionPtr ptr[3]) const { + Uint32 tLen32 = header->theLength; + Uint32 no_seg = header->m_noOfSections; + tLen32 += checksumUsed; + tLen32 += signalIdUsed; + tLen32 += no_seg; + + for(Uint32 i = 0; i<no_seg; i++){ + tLen32 += ptr[i].sz; + } + + return (tLen32 * 4) + sizeof(Protocol6); +} + +inline +Uint32 +Packer::getMessageLength(const SignalHeader* header, + const SegmentedSectionPtr ptr[3]) const { + Uint32 tLen32 = header->theLength; + Uint32 no_seg = header->m_noOfSections; + tLen32 += checksumUsed; + tLen32 += signalIdUsed; + tLen32 += no_seg; + + for(Uint32 i = 0; i<no_seg; i++){ + tLen32 += ptr[i].sz; + } + + return (tLen32 * 4) + sizeof(Protocol6); +} + +#endif diff --git a/ndb/src/common/transporter/SCI_Transporter.cpp b/ndb/src/common/transporter/SCI_Transporter.cpp new file mode 100644 index 00000000000..2be857e8115 --- /dev/null +++ b/ndb/src/common/transporter/SCI_Transporter.cpp @@ -0,0 +1,1006 @@ +/* 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 "SCI_Transporter.hpp" +#include <NdbStdio.h> +#include <NdbOut.hpp> +#include <NdbSleep.h> +#include <NdbTick.h> +#include <stdlib.h> +#include <NdbTick.h> +#if 0 +#include <malloc.h> +#include <sys/time.h> +#endif +#include "TransporterInternalDefinitions.hpp" +#include <TransporterCallback.hpp> + +#define FLAGS 0 + +SCI_Transporter::SCI_Transporter(Uint32 packetSize, + Uint32 bufferSize, + Uint32 nAdapters, + Uint16 remoteSciNodeId0, + Uint16 remoteSciNodeId1, + NodeId _localNodeId, + NodeId _remoteNodeId, + int byte_order, + bool compr, + bool chksm, + bool signalId, + Uint32 reportFreq) : + Transporter(_localNodeId, _remoteNodeId, byte_order, compr, chksm, signalId) +{ + m_PacketSize = (packetSize + 3)/4 ; + m_BufferSize = bufferSize; + m_sendBuffer.m_buffer = NULL; + + m_RemoteSciNodeId = remoteSciNodeId0; + + if(remoteSciNodeId0 == 0 || remoteSciNodeId1 == 0) + m_numberOfRemoteNodes=1; + else + m_numberOfRemoteNodes=2; + + m_RemoteSciNodeId1 = remoteSciNodeId1; + + + m_initLocal=false; + m_remoteNodes= new Uint16[m_numberOfRemoteNodes]; + if(m_remoteNodes == NULL) { + //DO WHAT?? + } + m_swapCounter=0; + m_failCounter=0; + m_remoteNodes[0]=remoteSciNodeId0; + m_remoteNodes[1]=remoteSciNodeId1; + m_adapters = nAdapters; + // The maximum number of times to try and create, + // start and destroy a sequence + m_ActiveAdapterId=0; + m_StandbyAdapterId=1; + + m_mapped = false; + m_sciinit=false; + + sciAdapters= new SciAdapter[nAdapters* (sizeof (SciAdapter))]; + if(sciAdapters==NULL) { + } + m_SourceSegm= new sourceSegm[nAdapters* (sizeof (sourceSegm))]; + if(m_SourceSegm==NULL) { + } + m_TargetSegm= new targetSegm[nAdapters* (sizeof (targetSegm))]; + if(m_TargetSegm==NULL) { + } + m_reportFreq= reportFreq; + + //reset all statistic counters. +#ifdef DEBUG_TRANSPORTER + i1024=0; + i2048=0; + i2049=0; + i10242048=0; + i20484096=0; + i4096=0; + i4097=0; +#endif + +} + + + +void SCI_Transporter::disconnectImpl() +{ + sci_error_t err; + if(m_mapped){ + setDisconnect(); +#ifdef DEBUG_TRANSPORTER + ndbout << "DisconnectImpl " << getConnectionStatus() << endl; + ndbout << "remote node " << remoteNodeId << endl; +#endif + disconnectRemote(); + disconnectLocal(); + } + + // Empty send buffer + + m_sendBuffer.m_dataSize = 0; + + m_initLocal=false; + m_mapped = false; + + if(m_sciinit) { + for(Uint32 i=0; i<m_adapters ; i++) { + SCIClose(sciAdapters[i].scidesc, FLAGS, &err); + + if(err != SCI_ERR_OK) { + reportError(callbackObj, localNodeId, TE_SCI_UNABLE_TO_CLOSE_CHANNEL); +#ifdef DEBUG_TRANSPORTER + fprintf(stderr, + "\nCannot close channel to the driver. Error code 0x%x", + err); +#endif + } + } + } + m_sciinit=false; + +#ifdef DEBUG_TRANSPORTER + ndbout << "total: " << i1024+ i10242048 + i2048+i2049 << endl; + ndbout << "<1024: " << i1024 << endl; + ndbout << "1024-2047: " << i10242048 << endl; + ndbout << "==2048: " << i2048 << endl; + ndbout << "2049-4096: " << i20484096 << endl; + ndbout << "==4096: " << i4096 << endl; + ndbout << ">4096: " << i4097 << endl; + +#endif + +} + + +bool SCI_Transporter::initTransporter() { + if(m_BufferSize < (2*MAX_MESSAGE_SIZE)){ + m_BufferSize = 2 * MAX_MESSAGE_SIZE; + } + + // Allocate buffers for sending + Uint32 sz = 0; + if(m_BufferSize < (m_PacketSize * 4)){ + sz = m_BufferSize + MAX_MESSAGE_SIZE; + } else { + /** + * 3 packages + */ + sz = (m_PacketSize * 4) * 3 + MAX_MESSAGE_SIZE; + } + + m_sendBuffer.m_bufferSize = 4 * ((sz + 3) / 4); + m_sendBuffer.m_buffer = new Uint32[m_sendBuffer.m_bufferSize / 4]; + m_sendBuffer.m_dataSize = 0; + + if(!getLinkStatus(m_ActiveAdapterId) || + !getLinkStatus(m_StandbyAdapterId)) { +#ifdef DEBUG_TRANSPORTER + ndbout << "The link is not fully operational. " << endl; + ndbout << "Check the cables and the switches" << endl; +#endif + //reportDisconnect(remoteNodeId, 0); + //doDisconnect(); + //NDB should terminate + reportError(callbackObj, localNodeId, TE_SCI_LINK_ERROR); + return false; + } + + return true; +} // initTransporter() + + + +Uint32 SCI_Transporter::getLocalNodeId(Uint32 adapterNo) +{ + sci_query_adapter_t queryAdapter; + sci_error_t error; + Uint32 _localNodeId; + + queryAdapter.subcommand = SCI_Q_ADAPTER_NODEID; + queryAdapter.localAdapterNo = adapterNo; + queryAdapter.data = &_localNodeId; + + SCIQuery(SCI_Q_ADAPTER,(void*)(&queryAdapter),(Uint32)NULL,&error); + + if(error != SCI_ERR_OK) + return 0; + return _localNodeId; +} + + +bool SCI_Transporter::getLinkStatus(Uint32 adapterNo) +{ + sci_query_adapter_t queryAdapter; + sci_error_t error; + int linkstatus; + queryAdapter.subcommand = SCI_Q_ADAPTER_LINK_OPERATIONAL; + + queryAdapter.localAdapterNo = adapterNo; + queryAdapter.data = &linkstatus; + + SCIQuery(SCI_Q_ADAPTER,(void*)(&queryAdapter),(Uint32)NULL,&error); + + if(error != SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout << "error querying adapter " << endl; +#endif + return false; + } + if(linkstatus<=0) + return false; + return true; +} + + + +sci_error_t SCI_Transporter::initLocalSegment() { + Uint32 segmentSize = m_BufferSize; + Uint32 offset = 0; + sci_error_t err; + if(!m_sciinit) { + for(Uint32 i=0; i<m_adapters ; i++) { + SCIOpen(&(sciAdapters[i].scidesc), FLAGS, &err); + sciAdapters[i].localSciNodeId=getLocalNodeId(i); +#ifdef DEBUG_TRANSPORTER + ndbout_c("SCInode iD %d adapter %d\n", + sciAdapters[i].localSciNodeId, i); +#endif + if(err != SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("\nCannot open an SCI virtual device. Error code 0x%x", + err); +#endif + return err; + } + } + } + + m_sciinit=true; + + SCICreateSegment(sciAdapters[0].scidesc, + &(m_SourceSegm[0].localHandle), + hostSegmentId(localNodeId, remoteNodeId), + segmentSize, + 0, + 0, + 0, + &err); + + if(err != SCI_ERR_OK) { + return err; + } else { +#ifdef DEBUG_TRANSPORTER + ndbout << "created segment id : " + << hostSegmentId(localNodeId, remoteNodeId) << endl; +#endif + } + + /** Prepare the segment*/ + for(Uint32 i=0; i < m_adapters; i++) { + SCIPrepareSegment((m_SourceSegm[0].localHandle), + i, + FLAGS, + &err); + + if(err != SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("Local Segment is not accessible by an SCI adapter."); + ndbout_c("Error code 0x%x\n", err); +#endif + return err; + } + } + + + m_SourceSegm[0].mappedMemory = + SCIMapLocalSegment((m_SourceSegm[0].localHandle), + &(m_SourceSegm[0].lhm[0].map), + offset, + segmentSize, + NULL, + FLAGS, + &err); + + + + if(err != SCI_ERR_OK) { + +#ifdef DEBUG_TRANSPORTER + fprintf(stderr, "\nCannot map area of size %d. Error code 0x%x", + segmentSize,err); + ndbout << "initLocalSegment does a disConnect" << endl; +#endif + doDisconnect(); + return err; + } + + + /** Make the local segment available*/ + for(Uint32 i=0; i < m_adapters; i++) { + SCISetSegmentAvailable((m_SourceSegm[0].localHandle), + i, + FLAGS, + &err); + + if(err != SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("\nLocal Segment is not available for remote connections."); + ndbout_c("Error code 0x%x\n", err); +#endif + return err; + } + } + + + setupLocalSegment(); + + return err; + +} // initLocalSegment() + + +bool SCI_Transporter::doSend() { +#ifdef DEBUG_TRANSPORTER + NDB_TICKS startSec=0, stopSec=0; + Uint32 startMicro=0, stopMicro=0, totalMicro=0; +#endif + sci_error_t err; + Uint32 retry=0; + + const char * const sendPtr = (char*)m_sendBuffer.m_buffer; + const Uint32 sizeToSend = m_sendBuffer.m_dataSize; + + if (sizeToSend > 0){ +#ifdef DEBUG_TRANSPORTER + if(sizeToSend < 1024 ) + i1024++; + if(sizeToSend > 1024 && sizeToSend < 2048 ) + i10242048++; + if(sizeToSend==2048) + i2048++; + if(sizeToSend>2048 && sizeToSend < 4096) + i20484096++; + if(sizeToSend==4096) + i4096++; + if(sizeToSend==4097) + i4097++; +#endif + if(startSequence(m_ActiveAdapterId)!=SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout << "Start sequence failed" << endl; +#endif + reportError(callbackObj, remoteNodeId, TE_SCI_UNABLE_TO_START_SEQUENCE); + return false; + } + + + tryagain: + Uint32 * insertPtr = (Uint32 *) + (m_TargetSegm[m_ActiveAdapterId].writer)->getWritePtr(sizeToSend); + + if(insertPtr != 0) { + + const Uint32 remoteOffset=(Uint32) + ((char*)insertPtr - + (char*)(m_TargetSegm[m_ActiveAdapterId].mappedMemory)); + + SCIMemCpy(m_TargetSegm[m_ActiveAdapterId].sequence, + (void*)sendPtr, + m_TargetSegm[m_ActiveAdapterId].rhm[m_ActiveAdapterId].map, + remoteOffset, + sizeToSend, + SCI_FLAG_ERROR_CHECK, + &err); + + + if(err == SCI_ERR_OUT_OF_RANGE) { +#ifdef DEBUG_TRANSPORTER + ndbout << "Data transfer : out of range error \n" << endl; +#endif + goto tryagain; + } + if(err == SCI_ERR_SIZE_ALIGNMENT) { +#ifdef DEBUG_TRANSPORTER + ndbout << "Data transfer : aligne\n" << endl; +#endif + goto tryagain; + } + if(err == SCI_ERR_OFFSET_ALIGNMENT) { +#ifdef DEBUG_TRANSPORTER + ndbout << "Data transfer : offset alignment\n" << endl; +#endif + goto tryagain; + } + if(err == SCI_ERR_TRANSFER_FAILED) { + //(m_TargetSegm[m_StandbyAdapterId].writer)->heavyLock(); + if(getLinkStatus(m_ActiveAdapterId)) { + retry++; + if(retry>3) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR); + return false; + } + goto tryagain; + } + m_failCounter++; + Uint32 temp=m_ActiveAdapterId; + switch(m_swapCounter) { + case 0: + /**swap from active (0) to standby (1)*/ + if(getLinkStatus(m_StandbyAdapterId)) { +#ifdef DEBUG_TRANSPORTER + ndbout << "Swapping from 0 to 1 " << endl; +#endif + failoverShmWriter(); + SCIStoreBarrier(m_TargetSegm[m_StandbyAdapterId].sequence,0); + m_ActiveAdapterId=m_StandbyAdapterId; + m_StandbyAdapterId=temp; + SCIRemoveSequence((m_TargetSegm[m_StandbyAdapterId].sequence), + FLAGS, + &err); + if(err!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_REMOVE_SEQUENCE); + return false; + } + if(startSequence(m_ActiveAdapterId)!=SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout << "Start sequence failed" << endl; +#endif + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_START_SEQUENCE); + return false; + } + m_swapCounter++; +#ifdef DEBUG_TRANSPORTER + ndbout << "failover complete.." << endl; +#endif + goto tryagain; + } else { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR); + return false; + } + return false; + break; + case 1: + /** swap back from 1 to 0 + must check that the link is up */ + + if(getLinkStatus(m_StandbyAdapterId)) { + failoverShmWriter(); + m_ActiveAdapterId=m_StandbyAdapterId; + m_StandbyAdapterId=temp; +#ifdef DEBUG_TRANSPORTER + ndbout << "Swapping from 1 to 0 " << endl; +#endif + if(createSequence(m_ActiveAdapterId)!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_CREATE_SEQUENCE); + return false; + } + if(startSequence(m_ActiveAdapterId)!=SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout << "startSequence failed... disconnecting" << endl; +#endif + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_START_SEQUENCE); + return false; + } + + SCIRemoveSequence((m_TargetSegm[m_StandbyAdapterId].sequence) + , FLAGS, + &err); + if(err!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_REMOVE_SEQUENCE); + return false; + } + + if(createSequence(m_StandbyAdapterId)!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_CREATE_SEQUENCE); + return false; + } + + m_swapCounter=0; + +#ifdef DEBUG_TRANSPORTER + ndbout << "failover complete.." << endl; +#endif + goto tryagain; + + } else { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR); + return false; + } + + break; + default: + reportError(callbackObj, + remoteNodeId, TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR); + return false; + break; + } + } else { + SHM_Writer * writer = (m_TargetSegm[m_ActiveAdapterId].writer); + writer->updateWritePtr(sizeToSend); + + Uint32 sendLimit = writer->getBufferSize(); + sendLimit -= writer->getWriteIndex(); + + m_sendBuffer.m_dataSize = 0; + m_sendBuffer.m_forceSendLimit = sendLimit; + } + + } else { + /** + * If we end up here, the SCI segment is full. + */ +#ifdef DEBUG_TRANSPORTER + ndbout << "the segment is full for some reason" << endl; +#endif + return false; + } //if + } + + return true; +} // doSend() + + + +void SCI_Transporter::failoverShmWriter() { +#if 0 + (m_TargetSegm[m_StandbyAdapterId].writer) + ->copyIndexes((m_TargetSegm[m_StandbyAdapterId].writer)); +#endif +} //failoverShm + + +void SCI_Transporter::setupLocalSegment() +{ + + Uint32 sharedSize = 0; + sharedSize += 16; //SHM_Reader::getSharedSize(); + sharedSize += 16; //SHM_Writer::getSharedSize(); + sharedSize += 32; //SHM_Writer::getSharedSize(); + sharedSize =4096; //start of the buffer is page aligend + + Uint32 sizeOfBuffer = m_BufferSize; + + sizeOfBuffer -= sharedSize; + + Uint32 * localReadIndex = + (Uint32*)m_SourceSegm[m_ActiveAdapterId].mappedMemory; + Uint32 * localWriteIndex = + (Uint32*)(localReadIndex+ 1); + + Uint32 * localEndOfDataIndex = (Uint32*) + (localReadIndex + 2); + + m_localStatusFlag = (Uint32*)(localReadIndex + 3); + + Uint32 * sharedLockIndex = (Uint32*) + (localReadIndex + 4); + + Uint32 * sharedHeavyLock = (Uint32*) + (localReadIndex + 5); + + char * localStartOfBuf = (char*) + ((char*)m_SourceSegm[m_ActiveAdapterId].mappedMemory+sharedSize); + + + * localReadIndex = * localWriteIndex = 0; + * localEndOfDataIndex = sizeOfBuffer -1; + + const Uint32 slack = MAX_MESSAGE_SIZE; + + reader = new SHM_Reader(localStartOfBuf, + sizeOfBuffer, + slack, + localReadIndex, + localWriteIndex); + + * localReadIndex = 0; + * localWriteIndex = 0; + + reader->clear(); +} //setupLocalSegment + + + +void SCI_Transporter::setupRemoteSegment() +{ + Uint32 sharedSize = 0; + sharedSize += 16; //SHM_Reader::getSharedSize(); + sharedSize += 16; //SHM_Writer::getSharedSize(); + sharedSize += 32; + sharedSize =4096; //start of the buffer is page aligend + + + Uint32 sizeOfBuffer = m_BufferSize; + sizeOfBuffer -= sharedSize; + Uint32 * segPtr = (Uint32*) m_TargetSegm[m_StandbyAdapterId].mappedMemory ; + + Uint32 * remoteReadIndex2 = (Uint32*)segPtr; + Uint32 * remoteWriteIndex2 = (Uint32*) (segPtr + 1); + Uint32 * remoteEndOfDataIndex2 = (Uint32*) (segPtr + 2); + Uint32 * sharedLockIndex2 = (Uint32*) (segPtr + 3); + m_remoteStatusFlag2 = (Uint32*)(segPtr + 4); + Uint32 * sharedHeavyLock2 = (Uint32*) (segPtr + 5); + + + char * remoteStartOfBuf2 = ( char*)((char *)segPtr+sharedSize); + + segPtr = (Uint32*) m_TargetSegm[m_ActiveAdapterId].mappedMemory ; + + Uint32 * remoteReadIndex = (Uint32*)segPtr; + Uint32 * remoteWriteIndex = (Uint32*) (segPtr + 1); + Uint32 * remoteEndOfDataIndex = (Uint32*) (segPtr + 2); + Uint32 * sharedLockIndex = (Uint32*) (segPtr + 3); + m_remoteStatusFlag = (Uint32*)(segPtr + 4); + Uint32 * sharedHeavyLock = (Uint32*) (segPtr + 5); + + char * remoteStartOfBuf = ( char*)((char*)segPtr+(sharedSize)); + + * remoteReadIndex = * remoteWriteIndex = 0; + * remoteReadIndex2 = * remoteWriteIndex2 = 0; + * remoteEndOfDataIndex = sizeOfBuffer - 1; + * remoteEndOfDataIndex2 = sizeOfBuffer - 1; + + /** + * setup two writers. writer2 is used to mirror the changes of + * writer on the standby + * segment, so that in the case of a failover, we can switch + * to the stdby seg. quickly.* + */ + const Uint32 slack = MAX_MESSAGE_SIZE; + + writer = new SHM_Writer(remoteStartOfBuf, + sizeOfBuffer, + slack, + remoteReadIndex, + remoteWriteIndex); + + writer2 = new SHM_Writer(remoteStartOfBuf2, + sizeOfBuffer, + slack, + remoteReadIndex2, + remoteWriteIndex2); + + * remoteReadIndex = 0; + * remoteWriteIndex = 0; + + writer->clear(); + writer2->clear(); + + m_TargetSegm[0].writer=writer; + m_TargetSegm[1].writer=writer2; + + m_sendBuffer.m_forceSendLimit = writer->getBufferSize(); + + if(createSequence(m_ActiveAdapterId)!=SCI_ERR_OK) { + reportThreadError(remoteNodeId, TE_SCI_UNABLE_TO_CREATE_SEQUENCE); + doDisconnect(); + } + if(createSequence(m_StandbyAdapterId)!=SCI_ERR_OK) { + reportThreadError(remoteNodeId, TE_SCI_UNABLE_TO_CREATE_SEQUENCE); + doDisconnect(); + } + + +} //setupRemoteSegment + + +bool SCI_Transporter::connectImpl(Uint32 timeout) { + + sci_error_t err; + Uint32 offset = 0; + + if(!m_initLocal) { + if(initLocalSegment()!=SCI_ERR_OK){ + NdbSleep_MilliSleep(timeout); + //NDB SHOULD TERMINATE AND COMPUTER REBOOTED! + reportThreadError(localNodeId, TE_SCI_CANNOT_INIT_LOCALSEGMENT); + return false; + } + m_initLocal=true; + } + + if(!m_mapped ) { + + for(Uint32 i=0; i < m_adapters ; i++) { + m_TargetSegm[i].rhm[i].remoteHandle=0; + SCIConnectSegment(sciAdapters[i].scidesc, + &(m_TargetSegm[i].rhm[i].remoteHandle), + m_remoteNodes[i], + remoteSegmentId(localNodeId, remoteNodeId), + i, + 0, + 0, + 0, + 0, + &err); + + if(err != SCI_ERR_OK) { + NdbSleep_MilliSleep(timeout); + return false; + } + + } + + + // Map the remote memory segment into program space + for(Uint32 i=0; i < m_adapters ; i++) { + m_TargetSegm[i].mappedMemory = + SCIMapRemoteSegment((m_TargetSegm[i].rhm[i].remoteHandle), + &(m_TargetSegm[i].rhm[i].map), + offset, + m_BufferSize, + NULL, + FLAGS, + &err); + + + if(err!= SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("\nCannot map a segment to the remote node %d."); + ndbout_c("Error code 0x%x",m_RemoteSciNodeId, err); +#endif + //NDB SHOULD TERMINATE AND COMPUTER REBOOTED! + reportThreadError(remoteNodeId, TE_SCI_CANNOT_MAP_REMOTESEGMENT); + return false; + } + + + } + m_mapped=true; + setupRemoteSegment(); + setConnected(); +#ifdef DEBUG_TRANSPORTER + ndbout << "connected and mapped to segment : " << endl; + ndbout << "remoteNode: " << m_remoteNodes[0] << endl; + ndbout << "remoteNode: " << m_remotenodes[1] << endl; + ndbout << "remoteSegId: " + << remoteSegmentId(localNodeId, remoteNodeId) + << endl; +#endif + return true; + } + else { + return getConnectionStatus(); + } +} // connectImpl() + + +sci_error_t SCI_Transporter::createSequence(Uint32 adapterid) { + sci_error_t err; + SCICreateMapSequence((m_TargetSegm[adapterid].rhm[adapterid].map), + &(m_TargetSegm[adapterid].sequence), + SCI_FLAG_FAST_BARRIER, + &err); + + + return err; +} // createSequence() + + +sci_error_t SCI_Transporter::startSequence(Uint32 adapterid) { + + sci_error_t err; + /** Perform preliminary error check on an SCI adapter before starting a + * sequence of read and write operations on the mapped segment. + */ + m_SequenceStatus = SCIStartSequence( + (m_TargetSegm[adapterid].sequence), + FLAGS, &err); + + + // If there still is an error then data cannot be safely send + return err; +} // startSequence() + + + +bool SCI_Transporter::disconnectLocal() +{ + sci_error_t err; + m_ActiveAdapterId=0; + + /** Free resources used by a local segment + */ + + SCIUnmapSegment(m_SourceSegm[0].lhm[0].map,0,&err); + if(err!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_UNMAP_SEGMENT); + return false; + } + + SCIRemoveSegment((m_SourceSegm[m_ActiveAdapterId].localHandle), + FLAGS, + &err); + + if(err!=SCI_ERR_OK) { + reportError(callbackObj, remoteNodeId, TE_SCI_UNABLE_TO_REMOVE_SEGMENT); + return false; + } + + if(err == SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + printf("Local memory segment is unmapped and removed\n" ); +#endif + } + return true; +} // disconnectLocal() + + +bool SCI_Transporter::disconnectRemote() { + sci_error_t err; + for(Uint32 i=0; i<m_adapters; i++) { + /** + * Segment unmapped, disconnect from the remotely connected segment + */ + SCIUnmapSegment(m_TargetSegm[i].rhm[i].map,0,&err); + if(err!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_DISCONNECT_SEGMENT); + return false; + } + + SCIDisconnectSegment(m_TargetSegm[i].rhm[i].remoteHandle, + FLAGS, + &err); + if(err!=SCI_ERR_OK) { + reportError(callbackObj, + remoteNodeId, TE_SCI_UNABLE_TO_DISCONNECT_SEGMENT); + return false; + } +#ifdef DEBUG_TRANSPORTER + ndbout_c("Remote memory segment is unmapped and disconnected\n" ); +#endif + } + return true; +} // disconnectRemote() + + +SCI_Transporter::~SCI_Transporter() { + // Close channel to the driver +#ifdef DEBUG_TRANSPORTER + ndbout << "~SCITransporter does a disConnect" << endl; +#endif + doDisconnect(); + if(m_sendBuffer.m_buffer != NULL) + delete[] m_sendBuffer.m_buffer; +} // ~SCI_Transporter() + + + + +void SCI_Transporter::closeSCI() { + // Termination of SCI + sci_error_t err; + printf("\nClosing SCI Transporter...\n"); + + // Disconnect and remove remote segment + disconnectRemote(); + + // Unmap and remove local segment + + disconnectLocal(); + + // Closes an SCI virtual device + SCIClose(activeSCIDescriptor, FLAGS, &err); + + if(err != SCI_ERR_OK) + fprintf(stderr, + "\nCannot close SCI channel to the driver. Error code 0x%x", + err); + SCITerminate(); +} // closeSCI() + +Uint32 * +SCI_Transporter::getWritePtr(Uint32 lenBytes, Uint32 prio){ + + if(m_sendBuffer.full()){ + /**------------------------------------------------- + * Buffer was completely full. We have severe problems. + * ------------------------------------------------- + */ + if(!doSend()){ + return 0; + } + } + + Uint32 sz = m_sendBuffer.m_dataSize; + return &m_sendBuffer.m_buffer[sz]; +} + +void +SCI_Transporter::updateWritePtr(Uint32 lenBytes, Uint32 prio){ + + Uint32 sz = m_sendBuffer.m_dataSize; + sz += (lenBytes / 4); + m_sendBuffer.m_dataSize = sz; + + if(sz > m_PacketSize) { + /**------------------------------------------------- + * Buffer is full and we are ready to send. We will + * not wait since the signal is already in the buffer. + * Force flag set has the same indication that we + * should always send. If it is not possible to send + * we will not worry since we will soon be back for + * a renewed trial. + *------------------------------------------------- + */ + doSend(); + } +} + +enum SciStatus { + SCIDISCONNECT = 1, + SCICONNECTED = 2 +}; + +bool +SCI_Transporter::getConnectionStatus() { + if(*m_localStatusFlag == SCICONNECTED && + (*m_remoteStatusFlag == SCICONNECTED || + *m_remoteStatusFlag2 == SCICONNECTED)) + return true; + else + return false; +} + + +void +SCI_Transporter::setConnected() { + *m_remoteStatusFlag = SCICONNECTED; + *m_remoteStatusFlag2 = SCICONNECTED; + *m_localStatusFlag = SCICONNECTED; +} + + +void +SCI_Transporter::setDisconnect() { + if(getLinkStatus(m_ActiveAdapterId)) + *m_remoteStatusFlag = SCIDISCONNECT; + if(getLinkStatus(m_StandbyAdapterId)) + *m_remoteStatusFlag2 = SCIDISCONNECT; +} + + +bool +SCI_Transporter::checkConnected() { + if (*m_localStatusFlag == SCIDISCONNECT) { + return false; + } + else + return true; +} + +static bool init = false; + +bool +SCI_Transporter::initSCI() { + if(!init){ + sci_error_t error; + // Initialize SISCI library + SCIInitialize(0, &error); + if(error != SCI_ERR_OK) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("\nCannot initialize SISCI library."); + ndbout_c("\nInconsistency between SISCI library and SISCI driver.Error code 0x%x", error); +#endif + return false; + } + init = true; + } + return true; +} + + + + + diff --git a/ndb/src/common/transporter/SCI_Transporter.hpp b/ndb/src/common/transporter/SCI_Transporter.hpp new file mode 100644 index 00000000000..03496c2ce21 --- /dev/null +++ b/ndb/src/common/transporter/SCI_Transporter.hpp @@ -0,0 +1,390 @@ +/* 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 */ + +#ifndef SCI_Transporter_H +#define SCI_Transporter_H +#include "Transporter.hpp" +#include "SHM_Buffer.hpp" + + +#include <sisci_api.h> +#include <sisci_error.h> +#include <sisci_types.h> + +#include <ndb_types.h> + + /** + * The SCI Transporter + * + * The design goal of the SCI transporter is to deliver high performance + * data transfers (low latency, high bandwidth) combined with very high + * availability (failover support). + * High performance is an inherit feature of SCI and the, whereas failover + * support is implemented at the application level. + * In SCI the programming model is similar to the shared memory paradigm. + * A process on one node (A) allocates a memory segment and import the + * segment to its virtual address space. Another node (B) can connect to + * the segment and map this segment into its virtual address space. + * If A writes data to the segment, then B can read it and vice versa, through + * ordinary loads and stores. This is also called PIO (programmable IO), and + * is one thing that distinguish SCI from other interconnects such as, + * ethernet, Gig-e, Myrinet, and Infiniband. By using PIO, lower network + * latency is achieved, compared to the interconnects mentioned above. + * In order for NDB to utilize SCI, the SCI transporter relies on the + * SISCI api. The SISCI api provides a high level abstraction to the low + * level SCI driver called PCISCI driver. + * The SISCI api provides functions to setup, export, and import + * memory segments in a process virtual address space, and also functions to + * guarantee the correctness of data transfers between nodes. Basically, the + * + * In NDB Cluster, each SCI transporter creates a local segment + * that is mapped into the virtual address space. After the creation of the + * local segment, the SCI transporter connects to a segment created by another + * transporter at a remote node, and the maps the remote segment into its + * virtual address space. However, since NDB Cluster relies on redundancy + * at the network level, by using dual SCI adapters communica + * + * + */ + + +/** + * class SCITransporter + * @brief - main class for the SCI transporter. + */ +class SCI_Transporter : public Transporter { + friend class TransporterRegistry; +public: + + /** + * Init the transporter. Allocate sendbuffers and open a SCI virtual device + * for each adapter. + * @return true if successful, otherwize false + */ + bool initTransporter(); + + + /** + * Creates a sequence for error checking. + * @param adapterid the adapter on which to create a new sequence. + * @return SCI_ERR_OK if ok, otherwize something else. + */ + sci_error_t createSequence(Uint32 adapterid); + + + /** + * starts a sequence for error checking. + * The actual checking that a sequence is correct is done implicitly + * in SCIMemCpy (in doSend). + * @param adapterid the adapter on which to start the sequence. + * @return SCI_ERR_OK if ok, otherwize something else. + */ + sci_error_t startSequence(Uint32 adapterid); + + + /** Initiate Local Segment: create a memory segment, + * prepare a memory segment, map the local segment + * into memory space and make segment available. + * @return SCI_ERR_OK if ok, otherwize something else. + */ + sci_error_t initLocalSegment(); + + /** + * Calculate the segment id for the remote segment + * @param localNodeId - local id (e.g. 1 = mgm , 2 = ndb.2 etc.) + * @param remoteNodeId - remote id (e.g. 1 = mgm , 2 = ndb.2 etc.) + * @return a segment id + */ + Uint32 remoteSegmentId(Uint16 localNodeId, Uint16 remoteNodeId); + + // Get local segment id (inline) + Uint32 hostSegmentId(Uint16 localNodeId, Uint16 remoteNodeId); + + /** + * closeSCI closes the SCI virtual device + */ + void closeSCI(); + + + /** + * Check the status of the remote node, + * if it is connected or has disconnected + * @return true if connected, otherwize false. + */ + bool checkConnected(); + + /** + * Check if the segment are properly connected to each other (remotely + * and locally). + * @return True if the both the local segment is mapped and the + * remote segment is mapped. Otherwize false. + */ + bool getConnectionStatus(); + +private: + SCI_Transporter(Uint32 packetSize, + Uint32 bufferSize, + Uint32 nAdapters, + Uint16 remoteSciNodeId0, + Uint16 remoteSciNodeId1, + NodeId localNodeID, + NodeId remoteNodeID, + int byteorder, + bool compression, + bool checksum, + bool signalId, + Uint32 reportFreq = 4096); + + /** + * Destructor. Disconnects the transporter. + */ + ~SCI_Transporter(); + bool m_mapped; + bool m_initLocal; + bool m_sciinit; + Uint32 m_swapCounter; + Uint32 m_failCounter; + /** + * For statistics on transfered packets + */ +#ifdef DEBUG_TRANSPORTER + Uint32 i1024; + Uint32 i2048; + Uint32 i2049; + Uint32 i10242048; + Uint32 i20484096; + Uint32 i4096; + Uint32 i4097; +#endif + + volatile Uint32 * m_localStatusFlag; + volatile Uint32 * m_remoteStatusFlag; + volatile Uint32 * m_remoteStatusFlag2; + + struct { + Uint32 * m_buffer; // The buffer + Uint32 m_dataSize; // No of words in buffer + Uint32 m_bufferSize; // Buffer size + Uint32 m_forceSendLimit; // Send when buffer is this full + + bool full() const { return (m_dataSize * 4) > m_forceSendLimit ;} + } m_sendBuffer; + + SHM_Reader * reader; + SHM_Writer * writer; + SHM_Writer * writer2; + + /** + * Statistics + */ + Uint32 m_reportFreq; + + + Uint32 m_adapters; + Uint32 m_numberOfRemoteNodes; + + Uint16* m_remoteNodes; + + typedef struct SciAdapter { + sci_desc_t scidesc; + Uint32 localSciNodeId; + bool linkStatus; + } SciAdapter; + + SciAdapter* sciAdapters; + Uint32 m_ActiveAdapterId; + Uint32 m_StandbyAdapterId; + + typedef struct sourceSegm { + sci_local_segment_t localHandle; // Handle to local segment to be mapped + struct localHandleMap { + sci_map_t map; // Handle to the new mapped segment. + // 2 = max adapters in one node + } lhm[2]; + + volatile void *mappedMemory; // Used when reading + } sourceSegm; + + typedef struct targetSegm { + struct remoteHandleMap { + sci_remote_segment_t remoteHandle; //Handle to local segment to be mapped + sci_map_t map; //Handle to the new mapped segment + } rhm[2]; + + sci_sequence_status_t m_SequenceStatus; // Used for error checking + sci_sequence_t sequence; + volatile void * mappedMemory; // Used when writing + SHM_Writer * writer; + } targetSegm; + + sci_sequence_status_t m_SequenceStatus; // Used for error checking + + + // Shared between all SCI users active=(either prim or second) + sci_desc_t activeSCIDescriptor; + + sourceSegm* m_SourceSegm; // Local segment reference + targetSegm* m_TargetSegm; // Remote segment reference + + Uint32 m_LocalAdapterId; // Adapter Id + Uint16 m_LocalSciNodeId; // The SCI-node Id of this machine (adapter 0) + Uint16 m_LocalSciNodeId1; // The SCI-node Id of this machine (adapter 1) + Uint16 m_RemoteSciNodeId; // The SCI-node Id of remote machine (adapter 0) + Uint16 m_RemoteSciNodeId1; // The SCI-node Id of remote machine (adapter 1) + + Uint32 m_PacketSize; // The size of each data packet + Uint32 m_BufferSize; // Mapped SCI buffer size + + Uint32 * getWritePtr(Uint32 lenBytes, Uint32 prio); + void updateWritePtr(Uint32 lenBytes, Uint32 prio); + + /** + * doSend. Copies the data from the source (the send buffer) to the + * shared mem. segment. + * Sequences are used for error checking. + * If an error occurs, the transfer is retried. + * If the link that we need to swap to is broken, we will disconnect. + * @return Returns true if datatransfer ok. If not retriable + * then false is returned. + */ + bool doSend(); + + /** + * @param adapterNo the adapter for which to retrieve the node id. + * @return Returns the node id for an adapter. + */ + Uint32 getLocalNodeId(Uint32 adapterNo); + + bool hasDataToRead() const { + return reader->empty() == false; + } + + bool hasDataToSend() const { + return m_sendBuffer.m_dataSize > 0; + } + + /** + * Make the local segment unavailable, no new connections will be accepted. + * @return Returns true if the segment was successfully disconnected. + */ + bool disconnectLocal(); + + /** + * Make the local segment unavailable, no new connections will be accepted. + * @return Returns true if the segment was successfully disconnected. + */ + bool disconnectRemote(); + + void resetToInitialState(); + + /** + * It is always possible to send data with SCI! + * @return True (always) + */ + bool sendIsPossible(struct timeval * timeout); + + + void getReceivePtr(Uint32 ** ptr, Uint32 ** eod){ + reader->getReadPtr(* ptr, * eod); + } + + void updateReceivePtr(Uint32 * ptr){ + reader->updateReadPtr(ptr); + } + + /** + * Corresponds to SHM_Transporter::setupBuffers() + * Initiates the start pointer of the buffer and read pointers. + * Initiate the localSegment for the SHM reader. + */ + void setupLocalSegment(); + + /** + * Initiate the remoteSegment for the SHM writer + */ + void setupRemoteSegment(); + + /** + * Set the connect flag in the remote memory segment (write through) + */ + void setConnected(); + + /** + * Set the disconnect flag in the remote memory segment (write through) + */ + void setDisconnect(); + + /** + * Check if there is a link between the adapter and the switch + * @param adapterNo the adapter for which to retrieve the link status. + * @return Returns true if there is a link between adapter and switch. + * Otherwize false is returned and the cables must be checked. + */ + bool getLinkStatus(Uint32 adapterNo); + + /** + * failoverShmWriter takes the state of the active writer and inserts into + * the standby writer. + */ + void failoverShmWriter(); + + +protected: + + /** Perform a connection between segment + * This is a client node, trying to connect to a remote segment. + * @param timeout, the time the connect thread sleeps before + * retrying. + * @return Returns true on success, otherwize falser + */ + bool connectImpl(Uint32 timeOutMillis); + + /** + * We will disconnect if: + * -# the other node has disconnected from us + * -# unrecoverable error in transmission, on both adapters + * -# if we are shutdown properly + */ + void disconnectImpl(); + + static bool initSCI(); +}; + + +/** The theLocalAdapterId combined with the theRemoteNodeId constructs + * (SCI ids)* a unique identifier for the local segment + */ +inline +Uint32 +SCI_Transporter::hostSegmentId(Uint16 SciLocalNodeId, + Uint16 SciRemoteNodeId) { + + return (SciLocalNodeId << 16) | SciRemoteNodeId; +} + +/** The theLocalAdapterId combined with the theRemoteNodeId constructs + * (SCI ids)* a unique identifier for the remote segment + */ +inline +Uint32 +SCI_Transporter::remoteSegmentId(Uint16 SciLocalNodeId, + Uint16 SciRemoteNodeId) { + + return (SciRemoteNodeId << 16) | SciLocalNodeId; +} + + +#endif diff --git a/ndb/src/common/transporter/SHM_Buffer.hpp b/ndb/src/common/transporter/SHM_Buffer.hpp new file mode 100644 index 00000000000..43250853fee --- /dev/null +++ b/ndb/src/common/transporter/SHM_Buffer.hpp @@ -0,0 +1,217 @@ +/* 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 */ + +#ifndef SHM_BUFFER_HPP +#define SHM_BUFFER_HPP + +#include <stdio.h> +#include <ndb_types.h> +#include <NdbSleep.h> +#include <assert.h> + +/** + * These classes implement a circular buffer + * + * One reader and one writer + */ + +/** + * SHM_Reader + * + * Use as follows: + * getReadPtr(ptr, sz); + * for(int i = 0; i<sz; i++) + * printf("%c\n", ptr[i]); + * updateReadPtr(sz); + */ +class SHM_Reader { +public: + SHM_Reader(char * const _startOfBuffer, + Uint32 _sizeOfBuffer, + Uint32 _slack, + Uint32 * _readIndex, + Uint32 * _writeIndex) : + m_startOfBuffer(_startOfBuffer), + m_totalBufferSize(_sizeOfBuffer), + m_bufferSize(_sizeOfBuffer - _slack), + m_sharedReadIndex(_readIndex), + m_sharedWriteIndex(_writeIndex) + { + } + + void clear() { + m_readIndex = * m_sharedReadIndex; + } + + /** + * + */ + inline bool empty() const; + + /** + * Get read pointer + * + * returns ptr - where to start reading + * sz - how much can I read + */ + inline void getReadPtr(Uint32 * & ptr, Uint32 * & eod); + + /** + * Update read ptr + */ + inline void updateReadPtr(Uint32 * readPtr); + +private: + char * const m_startOfBuffer; + Uint32 m_totalBufferSize; + Uint32 m_bufferSize; + Uint32 m_readIndex; + + Uint32 * m_sharedReadIndex; + Uint32 * m_sharedWriteIndex; +}; + +inline +bool +SHM_Reader::empty() const{ + bool ret = (m_readIndex == * m_sharedWriteIndex); + return ret; +} + +/** + * Get read pointer + * + * returns ptr - where to start reading + * sz - how much can I read + */ +inline +void +SHM_Reader::getReadPtr(Uint32 * & ptr, Uint32 * & eod){ + + Uint32 tReadIndex = m_readIndex; + Uint32 tWriteIndex = * m_sharedWriteIndex; + + ptr = (Uint32*)&m_startOfBuffer[tReadIndex]; + + if(tReadIndex <= tWriteIndex){ + eod = (Uint32*)&m_startOfBuffer[tWriteIndex]; + } else { + eod = (Uint32*)&m_startOfBuffer[m_bufferSize]; + } +} + +/** + * Update read ptr + */ +inline +void +SHM_Reader::updateReadPtr(Uint32 * ptr){ + + Uint32 tReadIndex = ((char *)ptr) - m_startOfBuffer; + + assert(tReadIndex < m_totalBufferSize); + + if(tReadIndex >= m_bufferSize){ + tReadIndex = 0; //-= m_bufferSize; + } + + m_readIndex = tReadIndex; + * m_sharedReadIndex = tReadIndex; +} + +#define WRITER_SLACK 4 + +class SHM_Writer { +public: + SHM_Writer(char * const _startOfBuffer, + Uint32 _sizeOfBuffer, + Uint32 _slack, + Uint32 * _readIndex, + Uint32 * _writeIndex) : + m_startOfBuffer(_startOfBuffer), + m_totalBufferSize(_sizeOfBuffer), + m_bufferSize(_sizeOfBuffer - _slack), + m_sharedReadIndex(_readIndex), + m_sharedWriteIndex(_writeIndex) + { + } + + void clear() { + m_writeIndex = * m_sharedWriteIndex; + } + + inline char * getWritePtr(Uint32 sz); + inline void updateWritePtr(Uint32 sz); + + inline Uint32 getWriteIndex() const { return m_writeIndex;} + inline Uint32 getBufferSize() const { return m_bufferSize;} + + inline void copyIndexes(SHM_Writer * standbyWriter); + +private: + char * const m_startOfBuffer; + Uint32 m_totalBufferSize; + Uint32 m_bufferSize; + + Uint32 m_writeIndex; + + Uint32 * m_sharedReadIndex; + Uint32 * m_sharedWriteIndex; +}; + +inline +char * +SHM_Writer::getWritePtr(Uint32 sz){ + Uint32 tReadIndex = * m_sharedReadIndex; + Uint32 tWriteIndex = m_writeIndex; + + char * ptr = &m_startOfBuffer[tWriteIndex]; + + Uint32 free; + if(tReadIndex <= tWriteIndex){ + free = m_bufferSize + tReadIndex - tWriteIndex; + } else { + free = tReadIndex - tWriteIndex; + } + + sz += 4; + if(sz < free){ + return ptr; + } + + return 0; +} + +inline +void +SHM_Writer::updateWritePtr(Uint32 sz){ + + assert(m_writeIndex == * m_sharedWriteIndex); + + Uint32 tWriteIndex = m_writeIndex; + tWriteIndex += sz; + + assert(tWriteIndex < m_totalBufferSize); + + if(tWriteIndex >= m_bufferSize){ + tWriteIndex = 0; //-= m_bufferSize; + } + + m_writeIndex = tWriteIndex; + * m_sharedWriteIndex = tWriteIndex; +} + +#endif diff --git a/ndb/src/common/transporter/SHM_Transporter.cpp b/ndb/src/common/transporter/SHM_Transporter.cpp new file mode 100644 index 00000000000..f18b775efa4 --- /dev/null +++ b/ndb/src/common/transporter/SHM_Transporter.cpp @@ -0,0 +1,238 @@ +/* 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 "SHM_Transporter.hpp" +#include "TransporterInternalDefinitions.hpp" +#include <TransporterCallback.hpp> +#include <NdbSleep.h> +#include <NdbOut.hpp> + +#include <stdio.h> +#include <stdlib.h> + +#ifdef NDB_WIN32 +#include <windows.h> +#else +#include <sys/ipc.h> +#include <sys/shm.h> +#endif + + +SHM_Transporter::SHM_Transporter(NodeId lNodeId, + NodeId rNodeId, + key_t _shmKey, + Uint32 _shmSize, + bool compression, + bool checksum, + bool signalId) : + Transporter(lNodeId, + rNodeId, + 0, + compression, + checksum, + signalId), + isServer(lNodeId < rNodeId), + shmKey(_shmKey), + shmSize(_shmSize) +{ + _shmSegCreated = false; + _attached = false; + + shmBuf = 0; + reader = 0; + writer = 0; + + setupBuffersDone=false; +#ifdef DEBUG_TRANSPORTER + printf("shm key (%d - %d) = %d\n", lNodeId, rNodeId, shmKey); +#endif +} + +SHM_Transporter::~SHM_Transporter(){ + doDisconnect(); +} + +bool +SHM_Transporter::initTransporter(){ + return true; +} + +bool +SHM_Transporter::connectImpl(Uint32 timeOutMillis){ + bool res; + if(isServer) + res = connectServer(timeOutMillis); + else + res = connectClient(timeOutMillis); + return res; +} + +void +SHM_Transporter::setupBuffers(){ + Uint32 sharedSize = 0; + sharedSize += 28; //SHM_Reader::getSharedSize(); + sharedSize += 28; //SHM_Writer::getSharedSize(); + + const Uint32 slack = MAX_MESSAGE_SIZE; + + /** + * NOTE: There is 7th shared variable in Win2k (sharedCountAttached). + */ + Uint32 sizeOfBuffer = shmSize; + sizeOfBuffer -= 2*sharedSize; + sizeOfBuffer /= 2; + + Uint32 * base1 = (Uint32*)shmBuf; + + Uint32 * sharedReadIndex1 = base1; + Uint32 * sharedWriteIndex1 = base1 + 1; + serverStatusFlag = base1 + 4; + char * startOfBuf1 = shmBuf+sharedSize; + + Uint32 * base2 = (Uint32*)(shmBuf + sizeOfBuffer + sharedSize); + Uint32 * sharedReadIndex2 = base2; + Uint32 * sharedWriteIndex2 = base2 + 1; + clientStatusFlag = base2 + 4; + char * startOfBuf2 = ((char *)base2)+sharedSize; + + * sharedReadIndex2 = * sharedWriteIndex2 = 0; + + if(isServer){ + * serverStatusFlag = 0; + reader = new SHM_Reader(startOfBuf1, + sizeOfBuffer, + slack, + sharedReadIndex1, + sharedWriteIndex1); + + writer = new SHM_Writer(startOfBuf2, + sizeOfBuffer, + slack, + sharedReadIndex2, + sharedWriteIndex2); + + * sharedReadIndex1 = 0; + * sharedWriteIndex2 = 0; + + * sharedReadIndex2 = 0; + * sharedWriteIndex1 = 0; + + reader->clear(); + writer->clear(); + + * serverStatusFlag = 1; + +#ifdef DEBUG_TRANSPORTER + printf("-- (%d - %d) - Server -\n", localNodeId, remoteNodeId); + printf("Reader at: %d (%p)\n", startOfBuf1 - shmBuf, startOfBuf1); + printf("sharedReadIndex1 at %d (%p) = %d\n", + (char*)sharedReadIndex1-shmBuf, + sharedReadIndex1, *sharedReadIndex1); + printf("sharedWriteIndex1 at %d (%p) = %d\n", + (char*)sharedWriteIndex1-shmBuf, + sharedWriteIndex1, *sharedWriteIndex1); + + printf("Writer at: %d (%p)\n", startOfBuf2 - shmBuf, startOfBuf2); + printf("sharedReadIndex2 at %d (%p) = %d\n", + (char*)sharedReadIndex2-shmBuf, + sharedReadIndex2, *sharedReadIndex2); + printf("sharedWriteIndex2 at %d (%p) = %d\n", + (char*)sharedWriteIndex2-shmBuf, + sharedWriteIndex2, *sharedWriteIndex2); + + printf("sizeOfBuffer = %d\n", sizeOfBuffer); +#endif + } else { + * clientStatusFlag = 0; + reader = new SHM_Reader(startOfBuf2, + sizeOfBuffer, + slack, + sharedReadIndex2, + sharedWriteIndex2); + + writer = new SHM_Writer(startOfBuf1, + sizeOfBuffer, + slack, + sharedReadIndex1, + sharedWriteIndex1); + + * sharedReadIndex2 = 0; + * sharedWriteIndex1 = 0; + + reader->clear(); + writer->clear(); + * clientStatusFlag = 1; +#ifdef DEBUG_TRANSPORTER + printf("-- (%d - %d) - Client -\n", localNodeId, remoteNodeId); + printf("Reader at: %d (%p)\n", startOfBuf2 - shmBuf, startOfBuf2); + printf("sharedReadIndex2 at %d (%p) = %d\n", + (char*)sharedReadIndex2-shmBuf, + sharedReadIndex2, *sharedReadIndex2); + printf("sharedWriteIndex2 at %d (%p) = %d\n", + (char*)sharedWriteIndex2-shmBuf, + sharedWriteIndex2, *sharedWriteIndex2); + + printf("Writer at: %d (%p)\n", startOfBuf1 - shmBuf, startOfBuf1); + printf("sharedReadIndex1 at %d (%p) = %d\n", + (char*)sharedReadIndex1-shmBuf, + sharedReadIndex1, *sharedReadIndex1); + printf("sharedWriteIndex1 at %d (%p) = %d\n", + (char*)sharedWriteIndex1-shmBuf, + sharedWriteIndex1, *sharedWriteIndex1); + + printf("sizeOfBuffer = %d\n", sizeOfBuffer); +#endif + } +#ifdef DEBUG_TRANSPORTER + printf("Mapping from %p to %p\n", shmBuf, shmBuf+shmSize); +#endif +} + +#if 0 +SendStatus +SHM_Transporter::prepareSend(const SignalHeader * const signalHeader, + Uint8 prio, + const Uint32 * const signalData, + const LinearSegmentPtr ptr[3], + bool force){ + + if(isConnected()){ + + const Uint32 lenBytes = m_packer.getMessageLength(signalHeader, ptr); + + Uint32 * insertPtr = (Uint32 *)writer->getWritePtr(lenBytes); + + if(insertPtr != 0){ + + m_packer.pack(insertPtr, prio, signalHeader, signalData, ptr); + + /** + * Do funky membar stuff + */ + + writer->updateWritePtr(lenBytes); + return SEND_OK; + + } else { + // NdbSleep_MilliSleep(3); + //goto tryagain; + return SEND_BUFFER_FULL; + } + } + return SEND_DISCONNECTED; +} +#endif diff --git a/ndb/src/common/transporter/SHM_Transporter.hpp b/ndb/src/common/transporter/SHM_Transporter.hpp new file mode 100644 index 00000000000..da4566515e3 --- /dev/null +++ b/ndb/src/common/transporter/SHM_Transporter.hpp @@ -0,0 +1,156 @@ +/* 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 */ + +#ifndef SHM_Transporter_H +#define SHM_Transporter_H + +#include "Transporter.hpp" +#include "SHM_Buffer.hpp" + +#ifdef NDB_WIN32 +typedef Uint32 key_t; +#endif + +/** + * class SHMTransporter + * @brief - main class for the SHM transporter. + */ + +class SHM_Transporter : public Transporter { + friend class TransporterRegistry; +public: + SHM_Transporter(NodeId lNodeId, + NodeId rNodeId, + key_t shmKey, + Uint32 shmSize, + bool compression, + bool checksum, + bool signalId); + + /** + * SHM destructor + */ + virtual ~SHM_Transporter(); + + /** + * Do initialization + */ + bool initTransporter(); + + Uint32 * getWritePtr(Uint32 lenBytes, Uint32 prio){ + return (Uint32 *)writer->getWritePtr(lenBytes); + } + + void updateWritePtr(Uint32 lenBytes, Uint32 prio){ + writer->updateWritePtr(lenBytes); + } + + void getReceivePtr(Uint32 ** ptr, Uint32 ** eod){ + reader->getReadPtr(* ptr, * eod); + } + + void updateReceivePtr(Uint32 * ptr){ + reader->updateReadPtr(ptr); + } + +protected: + /** + * disconnect a segmnet + * -# deletes the shm buffer associated with a segment + * -# marks the segment for removal + */ + void disconnectImpl(); + + /** + * Invokes the connectServer or connectClient. + * @param timeOutMillis - the timeout the connect thread waits before + * retrying. + * @return True if connectImpl successful, otherwise false. + */ + bool connectImpl(Uint32 timeOutMillis); + + /** + * Blocking + * + * -# Create shm segment + * -# Attach to it + * -# Wait for someone to attach (max wait = timeout), then rerun again + * until connection established. + * @param timeOutMillis - the time to sleep before (ms) trying again. + * @returns - True if the server managed to hook up with the client, + * i.e., both agrees that the other one has setup the segment. + * Otherwise false. + */ + bool connectServer(Uint32 timeOutMillis); + + /** + * Blocking + * + * -# Attach to shm segment + * -# Check if the segment is setup + * -# Check if the server set it up + * -# If all clear, return. + * @param timeOutMillis - the time to sleep before (ms) trying again. + * @returns - True if the client managed to hook up with the server, + * i.e., both agrees that the other one has setup the segment. + * Otherwise false. + */ + bool connectClient(Uint32 timeOutMillis); + + + /** + * Check if there are two processes attached to the segment (a connection) + * @return - True if the above holds. Otherwise false. + */ + bool checkConnected(); + + + /** + * Initialises the SHM_Reader and SHM_Writer on the segment + */ + void setupBuffers(); + +private: + bool _shmSegCreated; + bool _attached; + + const bool isServer; + key_t shmKey; + volatile Uint32 * serverStatusFlag; + volatile Uint32 * clientStatusFlag; + bool setupBuffersDone; + +#ifdef NDB_WIN32 + HANDLE hFileMapping; +#else + int shmId; +#endif + + int shmSize; + char * shmBuf; + + SHM_Reader * reader; + SHM_Writer * writer; + + /** + * @return - True if the reader has data to read on its segment. + */ + bool hasDataToRead() const { + return reader->empty() == false; + } +}; + +#endif diff --git a/ndb/src/common/transporter/SHM_Transporter.unix.cpp b/ndb/src/common/transporter/SHM_Transporter.unix.cpp new file mode 100644 index 00000000000..975c1191aea --- /dev/null +++ b/ndb/src/common/transporter/SHM_Transporter.unix.cpp @@ -0,0 +1,179 @@ +/* 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 "SHM_Transporter.hpp" +#include "TransporterInternalDefinitions.hpp" +#include <TransporterCallback.hpp> +#include <NdbSleep.h> +#include <NdbOut.hpp> + +#include <stdio.h> + + +#include <sys/ipc.h> +#include <sys/shm.h> + + + +bool +SHM_Transporter::connectServer(Uint32 timeOutMillis){ + if(!_shmSegCreated){ + shmId = shmget(shmKey, shmSize, IPC_CREAT | 960); + if(shmId == -1){ + perror("shmget: "); + reportThreadError(remoteNodeId, TE_SHM_UNABLE_TO_CREATE_SEGMENT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + _shmSegCreated = true; + } + + if(!_attached){ + shmBuf = (char *)shmat(shmId, 0, 0); + if(shmBuf == 0){ + perror("shmat: "); + reportThreadError(remoteNodeId, TE_SHM_UNABLE_TO_ATTACH_SEGMENT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + _attached = true; + } + + struct shmid_ds info; + const int res = shmctl(shmId, IPC_STAT, &info); + if(res == -1){ + perror("shmctl: "); + reportThreadError(remoteNodeId, TE_SHM_IPC_STAT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + + if(info.shm_nattch == 2 && !setupBuffersDone) { + setupBuffers(); + setupBuffersDone=true; + } + + if(setupBuffersDone) { + NdbSleep_MilliSleep(timeOutMillis); + if(*serverStatusFlag==1 && *clientStatusFlag==1) + return true; + } + + + if(info.shm_nattch > 2){ + reportThreadError(remoteNodeId, TE_SHM_DISCONNECT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + + NdbSleep_MilliSleep(timeOutMillis); + return false; +} + +bool +SHM_Transporter::connectClient(Uint32 timeOutMillis){ + if(!_shmSegCreated){ + + shmId = shmget(shmKey, shmSize, 0); + if(shmId == -1){ + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + _shmSegCreated = true; + } + + if(!_attached){ + shmBuf = (char *)shmat(shmId, 0, 0); + if(shmBuf == 0){ + reportThreadError(remoteNodeId, TE_SHM_UNABLE_TO_ATTACH_SEGMENT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + _attached = true; + } + + struct shmid_ds info; + + const int res = shmctl(shmId, IPC_STAT, &info); + if(res == -1){ + reportThreadError(remoteNodeId, TE_SHM_IPC_STAT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + + + if(info.shm_nattch == 2 && !setupBuffersDone) { + setupBuffers(); + setupBuffersDone=true; + } + + if(setupBuffersDone) { + NdbSleep_MilliSleep(timeOutMillis); + if(*serverStatusFlag==1 && *clientStatusFlag==1) + return true; + } + + if(info.shm_nattch > 2){ + reportThreadError(remoteNodeId, TE_SHM_DISCONNECT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + + NdbSleep_MilliSleep(timeOutMillis); + return false; +} + +bool +SHM_Transporter::checkConnected(){ + struct shmid_ds info; + const int res = shmctl(shmId, IPC_STAT, &info); + if(res == -1){ + reportError(callbackObj, remoteNodeId, TE_SHM_IPC_STAT); + return false; + } + + if(info.shm_nattch != 2){ + reportError(callbackObj, remoteNodeId, TE_SHM_DISCONNECT); + return false; + } + return true; +} + +void +SHM_Transporter::disconnectImpl(){ + if(_attached){ + const int res = shmdt(shmBuf); + if(res == -1){ + perror("shmdelete: "); + return; + } + _attached = false; + if(!isServer && _shmSegCreated) + _shmSegCreated = false; + } + + if(isServer && _shmSegCreated){ + const int res = shmctl(shmId, IPC_RMID, 0); + if(res == -1){ + reportError(callbackObj, remoteNodeId, TE_SHM_UNABLE_TO_REMOVE_SEGMENT); + return; + } + _shmSegCreated = false; + } + setupBuffersDone=false; +} + diff --git a/ndb/src/common/transporter/SHM_Transporter.win32.cpp b/ndb/src/common/transporter/SHM_Transporter.win32.cpp new file mode 100644 index 00000000000..4ba52c9179d --- /dev/null +++ b/ndb/src/common/transporter/SHM_Transporter.win32.cpp @@ -0,0 +1,172 @@ +/* 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 "SHM_Transporter.hpp" +#include "TransporterInternalDefinitions.hpp" +#include <TransporterCallback.hpp> +#include <NdbSleep.h> +#include <NdbOut.hpp> + +#include <stdio.h> + +#include <windows.h> + + +bool +SHM_Transporter::connectServer(Uint32 timeOutMillis){ + if(!_shmSegCreated) + { + char szName[32]; + sprintf(szName, "ndb%lu", shmKey); + hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, + 0, + PAGE_READWRITE, + 0, + shmSize, + szName); + + if(!hFileMapping) + { + reportThreadError(remoteNodeId, TE_SHM_UNABLE_TO_CREATE_SEGMENT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + _shmSegCreated = true; + } + + if(!_attached){ + shmBuf = (char*)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if(shmBuf == 0){ + reportThreadError(remoteNodeId, TE_SHM_UNABLE_TO_ATTACH_SEGMENT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + volatile Uint32 * sharedCountAttached = + (volatile Uint32*)(shmBuf + 6*sizeof(Uint32*)); + ++*sharedCountAttached; + _attached = true; + } + + volatile Uint32 * sharedCountAttached = + (volatile Uint32*)(shmBuf + 6*sizeof(Uint32*)); + + if(*sharedCountAttached == 2 && !setupBuffersDone) { + setupBuffers(); + setupBuffersDone=true; + } + if(*sharedCountAttached > 2) { + reportThreadError(remoteNodeId, TE_SHM_DISCONNECT); + return false; + } + + if(setupBuffersDone) { + NdbSleep_MilliSleep(timeOutMillis); + if(*serverStatusFlag==1 && *clientStatusFlag==1) + return true; + } + + NdbSleep_MilliSleep(timeOutMillis); + return false; +} + +bool +SHM_Transporter::connectClient(Uint32 timeOutMillis){ + if(!_shmSegCreated) + { + char szName[32]; + sprintf(szName, "ndb%lu", shmKey); + hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName); + + if(!hFileMapping) + { + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + _shmSegCreated = true; + } + + if(!_attached){ + shmBuf = (char*)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if(shmBuf == 0){ + reportThreadError(remoteNodeId, TE_SHM_UNABLE_TO_ATTACH_SEGMENT); + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + volatile Uint32 * sharedCountAttached = + (volatile Uint32*)(shmBuf + 6*sizeof(Uint32*)); + ++*sharedCountAttached; + _attached = true; + } + + volatile Uint32 * sharedCountAttached = + (volatile Uint32*)(shmBuf + 6*sizeof(Uint32*)); + + if(*sharedCountAttached == 2 && !setupBuffersDone) { + setupBuffers(); + setupBuffersDone=true; + } + + if(setupBuffersDone) { + if(*serverStatusFlag==1 && *clientStatusFlag==1) + return true; + } + NdbSleep_MilliSleep(timeOutMillis); + return false; + +} + + +bool +SHM_Transporter::checkConnected(){ + volatile Uint32 * sharedCountAttached = + (volatile Uint32*)(shmBuf + 6*sizeof(Uint32*)); + if(*sharedCountAttached != 2) { + reportError(callbackObj, remoteNodeId, TE_SHM_DISCONNECT); + return false; + } + return true; +} + +void +SHM_Transporter::disconnectImpl(){ + if(_attached) { + volatile Uint32 * sharedCountAttached = + (volatile Uint32*)(shmBuf + 6*sizeof(Uint32*)); + + --*sharedCountAttached; + + if(!UnmapViewOfFile(shmBuf)) { + reportError(callbackObj, remoteNodeId, TE_SHM_UNABLE_TO_REMOVE_SEGMENT); + return; + } + + _attached = false; + if(!isServer && _shmSegCreated) + _shmSegCreated = false; + } + + if(_shmSegCreated){ + if(!CloseHandle(hFileMapping)) { + reportError(callbackObj, remoteNodeId, TE_SHM_UNABLE_TO_REMOVE_SEGMENT); + return; + } + _shmSegCreated = false; + } + setupBuffersDone=false; + +} + diff --git a/ndb/src/common/transporter/SendBuffer.cpp b/ndb/src/common/transporter/SendBuffer.cpp new file mode 100644 index 00000000000..58cad96931f --- /dev/null +++ b/ndb/src/common/transporter/SendBuffer.cpp @@ -0,0 +1,89 @@ +/* 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 "SendBuffer.hpp" +#include "TransporterInternalDefinitions.hpp" + +SendBuffer::SendBuffer(Uint32 bufSize) { + + sizeOfBuffer = bufSize; + if(sizeOfBuffer < MAX_MESSAGE_SIZE) + sizeOfBuffer = 2 * MAX_MESSAGE_SIZE; + startOfBuffer = NULL; + + // Initalise pointers + endOfBuffer = NULL; + insertPtr = NULL; + sendPtr = NULL; + sendDataSize = 0; + dataSize = 0; +} + +bool +SendBuffer::initBuffer(Uint32 aRemoteNodeId) { + + // Allocate memory for the buffer +#ifdef DEBUG_TRANSPORTER + ndbout << "Allocating " << sizeOfBuffer << " bytes for send buffer" << endl; +#endif + + startOfBuffer = new Uint32[(sizeOfBuffer >> 2) + 1]; + endOfBuffer = startOfBuffer + (sizeOfBuffer >> 2); + + emptyBuffer(); + theRemoteNodeId = aRemoteNodeId; + return true; +} + +SendBuffer::~SendBuffer() { + // Deallocate the buffer memory + if(startOfBuffer != NULL) + delete[] startOfBuffer; +} + +int +SendBuffer::bufferSize() { + return dataSize; +} + +Uint32 +SendBuffer::bufferSizeRemaining() { + return (sizeOfBuffer - dataSize); +} + +void +SendBuffer::emptyBuffer() { + insertPtr = startOfBuffer; + sendPtr = (char*)startOfBuffer; + dataSize = 0; + sendDataSize = 0; +} + +#ifdef DEBUG_TRANSPORTER +void +SendBuffer::print() { + + printf("SendBuffer status printouts\n"); + + printf( "sizeOfBuffer: %d\n", sizeOfBuffer); + printf( "startOfBuffer: %.8x\n", startOfBuffer); + printf( "endOfBuffer: %.8x\n", endOfBuffer); + printf( "insertPtr: %.8x\n", insertPtr); + printf( "sendPtr: %.8x\n", sendPtr); + printf( "sendDataSize: %d\n", sendDataSize); + printf( "dataSize: %d\n", dataSize); +} +#endif diff --git a/ndb/src/common/transporter/SendBuffer.hpp b/ndb/src/common/transporter/SendBuffer.hpp new file mode 100644 index 00000000000..75ef0708e83 --- /dev/null +++ b/ndb/src/common/transporter/SendBuffer.hpp @@ -0,0 +1,191 @@ +/* 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 */ + +//**************************************************************************** +// +// NAME +// SendBuffer +// +// DESCRIPTION +// The SendBuffer is a circular buffer storing signals waiting to be sent. +// The signals can be of variable size and are copied into the buffer +// in Protocol 6 format. There will be two SendBuffer instances +// (priority level A and B) for each transporter using a buffer for +// sending. The buffering will in most cases be done to send as big +// packages as possible over TCP/IP. +// +//***************************************************************************/ +#ifndef SendBuffer_H +#define SendBuffer_H + +#include "TransporterDefinitions.hpp" +#include <TransporterCallback.hpp> +#include <stdlib.h> + +#ifdef DEBUG_TRANSPORTER +#include <stdio.h> +#endif + +class SendBuffer { + friend class TCP_Transporter; +public: + // Set member variables + SendBuffer(Uint32 bufSize); + + // Deallocate the buffer memory + ~SendBuffer(); + + // Allocate memory for the buffer and initialize the buffer pointers + bool initBuffer(Uint32 aRemoteNodeId); + + // Number of bytes remaining in the buffer + Uint32 bufferSizeRemaining(); + + // Number of bytes of data in the buffer + int bufferSize(); + + // Empty the buffer + void emptyBuffer(); + + /** + * The transporter calls updateBuffer after a retrieve followed by + * a successful send, to update the cirkular buffer pointers. + * updateBuffer is called with the number of bytes really sent, + * it may be that it is less than what was retrived from the buffer. + * If that is the case there will be an incomplete message (slack) + * in the SendBuffer. + * + * Returns 0 if buffer empty + * else ~0 + */ + Uint32 bytesSent(Uint32 len); + +#ifdef DEBUG_TRANSPORTER + // Prints the buffer status on the screen. Can be used for testing purposes. + void print(); +#endif + + Uint32* getInsertPtr(Uint32 bytes); + void updateInsertPtr(Uint32 bytes); + +private: + + Uint32 sizeOfBuffer; // Length, in number of bytes, of the buffer memory + Uint32 dataSize; // Number of bytes in buffer + + Uint32 * startOfBuffer; // Pointer to the start of the buffer memory + Uint32 * endOfBuffer; // Pointer to end of buffer + + Uint32 * insertPtr; // Where to insert next + + char * sendPtr; // Where data to send starts + Uint32 sendDataSize; // Num bytes to send + + Uint32 theRemoteNodeId; +}; + +inline +Uint32 +SendBuffer::bytesSent(Uint32 bytes) { + + if(bytes > dataSize){ +#ifdef DEBUG_TRANSPORTER + printf("bytes(%d) > dataSize(%d)\n", bytes, dataSize); +#endif + abort(); + // reportError(0 ,theRemoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return 0; + }//if + + if(bytes > sendDataSize){ +#ifdef DEBUG_TRANSPORTER + printf("bytes(%d) > sendDataSize(%d)\n", bytes, sendDataSize); +#endif + abort(); + //reportError(0,theRemoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return 0; + }//if + + dataSize -= bytes; + sendPtr += bytes; + sendDataSize -= bytes; + + if(sendDataSize == 0){ + if(sendPtr > (char*)insertPtr){ + sendPtr = (char *)startOfBuffer; + sendDataSize = dataSize; + } else { + sendPtr = ((char*)insertPtr) - dataSize; + sendDataSize = dataSize; + } + } + + if(dataSize == 0) + return 0; + return ~0; +} + +inline +Uint32* +SendBuffer::getInsertPtr(Uint32 len){ + if (bufferSizeRemaining() < len){ + return 0; + } + + const char * const tmpInsertPtr = (char *) insertPtr; + + if(tmpInsertPtr >= sendPtr){ + // Is there enough space at the end of the buffer? + if ((tmpInsertPtr + len) < (char*)endOfBuffer){ + sendDataSize += len; + return insertPtr; + } else { + // We have passed the end of the cirkular buffer, + // must start from the beginning + // Is there enough space in the beginning of the buffer? + if ((Uint32)(sendPtr - (char *)startOfBuffer) <= len){ + // Not enough space available, insert failed + return 0; + } else { + // There is space available at the beginning of the buffer + // We start from the beginning, set endOfData and insertPtr + insertPtr = startOfBuffer; + if(sendDataSize != 0){ + return insertPtr; + } + sendPtr = (char *)startOfBuffer; + sendDataSize = len; + return insertPtr; + } + } + } else { + // sendPtr > insertPtr + // Is there enought room + if((tmpInsertPtr + len) < sendPtr){ + return insertPtr; + } + return 0; + } +} + +inline +void +SendBuffer::updateInsertPtr(Uint32 lenBytes){ + dataSize += lenBytes; + insertPtr += (lenBytes / 4); +} + +#endif // Define of SendBuffer_H diff --git a/ndb/src/common/transporter/TCP_Transporter.cpp b/ndb/src/common/transporter/TCP_Transporter.cpp new file mode 100644 index 00000000000..8a7d1741636 --- /dev/null +++ b/ndb/src/common/transporter/TCP_Transporter.cpp @@ -0,0 +1,603 @@ +/* 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 <NdbTCP.h> +#include "TCP_Transporter.hpp" +#include <NdbOut.hpp> +#include <NdbSleep.h> +// End of stuff to be moved + +#if defined NDB_OSE || defined NDB_SOFTOSE +#define inet_send inet_send +#else +#include <NdbStdio.h> +#define inet_send send +#endif + +#include <stdlib.h> + + +#ifdef NDB_WIN32 +class ndbstrerror +{ +public: + ndbstrerror(int iError); + ~ndbstrerror(void); + operator char*(void) { return m_szError; }; + +private: + int m_iError; + char* m_szError; +}; + +ndbstrerror::ndbstrerror(int iError) +: m_iError(iError) +{ + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, + iError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&m_szError, + 0, + 0); +} + +ndbstrerror::~ndbstrerror(void) +{ + LocalFree( m_szError ); + m_szError = 0; +} +#else +#define ndbstrerror strerror +#endif + +TCP_Transporter::TCP_Transporter(int sendBufSize, int maxRecvSize, + int portNo, + const char *rHostName, + const char *lHostName, + NodeId rNodeId, NodeId lNodeId, + int byte_order, + bool compr, bool chksm, bool signalId, + Uint32 _reportFreq) : + Transporter(lNodeId, rNodeId, byte_order, compr, chksm, signalId), + m_sendBuffer(sendBufSize), + isServer(lNodeId < rNodeId), + port(portNo) +{ + maxReceiveSize = maxRecvSize; + + strncpy(remoteHostName, rHostName, sizeof(remoteHostName)); + + // Initialize member variables + Ndb_getInAddr(&remoteHostAddress, rHostName); + + Ndb_getInAddr(&localHostAddress, lHostName); + theSocket = NDB_INVALID_SOCKET; + + sendCount = receiveCount = 0; + sendSize = receiveSize = 0; + reportFreq = _reportFreq; + + sockOptRcvBufSize = 70080; + sockOptSndBufSize = 71540; + sockOptNodelay = 1; + sockOptTcpMaxSeg = 4096; +} + +TCP_Transporter::~TCP_Transporter() { + + // Disconnect + if (theSocket != NDB_INVALID_SOCKET) + doDisconnect(); + + // Delete send buffers + + // Delete receive buffer!! + receiveBuffer.destroy(); +} + +bool +TCP_Transporter::initTransporter() { + + // Allocate buffer for receiving + // Let it be the maximum size we receive plus 8 kB for any earlier received + // incomplete messages (slack) + Uint32 recBufSize = maxReceiveSize; + if(recBufSize < MAX_MESSAGE_SIZE){ + recBufSize = MAX_MESSAGE_SIZE; + } + + if(!receiveBuffer.init(recBufSize+MAX_MESSAGE_SIZE)){ + return false; + } + + // Allocate buffers for sending + if (!m_sendBuffer.initBuffer(remoteNodeId)) { + // XXX What shall be done here? + // The same is valid for the other init-methods + return false; + } + + return true; +} + +void +TCP_Transporter::setSocketOptions(){ + if (setsockopt(theSocket, SOL_SOCKET, SO_RCVBUF, + (char*)&sockOptRcvBufSize, sizeof(sockOptRcvBufSize)) < 0) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("The setsockopt SO_RCVBUF error code = %d", InetErrno); +#endif + }//if + + if (setsockopt(theSocket, SOL_SOCKET, SO_SNDBUF, + (char*)&sockOptSndBufSize, sizeof(sockOptSndBufSize)) < 0) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("The setsockopt SO_SNDBUF error code = %d", InetErrno); +#endif + }//if + + //----------------------------------------------- + // Set the TCP_NODELAY option so also small packets are sent + // as soon as possible + //----------------------------------------------- + if (setsockopt(theSocket, IPPROTO_TCP, TCP_NODELAY, + (char*)&sockOptNodelay, sizeof(sockOptNodelay)) < 0) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("The setsockopt TCP_NODELAY error code = %d", InetErrno); +#endif + }//if +} + + +#ifdef NDB_WIN32 + +bool +TCP_Transporter::setSocketNonBlocking(NDB_SOCKET_TYPE socket){ + unsigned long ul = 1; + if(ioctlsocket(socket, FIONBIO, &ul)) + { +#ifdef DEBUG_TRANSPORTER + ndbout_c("Set non-blocking server error3: %d", InetErrno); +#endif + }//if + return true; +} + +#else + +bool +TCP_Transporter::setSocketNonBlocking(NDB_SOCKET_TYPE socket){ + int flags; + flags = fcntl(socket, F_GETFL, 0); + if (flags < 0) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("Set non-blocking server error1: %s", strerror(InetErrno)); +#endif + }//if + flags |= NDB_NONBLOCK; + if (fcntl(socket, F_SETFL, flags) == -1) { +#ifdef DEBUG_TRANSPORTER + ndbout_c("Set non-blocking server error2: %s", strerror(InetErrno)); +#endif + }//if + return true; +} + +#endif + +bool +TCP_Transporter::sendIsPossible(struct timeval * timeout) { +#ifdef NDB_OSE + /** + * In OSE you cant do select without owning a socket, + * and since this method might be called by any thread in the api + * we choose not to implementet and always return true after sleeping + * a while. + * + * Note that this only sensible as long as the sockets are non blocking + */ + if(theSocket >= 0){ + Uint32 timeOutMillis = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + NdbSleep_MilliSleep(timeOutMillis); + return true; + } + return false; +#else + if(theSocket != NDB_INVALID_SOCKET){ + fd_set writeset; + FD_ZERO(&writeset); + FD_SET(theSocket, &writeset); + + int selectReply = select(theSocket + 1, NULL, &writeset, NULL, timeout); + + if ((selectReply > 0) && FD_ISSET(theSocket, &writeset)) + return true; + else + return false; + } + return false; +#endif +} + + +Uint32 * +TCP_Transporter::getWritePtr(Uint32 lenBytes, Uint32 prio){ + + Uint32 * insertPtr = m_sendBuffer.getInsertPtr(lenBytes); + + struct timeval timeout = {0, 10000}; + + if (insertPtr == 0) { + //------------------------------------------------- + // Buffer was completely full. We have severe problems. + // We will attempt to wait for a small time + //------------------------------------------------- + if(sendIsPossible(&timeout)) { + //------------------------------------------------- + // Send is possible after the small timeout. + //------------------------------------------------- + if(!doSend()){ + return 0; + } else { + //------------------------------------------------- + // Since send was successful we will make a renewed + // attempt at inserting the signal into the buffer. + //------------------------------------------------- + insertPtr = m_sendBuffer.getInsertPtr(lenBytes); + }//if + } else { + return 0; + }//if + } + return insertPtr; +} + +void +TCP_Transporter::updateWritePtr(Uint32 lenBytes, Uint32 prio){ + m_sendBuffer.updateInsertPtr(lenBytes); + + const int bufsize = m_sendBuffer.bufferSize(); + if(bufsize > TCP_SEND_LIMIT) { + //------------------------------------------------- + // Buffer is full and we are ready to send. We will + // not wait since the signal is already in the buffer. + // Force flag set has the same indication that we + // should always send. If it is not possible to send + // we will not worry since we will soon be back for + // a renewed trial. + //------------------------------------------------- + struct timeval no_timeout = {0,0}; + if(sendIsPossible(&no_timeout)) { + //------------------------------------------------- + // Send was possible, attempt at a send. + //------------------------------------------------- + doSend(); + }//if + } +} + +#define DISCONNECT_ERRNO(e, sz) ((sz == 0) || \ + (!((sz == -1) && (e == EAGAIN) || (e == EWOULDBLOCK) || (e == EINTR)))) + + +bool +TCP_Transporter::doSend() { + // If no sendbuffers are used nothing is done + // Sends the contents of the SendBuffers until they are empty + // or until select does not select the socket for write. + // Before calling send, the socket must be selected for write + // using "select" + // It writes on the external TCP/IP interface until the send buffer is empty + // and as long as write is possible (test it using select) + + // Empty the SendBuffers + + const char * const sendPtr = m_sendBuffer.sendPtr; + const Uint32 sizeToSend = m_sendBuffer.sendDataSize; + if (sizeToSend > 0){ + const int nBytesSent = inet_send(theSocket, sendPtr, sizeToSend, 0); + + if (nBytesSent > 0) { + m_sendBuffer.bytesSent(nBytesSent); + + sendCount ++; + sendSize += nBytesSent; + if(sendCount == reportFreq){ + reportSendLen(callbackObj,remoteNodeId, sendCount, sendSize); + sendCount = 0; + sendSize = 0; + } + } else { + // Send failed +#if defined DEBUG_TRANSPORTER + ndbout_c("Send Failure(disconnect==%d) to node = %d nBytesSent = %d " + "errno = %d strerror = %s", + DISCONNECT_ERRNO(InetErrno, nBytesSent), + remoteNodeId, nBytesSent, InetErrno, + (char*)ndbstrerror(InetErrno)); +#endif + if(DISCONNECT_ERRNO(InetErrno, nBytesSent)){ + doDisconnect(); + reportDisconnect(callbackObj, remoteNodeId, InetErrno); + } + + return false; + } + } + return true; +} + +int +TCP_Transporter::doReceive() { + // Select-function must return the socket for read + // before this method is called + // It reads the external TCP/IP interface once + + const int nBytesRead = recv(theSocket, + receiveBuffer.insertPtr, maxReceiveSize, 0); + + if (nBytesRead > 0) { + receiveBuffer.sizeOfData += nBytesRead; + receiveBuffer.insertPtr += nBytesRead; + + if(receiveBuffer.sizeOfData > receiveBuffer.sizeOfBuffer){ +#ifdef DEBUG_TRANSPORTER + ndbout_c("receiveBuffer.sizeOfData(%d) > receiveBuffer.sizeOfBuffer(%d)", + receiveBuffer.sizeOfData, receiveBuffer.sizeOfBuffer); + ndbout_c("nBytesRead = %d", nBytesRead); +#endif + ndbout_c("receiveBuffer.sizeOfData(%d) > receiveBuffer.sizeOfBuffer(%d)", + receiveBuffer.sizeOfData, receiveBuffer.sizeOfBuffer); + reportError(callbackObj, remoteNodeId, TE_INVALID_MESSAGE_LENGTH); + return 0; + } + + receiveCount ++; + receiveSize += nBytesRead; + if(receiveCount == reportFreq){ + reportReceiveLen(callbackObj, remoteNodeId, receiveCount, receiveSize); + receiveCount = 0; + receiveSize = 0; + } + return nBytesRead; + } else { +#if defined DEBUG_TRANSPORTER + ndbout_c("Receive Failure(disconnect==%d) to node = %d nBytesSent = %d " + "errno = %d strerror = %s", + DISCONNECT_ERRNO(InetErrno, nBytesRead), + remoteNodeId, nBytesRead, InetErrno, + (char*)ndbstrerror(InetErrno)); +#endif + if(DISCONNECT_ERRNO(InetErrno, nBytesRead)){ + // The remote node has closed down + doDisconnect(); + reportDisconnect(callbackObj, remoteNodeId,InetErrno); + } + } + return nBytesRead; +} + +bool +TCP_Transporter::connectImpl(Uint32 timeOutMillis){ + struct timeval timeout = {0, 0}; + timeout.tv_sec = timeOutMillis / 1000; + timeout.tv_usec = (timeOutMillis % 1000)*1000; + + bool retVal = false; + + if(isServer){ + if(theSocket == NDB_INVALID_SOCKET){ + startTCPServer(); + } + if(theSocket == NDB_INVALID_SOCKET) + { + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + retVal = acceptClient(&timeout); + } else { + // Is client + retVal = connectClient(&timeout); + } + + if(!retVal) { + NdbSleep_MilliSleep(timeOutMillis); + return false; + } + +#if defined NDB_OSE || defined NDB_SOFTOSE + if(setsockopt(theSocket, SOL_SOCKET, SO_OSEOWNER, + &theReceiverPid, sizeof(PROCESS)) != 0){ + + ndbout << "Failed to transfer ownership of socket" << endl; + NDB_CLOSE_SOCKET(theSocket); + theSocket = -1; + return false; + } +#endif + + return true; +} + + +void +TCP_Transporter::disconnectImpl() { + if(theSocket != NDB_INVALID_SOCKET){ + if(NDB_CLOSE_SOCKET(theSocket) < 0){ + reportError(callbackObj, remoteNodeId, TE_ERROR_CLOSING_SOCKET); + } + } + + // Empty send och receive buffers + receiveBuffer.clear(); + m_sendBuffer.emptyBuffer(); + + theSocket = NDB_INVALID_SOCKET; +} + +bool +TCP_Transporter::startTCPServer() { + + int bindResult, listenResult; + + // The server variable is the remote server when we are a client + // htonl and htons returns the parameter in network byte order + // INADDR_ANY tells the OS kernel to choose the IP address + struct sockaddr_in server; + memset((void*)&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = localHostAddress.s_addr; + server.sin_port = htons(port); + + if (theSocket != NDB_INVALID_SOCKET) { + return true; // Server socket is already initialized + } + + // Create the socket + theSocket = socket(AF_INET, SOCK_STREAM, 0); + if (theSocket == NDB_INVALID_SOCKET) { + reportThreadError(remoteNodeId, TE_COULD_NOT_CREATE_SOCKET); + return false; + } + + // Set the socket reuse addr to true, so we are sure we can bind the + // socket + int reuseAddr = 1; + setsockopt(theSocket, SOL_SOCKET, SO_REUSEADDR, + (char*)&reuseAddr, sizeof(reuseAddr)); + + // Set the TCP_NODELAY option so also small packets are sent + // as soon as possible + int nodelay = 1; + setsockopt(theSocket, IPPROTO_TCP, TCP_NODELAY, + (char*)&nodelay, sizeof(nodelay)); + + // Bind the socket + bindResult = bind(theSocket, (struct sockaddr *) &server, + sizeof(server)); + if (bindResult < 0) { + reportThreadError(remoteNodeId, TE_COULD_NOT_BIND_SOCKET); + NDB_CLOSE_SOCKET(theSocket); + theSocket = NDB_INVALID_SOCKET; + return false; + } + + // Perform listen. + listenResult = listen(theSocket, 1); + if (listenResult == 1) { + reportThreadError(remoteNodeId, TE_LISTEN_FAILED); + NDB_CLOSE_SOCKET(theSocket); + theSocket = NDB_INVALID_SOCKET; + return false; + } + + return true; +} + + +bool +TCP_Transporter::acceptClient (struct timeval * timeout){ + + struct sockaddr_in clientAddress; + + fd_set readset; + FD_ZERO(&readset); + FD_SET(theSocket, &readset); + const int res = select(theSocket + 1, &readset, 0, 0, timeout); + if(res == 0) + return false; + + if(res < 0){ + reportThreadError(remoteNodeId, TE_ERROR_IN_SELECT_BEFORE_ACCEPT); + return false; + } + + NDB_SOCKLEN_T clientAddressLen = sizeof(clientAddress); + const NDB_SOCKET_TYPE clientSocket = accept(theSocket, + (struct sockaddr*)&clientAddress, + &clientAddressLen); + if (clientSocket == NDB_INVALID_SOCKET) { + reportThreadError(remoteNodeId, TE_ACCEPT_RETURN_ERROR); + return false; + } + + if (clientAddress.sin_addr.s_addr != remoteHostAddress.s_addr) { + ndbout_c("Wrong client connecting!"); + ndbout_c("connecting address: %s", inet_ntoa(clientAddress.sin_addr)); + ndbout_c("expecting address: %s", inet_ntoa(remoteHostAddress)); + // The newly connected host is not the remote host + // we wanted to connect to. Disconnect it. + // XXX This is not valid. We cannot disconnect it. + NDB_CLOSE_SOCKET(clientSocket); + return false; + } else { + NDB_CLOSE_SOCKET(theSocket); + theSocket = clientSocket; + setSocketOptions(); + setSocketNonBlocking(theSocket); + return true; + } +} + +bool +TCP_Transporter::connectClient (struct timeval * timeout){ + + // Create the socket + theSocket = socket(AF_INET, SOCK_STREAM, 0); + if (theSocket == NDB_INVALID_SOCKET) { + reportThreadError(remoteNodeId, TE_COULD_NOT_CREATE_SOCKET); + return false; + } + + struct sockaddr_in server; + memset((void*)&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr = remoteHostAddress; + server.sin_port = htons(port); + + struct sockaddr_in client; + memset((void*)&client, 0, sizeof(client)); + client.sin_family = AF_INET; + client.sin_addr = localHostAddress; + client.sin_port = 0; // Any port + + // Bind the socket + const int bindResult = bind(theSocket, (struct sockaddr *) &client, + sizeof(client)); + if (bindResult < 0) { + reportThreadError(remoteNodeId, TE_COULD_NOT_BIND_SOCKET); + NDB_CLOSE_SOCKET(theSocket); + theSocket = NDB_INVALID_SOCKET; + return false; + } + + const int connectRes = ::connect(theSocket, (struct sockaddr *) &server, + sizeof(server)); + if(connectRes == 0){ + setSocketOptions(); + setSocketNonBlocking(theSocket); + return true; + } + + NDB_CLOSE_SOCKET(theSocket); + theSocket = NDB_INVALID_SOCKET; + return false; +} + + + diff --git a/ndb/src/common/transporter/TCP_Transporter.hpp b/ndb/src/common/transporter/TCP_Transporter.hpp new file mode 100644 index 00000000000..30b730a5b1c --- /dev/null +++ b/ndb/src/common/transporter/TCP_Transporter.hpp @@ -0,0 +1,290 @@ +/* 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 */ + +//**************************************************************************** +// +// AUTHOR +// Åsa Fransson +// +// NAME +// TCP_Transporter +// +// DESCRIPTION +// A TCP_Transporter instance is created when TCP/IP-communication +// shall be used (user specified). It handles connect, disconnect, +// send and receive. +// +// +// +//***************************************************************************/ +#ifndef TCP_Transporter_H +#define TCP_Transporter_H + +#include "Transporter.hpp" +#include "SendBuffer.hpp" + +#include <NdbTCP.h> + +struct ReceiveBuffer { + Uint32 *startOfBuffer; // Pointer to start of the receive buffer + Uint32 *readPtr; // Pointer to start reading data + + char *insertPtr; // Pointer to first position in the receiveBuffer + // in which to insert received data. Earlier + // received incomplete messages (slack) are + // copied into the first part of the receiveBuffer + + Uint32 sizeOfData; // In bytes + Uint32 sizeOfBuffer; + + bool init(int bytes); + void destroy(); + + void clear(); + void incompleteMessage(); +}; + +class TCP_Transporter : public Transporter { + friend class TransporterRegistry; +private: + // Initialize member variables + TCP_Transporter(int sendBufferSize, int maxReceiveSize, + int port, + const char *rHostName, + const char *lHostName, + NodeId rHostId, NodeId lHostId, + int byteorder, + bool compression, bool checksum, bool signalId, + Uint32 reportFreq = 4096); + + // Disconnect, delete send buffers and receive buffer + virtual ~TCP_Transporter(); + + /** + * Allocate buffers for sending and receiving + */ + bool initTransporter(); + + Uint32 * getWritePtr(Uint32 lenBytes, Uint32 prio); + void updateWritePtr(Uint32 lenBytes, Uint32 prio); + + bool hasDataToSend() const ; + + /** + * Retrieves the contents of the send buffers and writes it on + * the external TCP/IP interface until the send buffers are empty + * and as long as write is possible. + */ + bool doSend(); + + /** + * It reads the external TCP/IP interface once + * and puts the data in the receiveBuffer + */ + int doReceive(); + + /** + * Returns socket (used for select) + */ + NDB_SOCKET_TYPE getSocket() const; + + /** + * Get Receive Data + * + * Returns - no of bytes to read + * and set ptr + */ + virtual Uint32 getReceiveData(Uint32 ** ptr); + + /** + * Update receive data ptr + */ + virtual void updateReceiveDataPtr(Uint32 bytesRead); + +protected: + /** + * Setup client/server and perform connect/accept + * Is used both by clients and servers + * A client connects to the remote server + * A server accepts any new connections + */ + bool connectImpl(Uint32 timeOutMillis); + + /** + * Disconnects a TCP/IP node. Empty send and receivebuffer. + */ + void disconnectImpl(); + +private: + /** + * Send buffers + */ + SendBuffer m_sendBuffer; + + const bool isServer; + const unsigned int port; + + // Sending/Receiving socket used by both client and server + NDB_SOCKET_TYPE theSocket; + + Uint32 maxReceiveSize; + + /** + * Remote host name/and address + */ + char remoteHostName[256]; + struct in_addr remoteHostAddress; + struct in_addr localHostAddress; + + /** + * Socket options + */ + int sockOptRcvBufSize; + int sockOptSndBufSize; + int sockOptNodelay; + int sockOptTcpMaxSeg; + + void setSocketOptions(); + + static bool setSocketNonBlocking(NDB_SOCKET_TYPE aSocket); + + bool sendIsPossible(struct timeval * timeout); + + /** + * startTCPServer - None blocking + * + * create a server socket + * bind + * listen + * + * Note: Does not call accept + */ + bool startTCPServer(); + + /** + * acceptClient - Blocking + * + * Accept a connection + * checks if "right" client has connected + * if so + * close server socket + * else + * close newly created socket and goto begin + */ + bool acceptClient(struct timeval * timeout); + + /** + * Creates a client socket + * + * Note does not call connect + */ + bool createClientSocket(); + + /** + * connectClient - Blocking + * + * connects to remote host + */ + bool connectClient(struct timeval * timeout); + + /** + * Statistics + */ + Uint32 reportFreq; + Uint32 receiveCount; + Uint64 receiveSize; + Uint32 sendCount; + Uint64 sendSize; + + ReceiveBuffer receiveBuffer; + +#if defined NDB_OSE || defined NDB_SOFTOSE + PROCESS theReceiverPid; +#endif +}; + +inline +NDB_SOCKET_TYPE +TCP_Transporter::getSocket() const { + return theSocket; +} + +inline +Uint32 +TCP_Transporter::getReceiveData(Uint32 ** ptr){ + (* ptr) = receiveBuffer.readPtr; + return receiveBuffer.sizeOfData; +} + +inline +void +TCP_Transporter::updateReceiveDataPtr(Uint32 bytesRead){ + char * ptr = (char *)receiveBuffer.readPtr; + ptr += bytesRead; + receiveBuffer.readPtr = (Uint32*)ptr; + receiveBuffer.sizeOfData -= bytesRead; + receiveBuffer.incompleteMessage(); +} + +inline +bool +TCP_Transporter::hasDataToSend() const { + return m_sendBuffer.dataSize > 0; +} + +inline +bool +ReceiveBuffer::init(int bytes){ +#ifdef DEBUG_TRANSPORTER + ndbout << "Allocating " << bytes << " bytes as receivebuffer" << endl; +#endif + + startOfBuffer = new Uint32[((bytes + 0) >> 2) + 1]; + sizeOfBuffer = bytes + sizeof(Uint32); + clear(); + return true; +} + +inline +void +ReceiveBuffer::destroy(){ + delete[] startOfBuffer; + sizeOfBuffer = 0; + startOfBuffer = 0; + clear(); +} + +inline +void +ReceiveBuffer::clear(){ + readPtr = startOfBuffer; + insertPtr = (char *)startOfBuffer; + sizeOfData = 0; +} + +inline +void +ReceiveBuffer::incompleteMessage() { + if(startOfBuffer != readPtr){ + if(sizeOfData != 0) + memmove(startOfBuffer, readPtr, sizeOfData); + readPtr = startOfBuffer; + insertPtr = ((char *)startOfBuffer) + sizeOfData; + } +} + + +#endif // Define of TCP_Transporter_H diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp new file mode 100644 index 00000000000..1e19a8375ba --- /dev/null +++ b/ndb/src/common/transporter/Transporter.cpp @@ -0,0 +1,147 @@ +/* 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 "Transporter.hpp" +#include "TransporterInternalDefinitions.hpp" +#include <NdbStdio.h> +#include <NdbSleep.h> + +Transporter::Transporter(NodeId lNodeId, NodeId rNodeId, + int _byteorder, + bool _compression, bool _checksum, bool _signalId) + : localNodeId(lNodeId), remoteNodeId(rNodeId), + m_packer(_signalId, _checksum) +{ + byteOrder = _byteorder; + compressionUsed = _compression; + checksumUsed = _checksum; + signalIdUsed = _signalId; + + _threadError = TE_NO_ERROR; + + _connecting = false; + _disconnecting = false; + _connected = false; + _timeOutMillis = 1000; + theThreadPtr = NULL; + theMutexPtr = NdbMutex_Create(); +} + +Transporter::~Transporter(){ + NdbMutex_Destroy(theMutexPtr); + + if(theThreadPtr != 0){ + void * retVal; + NdbThread_WaitFor(theThreadPtr, &retVal); + NdbThread_Destroy(&theThreadPtr); + } +} + +extern "C" +void * +runConnect_C(void * me) +{ + runConnect(me); + NdbThread_Exit(0); + return NULL; +} + +void * +runConnect(void * me){ + Transporter * t = (Transporter *) me; + + DEBUG("Connect thread to " << t->remoteNodeId << " started"); + + while(true){ + NdbMutex_Lock(t->theMutexPtr); + if(t->_disconnecting){ + t->_connecting = false; + NdbMutex_Unlock(t->theMutexPtr); + DEBUG("Connect Thread " << t->remoteNodeId << " stop due to disconnect"); + return 0; + } + NdbMutex_Unlock(t->theMutexPtr); + + bool res = t->connectImpl(t->_timeOutMillis); // 1000 ms + DEBUG("Waiting for " << t->remoteNodeId << "..."); + if(res){ + t->_connected = true; + t->_connecting = false; + t->_errorCount = 0; + t->_threadError = TE_NO_ERROR; + DEBUG("Connect Thread " << t->remoteNodeId << " stop due to connect"); + return 0; + } + } +} + +void +Transporter::doConnect() { + + NdbMutex_Lock(theMutexPtr); + if(_connecting || _disconnecting || _connected){ + NdbMutex_Unlock(theMutexPtr); + return; + } + + _connecting = true; + + _threadError = TE_NO_ERROR; + + // Start thread + + char buf[16]; + snprintf(buf, sizeof(buf), "ndb_con_%d", remoteNodeId); + + if(theThreadPtr != 0){ + void * retVal; + NdbThread_WaitFor(theThreadPtr, &retVal); + NdbThread_Destroy(&theThreadPtr); + } + + theThreadPtr = NdbThread_Create(runConnect_C, + (void**)this, + 32768, + buf, + NDB_THREAD_PRIO_LOW); + + NdbSleep_MilliSleep(100); // Let thread start + + NdbMutex_Unlock(theMutexPtr); +} + +void +Transporter::doDisconnect() { + + NdbMutex_Lock(theMutexPtr); + _disconnecting = true; + while(_connecting){ + DEBUG("Waiting for connect to finish..."); + + NdbMutex_Unlock(theMutexPtr); + NdbSleep_MilliSleep(500); + NdbMutex_Lock(theMutexPtr); + } + + _connected = false; + + disconnectImpl(); + _threadError = TE_NO_ERROR; + _disconnecting = false; + + NdbMutex_Unlock(theMutexPtr); +} diff --git a/ndb/src/common/transporter/Transporter.hpp b/ndb/src/common/transporter/Transporter.hpp new file mode 100644 index 00000000000..c562451a1b0 --- /dev/null +++ b/ndb/src/common/transporter/Transporter.hpp @@ -0,0 +1,177 @@ +/* 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 */ + +#ifndef Transporter_H +#define Transporter_H + +#include <TransporterCallback.hpp> +#include "TransporterDefinitions.hpp" +#include "Packer.hpp" + +#include <NdbMutex.h> +#include <NdbThread.h> + +class Transporter { + friend class TransporterRegistry; +public: + virtual bool initTransporter() = 0; + + /** + * Destructor + */ + virtual ~Transporter(); + + /** + * None blocking + * Use isConnected() to check status + */ + virtual void doConnect(); + + /** + * Blocking + */ + virtual void doDisconnect(); + + virtual Uint32 * getWritePtr(Uint32 lenBytes, Uint32 prio) = 0; + virtual void updateWritePtr(Uint32 lenBytes, Uint32 prio) = 0; + + /** + * Are we currently connected + */ + bool isConnected() const; + + /** + * Remote Node Id + */ + NodeId getRemoteNodeId() const; + + + /** + * Set callback object + */ + void setCallbackObject(void * callback); + +protected: + Transporter(NodeId lNodeId, + NodeId rNodeId, + int byteorder, + bool compression, + bool checksum, + bool signalId); + + /** + * Blocking, for max timeOut milli seconds + * Returns true if connect succeded + */ + virtual bool connectImpl(Uint32 timeOut) = 0; + + /** + * Blocking + */ + virtual void disconnectImpl() = 0; + + const NodeId localNodeId; + const NodeId remoteNodeId; + + unsigned createIndex; + + int byteOrder; + bool compressionUsed; + bool checksumUsed; + bool signalIdUsed; + Packer m_packer; + + +private: + /** + * Thread and mutex for connect + */ + NdbThread* theThreadPtr; + friend void* runConnect(void * me); + +protected: + /** + * Error reporting from connect thread(s) + */ + void reportThreadError(NodeId nodeId, + TransporterError errorCode); + Uint32 getErrorCount(); + TransporterError getThreadError(); + void resetThreadError(); + TransporterError _threadError; + Uint32 _timeOutMillis; + Uint32 _errorCount; + +protected: + NdbMutex* theMutexPtr; + bool _connected; // Are we connected + bool _connecting; // Connect thread is running + bool _disconnecting; // We are disconnecting + + void * callbackObj; +}; + +inline +bool +Transporter::isConnected() const { + return _connected; +} + +inline +NodeId +Transporter::getRemoteNodeId() const { + return remoteNodeId; +} + +inline +void +Transporter::reportThreadError(NodeId nodeId, TransporterError errorCode) +{ +#if 0 + ndbout_c("Transporter::reportThreadError (NodeId: %d, Error code: %d)", + nodeId, errorCode); +#endif + _threadError = errorCode; + _errorCount++; +} + +inline +TransporterError +Transporter::getThreadError(){ + return _threadError; +} + +inline +Uint32 +Transporter::getErrorCount() +{ + return _errorCount; +} + +inline +void +Transporter::resetThreadError() +{ + _threadError = TE_NO_ERROR; +} + +inline +void +Transporter::setCallbackObject(void * callback) { + callbackObj = callback; +} + +#endif // Define of Transporter_H diff --git a/ndb/src/common/transporter/TransporterInternalDefinitions.hpp b/ndb/src/common/transporter/TransporterInternalDefinitions.hpp new file mode 100644 index 00000000000..18d54ca1e89 --- /dev/null +++ b/ndb/src/common/transporter/TransporterInternalDefinitions.hpp @@ -0,0 +1,323 @@ +/* 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 */ + +#ifndef TransporterInternalDefinitions_H +#define TransporterInternalDefinitions_H + +#if defined DEBUG_TRANSPORTER || defined VM_TRACE +#include <NdbOut.hpp> +#endif + +#ifdef NDB_SOLARIS +#define NDB_TCP_TRANSPORTER +//#define NDB_SCI_TRANSPORTER +#define NDB_SHM_TRANSPORTER +#elif defined NDB_OSE || defined NDB_SOFTOSE +#define NDB_TCP_TRANSPORTER +#define NDB_OSE_TRANSPORTER +#elif defined NDB_LINUX +#define NDB_TCP_TRANSPORTER +#define NDB_SCI_TRANSPORTER +#define NDB_SHM_TRANSPORTER +#elif defined NDB_WIN32 +#define NDB_TCP_TRANSPORTER +#elif defined NDB_HPUX +#define NDB_TCP_TRANSPORTER +#define NDB_SHM_TRANSPORTER +#elif defined NDB_MACOSX +#define NDB_TCP_TRANSPORTER +#define NDB_SHM_TRANSPORTER +#elif defined NDB_IBMAIX +#define NDB_TCP_TRANSPORTER +#define NDB_SHM_TRANSPORTER +#elif defined NDB_TRU64X +#define NDB_TCP_TRANSPORTER +#define NDB_SHM_TRANSPORTER +#else +#error unsupported platform +#endif + +#ifndef HAVE_SCI +#ifdef NDB_SCI_TRANSPORTER +#undef NDB_SCI_TRANSPORTER +#endif +#endif + +#ifdef DEBUG_TRANSPORTER +#define DEBUG(x) ndbout << x << endl +#else +#define DEBUG(x) +#endif + +#if defined VM_TRACE || defined DEBUG_TRANSPORTER +#define WARNING(X) ndbout << X << endl; +#else +#define WARNING(X) +#endif + +// Calculate a checksum +inline +Uint32 +computeChecksum(const Uint32 * const startOfData, int nWords) { + Uint32 chksum = startOfData[0]; + for (int i=1; i < nWords; i++) + chksum ^= startOfData[i]; + return chksum; +} + +struct Protocol6 { + Uint32 word1; + Uint32 word2; + Uint32 word3; + +/** + * + * b = Byte order - 4 Bits (Note 1 significant bit) + * g = GSN - 16 Bits + * p = Prio - 2 Bits + * c = Checksum included - 1 Bit + * z = Compression - 1 Bit + * v = Version id - 4 Bits + * i = Signal id included - 1 Bit + * m = Message length - 16 Bits (0-65536) (In word -> 0-256k bytes) + * d = Signal data length - 5 Bits (0-31) + * t = trace - 6 Bits (0-63) + * r = Recievers block no - 16 Bits + * s = Senders block no - 16 Bits + * u = Unused - 7 Bits + * f = FragmentInfo1 - 1 Bit + * h = FragmentInfo2 - 1 bit + * n = No of segments - 2 Bits + + * Word 1 + * + * + * 1111111111222222222233 + * 01234567890123456789012345678901 + * bfizcppbmmmmmmmmmmmmmmmmbhdddddb + + ** + * Word 2 + * + * 1111111111222222222233 + * 01234567890123456789012345678901 + * ggggggggggggggggvvvvttttttnn + + ** + * Word 3 + * + * 1111111111222222222233 + * 01234567890123456789012345678901 + * rrrrrrrrrrrrrrrrssssssssssssssss + + ** + * Word 4 (Optional Signal Id) + */ + + /** + * 0 = Big endian (Sparc), 1 = Little endian (Intel) + */ + static Uint32 getByteOrder (const Uint32 & word1); + static Uint32 getCompressed (const Uint32 & word1); + static Uint32 getSignalIdIncluded(const Uint32 & word1); + static Uint32 getCheckSumIncluded(const Uint32 & word1); + static Uint32 getPrio (const Uint32 & word1); + static Uint32 getMessageLength (const Uint32 & word1); + + static void setByteOrder (Uint32 & word1, Uint32 byteOrder); + static void setCompressed (Uint32 & word1, Uint32 compressed); + static void setSignalIdIncluded(Uint32 & word1, Uint32 signalId); + static void setCheckSumIncluded(Uint32 & word1, Uint32 checkSum); + static void setPrio (Uint32 & word1, Uint32 prio); + static void setMessageLength (Uint32 & word1, Uint32 messageLen); + + static void createSignalHeader(SignalHeader * const dst, + const Uint32 & word1, + const Uint32 & word2, + const Uint32 & word3); + + static void createProtocol6Header(Uint32 & word1, + Uint32 & word2, + Uint32 & word3, + const SignalHeader * const src); +}; + +#define WORD1_BYTEORDER_MASK (0x81000081) +#define WORD1_SIGNALID_MASK (0x00000004) +#define WORD1_COMPRESSED_MASK (0x00000008) +#define WORD1_CHECKSUM_MASK (0x00000010) +#define WORD1_PRIO_MASK (0x00000060) +#define WORD1_MESSAGELEN_MASK (0x00FFFF00) +#define WORD1_SIGNAL_LEN_MASK (0x7C000000) +#define WORD1_FRAG_INF_MASK (0x00000002) +#define WORD1_FRAG_INF2_MASK (0x02000000) + +#define WORD1_FRAG_INF_SHIFT (1) +#define WORD1_SIGNALID_SHIFT (2) +#define WORD1_COMPRESSED_SHIFT (3) +#define WORD1_CHECKSUM_SHIFT (4) +#define WORD1_PRIO_SHIFT (5) +#define WORD1_MESSAGELEN_SHIFT (8) +#define WORD1_FRAG_INF2_SHIFT (25) +#define WORD1_SIGNAL_LEN_SHIFT (26) + +#define WORD2_VERID_GSN_MASK (0x000FFFFF) +#define WORD2_TRACE_MASK (0x03f00000) +#define WORD2_SEC_COUNT_MASK (0x0c000000) + +#define WORD2_TRACE_SHIFT (20) +#define WORD2_SEC_COUNT_SHIFT (26) + +#define WORD3_SENDER_MASK (0x0000FFFF) +#define WORD3_RECEIVER_MASK (0xFFFF0000) + +#define WORD3_RECEIVER_SHIFT (16) + +inline +Uint32 +Protocol6::getByteOrder(const Uint32 & word1){ + return word1 & 1; +} + +inline +Uint32 +Protocol6::getCompressed(const Uint32 & word1){ + return (word1 & WORD1_COMPRESSED_MASK) >> WORD1_COMPRESSED_SHIFT; +} + +inline +Uint32 +Protocol6::getSignalIdIncluded(const Uint32 & word1){ + return (word1 & WORD1_SIGNALID_MASK) >> WORD1_SIGNALID_SHIFT; +} + +inline +Uint32 +Protocol6::getCheckSumIncluded(const Uint32 & word1){ + return (word1 & WORD1_CHECKSUM_MASK) >> WORD1_CHECKSUM_SHIFT; +} + +inline +Uint32 +Protocol6::getMessageLength(const Uint32 & word1){ + return (word1 & WORD1_MESSAGELEN_MASK) >> WORD1_MESSAGELEN_SHIFT; +} + +inline +Uint32 +Protocol6::getPrio(const Uint32 & word1){ + return (word1 & WORD1_PRIO_MASK) >> WORD1_PRIO_SHIFT; +} + +inline +void +Protocol6::setByteOrder(Uint32 & word1, Uint32 byteOrder){ + Uint32 tmp = byteOrder; + tmp |= (tmp << 7); + tmp |= (tmp << 24); + word1 |= (tmp & WORD1_BYTEORDER_MASK); +} + +inline +void +Protocol6::setCompressed(Uint32 & word1, Uint32 compressed){ + word1 |= ((compressed << WORD1_COMPRESSED_SHIFT) & WORD1_COMPRESSED_MASK); +} + +inline +void +Protocol6::setSignalIdIncluded(Uint32 & word1, Uint32 signalId){ + word1 |= ((signalId << WORD1_SIGNALID_SHIFT) & WORD1_SIGNALID_MASK); +} + +inline +void +Protocol6::setCheckSumIncluded(Uint32 & word1, Uint32 checkSum){ + word1 |= ((checkSum << WORD1_CHECKSUM_SHIFT) & WORD1_CHECKSUM_MASK); +} + +inline +void +Protocol6::setMessageLength(Uint32 & word1, Uint32 messageLen){ + word1 |= ((messageLen << WORD1_MESSAGELEN_SHIFT) & WORD1_MESSAGELEN_MASK); +} + +inline +void +Protocol6::setPrio(Uint32 & word1, Uint32 prio){ + word1 |= ((prio << WORD1_PRIO_SHIFT) & WORD1_PRIO_MASK); +} + +inline +void +Protocol6::createSignalHeader(SignalHeader * const dst, + const Uint32 & word1, + const Uint32 & word2, + const Uint32 & word3){ + + Uint32 signal_len = (word1 & WORD1_SIGNAL_LEN_MASK)>> WORD1_SIGNAL_LEN_SHIFT; + Uint32 fragInfo1 = (word1 & WORD1_FRAG_INF_MASK) >> (WORD1_FRAG_INF_SHIFT-1); + Uint32 fragInfo2 = (word1 & WORD1_FRAG_INF2_MASK) >> (WORD1_FRAG_INF2_SHIFT); + Uint32 trace = (word2 & WORD2_TRACE_MASK) >> WORD2_TRACE_SHIFT; + Uint32 verid_gsn = (word2 & WORD2_VERID_GSN_MASK); + Uint32 secCount = (word2 & WORD2_SEC_COUNT_MASK) >> WORD2_SEC_COUNT_SHIFT; + + dst->theTrace = trace; + dst->m_noOfSections = secCount; + dst->m_fragmentInfo = fragInfo1 | fragInfo2; + + dst->theLength = signal_len; + dst->theVerId_signalNumber = verid_gsn; + + Uint32 sBlockNum = (word3 & WORD3_SENDER_MASK); + Uint32 rBlockNum = (word3 & WORD3_RECEIVER_MASK) >> WORD3_RECEIVER_SHIFT; + + dst->theSendersBlockRef = sBlockNum; + dst->theReceiversBlockNumber = rBlockNum; +} + +inline +void +Protocol6::createProtocol6Header(Uint32 & word1, + Uint32 & word2, + Uint32 & word3, + const SignalHeader * const src){ + const Uint32 signal_len = src->theLength; + const Uint32 fragInfo = src->m_fragmentInfo; + const Uint32 fragInfo1 = (fragInfo & 2); + const Uint32 fragInfo2 = (fragInfo & 1); + + const Uint32 trace = src->theTrace; + const Uint32 verid_gsn = src->theVerId_signalNumber; + const Uint32 secCount = src->m_noOfSections; + + word1 |= ((signal_len << WORD1_SIGNAL_LEN_SHIFT) & WORD1_SIGNAL_LEN_MASK); + word1 |= ((fragInfo1 << (WORD1_FRAG_INF_SHIFT-1)) & WORD1_FRAG_INF_MASK); + word1 |= ((fragInfo2 << WORD1_FRAG_INF2_SHIFT) & WORD1_FRAG_INF2_MASK); + + word2 |= ((trace << WORD2_TRACE_SHIFT) & WORD2_TRACE_MASK); + word2 |= (verid_gsn & WORD2_VERID_GSN_MASK); + word2 |= ((secCount << WORD2_SEC_COUNT_SHIFT) & WORD2_SEC_COUNT_MASK); + + Uint32 sBlockNum = src->theSendersBlockRef ; + Uint32 rBlockNum = src->theReceiversBlockNumber ; + + word3 |= (sBlockNum & WORD3_SENDER_MASK); + word3 |= ((rBlockNum << WORD3_RECEIVER_SHIFT) & WORD3_RECEIVER_MASK); +} + +// Define of TransporterInternalDefinitions_H +#endif diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp new file mode 100644 index 00000000000..dcd957f40ce --- /dev/null +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -0,0 +1,1188 @@ +/* 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 "TransporterRegistry.hpp" +#include "TransporterInternalDefinitions.hpp" + +#include "Transporter.hpp" + +#include <assert.h> +#include <stdlib.h> + +#ifdef NDB_TCP_TRANSPORTER +#include "TCP_Transporter.hpp" +#endif + +#ifdef NDB_OSE_TRANSPORTER +#include "OSE_Receiver.hpp" +#include "OSE_Transporter.hpp" +#endif + +#ifdef NDB_SCI_TRANSPORTER +#include "SCI_Transporter.hpp" +#endif + +#ifdef NDB_SHM_TRANSPORTER +#include "SHM_Transporter.hpp" +#endif + +#include "TransporterCallback.hpp" +#include "NdbOut.hpp" +#include <NdbSleep.h> +#include <NdbTick.h> +#define STEPPING 1 + +TransporterRegistry::TransporterRegistry(void * callback, + unsigned _maxTransporters, + unsigned sizeOfLongSignalMemory) { + + nodeIdSpecified = false; + maxTransporters = _maxTransporters; + sendCounter = 1; + m_ccCount = 0; + m_ccIndex = 0; + m_ccStep = STEPPING; + m_ccReady = false; + m_nTransportersPerformConnect=0; + + callbackObj=callback; + + theTCPTransporters = new TCP_Transporter * [maxTransporters]; + theSCITransporters = new SCI_Transporter * [maxTransporters]; + theSHMTransporters = new SHM_Transporter * [maxTransporters]; + theOSETransporters = new OSE_Transporter * [maxTransporters]; + theTransporterTypes = new TransporterType [maxTransporters]; + theTransporters = new Transporter * [maxTransporters]; + performStates = new PerformState [maxTransporters]; + ioStates = new IOState [maxTransporters]; + + // Initialize member variables + nTransporters = 0; + nTCPTransporters = 0; + nSCITransporters = 0; + nSHMTransporters = 0; + nOSETransporters = 0; + + // Initialize the transporter arrays + for (unsigned i=0; i<maxTransporters; i++) { + theTCPTransporters[i] = NULL; + theSCITransporters[i] = NULL; + theSHMTransporters[i] = NULL; + theOSETransporters[i] = NULL; + theTransporters[i] = NULL; + performStates[i] = PerformNothing; + ioStates[i] = NoHalt; + } + theOSEReceiver = 0; + theOSEJunkSocketSend = 0; + theOSEJunkSocketRecv = 0; +} + +TransporterRegistry::~TransporterRegistry() { + + removeAll(); + + delete[] theTCPTransporters; + delete[] theSCITransporters; + delete[] theSHMTransporters; + delete[] theOSETransporters; + delete[] theTransporterTypes; + delete[] theTransporters; + delete[] performStates; + delete[] ioStates; + +#ifdef NDB_OSE_TRANSPORTER + if(theOSEReceiver != NULL){ + theOSEReceiver->destroyPhantom(); + delete theOSEReceiver; + theOSEReceiver = 0; + } +#endif +} + +void +TransporterRegistry::removeAll(){ + for(unsigned i = 0; i<maxTransporters; i++){ + if(theTransporters[i] != NULL) + removeTransporter(theTransporters[i]->getRemoteNodeId()); + } +} + +void +TransporterRegistry::disconnectAll(){ + for(unsigned i = 0; i<maxTransporters; i++){ + if(theTransporters[i] != NULL) + theTransporters[i]->doDisconnect(); + } +} + +bool +TransporterRegistry::init(NodeId nodeId) { + nodeIdSpecified = true; + localNodeId = nodeId; + + DEBUG("TransporterRegistry started node: " << localNodeId); + + // return allocateLongSignalMemoryPool(nLargeSegments); + return true; +} + +bool +TransporterRegistry::createTransporter(TCP_TransporterConfiguration *config) { +#ifdef NDB_TCP_TRANSPORTER + + if(!nodeIdSpecified){ + init(config->localNodeId); + } + + if(config->localNodeId != localNodeId) + return false; + + if(theTransporters[config->remoteNodeId] != NULL) + return false; + + + TCP_Transporter * t = new TCP_Transporter(config->sendBufferSize, + config->maxReceiveSize, + config->port, + config->remoteHostName, + config->localHostName, + config->remoteNodeId, + localNodeId, + config->byteOrder, + config->compression, + config->checksum, + config->signalId); + if (t == NULL) + return false; + else if (!t->initTransporter()) { + delete t; + return false; + } + + t->setCallbackObject(callbackObj); + + // Put the transporter in the transporter arrays + theTCPTransporters[nTCPTransporters] = t; + theTransporters[t->getRemoteNodeId()] = t; + theTransporterTypes[t->getRemoteNodeId()] = tt_TCP_TRANSPORTER; + performStates[t->getRemoteNodeId()] = PerformNothing; + nTransporters++; + nTCPTransporters++; + +#if defined NDB_OSE || defined NDB_SOFTOSE + t->theReceiverPid = theReceiverPid; +#endif + + return true; +#else + return false; +#endif +} + +bool +TransporterRegistry::createTransporter(OSE_TransporterConfiguration *conf) { +#ifdef NDB_OSE_TRANSPORTER + + if(!nodeIdSpecified){ + init(conf->localNodeId); + } + + if(conf->localNodeId != localNodeId) + return false; + + if(theTransporters[conf->remoteNodeId] != NULL) + return false; + + if(theOSEReceiver == NULL){ + theOSEReceiver = new OSE_Receiver(this, + 10, + localNodeId); + } + + OSE_Transporter * t = new OSE_Transporter(conf->prioASignalSize, + conf->prioBSignalSize, + localNodeId, + conf->localHostName, + conf->remoteNodeId, + conf->remoteHostName, + conf->byteOrder, + conf->compression, + conf->checksum, + conf->signalId); + if (t == NULL) + return false; + else if (!t->initTransporter()) { + delete t; + return false; + } + t->setCallbackObject(callbackObj); + // Put the transporter in the transporter arrays + theOSETransporters[nOSETransporters] = t; + theTransporters[t->getRemoteNodeId()] = t; + theTransporterTypes[t->getRemoteNodeId()] = tt_OSE_TRANSPORTER; + performStates[t->getRemoteNodeId()] = PerformNothing; + + nTransporters++; + nOSETransporters++; + + return true; +#else + return false; +#endif +} + +bool +TransporterRegistry::createTransporter(SCI_TransporterConfiguration *config) { +#ifdef NDB_SCI_TRANSPORTER + + if(!SCI_Transporter::initSCI()) + abort(); + + if(!nodeIdSpecified){ + init(config->localNodeId); + } + + if(config->localNodeId != localNodeId) + return false; + + if(theTransporters[config->remoteNodeId] != NULL) + return false; + + SCI_Transporter * t = new SCI_Transporter(config->sendLimit, + config->bufferSize, + config->nLocalAdapters, + config->remoteSciNodeId0, + config->remoteSciNodeId1, + localNodeId, + config->remoteNodeId, + config->byteOrder, + config->compression, + config->checksum, + config->signalId); + + if (t == NULL) + return false; + else if (!t->initTransporter()) { + delete t; + return false; + } + t->setCallbackObject(callbackObj); + // Put the transporter in the transporter arrays + theSCITransporters[nSCITransporters] = t; + theTransporters[t->getRemoteNodeId()] = t; + theTransporterTypes[t->getRemoteNodeId()] = tt_SCI_TRANSPORTER; + performStates[t->getRemoteNodeId()] = PerformNothing; + nTransporters++; + nSCITransporters++; + + return true; +#else + return false; +#endif +} + +bool +TransporterRegistry::createTransporter(SHM_TransporterConfiguration *config) { +#ifdef NDB_SHM_TRANSPORTER + if(!nodeIdSpecified){ + init(config->localNodeId); + } + + if(config->localNodeId != localNodeId) + return false; + + if(theTransporters[config->remoteNodeId] != NULL) + return false; + + SHM_Transporter * t = new SHM_Transporter(config->localNodeId, + config->remoteNodeId, + config->shmKey, + config->shmSize, + config->compression, + config->checksum, + config->signalId + ); + if (t == NULL) + return false; + else if (!t->initTransporter()) { + delete t; + return false; + } + t->setCallbackObject(callbackObj); + // Put the transporter in the transporter arrays + theSHMTransporters[nSHMTransporters] = t; + theTransporters[t->getRemoteNodeId()] = t; + theTransporterTypes[t->getRemoteNodeId()] = tt_SHM_TRANSPORTER; + performStates[t->getRemoteNodeId()] = PerformNothing; + + nTransporters++; + nSHMTransporters++; + + return true; +#else + return false; +#endif +} + + +void +TransporterRegistry::removeTransporter(NodeId nodeId) { + + DEBUG("Removing transporter from " << localNodeId + << " to " << nodeId); + + if(theTransporters[nodeId] == NULL) + return; + + theTransporters[nodeId]->doDisconnect(); + + const TransporterType type = theTransporterTypes[nodeId]; + + int ind = 0; + switch(type){ + case tt_TCP_TRANSPORTER: +#ifdef NDB_TCP_TRANSPORTER + for(; ind < nTCPTransporters; ind++) + if(theTCPTransporters[ind]->getRemoteNodeId() == nodeId) + break; + ind++; + for(; ind<nTCPTransporters; ind++) + theTCPTransporters[ind-1] = theTCPTransporters[ind]; + nTCPTransporters --; +#endif + break; + case tt_SCI_TRANSPORTER: +#ifdef NDB_SCI_TRANSPORTER + for(; ind < nSCITransporters; ind++) + if(theSCITransporters[ind]->getRemoteNodeId() == nodeId) + break; + ind++; + for(; ind<nSCITransporters; ind++) + theSCITransporters[ind-1] = theSCITransporters[ind]; + nSCITransporters --; +#endif + break; + case tt_SHM_TRANSPORTER: +#ifdef NDB_SHM_TRANSPORTER + for(; ind < nSHMTransporters; ind++) + if(theSHMTransporters[ind]->getRemoteNodeId() == nodeId) + break; + ind++; + for(; ind<nSHMTransporters; ind++) + theSHMTransporters[ind-1] = theSHMTransporters[ind]; + nSHMTransporters --; +#endif + break; + case tt_OSE_TRANSPORTER: +#ifdef NDB_OSE_TRANSPORTER + for(; ind < nOSETransporters; ind++) + if(theOSETransporters[ind]->getRemoteNodeId() == nodeId) + break; + ind++; + for(; ind<nOSETransporters; ind++) + theOSETransporters[ind-1] = theOSETransporters[ind]; + nOSETransporters --; +#endif + break; + } + + nTransporters--; + + // Delete the transporter and remove it from theTransporters array + delete theTransporters[nodeId]; + theTransporters[nodeId] = NULL; +} + +SendStatus +TransporterRegistry::prepareSend(const SignalHeader * const signalHeader, + Uint8 prio, + const Uint32 * const signalData, + NodeId nodeId, + const LinearSectionPtr ptr[3]){ + + + Transporter *t = theTransporters[nodeId]; + if(t != NULL && + (((ioStates[nodeId] != HaltOutput) && (ioStates[nodeId] != HaltIO)) || + (signalHeader->theReceiversBlockNumber == 252))) { + + if(t->isConnected()){ + Uint32 lenBytes = t->m_packer.getMessageLength(signalHeader, ptr); + if(lenBytes <= MAX_MESSAGE_SIZE){ + Uint32 * insertPtr = t->getWritePtr(lenBytes, prio); + if(insertPtr != 0){ + t->m_packer.pack(insertPtr, prio, signalHeader, signalData, ptr); + t->updateWritePtr(lenBytes, prio); + return SEND_OK; + } + + int sleepTime = 2; + + /** + * @note: on linux/i386 the granularity is 10ms + * so sleepTime = 2 generates a 10 ms sleep. + */ + for(int i = 0; i<50; i++){ + if((nSHMTransporters+nSCITransporters) == 0) + NdbSleep_MilliSleep(sleepTime); + insertPtr = t->getWritePtr(lenBytes, prio); + if(insertPtr != 0){ + t->m_packer.pack(insertPtr, prio, signalHeader, signalData, ptr); + t->updateWritePtr(lenBytes, prio); + break; + } + } + + if(insertPtr != 0){ + /** + * Send buffer full, but resend works + */ + reportError(callbackObj, nodeId, TE_SEND_BUFFER_FULL); + return SEND_OK; + } + + WARNING("Signal to " << nodeId << " lost(buffer)"); + reportError(callbackObj, nodeId, TE_SIGNAL_LOST_SEND_BUFFER_FULL); + return SEND_BUFFER_FULL; + } else { + return SEND_MESSAGE_TOO_BIG; + } + } else { + DEBUG("Signal to " << nodeId << " lost(disconnect) "); + return SEND_DISCONNECTED; + } + } else { + DEBUG("Discarding message to block: " + << signalHeader->theReceiversBlockNumber + << " node: " << nodeId); + + if(t == NULL) + return SEND_UNKNOWN_NODE; + + return SEND_BLOCKED; + } +} + +SendStatus +TransporterRegistry::prepareSend(const SignalHeader * const signalHeader, + Uint8 prio, + const Uint32 * const signalData, + NodeId nodeId, + class SectionSegmentPool & thePool, + const SegmentedSectionPtr ptr[3]){ + + + Transporter *t = theTransporters[nodeId]; + if(t != NULL && + (((ioStates[nodeId] != HaltOutput) && (ioStates[nodeId] != HaltIO)) || + (signalHeader->theReceiversBlockNumber == 252))) { + + if(t->isConnected()){ + Uint32 lenBytes = t->m_packer.getMessageLength(signalHeader, ptr); + if(lenBytes <= MAX_MESSAGE_SIZE){ + Uint32 * insertPtr = t->getWritePtr(lenBytes, prio); + if(insertPtr != 0){ + t->m_packer.pack(insertPtr, prio, signalHeader, signalData, thePool, ptr); + t->updateWritePtr(lenBytes, prio); + return SEND_OK; + } + + + /** + * @note: on linux/i386 the granularity is 10ms + * so sleepTime = 2 generates a 10 ms sleep. + */ + int sleepTime = 2; + for(int i = 0; i<50; i++){ + if((nSHMTransporters+nSCITransporters) == 0) + NdbSleep_MilliSleep(sleepTime); + insertPtr = t->getWritePtr(lenBytes, prio); + if(insertPtr != 0){ + t->m_packer.pack(insertPtr, prio, signalHeader, signalData, thePool, ptr); + t->updateWritePtr(lenBytes, prio); + break; + } + } + + if(insertPtr != 0){ + /** + * Send buffer full, but resend works + */ + reportError(callbackObj, nodeId, TE_SEND_BUFFER_FULL); + return SEND_OK; + } + + WARNING("Signal to " << nodeId << " lost(buffer)"); + reportError(callbackObj, nodeId, TE_SIGNAL_LOST_SEND_BUFFER_FULL); + return SEND_BUFFER_FULL; + } else { + return SEND_MESSAGE_TOO_BIG; + } + } else { + DEBUG("Signal to " << nodeId << " lost(disconnect) "); + return SEND_DISCONNECTED; + } + } else { + DEBUG("Discarding message to block: " + << signalHeader->theReceiversBlockNumber + << " node: " << nodeId); + + if(t == NULL) + return SEND_UNKNOWN_NODE; + + return SEND_BLOCKED; + } +} + +void +TransporterRegistry::external_IO(Uint32 timeOutMillis) { + //----------------------------------------------------------- + // Most of the time we will send the buffers here and then wait + // for new signals. Thus we start by sending without timeout + // followed by the receive part where we expect to sleep for + // a while. + //----------------------------------------------------------- + if(pollReceive(timeOutMillis)){ + performReceive(); + } + performSend(); +} + +Uint32 +TransporterRegistry::pollReceive(Uint32 timeOutMillis){ + Uint32 retVal = 0; +#ifdef NDB_OSE_TRANSPORTER + retVal |= poll_OSE(timeOutMillis); + retVal |= poll_TCP(0); + return retVal; +#endif + + if((nSHMTransporters+nSCITransporters) > 0) + timeOutMillis=0; +#ifdef NDB_TCP_TRANSPORTER + if(nTCPTransporters > 0) + retVal |= poll_TCP(timeOutMillis); + else + tcpReadSelectReply = 0; +#endif +#ifdef NDB_SCI_TRANSPORTER + if(nSCITransporters > 0) + retVal |= poll_SCI(timeOutMillis); +#endif +#ifdef NDB_SHM_TRANSPORTER + if(nSHMTransporters > 0) + retVal |= poll_SHM(timeOutMillis); +#endif + return retVal; +} + + +#ifdef NDB_SCI_TRANSPORTER +Uint32 +TransporterRegistry::poll_SCI(Uint32 timeOutMillis){ + + for (int i=0; i<nSCITransporters; i++) { + SCI_Transporter * t = theSCITransporters[i]; + if (t->isConnected()) { + if(t->hasDataToRead()) + return 1; + } + } + return 0; +} +#endif + + +#ifdef NDB_SHM_TRANSPORTER +Uint32 +TransporterRegistry::poll_SHM(Uint32 timeOutMillis) +{ + for(int j=0; j < 20; j++) + for (int i=0; i<nSHMTransporters; i++) { + SHM_Transporter * t = theSHMTransporters[i]; + if (t->isConnected()) { + if(t->hasDataToRead()) { + return 1; + } + } + } + /** + * @note: granularity of linux/i386 timer is not good enough. + * Can't sleep if using SHM as it is now. + */ + /* + if(timeOutMillis > 0) + NdbSleep_MilliSleep(timeOutMillis); + else + NdbSleep_MilliSleep(1); + */ + return 0; +#if 0 + NDB_TICKS startTime = NdbTick_CurrentMillisecond(); + for(int i=0; i<100; i++) { + for (int i=0; i<nSHMTransporters; i++) { + SHM_Transporter * t = theSHMTransporters[i]; + if (t->isConnected()) { + if(t->hasDataToRead()){ + return 1; + } + else + continue; + } + else + continue; + } + + if(NdbTick_CurrentMillisecond() > (startTime +timeOutMillis)) + return 0; + } + NdbSleep_MilliSleep(5); + return 0; + +#endif +#if 0 + + for(int j=0; j < 100; j++) { + for (int i=0; i<nSHMTransporters; i++) { + SHM_Transporter * t = theSHMTransporters[i]; + if (t->isConnected()) { + if(t->hasDataToRead()) + return 1; + } + } + } + return 0; +#endif +} + + +#endif + +#ifdef NDB_OSE_TRANSPORTER +Uint32 +TransporterRegistry::poll_OSE(Uint32 timeOutMillis){ + if(theOSEReceiver != NULL){ + return theOSEReceiver->doReceive(timeOutMillis); + } + NdbSleep_MilliSleep(timeOutMillis); + return 0; +} +#endif + +#ifdef NDB_TCP_TRANSPORTER +Uint32 +TransporterRegistry::poll_TCP(Uint32 timeOutMillis){ + + if (nTCPTransporters == 0){ + tcpReadSelectReply = 0; + return 0; + } + + struct timeval timeout; +#ifdef NDB_OSE + + // Return directly if there are no TCP transporters configured + + if(timeOutMillis <= 1){ + timeout.tv_sec = 0; + timeout.tv_usec = 1025; + } else { + timeout.tv_sec = timeOutMillis / 1000; + timeout.tv_usec = (timeOutMillis % 1000) * 1000; + } +#else + timeout.tv_sec = timeOutMillis / 1000; + timeout.tv_usec = (timeOutMillis % 1000) * 1000; +#endif + + NDB_SOCKET_TYPE maxSocketValue = 0; + + // Needed for TCP/IP connections + // The read- and writeset are used by select + + FD_ZERO(&tcpReadset); + + // Prepare for sending and receiving + for (int i = 0; i < nTCPTransporters; i++) { + TCP_Transporter * t = theTCPTransporters[i]; + + // If the transporter is connected + if (t->isConnected()) { + + const NDB_SOCKET_TYPE socket = t->getSocket(); + // Find the highest socket value. It will be used by select + if (socket > maxSocketValue) + maxSocketValue = socket; + + // Put the connected transporters in the socket read-set + FD_SET(socket, &tcpReadset); + } + } + + // The highest socket value plus one + maxSocketValue++; + + tcpReadSelectReply = select(maxSocketValue, &tcpReadset, 0, 0, &timeout); +#ifdef NDB_WIN32 + if(tcpReadSelectReply == SOCKET_ERROR) + { + NdbSleep_MilliSleep(timeOutMillis); + } +#endif + + return tcpReadSelectReply; +} +#endif + + +void +TransporterRegistry::performReceive(){ +#ifdef NDB_OSE_TRANSPORTER + if(theOSEReceiver != 0){ + while(theOSEReceiver->hasData()){ + NodeId remoteNodeId; + Uint32 * readPtr; + Uint32 sz = theOSEReceiver->getReceiveData(&remoteNodeId, &readPtr); + Uint32 szUsed = unpack(readPtr, + sz, + remoteNodeId, + ioStates[remoteNodeId]); +#ifdef DEBUG_TRANSPORTER + /** + * OSE transporter can handle executions of + * half signals + */ + assert(sz == szUsed); +#endif + theOSEReceiver->updateReceiveDataPtr(szUsed); + theOSEReceiver->doReceive(0); + // checkJobBuffer(); + } + } +#endif + +#ifdef NDB_TCP_TRANSPORTER + if(tcpReadSelectReply > 0){ + for (int i=0; i<nTCPTransporters; i++) { + checkJobBuffer(); + TCP_Transporter *t = theTCPTransporters[i]; + const NodeId nodeId = t->getRemoteNodeId(); + const NDB_SOCKET_TYPE socket = t->getSocket(); + if(performStates[nodeId] == PerformIO){ + if(t->isConnected() && FD_ISSET(socket, &tcpReadset)) { + const int receiveSize = t->doReceive(); + if(receiveSize > 0){ + Uint32 * ptr; + Uint32 sz = t->getReceiveData(&ptr); + Uint32 szUsed = unpack(ptr, sz, nodeId, ioStates[nodeId]); + t->updateReceiveDataPtr(szUsed); + } + } + } + } + } +#endif + + +#ifdef NDB_SCI_TRANSPORTER + //performReceive + //do prepareReceive on the SCI transporters (prepareReceive(t,,,,)) + for (int i=0; i<nSCITransporters; i++) { + checkJobBuffer(); + SCI_Transporter *t = theSCITransporters[i]; + const NodeId nodeId = t->getRemoteNodeId(); + if(performStates[nodeId] == PerformIO){ + if(t->isConnected() && t->checkConnected()){ + Uint32 * readPtr, * eodPtr; + t->getReceivePtr(&readPtr, &eodPtr); + readPtr = unpack(readPtr, eodPtr, nodeId, ioStates[nodeId]); + t->updateReceivePtr(readPtr); + } + } + } +#endif +#ifdef NDB_SHM_TRANSPORTER + for (int i=0; i<nSHMTransporters; i++) { + checkJobBuffer(); + SHM_Transporter *t = theSHMTransporters[i]; + const NodeId nodeId = t->getRemoteNodeId(); + if(performStates[nodeId] == PerformIO){ + if(t->isConnected() && t->checkConnected()){ + Uint32 * readPtr, * eodPtr; + t->getReceivePtr(&readPtr, &eodPtr); + readPtr = unpack(readPtr, eodPtr, nodeId, ioStates[nodeId]); + t->updateReceivePtr(readPtr); + } + } + } +#endif +} + +static int x = 0; +void +TransporterRegistry::performSend(){ + + sendCounter = 1; + +#ifdef NDB_OSE_TRANSPORTER + for (int i = 0; i < nOSETransporters; i++){ + OSE_Transporter *t = theOSETransporters[i]; + if((performStates[t->getRemoteNodeId()] == PerformIO) && + (t->isConnected())) { + t->doSend(); + }//if + }//for +#endif + +#ifdef NDB_TCP_TRANSPORTER +#ifdef NDB_OSE + { + int maxSocketValue = 0; + + // Needed for TCP/IP connections + // The writeset are used by select + fd_set writeset; + FD_ZERO(&writeset); + + // Prepare for sending and receiving + for (int i = 0; i < nTCPTransporters; i++) { + TCP_Transporter * t = theTCPTransporters[i]; + + // If the transporter is connected + if ((t->hasDataToSend()) && (t->isConnected())) { + const int socket = t->getSocket(); + // Find the highest socket value. It will be used by select + if (socket > maxSocketValue) { + maxSocketValue = socket; + }//if + FD_SET(socket, &writeset); + }//if + }//for + + // The highest socket value plus one + if(maxSocketValue == 0) + return; + + maxSocketValue++; + struct timeval timeout = { 0, 1025 }; + Uint32 tmp = select(maxSocketValue, 0, &writeset, 0, &timeout); + + if (tmp == 0) { + return; + }//if + for (int i = 0; i < nTCPTransporters; i++) { + TCP_Transporter *t = theTCPTransporters[i]; + const NodeId nodeId = t->getRemoteNodeId(); + const int socket = t->getSocket(); + if(performStates[nodeId] == PerformIO){ + if(t->isConnected() && FD_ISSET(socket, &writeset)) { + t->doSend(); + }//if + }//if + }//for + } +#endif +#ifdef NDB_TCP_TRANSPORTER + for (int i = x; i < nTCPTransporters; i++) { + TCP_Transporter *t = theTCPTransporters[i]; + if (t && + (t->hasDataToSend()) && + (t->isConnected()) && + (performStates[t->getRemoteNodeId()] == PerformIO)) { + t->doSend(); + }//if + }//for + for (int i = 0; i < x && i < nTCPTransporters; i++) { + TCP_Transporter *t = theTCPTransporters[i]; + if (t && + (t->hasDataToSend()) && + (t->isConnected()) && + (performStates[t->getRemoteNodeId()] == PerformIO)) { + t->doSend(); + }//if + }//for + x++; + if (x == nTCPTransporters) x = 0; +#endif +#endif +#ifdef NDB_SCI_TRANSPORTER + //scroll through the SCI transporters, + // get each transporter, check if connected, send data + for (int i=0; i<nSCITransporters; i++) { + SCI_Transporter *t = theSCITransporters[i]; + const NodeId nodeId = t->getRemoteNodeId(); + + if(performStates[nodeId] == PerformIO){ + if(t->isConnected() && t->hasDataToSend()) { + t->doSend(); + } //if + } //if + } //if +#endif +} + +int +TransporterRegistry::forceSendCheck(int sendLimit){ + int tSendCounter = sendCounter; + sendCounter = tSendCounter + 1; + if (tSendCounter >= sendLimit) { + performSend(); + sendCounter = 1; + return 1; + }//if + return 0; +}//TransporterRegistry::forceSendCheck() + +#ifdef DEBUG_TRANSPORTER +void +TransporterRegistry::printState(){ + ndbout << "-- TransporterRegistry -- " << endl << endl + << "Transporters = " << nTransporters << endl; + for(int i = 0; i<maxTransporters; i++) + if(theTransporters[i] != NULL){ + const NodeId remoteNodeId = theTransporters[i]->getRemoteNodeId(); + ndbout << "Transporter: " << remoteNodeId + << " PerformState: " << performStates[remoteNodeId] + << " IOState: " << ioStates[remoteNodeId] << endl; + } +} +#endif + +PerformState +TransporterRegistry::performState(NodeId nodeId) { + return performStates[nodeId]; +} + +#ifdef DEBUG_TRANSPORTER +const char * +performStateString(PerformState state){ + switch(state){ + case PerformNothing: + return "PerformNothing"; + break; + case PerformIO: + return "PerformIO"; + break; + case PerformConnect: + return "PerformConnect"; + break; + case PerformDisconnect: + return "PerformDisconnect"; + break; + case RemoveTransporter: + return "RemoveTransporter"; + break; + } + return "Unknown"; +} +#endif + +void +TransporterRegistry::setPerformState(NodeId nodeId, PerformState state) { + DEBUG("TransporterRegistry::setPerformState(" + << nodeId << ", " << performStateString(state) << ")"); + + performStates[nodeId] = state; +} + +void +TransporterRegistry::setPerformState(PerformState state) { + int count = 0; + int index = 0; + while(count < nTransporters){ + if(theTransporters[index] != 0){ + setPerformState(theTransporters[index]->getRemoteNodeId(), state); + count ++; + } + index ++; + } +} + +IOState +TransporterRegistry::ioState(NodeId nodeId) { + return ioStates[nodeId]; +} + +void +TransporterRegistry::setIOState(NodeId nodeId, IOState state) { + DEBUG("TransporterRegistry::setIOState(" + << nodeId << ", " << state << ")"); + ioStates[nodeId] = state; +} + +void +TransporterRegistry::startReceiving(){ +#ifdef NDB_OSE_TRANSPORTER + if(theOSEReceiver != NULL){ + theOSEReceiver->createPhantom(); + } +#endif + +#ifdef NDB_OSE + theOSEJunkSocketRecv = socket(AF_INET, SOCK_STREAM, 0); +#endif + +#if defined NDB_OSE || defined NDB_SOFTOSE + theReceiverPid = current_process(); + for(int i = 0; i<nTCPTransporters; i++) + theTCPTransporters[i]->theReceiverPid = theReceiverPid; +#endif +} + +void +TransporterRegistry::stopReceiving(){ +#ifdef NDB_OSE_TRANSPORTER + if(theOSEReceiver != NULL){ + theOSEReceiver->destroyPhantom(); + } +#endif + + /** + * Disconnect all transporters, this includes detach from remote node + * and since that must be done from the same process that called attach + * it's done here in the receive thread + */ + disconnectAll(); + +#if defined NDB_OSE || defined NDB_SOFTOSE + if(theOSEJunkSocketRecv > 0) + close(theOSEJunkSocketRecv); + theOSEJunkSocketRecv = -1; +#endif + +} + +void +TransporterRegistry::startSending(){ +#if defined NDB_OSE || defined NDB_SOFTOSE + theOSEJunkSocketSend = socket(AF_INET, SOCK_STREAM, 0); +#endif +} + +void +TransporterRegistry::stopSending(){ +#if defined NDB_OSE || defined NDB_SOFTOSE + if(theOSEJunkSocketSend > 0) + close(theOSEJunkSocketSend); + theOSEJunkSocketSend = -1; +#endif +} + +/** + * The old implementation did not scale with a large + * number of nodes. (Watchdog killed NDB because + * it took too long time to allocated threads in + * doConnect. + * + * The new implementation only checks the connection + * for a number of transporters (STEPPING), until to + * the point where all transporters has executed + * doConnect once. After that, the behaviour is as + * in the old implemenation, i.e, checking the connection + * for all transporters. + * @todo: instead of STEPPING, maybe we should only + * allow checkConnections to execute for a certain + * time that somehow factors in heartbeat times and + * watchdog times. + * + */ + +void +TransporterRegistry::checkConnections(){ + if(m_ccStep > nTransporters) + m_ccStep = nTransporters; + + while(m_ccCount < m_ccStep){ + if(theTransporters[m_ccIndex] != 0){ + Transporter * t = theTransporters[m_ccIndex]; + const NodeId nodeId = t->getRemoteNodeId(); + if(t->getThreadError() != 0) { + reportError(callbackObj, nodeId, t->getThreadError()); + t->resetThreadError(); + } + + switch(performStates[nodeId]){ + case PerformConnect: + if(!t->isConnected()){ + t->doConnect(); + if(m_nTransportersPerformConnect!=nTransporters) + m_nTransportersPerformConnect++; + + } else { + performStates[nodeId] = PerformIO; + reportConnect(callbackObj, nodeId); + } + break; + case PerformDisconnect: + { + bool wasConnected = t->isConnected(); + t->doDisconnect(); + performStates[nodeId] = PerformNothing; + if(wasConnected){ + reportDisconnect(callbackObj, nodeId,0); + } + } + break; + case RemoveTransporter: + removeTransporter(nodeId); + break; + case PerformNothing: + case PerformIO: + break; + } + m_ccCount ++; + } + m_ccIndex ++; + } + + if(!m_ccReady) { + if(m_ccCount < nTransporters) { + if(nTransporters - m_ccStep < STEPPING) + m_ccStep += nTransporters-m_ccStep; + else + m_ccStep += STEPPING; + + // ndbout_c("count %d step %d ", m_ccCount, m_ccStep); + } + else { + m_ccCount = 0; + m_ccIndex = 0; + m_ccStep = STEPPING; + // ndbout_c("count %d step %d ", m_ccCount, m_ccStep); + } + } + if((nTransporters == m_nTransportersPerformConnect) || m_ccReady) { + m_ccReady = true; + m_ccCount = 0; + m_ccIndex = 0; + m_ccStep = nTransporters; + // ndbout_c("alla count %d step %d ", m_ccCount, m_ccStep); + } + +}//TransporterRegistry::checkConnections() + +NdbOut & operator <<(NdbOut & out, SignalHeader & sh){ + out << "-- Signal Header --" << endl; + out << "theLength: " << sh.theLength << endl; + out << "gsn: " << sh.theVerId_signalNumber << endl; + out << "recBlockNo: " << sh.theReceiversBlockNumber << endl; + out << "sendBlockRef: " << sh.theSendersBlockRef << endl; + out << "sendersSig: " << sh.theSendersSignalId << endl; + out << "theSignalId: " << sh.theSignalId << endl; + out << "trace: " << (int)sh.theTrace << endl; + return out; +} diff --git a/ndb/src/common/transporter/basictest/Makefile b/ndb/src/common/transporter/basictest/Makefile new file mode 100644 index 00000000000..d86af360408 --- /dev/null +++ b/ndb/src/common/transporter/basictest/Makefile @@ -0,0 +1,15 @@ +include .defs.mk + +TYPE := ndbapi + +BIN_TARGET := basicTransporterTest +BIN_TARGET_ARCHIVES := transporter portlib general + +SOURCES = basicTransporterTest.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/transporter/basictest/basicTransporterTest.cpp b/ndb/src/common/transporter/basictest/basicTransporterTest.cpp new file mode 100644 index 00000000000..5d8186badb8 --- /dev/null +++ b/ndb/src/common/transporter/basictest/basicTransporterTest.cpp @@ -0,0 +1,536 @@ +/* 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 "TransporterRegistry.hpp" +#include "TransporterDefinitions.hpp" +#include "TransporterCallback.hpp" +#include <RefConvert.hpp> + +#include <NdbStdio.h> +#include <stdlib.h> +#include <NdbTick.h> +#include <NdbMain.h> +#include <NdbOut.hpp> +#include <NdbSleep.h> +#include <NdbString.h> + +int basePortTCP = 17000; + +SCI_TransporterConfiguration sciTemplate = { + 8000, + // Packet size + 2500000, // Buffer size + 2, // number of adapters + 1, // remote node id SCI + 2, // Remote node Id SCI + 0, // local ndb node id (server) + 0, // remote ndb node id (client) + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + +TCP_TransporterConfiguration tcpTemplate = { + 17000, // port; + "", // remoteHostName; + "", // localhostname + 2, // remoteNodeId; + 1, // localNodeId; + 10000, // sendBufferSize - Size of SendBuffer of priority B + 10000, // maxReceiveSize - Maximum no of bytes to receive + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + +OSE_TransporterConfiguration oseTemplate = { + "", // remoteHostName; + "", // localHostName; + 0, // remoteNodeId; + 0, // localNodeId; + false, // compression; + true, // checksum; + true, // signalId; + 0, // byteOrder; + + 2000, // prioASignalSize; + 1000, // prioBSignalSize; + 10 +}; + +SHM_TransporterConfiguration shmTemplate = { + 0, //remoteNodeId + 0, //localNodeId; + false, //compression + true, //checksum; + true, //signalId; + 0, //byteOrder; + 123, //shmKey; + 2500000 //shmSize; +}; + +TransporterRegistry *tReg = 0; + +#ifndef OSE_DELTA +#include <signal.h> +#endif + +extern "C" +void +signalHandler(int signo){ +#ifndef OSE_DELTA + ::signal(13, signalHandler); +#endif + char buf[255]; + sprintf(buf,"Signal: %d\n", signo); + ndbout << buf << endl; +} + +void +usage(const char * progName){ + ndbout << "Usage: " << progName << " <type> localNodeId localHostName" + << " remoteHostName1 remoteHostName2" << endl; + ndbout << " type = shm tcp ose sci" << endl; + ndbout << " localNodeId - 1 to 3" << endl; +} + +typedef void (* CreateTransporterFunc)(void * conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName); + +void createOSETransporter(void *, NodeId, NodeId, const char *, const char *); +void createSCITransporter(void *, NodeId, NodeId, const char *, const char *); +void createTCPTransporter(void *, NodeId, NodeId, const char *, const char *); +void createSHMTransporter(void *, NodeId, NodeId, const char *, const char *); + +int signalReceived[4]; + +int +main(int argc, const char **argv){ + + signalHandler(0); + + for(int i = 0; i<4; i++) + signalReceived[i] = 0; + + if(argc < 5){ + usage(argv[0]); + return 0; + } + + Uint32 noOfConnections = 0; + const char * progName = argv[0]; + const char * type = argv[1]; + const NodeId localNodeId = atoi(argv[2]); + const char * localHostName = argv[3]; + const char * remoteHost1 = argv[4]; + const char * remoteHost2 = NULL; + + if(argc == 5) + noOfConnections = 1; + else { + noOfConnections = 2; + remoteHost2 = argv[5]; + } + + if(localNodeId < 1 || localNodeId > 3){ + ndbout << "localNodeId = " << localNodeId << endl << endl; + usage(progName); + return 0; + } + + ndbout << "-----------------" << endl; + ndbout << "localNodeId: " << localNodeId << endl; + ndbout << "localHostName: " << localHostName << endl; + ndbout << "remoteHost1 (node " << (localNodeId == 1?2:1) << "): " + << remoteHost1 << endl; + if(noOfConnections == 2){ + ndbout << "remoteHost2 (node " << (localNodeId == 3?2:3) << "): " + << remoteHost2 << endl; + } + ndbout << "-----------------" << endl; + + void * confTemplate = 0; + CreateTransporterFunc func = 0; + + if(strcasecmp(type, "tcp") == 0){ + func = createTCPTransporter; + confTemplate = &tcpTemplate; + } else if(strcasecmp(type, "ose") == 0){ + func = createOSETransporter; + confTemplate = &oseTemplate; + } else if(strcasecmp(type, "sci") == 0){ + func = createSCITransporter; + confTemplate = &sciTemplate; + } else if(strcasecmp(type, "shm") == 0){ + func = createSHMTransporter; + confTemplate = &shmTemplate; + } else { + ndbout << "Unsupported transporter type" << endl; + return 0; + } + + ndbout << "Creating transporter registry" << endl; + tReg = new TransporterRegistry; + tReg->init(localNodeId); + + switch(localNodeId){ + case 1: + (* func)(confTemplate, 1, 2, localHostName, remoteHost1); + if(noOfConnections == 2) + (* func)(confTemplate, 1, 3, localHostName, remoteHost2); + break; + case 2: + (* func)(confTemplate, 2, 1, localHostName, remoteHost1); + if(noOfConnections == 2) + (* func)(confTemplate, 2, 3, localHostName, remoteHost2); + break; + case 3: + (* func)(confTemplate, 3, 1, localHostName, remoteHost1); + if(noOfConnections == 2) + (* func)(confTemplate, 3, 2, localHostName, remoteHost2); + break; + } + + ndbout << "Doing startSending/startReceiving" << endl; + tReg->startSending(); + tReg->startReceiving(); + + ndbout << "Connecting" << endl; + tReg->setPerformState(PerformConnect); + tReg->checkConnections(); + + unsigned sum = 0; + do { + sum = 0; + for(int i = 0; i<4; i++) + sum += signalReceived[i]; + + tReg->checkConnections(); + + tReg->external_IO(500); + NdbSleep_MilliSleep(500); + + ndbout << "In main loop" << endl; + } while(sum != 2*noOfConnections); + + ndbout << "Doing setPerformState(Disconnect)" << endl; + tReg->setPerformState(PerformDisconnect); + + ndbout << "Doing checkConnections()" << endl; + tReg->checkConnections(); + + ndbout << "Sleeping 3 secs" << endl; + NdbSleep_SecSleep(3); + + ndbout << "Deleting transporter registry" << endl; + delete tReg; tReg = 0; + + return 0; +} + +void +checkData(SignalHeader * const header, Uint8 prio, Uint32 * const theData, + LinearSectionPtr ptr[3]){ + Uint32 expectedLength = 0; + if(prio == 0) + expectedLength = 17; + else + expectedLength = 19; + + if(header->theLength != expectedLength){ + ndbout << "Unexpected signal length: " << header->theLength + << " expected: " << expectedLength << endl; + abort(); + } + + if(header->theVerId_signalNumber != expectedLength + 1) + abort(); + + if(header->theReceiversBlockNumber != expectedLength + 2) + abort(); + + if(refToBlock(header->theSendersBlockRef) != expectedLength + 3) + abort(); + + if(header->theSendersSignalId != expectedLength + 5) + abort(); + + if(header->theTrace != expectedLength + 6) + abort(); + + if(header->m_noOfSections != (prio == 0 ? 0 : 1)) + abort(); + + if(header->m_fragmentInfo != (prio + 1)) + abort(); + + Uint32 dataWordStart = header->theLength ; + for(unsigned i = 0; i<header->theLength; i++){ + if(theData[i] != i){ //dataWordStart){ + ndbout << "data corrupt!\n" << endl; + abort(); + } + dataWordStart ^= (~i*i); + } + + if(prio != 0){ + ndbout_c("Found section"); + if(ptr[0].sz != header->theLength) + abort(); + + if(memcmp(ptr[0].p, theData, (ptr[0].sz * 4)) != 0) + abort(); + } +} + +void +sendSignalTo(NodeId nodeId, int prio){ + SignalHeader sh; + sh.theLength = (prio == 0 ? 17 : 19); + sh.theVerId_signalNumber = sh.theLength + 1; + sh.theReceiversBlockNumber = sh.theLength + 2; + sh.theSendersBlockRef = sh.theLength + 3; + sh.theSendersSignalId = sh.theLength + 4; + sh.theSignalId = sh.theLength + 5; + sh.theTrace = sh.theLength + 6; + sh.m_noOfSections = (prio == 0 ? 0 : 1); + sh.m_fragmentInfo = prio + 1; + + Uint32 theData[25]; + + Uint32 dataWordStart = sh.theLength; + for(unsigned i = 0; i<sh.theLength; i++){ + theData[i] = i; + dataWordStart ^= (~i*i); + } + ndbout << "Sending prio " << (int)prio << " signal to node: " + << nodeId + << " gsn = " << sh.theVerId_signalNumber << endl; + + LinearSectionPtr ptr[3]; + ptr[0].p = &theData[0]; + ptr[0].sz = sh.theLength; + + SendStatus s = tReg->prepareSend(&sh, prio, theData, nodeId, ptr); + if(s != SEND_OK){ + ndbout << "Send was not ok. Send was: " << s << endl; + } +} + +void +execute(void* callbackObj, + SignalHeader * const header, Uint8 prio, Uint32 * const theData, + LinearSectionPtr ptr[3]){ + const NodeId nodeId = refToNode(header->theSendersBlockRef); + + ndbout << "Recieved prio " << (int)prio << " signal from node: " + << nodeId + << " gsn = " << header->theVerId_signalNumber << endl; + checkData(header, prio, theData, ptr); + ndbout << " Data is ok!\n" << endl; + + signalReceived[nodeId]++; + + if(prio == 0) + sendSignalTo(nodeId, 1); + else + tReg->setPerformState(nodeId, PerformDisconnect); +} + +void +copy(Uint32 * & insertPtr, + class SectionSegmentPool & thePool, const SegmentedSectionPtr & _ptr){ + abort(); +} + +void +reportError(void* callbackObj, NodeId nodeId, TransporterError errorCode){ + char buf[255]; + sprintf(buf, "reportError (%d, %x)", nodeId, errorCode); + ndbout << buf << endl; + if(errorCode & 0x8000){ + tReg->setPerformState(nodeId, PerformDisconnect); + abort(); + } +} + +/** + * Report average send theLength in bytes (4096 last sends) + */ +void +reportSendLen(void* callbackObj, NodeId nodeId, Uint32 count, Uint64 bytes){ + char buf[255]; + sprintf(buf, "reportSendLen(%d, %d)", nodeId, (Uint32)(bytes/count)); + ndbout << buf << endl; +} + +/** + * Report average receive theLength in bytes (4096 last receives) + */ +void +reportReceiveLen(void* callbackObj, NodeId nodeId, Uint32 count, Uint64 bytes){ + char buf[255]; + sprintf(buf, "reportReceiveLen(%d, %d)", nodeId, (Uint32)(bytes/count)); + ndbout << buf << endl; +} + +/** + * Report connection established + */ +void +reportConnect(void* callbackObj, NodeId nodeId){ + char buf[255]; + sprintf(buf, "reportConnect(%d)", nodeId); + ndbout << buf << endl; + tReg->setPerformState(nodeId, PerformIO); + + sendSignalTo(nodeId, 0); +} + +/** + * Report connection broken + */ +void +reportDisconnect(void* callbackObj, NodeId nodeId, Uint32 errNo){ + char buf[255]; + sprintf(buf, "reportDisconnect(%d)", nodeId); + ndbout << buf << endl; + if(signalReceived[nodeId] < 2) + tReg->setPerformState(nodeId, PerformConnect); +} + +int +checkJobBuffer() { + /** + * Check to see if jobbbuffers are starting to get full + * and if so call doJob + */ + return 0; +} + +void +createOSETransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName){ + ndbout << "Creating OSE transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + OSE_TransporterConfiguration * conf = (OSE_TransporterConfiguration*)_conf; + + conf->localNodeId = localNodeId; + conf->localHostName = localHostName; + conf->remoteNodeId = remoteNodeId; + conf->remoteHostName = remoteHostName; + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + +void +createTCPTransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName){ + ndbout << "Creating TCP transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + TCP_TransporterConfiguration * conf = (TCP_TransporterConfiguration*)_conf; + + int port; + if(localNodeId == 1 && remoteNodeId == 2) port = basePortTCP + 0; + if(localNodeId == 1 && remoteNodeId == 3) port = basePortTCP + 1; + if(localNodeId == 2 && remoteNodeId == 1) port = basePortTCP + 0; + if(localNodeId == 2 && remoteNodeId == 3) port = basePortTCP + 2; + if(localNodeId == 3 && remoteNodeId == 1) port = basePortTCP + 1; + if(localNodeId == 3 && remoteNodeId == 2) port = basePortTCP + 2; + + conf->localNodeId = localNodeId; + conf->localHostName = localHostName; + conf->remoteNodeId = remoteNodeId; + conf->remoteHostName = remoteHostName; + conf->port = port; + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + +void +createSCITransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName){ + + + ndbout << "Creating SCI transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + + SCI_TransporterConfiguration * conf = (SCI_TransporterConfiguration*)_conf; + + conf->remoteSciNodeId0= (Uint16)atoi(localHostName); + conf->remoteSciNodeId1= (Uint16)atoi(remoteHostName); + + + conf->localNodeId = localNodeId; + conf->remoteNodeId = remoteNodeId; + + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + +void +createSHMTransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName){ + + + ndbout << "Creating SHM transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + + SHM_TransporterConfiguration * conf = (SHM_TransporterConfiguration*)_conf; + + conf->localNodeId = localNodeId; + conf->remoteNodeId = remoteNodeId; + + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} diff --git a/ndb/src/common/transporter/buddy.cpp b/ndb/src/common/transporter/buddy.cpp new file mode 100644 index 00000000000..c65aad1df2c --- /dev/null +++ b/ndb/src/common/transporter/buddy.cpp @@ -0,0 +1,328 @@ +/* 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 "buddy.hpp" +#include <stdlib.h> +#include <math.h> + + +void Chunk256::setFree(bool free){ + // Bit 0 of allocationTimeStamp represents if the segment is free or not + Uint32 offMask = 0x0; // A mask to set the 0 bit to 0 + allocationTimeStamp = 0x0; + if(free) + // Set this bit to 0, if segment should be free + allocationTimeStamp = allocationTimeStamp & offMask; +} + +bool Chunk256::getFree(){ + Uint32 offMask = 0x0; + return ((allocationTimeStamp | offMask) == offMask ? true : false); +} + +void Chunk256::setAllocationTimeStamp(Uint32 cTime){ + // Bits 1-31 of allocationTimeStamp represent the allocation time for segment + + // printf("\nSet allocation time. Current time %d", cTime); + Uint32 onMask = 0x80000000; // A mask to set the 0 bit to 1 + allocationTimeStamp = 0x0; + allocationTimeStamp = onMask | cTime; +} + +Uint32 Chunk256::getAllocationTimeStamp(){ + Uint32 onMask = 0x80000000; + allocationTimeStamp = allocationTimeStamp ^ onMask; + printf("\nGet allocation time. Time is %d", allocationTimeStamp); + return allocationTimeStamp; +}; + +bool BuddyMemory::allocate(int nChunksToAllocate) { + + // Allocate the memory block needed. This memory is deallocated in the + // destructor of TransporterRegistry. + + printf("\nAllocating %d chunks...", nChunksToAllocate); + + startOfMemoryBlock = (Uint32*) malloc(256 * nChunksToAllocate); + + if (startOfMemoryBlock == NULL) + return false; + + // Allocate the array of 256-byte chunks + chunk = new Chunk256[nChunksToAllocate]; + + // Initialize the chunk-array. Every 8 kB segment consists of 32 chunks. + // Set all chunks to free and set the prev and next pointer + for (int i=0; i < nChunksToAllocate; i++) { + chunk[i].setFree(true); + if (i%32 == 0) { + // The first chunk in every segment will point to the prev and next segment + chunk[i].prevSegmentOfSameSize = i-32; + chunk[i].nextSegmentOfSameSize = i + 32; + chunk[0].prevSegmentOfSameSize = END_OF_CHUNK_LIST; + chunk[totalNoOfChunks-32].nextSegmentOfSameSize = END_OF_CHUNK_LIST; + } else { + // The rest of the chunks in the segments have undefined prev and next pointers + chunk[i].prevSegmentOfSameSize = UNDEFINED_CHUNK; + chunk[i].nextSegmentOfSameSize = UNDEFINED_CHUNK; + } + } + + // Initialize the freeSegment-pointers + for (int i=0; i<sz_MAX; i++) + freeSegment[i] = UNDEFINED_CHUNK; + + // There are only 8 kB segments at startup + freeSegment[sz_8192] = 0; + + for (int i=0; i<sz_MAX; i++) + printf("\nPointers: %d", freeSegment[i]); + + return true; +} + + +bool BuddyMemory::getSegment(Uint32 size, Segment * dst) { + + // The no of chunks the user asked for + Uint32 nChunksAskedFor = ceil((double(size)/double(256))); + int segm; + + printf("\n%d chunks asked for", nChunksAskedFor); + + // It may be that the closest segment size above + // nChunksAskedFor*256 is not a size that is available in + // the freeSegment-list, i.e. it may not be of FreeSegmentSize. + int nChunksToAllocate = nChunksAskedFor; + + // Find the FreeSegmentSize closest above nChunksAskedFor + if ((nChunksToAllocate != 1) && (nChunksToAllocate % 2 != 0)) + nChunksToAllocate++; + + printf("\n%d chunks to allocate", nChunksToAllocate); + int segmSize = logTwoPlus(nChunksToAllocate) - 1; + if (size-pow(2,segmSize) > 256) + segmSize ++; + printf("\nSegment size: %f", pow(2,int(8+segmSize))); + + while ((segmSize <= sz_GET_MAX) && (freeSegment[segmSize] == UNDEFINED_CHUNK)) + segmSize++; + + segm = freeSegment[segmSize]; + if (segm != UNDEFINED_CHUNK){ + // Free segment of asked size or larger is found + + // Remove the found segment from the freeSegment-list + removeFromFreeSegmentList(segmSize, segm); + + // Set all chunks to allocated (not free) and set the allocation time + // for the segment we are about to allocate + for (int i = segm; i <= segm+nChunksToAllocate; i++) { + chunk[i].setFree(false); + chunk[i].setAllocationTimeStamp(currentTime); + } + + // Before returning the segment, check if it is larger than the segment asked for + if (nChunksAskedFor < nChunksToAllocate) + release(nChunksAskedFor, nChunksToAllocate - nChunksAskedFor - 1); + + Segment segment; + segment.segmentAddress = startOfMemoryBlock+(segm * 256); + segment.segmentSize = 256 * nChunksAskedFor; + segment.releaseId = segm; + + printf("\nSegment: segment address = %d, segment size = %d, release Id = %d", + segment.segmentAddress, segment.segmentSize, segment.releaseId); + + return true; + } + printf("\nNo segments of asked size or larger are found"); + return false; +} + +void BuddyMemory::removeFromFreeSegmentList(int sz, int index) { + // Remove the segment from the freeSegment list + + printf("\nRemoving segment from list..."); + if (index != UNDEFINED_CHUNK) { + Chunk256 prevChunk; + Chunk256 nextChunk; + int prevChunkIndex = chunk[index].prevSegmentOfSameSize; + int nextChunkIndex = chunk[index].nextSegmentOfSameSize; + + if (prevChunkIndex == END_OF_CHUNK_LIST) { + if (nextChunkIndex == END_OF_CHUNK_LIST) + // We are about to remove the only element in the list + freeSegment[sz] = UNDEFINED_CHUNK; + else { + // We are about to remove the first element in the list + nextChunk = chunk[nextChunkIndex]; + nextChunk.prevSegmentOfSameSize = END_OF_CHUNK_LIST; + freeSegment[sz] = nextChunkIndex; + } + } else { + if (nextChunkIndex == END_OF_CHUNK_LIST) { + // We are about to remove the last element in the list + prevChunk = chunk[prevChunkIndex]; + prevChunk.nextSegmentOfSameSize = END_OF_CHUNK_LIST; + } else { + // We are about to remove an element in the middle of the list + prevChunk = chunk[prevChunkIndex]; + nextChunk = chunk[nextChunkIndex]; + prevChunk.nextSegmentOfSameSize = nextChunkIndex; + nextChunk.prevSegmentOfSameSize = prevChunkIndex; + } + } + } + for (int i=0; i<sz_MAX; i++) + printf("\nPointers: %d", freeSegment[i]); +} + +void BuddyMemory::release(int releaseId, int size) { + + int nChunksToRelease = (size == 0 ? 1 : ceil(double(size)/double(256))); + //nChunksToRelease = ceil(double(size)/double(256)); + int startChunk = releaseId; + int endChunk = releaseId + nChunksToRelease - 1; + + printf("\n%d chunks to release (initially)", nChunksToRelease); + + // Set the chunks we are about to release to free + for (int i = startChunk; i <= endChunk; i++){ + chunk[i].setFree(true); + } + + // Look at the chunks before the segment we are about to release + for (int i = releaseId-1; i >= 0; i--) { + if (!chunk[i].getFree()) + break; + else { + startChunk = i; + nChunksToRelease++; + // Look at the next-pointer. If it is valid, we have a + // chunk that is the start of a free segment. Remove it + // from the freeSegment-list. + if (chunk[i].nextSegmentOfSameSize != UNDEFINED_CHUNK) + removeFromFreeSegmentList(size, i); + } + } + + // Look at the chunks after the segment we are about to release + for (int i = endChunk+1; i <= totalNoOfChunks; i++) { + if (!chunk[i].getFree()) + break; + else { + endChunk = i; + nChunksToRelease++; + // Look at the next-pointer. If it is valid, we have a + // chunk that is the start of a free segment. Remove it + // from the free segment list + if (chunk[i].nextSegmentOfSameSize != UNDEFINED_CHUNK) + removeFromFreeSegmentList(size, i); + } + } + + // We have the start and end indexes and total no of free chunks. + // Separate the chunks into segments that can be added to the + // freeSegments-list. + int restChunk = 0; + int segmSize; + + printf("\n%d chunks to release (finally)", nChunksToRelease); + + segmSize = logTwoPlus(nChunksToRelease) - 1; + if (segmSize > sz_MAX) { + segmSize = sz_MAX; + } + + nChunksToRelease = pow(2,segmSize); + addToFreeSegmentList(nChunksToRelease*256, startChunk); +} + +void BuddyMemory::addToFreeSegmentList(int sz, int index) { + // Add a segment to the freeSegment list + + printf("\nAsked to add segment of size %d", sz); + + // Get an index in freeSegment list corresponding to sz size + int segmSize = logTwoPlus(sz) - 1; + if (sz - pow(2,segmSize) >= 256) + segmSize ++; + sz = segmSize - 8; + + int nextSegm = freeSegment[sz]; + + printf("\nAdding a segment of size %f", pow(2,(8 + sz))); + + freeSegment[sz] = index; + if (nextSegm == UNDEFINED_CHUNK) { + // We are about to add a segment to an empty list + chunk[index].prevSegmentOfSameSize = END_OF_CHUNK_LIST; + chunk[index].nextSegmentOfSameSize = END_OF_CHUNK_LIST; + } + else { + // Add the segment first in the list + chunk[index].prevSegmentOfSameSize = END_OF_CHUNK_LIST; + chunk[index].nextSegmentOfSameSize = nextSegm; + chunk[nextSegm].prevSegmentOfSameSize = index; + } + + for (int i=0; i<sz_MAX; i++) + printf("\nPointers: %d", freeSegment[i]); + +} + +Uint32 BuddyMemory::logTwoPlus(Uint32 arg) { + // Calculate log2(arg) + 1 + + Uint32 resValue; + + arg = arg | (arg >> 8); + arg = arg | (arg >> 4); + arg = arg | (arg >> 2); + arg = arg | (arg >> 1); + resValue = (arg & 0x5555) + ((arg >> 1) & 0x5555); + resValue = (resValue & 0x3333) + ((resValue >> 2) & 0x3333); + resValue = resValue + (resValue >> 4); + resValue = (resValue & 0xf) + ((resValue >> 8) & 0xf); + + return resValue; +} + +bool BuddyMemory::memoryAvailable() { + // Return true if there is at least 8 kB memory available + for (int i = sz_8192; i < sz_MAX; i++) + if (freeSegment[i] != UNDEFINED_CHUNK) + return true; + return false; +} + + +void BuddyMemory::refreshTime(Uint32 time) { + if (time - currentTime > 1000) { + // Update current time + currentTime = time; + // Go through the chunk-list every second and release + // any chunks that have been allocated for too long + for (int i=0; i<totalNoOfChunks; i++) { + if ((!chunk[i].getFree()) && + (currentTime-chunk[i].getAllocationTimeStamp() > ALLOCATION_TIMEOUT)) { + release(i, 256); + printf("\nChunks hve been allocated for too long"); + } + } + } +} diff --git a/ndb/src/common/transporter/buddy.hpp b/ndb/src/common/transporter/buddy.hpp new file mode 100644 index 00000000000..7272ac884ec --- /dev/null +++ b/ndb/src/common/transporter/buddy.hpp @@ -0,0 +1,173 @@ +/* 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 */ + +#ifndef BUDDY_H +#define BUDDY_H + +#include <stdlib.h> +#include <stdio.h> + +typedef unsigned int Uint32; +typedef unsigned short Uint16; +typedef unsigned long long Uint64; + +// +const int UNDEFINED_CHUNK = -2; // XXX Set to hex + +// +const int END_OF_CHUNK_LIST = -1; // XXX Set to hex + +// A timeout (no of seconds) for the memory segments in the TransporterRegistry +// memory pool. If a segment has been occupied (free=false) for a longer period +// than this timeout, it will be released. +const int ALLOCATION_TIMEOUT = 10000; + +// Free segments should always be as large as possible +// and are only allowed to be in any of these sizes +enum FreeSegmentSize { + sz_256 = 0, + sz_512 = 1, + sz_1024 = 2, + sz_2048 = 3, + sz_4096 = 4, + sz_8192 = 5, + sz_16384 = 6, + sz_32768 = 7, + sz_65536 = 8, + sz_131072 = 9, + sz_GET_MAX = 5, + sz_MAX = 9 +}; + +struct Segment; + +class BuddyMemory { +public: + + // Return true if there is at least 8 kB memory available + bool memoryAvailable(); + + // + bool allocate(int nChunksToAllocate); + + // Remove the segment from the freeSegment list + void removeFromFreeSegmentList(int sz, int index); + + // Release the segment of size + void release(int releaseId, int size); + + // Add a segment to the freeSegment list + void addToFreeSegmentList(int sz, int index); + + bool getSegment(Uint32 size, Segment * dst); + + void refreshTime(Uint32 time); + + //Calculate log2(arg) + 1 + Uint32 logTwoPlus(Uint32 arg); + + // The current time + Uint32 currentTime; + + // Pointer to the first free segment of size FreeSegmentSize + Uint32 freeSegment[sz_MAX]; + + // Start address of the memory block allocated + Uint32* startOfMemoryBlock; + + // Total number of 256 byte chunks. + Uint32 totalNoOfChunks; + + // Array of 256-byte chunks + struct Chunk256* chunk; +}; + +struct Segment { + Uint32 segmentSize; // Size of the segment in no of words + Uint16 index; // Index in the array of SegmentListElements + Uint16 releaseId; // Unique no used when releasing the segment + // Undefined if Long_signal.deallocIndicator==0 + union { + Uint32* segmentAddress; // Address to the memory segment + Uint64 _padding_NOT_TO_BE_USED_; + }; +}; + +struct Chunk256 { + Uint32 allocationTimeStamp; // Bit 0 represents if the segment is free or not + // Bit 1-31 is the allocation time for the segment + // Bit 1-31 are undefined if the segment is free + Uint32 nextSegmentOfSameSize; // Undefined if allocated. + // The first chunk in a free segment has a valid + // next-pointer. In the rest of the chunks + // belonging to the segment it is UNDEFINED_CHUNK. + Uint32 prevSegmentOfSameSize; // Undefined if allocated + // The first chunk in a free segment has a valid + // prev-pointer. In the rest of the chunks + // belonging to the segment it is UNDEFINED_CHUNK. + + void setFree(bool free); + + bool getFree(); + + void setAllocationTimeStamp(Uint32 cTime); + + Uint32 getAllocationTimeStamp(); +}; + +// inline void Chunk256::setFree(bool free){ +// // Bit 0 of allocationTimeStamp represents if the segment is free or not +// allocationTimeStamp = 0x0; + +// printf("\nSet free segment"); +// Uint32 offMask = 0x0; // A mask to set the 0 bit to 0 +// if(free) +// // Set this bit to 0, if segment should be free +// allocationTimeStamp = allocationTimeStamp & offMask; +// } + +// inline bool Chunk256::getFree(){ +// // Get free segment + +// allocationTimeStamp = 0x0; +// Uint32 offMask = 0x0; + +// printf("\nGet free segment"); +// return ((allocationTimeStamp | offMask) == offMask ? true : false); +// } + +// inline void Chunk256::setAllocationTimeStamp(Uint32 cTime){ +// // Bits 1-31 of allocationTimeStamp represent the allocation time for segment + +// Uint32 onMask = 0x80000000; // A mask to set the 0 bit to 1 +// allocationTimeStamp = 0x0; + +// printf("\nSet allocation time"); + +// allocationTimeStamp = onMask | cTime; +// } + +// inline Uint32 Chunk256::getAllocationTimeStamp(){ + +// Uint32 onMask = 0x80000000; // A mask to set the 0 bit to 1 +// allocationTimeStamp = 0x0; + +// printf("\nGet allocation time"); +// allocationTimeStamp = allocationTimeStamp ^ onMask; +// return allocationTimeStamp; +// }; + +#endif diff --git a/ndb/src/common/transporter/failoverSCI/Makefile b/ndb/src/common/transporter/failoverSCI/Makefile new file mode 100644 index 00000000000..1e3d5f4a4b7 --- /dev/null +++ b/ndb/src/common/transporter/failoverSCI/Makefile @@ -0,0 +1,18 @@ +include .defs.mk + +TYPE := ndbapi + +BIN_TARGET := failoverSCI +BIN_TARGET_LIBS := sisci +BIN_TARGET_ARCHIVES := portlib + +CCFLAGS_LOC += -I.. + +SOURCES = failoverSCI.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/transporter/failoverSCI/failoverSCI.cpp b/ndb/src/common/transporter/failoverSCI/failoverSCI.cpp new file mode 100644 index 00000000000..03ce7ea6df3 --- /dev/null +++ b/ndb/src/common/transporter/failoverSCI/failoverSCI.cpp @@ -0,0 +1,866 @@ +/* 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "sisci_types.h" +#include "sisci_api.h" +#include "sisci_error.h" +//#include "sisci_demolib.h" +#include <strings.h> +#include <ndb_types.h> +#include <NdbTick.h> +#include "NdbSleep.h" +#define NO_CALLBACK NULL +#define NO_FLAGS 0 +#define DATA_TRANSFER_READY 8 + +sci_error_t error; +sci_desc_t sdOne; +sci_desc_t sdTwo; +sci_local_segment_t localSegmentOne; +sci_local_segment_t localSegmentTwo; +sci_remote_segment_t remoteSegmentOne; +sci_remote_segment_t remoteSegmentTwo; +sci_map_t localMapOne; +sci_map_t localMapTwo; +sci_map_t remoteMapOne; +sci_map_t remoteMapTwo; +unsigned int localAdapterNo = 0; +unsigned int standbyAdapterNo = 1; +unsigned int localNodeId1; +unsigned int localNodeId2; +unsigned int remoteNodeId1 = 0; +unsigned int remoteNodeId2 = 0; +unsigned int localSegmentId; +unsigned int remoteSegmentId1; +unsigned int remoteSegmentId2; +unsigned int segmentSize = 8192; +unsigned int offset = 0; +unsigned int client = 0; +unsigned int server = 0; +unsigned int *localbufferPtr; +static int data; +static int interruptConnected=0; + +/*********************************************************************************/ +/* U S A G E */ +/* */ +/*********************************************************************************/ + +void Usage() +{ + printf("Usage of shmem\n"); + printf("shmem -rn <remote node-id> -client/server [ -adapterno <adapter no> -size <segment size> ] \n\n"); + printf(" -rn : Remote node-id\n"); + printf(" -client : The local node is client\n"); + printf(" -server : The local node is server\n"); + printf(" -adapterno : Local adapter number (default %d)\n", localAdapterNo); + printf(" -size : Segment block size (default %d)\n", segmentSize); + printf(" -help : This helpscreen\n"); + + printf("\n"); +} + + +/*********************************************************************************/ +/* P R I N T P A R A M E T E R S */ +/* */ +/*********************************************************************************/ +void PrintParameters(void) +{ + + printf("Test parameters for %s \n",(client) ? "client" : "server" ); + printf("----------------------------\n\n"); + printf("Local node-id1 : %d\n",localNodeId1); + printf("Local node-id2 : %d\n",localNodeId2); + // printf("Remote node-id : %d\n",remoteNodeId); + printf("Local adapter no. : %d\n",localAdapterNo); + printf("Segment size : %d\n",segmentSize); + printf("----------------------------\n\n"); + +} + + +/*********************************************************************************/ +/* F I L L S E G M E N T W I T H D A T A */ +/* */ +/*********************************************************************************/ + +sci_error_t GetLocalNodeId(Uint32 localAdapterNo, Uint32* localNodeId) +{ + sci_query_adapter_t queryAdapter; + sci_error_t error; + unsigned int _localNodeId; + + queryAdapter.subcommand = SCI_Q_ADAPTER_NODEID; + queryAdapter.localAdapterNo = localAdapterNo; + queryAdapter.data = &_localNodeId; + + SCIQuery(SCI_Q_ADAPTER,&queryAdapter,NO_FLAGS,&error); + + *localNodeId=_localNodeId; + + return error; +} + + + + + + +sci_error_t SendInterrupt(sci_desc_t sd, + Uint32 localAdapterNo, + Uint32 localSciNodeId, + Uint32 remoteSciNodeId, + Uint32 interruptNo){ + + sci_error_t error; + sci_remote_interrupt_t remoteInterrupt; + Uint32 timeOut = SCI_INFINITE_TIMEOUT; + + // Now connect to the other sides interrupt flag + do { + SCIConnectInterrupt(sd, &remoteInterrupt, remoteSciNodeId, localAdapterNo, + interruptNo, timeOut, NO_FLAGS, &error); + } while (error != SCI_ERR_OK); + + if (error != SCI_ERR_OK) { + fprintf(stderr, "SCIConnectInterrupt failed - Error code 0x%x\n", error); + return error; + } + + // Trigger interrupt + printf("\nNode %u sent interrupt (0x%x) to node %d\n",localSciNodeId, interruptNo, remoteSciNodeId); + SCITriggerInterrupt(remoteInterrupt, NO_FLAGS, &error); + if (error != SCI_ERR_OK) { + fprintf(stderr, "SCITriggerInterrupt failed - Error code 0x%x\n", error); + return error; + } + + + // Disconnect and remove interrupts + SCIDisconnectInterrupt(remoteInterrupt, NO_FLAGS, &error); + if (error != SCI_ERR_OK) { + fprintf(stderr, "SCIDisconnectInterrupt failed - Error code 0x%x\n", error); + return error; + } + + return error; +} + + +sci_error_t ReceiveInterrupt(sci_desc_t sd, + Uint32 localAdapterNo, + Uint32 localSciNodeId, + Uint32 interruptNo, + Uint32 timeout) { + + sci_error_t error; + sci_local_interrupt_t localInterrupt; + Uint32 timeOut = SCI_INFINITE_TIMEOUT; + + // Create an interrupt + SCICreateInterrupt(sd, &localInterrupt, localAdapterNo, + &interruptNo, 0, NULL, SCI_FLAG_FIXED_INTNO, &error); + if (error != SCI_ERR_OK) { + fprintf(stderr, "SCICreateInterrupt failed - Error code 0x%x\n", error); + return error; + } + + + // Wait for an interrupt + SCIWaitForInterrupt(localInterrupt, timeOut, NO_FLAGS, &error); + + printf("\nNode %u received interrupt (0x%x)\n", localSciNodeId, interruptNo); + + // Remove interrupt + + SCIRemoveInterrupt(localInterrupt, NO_FLAGS, &error); + if (error != SCI_ERR_OK) { + fprintf(stderr, "SCIRemoveInterrupt failed - Error code 0x%x\n", error); + return error; + } + return error; +} + + +sci_error_t FillSegmentWithData(unsigned int segmentSize, int reverse) +{ + unsigned int i; + unsigned int nostores; + + + nostores = (segmentSize) / sizeof(unsigned int); + + /* Allocate buffer */ + + localbufferPtr = (unsigned int*)malloc( segmentSize ); + if ( localbufferPtr == NULL ) { + /* + * Unable to create local buffer - Insufficient memory available + */ + return SCI_ERR_NOSPC; + } + if(reverse) { + /* Fill in the data into a local buffer */ + printf("Filling forward order \n"); + for (i=0;i<nostores;i++) { + localbufferPtr[i] = i; + } + } + else { + int temp=nostores; + printf("Filling reverse order \n"); + for (i=0;i<nostores;i++) { + localbufferPtr[i] = temp-- ; + + } + + } + + return SCI_ERR_OK; +} + + + + +/*********************************************************************************/ +/* P R I N T C L I E N T D A T A */ +/* */ +/*********************************************************************************/ + +void PrintClientData(void) +{ + unsigned int i; + + printf("\nClient data: "); + /* Print the first 20 entries in the segment */ + for (i=0;i<20;i++) { + printf("%d ",localbufferPtr[i]); + } + + printf("\n"); +} + + +/*********************************************************************************/ +/* P R I N T S E R V E R D A T A */ +/* */ +/*********************************************************************************/ + +void PrintServerData(volatile unsigned int *localMapAddr) +{ + + unsigned int *buffer; + int i; + + // printf("\nServer data: "); + buffer = (unsigned int *)localMapAddr; + + /* Print the first 20 entries in the segment */ + for (i=0; i< 20; i++) { + + printf("%d ",buffer[i]); + } + printf("\n"); + +} + + + +/*********************************************************************************/ +/* T R A N S F E R D A T A */ +/* */ +/*********************************************************************************/ + +unsigned int TransferData(sci_map_t remoteMap, + volatile unsigned int *remoteSegmentAddr1, + volatile unsigned int *remoteSegmentAddr2, + unsigned int segmentSize) + +{ + + volatile unsigned int *remoteBuffer1; + volatile unsigned int *remoteBuffer; + volatile unsigned int *remoteBuffer2; + static int times = 0; + sci_sequence_t sequence; + sci_error_t error; + unsigned int nostores; + unsigned int j; + sci_sequence_status_t sequenceStatus; + + + remoteBuffer1 = (volatile unsigned int *)remoteSegmentAddr1; + remoteBuffer2 = (volatile unsigned int *)remoteSegmentAddr2; + remoteBuffer=remoteBuffer1; + + /* 4-byte test only */ + nostores = (segmentSize) / sizeof(unsigned int); + + /* Create a sequence for data error checking */ + SCICreateMapSequence(remoteMapOne,&sequence,NO_FLAGS,&error); + if (error != SCI_ERR_OK) { + fprintf(stderr,"SCICreateMapSequence failed - Error code 0x%x\n",error); + return error; + } + + + + /* Fill in the data into a local buffer */ + error = SendInterrupt(sdOne,localAdapterNo,localNodeId1,remoteNodeId1, DATA_TRANSFER_READY); + + error = FillSegmentWithData(segmentSize, 0); + + tryagain: + PrintServerData(localbufferPtr); + fprintf(stderr,"After recover \n"); + while(1){ + + + //data=0; + + if (error != SCI_ERR_OK) { + /* + * Unable to create local buffer - Insufficient memory available + */ + printf( "Unable to create local buffer - Insufficient memory available\n" ); + + return error; + } + + do { + /* Start data error checking */ + sequenceStatus = SCIStartSequence(sequence,NO_FLAGS,&error); + } while (sequenceStatus != SCI_SEQ_OK) ; + + + /* Transfer data to remote node */ + for (j=0;j<nostores;j++) { + remoteBuffer[j] = localbufferPtr[j]; + } + + /* Check for error after data transfer */ + sequenceStatus = SCICheckSequence(sequence,NO_FLAGS,&error); + if (sequenceStatus != SCI_SEQ_OK) { + fprintf(stderr,"Data transfer failed\n"); + if(times==0) { + error = FillSegmentWithData(segmentSize, 1); + + SCICreateMapSequence(remoteMapTwo,&sequence,NO_FLAGS,&error); + if (error != SCI_ERR_OK) { + fprintf(stderr,"SCICreateMapSequence failed - Error code 0x%x\n",error); + return error; + return SCI_ERR_TRANSFER_FAILED; + } + } + else + { + error = FillSegmentWithData(segmentSize, 0); + /* Create a sequence for data error checking */ + SCICreateMapSequence(remoteMapOne,&sequence,NO_FLAGS,&error); + if (error != SCI_ERR_OK) { + fprintf(stderr,"SCICreateMapSequence failed - Error code 0x%x\n",error); + return error; + return SCI_ERR_TRANSFER_FAILED; + } + + } + fprintf(stderr,"Recovery \n"); + if(times==0) + remoteBuffer=remoteBuffer2; + else + remoteBuffer=remoteBuffer1; + times++; + printf("remotebuffer %p times %d\n", remoteBuffer, times); + goto tryagain; + + } + int timeout=0; + // error = SendInterrupt(sdOne,localAdapterNo,localNodeId1,remoteNodeId1, DATA_TRANSFER_READY); + // NdbSleep_MilliSleep(100); + //error = ReceiveInterrupt(sdOne,localAdapterNo,localNodeId1,DATA_TRANSFER_READY, timeout); + + } + /* Remove the Sequence */ + SCIRemoveSequence(sequence,NO_FLAGS, &error); + if (error != SCI_ERR_OK) { + fprintf(stderr,"SCIRemoveSequence failed - Error code 0x%x\n",error); + return error; + } + + return SCI_ERR_OK; +} + + +/*********************************************************************************/ +/* S H M E M C L I E N T N O D E */ +/* */ +/*********************************************************************************/ + +unsigned int ShmemClientNode(void) +{ + + volatile unsigned int *remoteMapAddr1; + volatile unsigned int *remoteMapAddr2; + printf("here?\n"); + + + /* Create a segmentId */ + remoteSegmentId1 = 1;//(remoteNodeId1 << 16) | localNodeId1; + + /* Connect to remote segment */ + + printf("Connect to remote segment .... \n"); + printf("segid = %d node %d \n",remoteSegmentId1, remoteNodeId1 ); + + do { + SCIConnectSegment(sdOne, + &remoteSegmentOne, + remoteNodeId1, + remoteSegmentId1, + localAdapterNo, + NO_CALLBACK, + NULL, + SCI_INFINITE_TIMEOUT, + NO_FLAGS, + &error); + + } while (error != SCI_ERR_OK); + + + printf("connected\n"); + + // remoteSegmentId2 = (remoteNodeId2 << 16) | localNodeId2; + // printf("segid = %d\n",remoteSegmentId2 ); + printf("segid = %d node %d \n",remoteSegmentId1, remoteNodeId1 ); + do { + SCIConnectSegment(sdTwo, + &remoteSegmentTwo, + remoteNodeId2, + remoteSegmentId1, + standbyAdapterNo, + NO_CALLBACK, + NULL, + SCI_INFINITE_TIMEOUT, + NO_FLAGS, + &error); + + } while (error != SCI_ERR_OK); + + + + printf("connected 3\n"); + printf("Remote segment (id=0x%x) is connected.\n", remoteSegmentId2); + + + /* Map remote segment to user space */ + remoteMapAddr1 = (unsigned int*)SCIMapRemoteSegment(remoteSegmentOne,&remoteMapOne,offset,segmentSize,NULL,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Remote segment (id=0x%x) is mapped to user space @ 0x%x. \n", remoteSegmentId1, remoteMapAddr1); + } else { + fprintf(stderr,"SCIMapRemoteSegment failed - Error code 0x%x\n",error); + return 0; + } + + remoteMapAddr2 = (unsigned int *)SCIMapRemoteSegment(remoteSegmentTwo,&remoteMapTwo,offset,segmentSize,NULL,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Remote segment (id=0x%x) is mapped to user space @ 0x%x. \n", remoteSegmentId2, remoteMapAddr2); + } else { + fprintf(stderr,"SCIMapRemoteSegment failed - Error code 0x%x\n",error); + return 0; + } + + + /* Start data transfer and error checking */ + error = (sci_error_t)TransferData(remoteMapOne,remoteMapAddr1, remoteMapAddr2,segmentSize); + if (error == SCI_ERR_OK) { + printf("Data transfer done!\n\n"); + } else { + fprintf(stderr,"Data transfer failed - Error code 0x%x\n\n",error); + return 0; + } + + /* Send an interrupt to remote node telling that the data transfer is ready */ + error = SendInterrupt(sdOne,localAdapterNo,localNodeId1,remoteNodeId1, DATA_TRANSFER_READY); + if (error == SCI_ERR_OK) { + printf("\nInterrupt message sent to remote node\n"); + } else { + printf("\nInterrupt synchronization failed\n"); + return 0; + } + + PrintClientData(); + + /* Unmap remote segment */ + SCIUnmapSegment(remoteMapOne,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The remote segment is unmapped\n"); + } else { + fprintf(stderr,"SCIUnmapSegment failed - Error code 0x%x\n",error); + return 0; + } + + SCIUnmapSegment(remoteMapTwo,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The remote segment is unmapped\n"); + } else { + fprintf(stderr,"SCIUnmapSegment failed - Error code 0x%x\n",error); + return 0; + } + /* Disconnect segment */ + SCIDisconnectSegment(remoteSegmentOne,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The segment is disconnected\n"); + } else { + fprintf(stderr,"SCIDisconnectSegment failed - Error code 0x%x\n",error); + return 0; + } + + SCIDisconnectSegment(remoteSegmentTwo,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The segment is disconnected\n"); + } else { + fprintf(stderr,"SCIDisconnectSegment failed - Error code 0x%x\n",error); + return 0; + } + + + return 1; +} + + +/*********************************************************************************/ +/* S H M E M S E R V E R N O D E */ +/* */ +/*********************************************************************************/ + +unsigned int ShmemServerNode(void) +{ + + unsigned int *localMapAddr; + + /* Create a segmentId */ + localSegmentId =1;// (localNodeId1 << 16) | remoteNodeId1; + + /* Create local segment */ + SCICreateSegment(sdOne,&localSegmentOne,localSegmentId, segmentSize, NO_CALLBACK, NULL, NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=%d, size=%d) is created. \n", localSegmentId, segmentSize); + } else { + fprintf(stderr,"SCICreateSegment failed - Error code 0x%x\n",error); + return 0; + } + + //localSegmentId = (localNodeId2 << 16) | remoteNodeId2; + /* + SCICreateSegment(sdTwo,&localSegmentTwo,localSegmentId+1, segmentSize, NO_CALLBACK, NULL, NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=%d, size=%d) is created (2). \n", localSegmentId, segmentSize); + } else { + fprintf(stderr,"SCICreateSegment failed - Error code 0x%x\n",error); + return 0; + } + + printf("segment one %p segment 2 %p\n", localSegmentOne, localSegmentTwo); + */ + /* Prepare the segment */ + SCIPrepareSegment(localSegmentOne,localAdapterNo,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=%d, size=%d) is prepared. \n", localSegmentId, segmentSize); + } else { + fprintf(stderr,"SCIPrepareSegment failed - Error code 0x%x\n",error); + return 0; + } + + + /* Prepare the segment */ + + SCIPrepareSegment(localSegmentOne,standbyAdapterNo,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=%d, size=%d) is created. \n", localSegmentId, segmentSize); + } else { + fprintf(stderr,"SCIPrepareSegment failed - Error code 0x%x\n",error); + return 0; + } + + + /* Map local segment to user space */ + localMapAddr = (unsigned int *)SCIMapLocalSegment(localSegmentOne,&localMapOne, offset,segmentSize, NULL,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=0x%x) is mapped to user space @ 0x%x.\n", localSegmentId, localMapAddr); + } else { + fprintf(stderr,"SCIMapLocalSegment failed - Error code 0x%x\n",error); + return 0; + } + + + /* Map local segment to user space */ + /* + localMapAddr = (unsigned int *)SCIMapLocalSegment(localSegmentTwo,&localMapTwo, offset,segmentSize, NULL,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=0x%x) is mapped to user space @ 0x%x.\n", localSegmentId, localMapAddr); + printf("Local segment (id=%d) is mapped to user space.\n", localSegmentId); + } else { + fprintf(stderr,"SCIMapLocalSegment failed - Error code 0x%x\n",error); + return 0; + } + */ + + /* Set the segment available */ + SCISetSegmentAvailable(localSegmentOne, localAdapterNo, NO_FLAGS, &error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=0x%x) is available for remote connections. \n", localSegmentId); + } else { + fprintf(stderr,"SCISetSegmentAvailable failed - Error code 0x%x\n",error); + return 0; + } + + + SCISetSegmentAvailable(localSegmentOne, standbyAdapterNo, NO_FLAGS, &error); + if (error == SCI_ERR_OK) { + printf("Local segment (id=0x%x) is available for remote connections. \n", localSegmentId); + } else { + fprintf(stderr,"SCISetSegmentAvailable failed - Error code 0x%x\n",error); + return 0; + } + int timeout=0; + error = ReceiveInterrupt(sdOne,localAdapterNo,localNodeId1,DATA_TRANSFER_READY, timeout); + + if (error == SCI_ERR_OK) { + printf("\nThe data transfer is ready\n"); + } else { + printf("\nInterrupt synchronization failed\n"); + return 0; + } + + + again: + + // printf("Wait for the shared memory data transfer ....."); + /* Wait for interrupt signal telling that block transfer is ready */ + + //printf("\nData transfer done!\n"); + //PrintClientData() + PrintServerData(localMapAddr); + /*Uint32 micros; + Uint32 micros2; + NDB_TICKS secs; + NdbTick_CurrentMicrosecond(&secs, µs); + error = SendInterrupt(sdOne,localAdapterNo,localNodeId1,remoteNodeId1, DATA_TRANSFER_READY); + NdbTick_CurrentMicrosecond(&secs, µs2); + printf("TIME ELAPSED %d \n", micros2-micros); +// NdbSleep_MilliSleep(100); + */ + goto again; + + /* Unmap local segment */ + SCIUnmapSegment(localMapTwo,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The local segment is unmapped\n"); + } else { + fprintf(stderr,"SCIUnmapSegment failed - Error code 0x%x\n",error); + return 0; + } + + /* Unmap local segment */ + SCIUnmapSegment(localMapOne,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The local segment is unmapped\n"); + } else { + fprintf(stderr,"SCIUnmapSegment failed - Error code 0x%x\n",error); + return 0; + } + /* Remove local segment */ + SCIRemoveSegment(localSegmentOne,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The local segment is removed\n"); + } else { + fprintf(stderr,"SCIRemoveSegment failed - Error code 0x%x\n",error); + return 0; + } + + /* Remove local segment */ + SCIRemoveSegment(localSegmentTwo,NO_FLAGS,&error); + if (error == SCI_ERR_OK) { + printf("The local segment is removed\n"); + } else { + fprintf(stderr,"SCIRemoveSegment failed - Error code 0x%x\n",error); + return 0; + } + + + + + return 1; +} + + + +/*********************************************************************************/ +/* M A I N */ +/* */ +/*********************************************************************************/ + +int main(int argc,char *argv[]) +{ + + int counter; + + printf("\n %s compiled %s : %s\n\n",argv[0],__DATE__,__TIME__); + + if (argc<3) { + Usage(); + exit(-1); + } + + + /* Get the parameters */ + for (counter=1; counter<argc; counter++) { + + if (!strcmp("-rn",argv[counter])) { + // remoteNodeId = strtol(argv[counter+1],(char **) NULL,10); + continue; + } + + if (!strcmp("-size",argv[counter])) { + segmentSize = strtol(argv[counter+1],(char **) NULL,10); + continue; + } + + if (!strcmp("-adapterno",argv[counter])) { + localAdapterNo = strtol(argv[counter+1],(char **) NULL,10); + continue; + } + + if (!strcmp("-client",argv[counter])) { + client = 1; + continue; + } + + if (!strcmp("-server",argv[counter])) { + server = 1; + continue; + } + + if (!strcmp("-help",argv[counter])) { + Usage(); + exit(0); + } + } + + // if (remoteNodeId == 0) { + // fprintf(stderr,"Remote node-id is not specified. Use -rn <remote node-id>\n"); + // exit(-1); + //} + + if (server == 0 && client == 0) { + fprintf(stderr,"You must specify a client node or a server node\n"); + exit(-1); + } + + if (server == 1 && client == 1) { + fprintf(stderr,"Both server node and client node is selected.\n"); + fprintf(stderr,"You must specify either a client or a server node\n"); + exit(-1); + } + + + /* Initialize the SISCI library */ + SCIInitialize(NO_FLAGS, &error); + if (error != SCI_ERR_OK) { + fprintf(stderr,"SCIInitialize failed - Error code: 0x%x\n",error); + exit(error); + } + + + /* Open a file descriptor */ + SCIOpen(&sdOne,NO_FLAGS,&error); + if (error != SCI_ERR_OK) { + if (error == SCI_ERR_INCONSISTENT_VERSIONS) { + fprintf(stderr,"Version mismatch between SISCI user library and SISCI driver\n"); + } + fprintf(stderr,"SCIOpen failed - Error code 0x%x\n",error); + exit(error); + } + + /* Open a file descriptor */ + SCIOpen(&sdTwo,NO_FLAGS,&error); + if (error != SCI_ERR_OK) { + if (error == SCI_ERR_INCONSISTENT_VERSIONS) { + fprintf(stderr,"Version mismatch between SISCI user library and SISCI driver\n"); + } + fprintf(stderr,"SCIOpen failed - Error code 0x%x\n",error); + exit(error); + } + + + /* Get local node-id */ + error = GetLocalNodeId(localAdapterNo, &localNodeId1); + error = GetLocalNodeId(standbyAdapterNo, &localNodeId2); + if (error != SCI_ERR_OK) { + fprintf(stderr,"Could not find the local adapter %d\n", localAdapterNo); + SCIClose(sdOne,NO_FLAGS,&error); + SCIClose(sdTwo,NO_FLAGS,&error); + exit(-1); + } + + + /* Print parameters */ + PrintParameters(); + + if (client) { + remoteNodeId1=324; + remoteNodeId2=328; + ShmemClientNode(); + } else { + remoteNodeId1=452; + remoteNodeId2=456; + ShmemServerNode(); + } + + /* Close the file descriptor */ + SCIClose(sdOne,NO_FLAGS,&error); + SCIClose(sdTwo,NO_FLAGS,&error); + if (error != SCI_ERR_OK) { + fprintf(stderr,"SCIClose failed - Error code: 0x%x\n",error); + } + + + /* Free allocated resources */ + SCITerminate(); + + return SCI_ERR_OK; +} + + + + + + + + + + + + + + + + + diff --git a/ndb/src/common/transporter/perftest/Makefile b/ndb/src/common/transporter/perftest/Makefile new file mode 100644 index 00000000000..01869e1acf9 --- /dev/null +++ b/ndb/src/common/transporter/perftest/Makefile @@ -0,0 +1,15 @@ +include .defs.mk + +TYPE := ndbapi + +BIN_TARGET := perfTransporterTest +BIN_TARGET_ARCHIVES := transporter portlib general + +SOURCES = perfTransporterTest.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/transporter/perftest/perfTransporterTest.cpp b/ndb/src/common/transporter/perftest/perfTransporterTest.cpp new file mode 100644 index 00000000000..6d7f7083a48 --- /dev/null +++ b/ndb/src/common/transporter/perftest/perfTransporterTest.cpp @@ -0,0 +1,774 @@ +/* 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 "TransporterRegistry.hpp" +#include "TransporterDefinitions.hpp" +#include "TransporterCallback.hpp" +#include <RefConvert.hpp> + +#include <NdbStdio.h> +#include <stdlib.h> +#include <NdbTick.h> +#include <NdbMain.h> +#include <NdbOut.hpp> +#include <NdbSleep.h> +#include <NdbString.h> + +int basePortTCP = 17000; + +SCI_TransporterConfiguration sciTemplate = { + 2000, + // Packet size + 2000000, // Buffer size + 2, // number of adapters + 1, // remote node id SCI + 2, // Remote node Id SCI + 0, // local ndb node id (server) + 0, // remote ndb node id (client) + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + + +SHM_TransporterConfiguration shmTemplate = { + 0, //remoteNodeId + 0, //localNodeId; + false, //compression + true, //checksum; + true, //signalId; + 0, //byteOrder; + 123, //shmKey; + 25000000 //shmSize; +}; + + +TCP_TransporterConfiguration tcpTemplate = { + 17000, // port; + "", // remoteHostName; + "", // localhostname + 2, // remoteNodeId; + 1, // localNodeId; + 25000000, // sendBufferSize - Size of SendBuffer of priority B + 5000000, // maxReceiveSize - Maximum no of bytes to receive + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + +OSE_TransporterConfiguration oseTemplate = { + "", // remoteHostName; + "", // localHostName; + 0, // remoteNodeId; + 0, // localNodeId; + false, // compression; + true, // checksum; + true, // signalId; + 0, // byteOrder; + + 2000, // prioASignalSize; + 2000, // prioBSignalSize; + 10 // Recv buf size +}; + +TransporterRegistry *tReg = 0; + +#ifndef OSE_DELTA +#include <signal.h> +#endif + +extern "C" +void +signalHandler(int signo){ +#ifndef OSE_DELTA + ::signal(13, signalHandler); +#endif + char buf[255]; + sprintf(buf,"Signal: %d\n", signo); + ndbout << buf << endl; +} + +void +usage(const char * progName){ + ndbout << "Usage: " << progName << " <type> localNodeId localHostName" + << " remoteHostName" + << " [<loop count>] [<send buf size>] [<recv buf size>]" << endl; + ndbout << " type = shm tcp ose sci" << endl; + ndbout << " localNodeId - {1,2}" << endl; +} + +typedef void (* CreateTransporterFunc)(void * conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendBuf, + int recvBuf); + +void +createOSETransporter(void*, NodeId, NodeId, const char*, const char*, int, int); +void +createTCPTransporter(void*, NodeId, NodeId, const char*, const char*, int, int); +void +createSHMTransporter(void*, NodeId, NodeId, const char*, const char*, int, int); +void +createSCITransporter(void*, NodeId, NodeId, const char*, const char*, int, int); + +struct TestPhase { + int signalSize; + int noOfSignals; + int noOfSignalSent; + int noOfSignalReceived; + NDB_TICKS startTime; + NDB_TICKS stopTime; + NDB_TICKS accTime; + int loopCount; + Uint64 sendLenBytes, sendCount; + Uint64 recvLenBytes, recvCount; +}; + +TestPhase testSpec[] = { + { 1, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 1, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 1, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 1, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 8, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 8, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 8, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 8, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 16, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 16, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 16, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 16, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 24, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 24, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 24, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 24, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 0, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of random size + ,{ 0, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of random size + ,{ 0, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of random size + ,{ 0, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of random size + + ,{ 100, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals + ,{ 100, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals + ,{ 100, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals + ,{ 100, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals + + ,{ 500, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals + ,{ 500, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals + ,{ 500, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals + ,{ 500, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals + + ,{ 1000, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals + ,{ 1000, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals + ,{ 1000, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals + ,{ 1000, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals +}; + +const int noOfTests = sizeof(testSpec)/sizeof(TestPhase); + +Uint32 StaticBuffer[1000]; + +SendStatus +sendSignalTo(NodeId nodeId, int signalSize, Uint32 count){ + if(signalSize == 0) + signalSize = (rand() % 25) + 1; + + SignalHeader sh; + sh.theLength = (signalSize > 25 ? 25 : signalSize); + sh.theVerId_signalNumber = count; + sh.theReceiversBlockNumber = rand(); + sh.theSendersBlockRef = rand(); + sh.theSendersSignalId = rand(); + sh.theSignalId = rand(); + sh.theTrace = rand(); + + Uint32 theData[25]; + for(int i = 0; i<25; i++) + theData[i] = (i+1) * (Uint32)(&theData[i]); + + theData[0] = count; + LinearSectionPtr ptr[3]; + + if(signalSize <= 25){ + sh.m_noOfSections = 0; + } else { + sh.m_noOfSections = 1; + ptr[0].sz = signalSize - 25; + ptr[0].p = &StaticBuffer[0]; + } + + return tReg->prepareSend(&sh, 1, theData, nodeId, ptr); +} + +void +reportHeader(){ + ndbout << "#Sigs\tSz\tTime\tSig/sec\tBps\tBps-tot\t" + << "s len\tr len" << endl; +} + +void +print(char * dst, int i){ + if(i > 1000000){ + const int d = i / 1000000; + const int r = (i - (d * 1000000)) / 100000; + if(d < 100) + sprintf(dst, "%d.%dM", d, r); + else + sprintf(dst, "%dM", d); + } else if(i > 1000){ + const int d = i / 1000; + const int r = (i - (d * 1000)) / 100; + if(d < 100) + sprintf(dst, "%d.%dk", d, r); + else + sprintf(dst, "%dk", d); + } else { + sprintf(dst, "%d", i); + } +} + +void +printReport(TestPhase & p){ + if(p.accTime > 0) { + Uint32 secs = (p.accTime/p.loopCount)/1000; + Uint32 mill = (p.accTime/p.loopCount)%1000; + char st[255]; + if(secs > 0){ + sprintf(st, "%d.%.2ds", secs, (mill/10)); + } else { + sprintf(st, "%dms", mill); + } + + Uint32 sps = (1000*p.noOfSignals*p.loopCount)/p.accTime; + Uint32 dps = ((4000*p.noOfSignals)/p.accTime)*(p.loopCount*p.signalSize); + Uint32 bps = ((4000*p.noOfSignals)/p.accTime)*(p.loopCount*(p.signalSize+3)); + if(p.signalSize == 0){ + dps = ((4000*p.noOfSignals)/p.accTime)*(p.loopCount*(13)); + bps = ((4000*p.noOfSignals)/p.accTime)*(p.loopCount*(13+3)); + } + char ssps[255]; + char sbps[255]; + char sdps[255]; + + print(ssps, sps); + print(sbps, bps); + print(sdps, dps); + + + char buf[255]; + if(p.signalSize != 0){ + snprintf(buf, 255, + "%d\t%d\t%s\t%s\t%s\t%s\t%d\t%d", + p.noOfSignals, + 4*p.signalSize, + st, + ssps, + sdps, + sbps, + (int)(p.sendLenBytes / (p.sendCount == 0 ? 1 : p.sendCount)), + (int)(p.recvLenBytes / (p.recvCount == 0 ? 1 : p.recvCount))); + } else { + snprintf(buf, 255, + "%d\trand\t%s\t%s\t%s\t%s\t%d\t%d", + p.noOfSignals, + st, + ssps, + sdps, + sbps, + (int)(p.sendLenBytes / (p.sendCount == 0 ? 1 : p.sendCount)), + (int)(p.recvLenBytes / (p.recvCount == 0 ? 1 : p.recvCount))); + + } + ndbout << buf << endl; + } +} + +int loopCount = 1; +int sendBufSz = -1; +int recvBufSz = -1; + +bool isClient = false; +bool isConnected = false; +bool isStarted = false; +int currentPhase = 0; +TestPhase allPhases[noOfTests]; +Uint32 signalToEcho; +Uint32 signalsEchoed; +NDB_TICKS startTime, stopTime; + +void +client(NodeId remoteNodeId){ + isClient = true; + + currentPhase = 0; + memcpy(allPhases, testSpec, sizeof(testSpec)); + + int counter = 0; + int sigCounter = 0; + + while(true){ + TestPhase * current = &allPhases[currentPhase]; + if(current->noOfSignals == current->noOfSignalSent && + current->noOfSignals == current->noOfSignalReceived){ + + /** + * Test phase done + */ + current->stopTime = NdbTick_CurrentMillisecond(); + current->accTime += (current->stopTime - current->startTime); + + NdbSleep_MilliSleep(500 / loopCount); + + current->startTime = NdbTick_CurrentMillisecond(); + + current->noOfSignalSent = 0; + current->noOfSignalReceived = 0; + + current->loopCount ++; + if(current->loopCount == loopCount){ + + printReport(allPhases[currentPhase]); + + currentPhase ++; + if(currentPhase == noOfTests){ + /** + * Now we are done + */ + break; + } + NdbSleep_MilliSleep(500); + current = &allPhases[currentPhase]; + current->startTime = NdbTick_CurrentMillisecond(); + } + } + + int signalsLeft = current->noOfSignals - current->noOfSignalSent; + if(signalsLeft > 0){ + for(; signalsLeft > 0; signalsLeft--){ + if(sendSignalTo(remoteNodeId,current->signalSize,sigCounter)== SEND_OK){ + current->noOfSignalSent++; + sigCounter++; + } else { + ndbout << "Failed to send: " << sigCounter << endl; + tReg->external_IO(10); + break; + } + } + } + if(counter % 10 == 0) + tReg->checkConnections(); + tReg->external_IO(0); + counter++; + } +} + +void +server(){ + isClient = false; + + signalToEcho = 0; + signalsEchoed = 0; + for(int i = 0; i<noOfTests; i++) + signalToEcho += testSpec[i].noOfSignals; + + signalToEcho *= loopCount; + + while(signalToEcho > signalsEchoed){ + tReg->checkConnections(); + for(int i = 0; i<10; i++) + tReg->external_IO(10); + } +} + +int +main(int argc, const char **argv){ + + const char * progName = argv[0]; + + loopCount = 100; + sendBufSz = -1; + recvBufSz = -1; + + isClient = false; + isConnected = false; + isStarted = false; + currentPhase = 0; + + signalHandler(0); + + if(argc < 5){ + usage(progName); + return 0; + } + + const char * type = argv[1]; + const NodeId localNodeId = atoi(argv[2]); + const char * localHostName = argv[3]; + const char * remoteHost1 = argv[4]; + + if(argc >= 6) + loopCount = atoi(argv[5]); + if(argc >= 7) + sendBufSz = atoi(argv[6]); + if(argc >= 8) + recvBufSz = atoi(argv[7]); + + if(localNodeId < 1 || localNodeId > 2){ + ndbout << "localNodeId = " << localNodeId << endl << endl; + usage(progName); + return 0; + } + + if(localNodeId == 1) + ndbout << "-- ECHO CLIENT --" << endl; + else + ndbout << "-- ECHO SERVER --" << endl; + + ndbout << "localNodeId: " << localNodeId << endl; + ndbout << "localHostName: " << localHostName << endl; + ndbout << "remoteHost1 (node " << (localNodeId == 1?2:1) << "): " + << remoteHost1 << endl; + ndbout << "Loop count: " << loopCount << endl; + ndbout << "-----------------" << endl; + + void * confTemplate = 0; + CreateTransporterFunc func = 0; + if(strcasecmp(type, "tcp") == 0){ + func = createTCPTransporter; + confTemplate = &tcpTemplate; + } else if(strcasecmp(type, "ose") == 0){ + func = createOSETransporter; + confTemplate = &oseTemplate; + } else if(strcasecmp(type, "sci") == 0){ + func = createSCITransporter; + confTemplate = &sciTemplate; + } else if(strcasecmp(type, "shm") == 0){ + func = createSHMTransporter; + confTemplate = &shmTemplate; + } else { + ndbout << "Unsupported transporter type" << endl; + return 0; + } + + ndbout << "Creating transporter registry" << endl; + tReg = new TransporterRegistry; + tReg->init(localNodeId); + + switch(localNodeId){ + case 1: + (* func)(confTemplate, 1, 2, localHostName, remoteHost1, + sendBufSz, recvBufSz); + break; + case 2: + (* func)(confTemplate, 2, 1, localHostName, remoteHost1, + sendBufSz, recvBufSz); + break; + } + + ndbout << "Doing startSending/startReceiving" << endl; + tReg->startSending(); + tReg->startReceiving(); + + ndbout << "Connecting" << endl; + tReg->setPerformState(PerformConnect); + tReg->checkConnections(); + + if(localNodeId == 1) + client(2); + else + server(); + + isStarted = false; + + ndbout << "Sleep 3 secs" << endl; + NdbSleep_SecSleep(3); + + ndbout << "Doing setPerformState(Disconnect)" << endl; + tReg->setPerformState(PerformDisconnect); + + ndbout << "Doing checkConnections()" << endl; + tReg->checkConnections(); + + ndbout << "Deleting transporter registry" << endl; + delete tReg; tReg = 0; + + return 0; +} + +void +execute(void* callbackObj, SignalHeader * const header, Uint8 prio, + Uint32 * const theData, + LinearSectionPtr ptr[3]){ + const NodeId nodeId = refToNode(header->theSendersBlockRef); + + if(isClient){ + allPhases[currentPhase].noOfSignalReceived++; + } else { + int sleepTime = 10; + if(theData[0] != signalsEchoed){ + ndbout << "Missing signal theData[0] = " << theData[0] + << " signalsEchoed = " << signalsEchoed << endl; + ndbout << (* header) << endl; + abort(); + } + while(tReg->prepareSend(header, prio, theData, nodeId, ptr) != SEND_OK){ + ndbout << "Failed to echo " << theData[0] << endl; + NdbSleep_MilliSleep(sleepTime); + // sleepTime += 10; + } + signalsEchoed++; + } +} + +void +copy(Uint32 * & insertPtr, + class SectionSegmentPool & thePool, const SegmentedSectionPtr & _ptr){ + abort(); +} + +void +reportError(void* callbackObj, NodeId nodeId, TransporterError errorCode){ + char buf[255]; + sprintf(buf, "reportError (%d, %x) in perfTest", nodeId, errorCode); + ndbout << buf << endl; + if(errorCode & 0x8000 && errorCode != 0x8014){ + abort(); //tReg->setPerformState(nodeId, PerformDisconnect); + } +} + +/** + * Report average send theLength in bytes (4096 last sends) + */ +void +reportSendLen(void* callbackObj, NodeId nodeId, Uint32 count, Uint64 bytes){ + allPhases[currentPhase].sendCount += count; + allPhases[currentPhase].sendLenBytes += bytes; + + if(!isClient){ + ndbout << "reportSendLen(" << nodeId << ", " + << (bytes/count) << ")" << endl; + } +} + +/** + * Report average receive theLength in bytes (4096 last receives) + */ +void +reportReceiveLen(void* callbackObj, NodeId nodeId, Uint32 count, Uint64 bytes){ + allPhases[currentPhase].recvCount += count; + allPhases[currentPhase].recvLenBytes += bytes; + + if(!isClient){ + ndbout << "reportReceiveLen(" << nodeId << ", " + << (bytes/count) << ")" << endl; + } +} + +/** + * Report connection established + */ +void +reportConnect(void* callbackObj, NodeId nodeId){ + char buf[255]; + sprintf(buf, "reportConnect(%d)", nodeId); + ndbout << buf << endl; + tReg->setPerformState(nodeId, PerformIO); + + if(!isStarted){ + isStarted = true; + startTime = NdbTick_CurrentMillisecond(); + if(isClient){ + reportHeader(); + allPhases[0].startTime = startTime; + } + } + else{ + // Resend signals that were lost when connection failed + TestPhase * current = &allPhases[currentPhase]; + current->noOfSignalSent = current->noOfSignalReceived; + } +} + +/** + * Report connection broken + */ +void +reportDisconnect(void* callbackObj, NodeId nodeId, Uint32 errNo){ + char buf[255]; + sprintf(buf, "reportDisconnect(%d)", nodeId); + ndbout << buf << endl; + + if(isStarted) + tReg->setPerformState(nodeId, PerformConnect); +} + + +int +checkJobBuffer() { + /** + * Check to see if jobbbuffers are starting to get full + * and if so call doJob + */ + return 0; +} + +void +createOSETransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendBuf, + int recvBuf){ + + ndbout << "Creating OSE transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + OSE_TransporterConfiguration * conf = (OSE_TransporterConfiguration*)_conf; + + if(sendBuf != -1){ + conf->prioBSignalSize = sendBuf; + } + if(recvBuf != -1){ + conf->receiveBufferSize = recvBuf; + } + + ndbout << "\tSendBufferSize: " << conf->prioBSignalSize << endl; + ndbout << "\tReceiveBufferSize: " << conf->receiveBufferSize << endl; + + conf->localNodeId = localNodeId; + conf->localHostName = localHostName; + conf->remoteNodeId = remoteNodeId; + conf->remoteHostName = remoteHostName; + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + + +void +createSCITransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendbuf, + int recvbuf) { + + + ndbout << "Creating SCI transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + + SCI_TransporterConfiguration * conf = (SCI_TransporterConfiguration*)_conf; + + conf->remoteSciNodeId0= (Uint16)atoi(localHostName); + conf->remoteSciNodeId1= (Uint16)atoi(remoteHostName); + + + conf->localNodeId = localNodeId; + conf->remoteNodeId = remoteNodeId; + + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + +void +createSHMTransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendbuf, + int recvbuf) { + + + ndbout << "Creating SHM transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + + SHM_TransporterConfiguration * conf = (SHM_TransporterConfiguration*)_conf; + + + conf->localNodeId = localNodeId; + conf->remoteNodeId = remoteNodeId; + + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + + +void +createTCPTransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendBuf, + int recvBuf){ + ndbout << "Creating TCP transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + TCP_TransporterConfiguration * conf = (TCP_TransporterConfiguration*)_conf; + + int port; + if(localNodeId == 1 && remoteNodeId == 2) port = basePortTCP + 0; + if(localNodeId == 1 && remoteNodeId == 3) port = basePortTCP + 1; + if(localNodeId == 2 && remoteNodeId == 1) port = basePortTCP + 0; + if(localNodeId == 2 && remoteNodeId == 3) port = basePortTCP + 2; + if(localNodeId == 3 && remoteNodeId == 1) port = basePortTCP + 1; + if(localNodeId == 3 && remoteNodeId == 2) port = basePortTCP + 2; + + if(sendBuf != -1){ + conf->sendBufferSize = sendBuf; + } + if(recvBuf != -1){ + conf->maxReceiveSize = recvBuf; + } + + ndbout << "\tSendBufferSize: " << conf->sendBufferSize << endl; + ndbout << "\tReceiveBufferSize: " << conf->maxReceiveSize << endl; + + conf->localNodeId = localNodeId; + conf->localHostName = localHostName; + conf->remoteNodeId = remoteNodeId; + conf->remoteHostName = remoteHostName; + conf->port = port; + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} diff --git a/ndb/src/common/transporter/priotest/Makefile b/ndb/src/common/transporter/priotest/Makefile new file mode 100644 index 00000000000..483fc0f1f07 --- /dev/null +++ b/ndb/src/common/transporter/priotest/Makefile @@ -0,0 +1,15 @@ +include .defs.mk + +TYPE := ndbapi + +SOURCES = prioTransporterTest.cpp +ARCHIVE_TARGET := libpriotransportertest.a + +DIRS := prioTCP prioSHM prioSCI + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/transporter/priotest/prioOSE/Makefile b/ndb/src/common/transporter/priotest/prioOSE/Makefile new file mode 100644 index 00000000000..4df66fa35e0 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioOSE/Makefile @@ -0,0 +1,17 @@ +include .defs.mk + +TYPE := ndbapi + +BIN_TARGET := perfOSE +BIN_TARGET_ARCHIVES := perftransportertest transporter portlib + +CCFLAGS_LOC += -I.. + +SOURCES = perfOSE.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/transporter/priotest/prioSCI/Makefile b/ndb/src/common/transporter/priotest/prioSCI/Makefile new file mode 100644 index 00000000000..7d403539bf3 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioSCI/Makefile @@ -0,0 +1,17 @@ +include .defs.mk + +TYPE := ndbapi +BIN_TARGET := prioSCI +BIN_TARGET_LIBS := sisci +BIN_TARGET_ARCHIVES := priotransportertest transporter portlib general + +CCFLAGS_LOC += -I.. + +SOURCES = prioSCI.cpp + +include $(NDB_TOP)/Epilogue.mk + + + + + diff --git a/ndb/src/common/transporter/priotest/prioSCI/prioSCI.cpp b/ndb/src/common/transporter/priotest/prioSCI/prioSCI.cpp new file mode 100644 index 00000000000..6218b764e09 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioSCI/prioSCI.cpp @@ -0,0 +1,29 @@ +/* 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 <prioTransporterTest.hpp> +#include <NdbMain.h> + +NDB_COMMAND(prioSCI, "prioSCI", "prioSCI", "Test the SCI Transporter", 65535) +{ + basePortTCP = 17000; + return prioTransporterTest(TestSCI, "prioSCI", argc, argv); +} + + + + diff --git a/ndb/src/common/transporter/priotest/prioSHM/Makefile b/ndb/src/common/transporter/priotest/prioSHM/Makefile new file mode 100644 index 00000000000..a827c6e3f1e --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioSHM/Makefile @@ -0,0 +1,13 @@ +include .defs.mk + +TYPE := ndbapi + +BIN_TARGET := prioSHM +BIN_TARGET_ARCHIVES := priotransportertest transporter portlib general + +CCFLAGS_LOC += -I.. + +SOURCES = prioSHM.cpp + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/src/common/transporter/priotest/prioSHM/prioSHM.cpp b/ndb/src/common/transporter/priotest/prioSHM/prioSHM.cpp new file mode 100644 index 00000000000..4c1701a91e4 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioSHM/prioSHM.cpp @@ -0,0 +1,26 @@ +/* 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 <prioTransporterTest.hpp> +#include <NdbMain.h> + +NDB_COMMAND(prioSHM, "prioSHM", "prioSHM", "Test the SHM Transporter", 65535) +{ + basePortTCP = 17000; + return prioTransporterTest(TestSHM, "prioSHM", argc, argv); +} + diff --git a/ndb/src/common/transporter/priotest/prioTCP/Makefile b/ndb/src/common/transporter/priotest/prioTCP/Makefile new file mode 100644 index 00000000000..92abf3e7424 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioTCP/Makefile @@ -0,0 +1,13 @@ +include .defs.mk + +TYPE := ndbapi + +BIN_TARGET := prioTCP +BIN_TARGET_ARCHIVES := priotransportertest transporter portlib general + +CCFLAGS_LOC += -I.. + +SOURCES = prioTCP.cpp + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/src/common/transporter/priotest/prioTCP/prioTCP.cpp b/ndb/src/common/transporter/priotest/prioTCP/prioTCP.cpp new file mode 100644 index 00000000000..f993dd05ac8 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioTCP/prioTCP.cpp @@ -0,0 +1,26 @@ +/* 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 <prioTransporterTest.hpp> +#include <NdbMain.h> + +NDB_COMMAND(prioTCP, "prioTCP", "prioTCP", "Test the TCP Transporter", 65535) +{ + basePortTCP = 17000; + return prioTransporterTest(TestTCP, "prioTCP", argc, argv); +} + diff --git a/ndb/src/common/transporter/priotest/prioTransporterTest.cpp b/ndb/src/common/transporter/priotest/prioTransporterTest.cpp new file mode 100644 index 00000000000..919cc9d7511 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioTransporterTest.cpp @@ -0,0 +1,768 @@ +/* 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 "TransporterRegistry.hpp" +#include "TransporterDefinitions.hpp" +#include "TransporterCallback.hpp" +#include <RefConvert.hpp> + +#include "prioTransporterTest.hpp" + +#include <NdbStdio.h> +#include <stdlib.h> +#include <NdbTick.h> +#include <NdbMain.h> +#include <NdbOut.hpp> +#include <NdbSleep.h> + +int basePortTCP = 17000; + +SCI_TransporterConfiguration sciTemplate = { + 2000, + // Packet size + 2000000, // Buffer size + 2, // number of adapters + 1, // remote node id SCI + 2, // Remote node Id SCI + 0, // local ndb node id (server) + 0, // remote ndb node id (client) + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + + +SHM_TransporterConfiguration shmTemplate = { + 100000, // shmSize + 0, // shmKey + 1, // local ndb node id (server) + 2, // remote ndb node id (client) + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + +TCP_TransporterConfiguration tcpTemplate = { + 17000, // port; + "", // remoteHostName; + "", // localhostname + 2, // remoteNodeId; + 1, // localNodeId; + 2000000, // sendBufferSize - Size of SendBuffer of priority B + 2000, // maxReceiveSize - Maximum no of bytes to receive + 0, // byteOrder; + false, // compression; + true, // checksum; + true // signalId; +}; + +OSE_TransporterConfiguration oseTemplate = { + "", // remoteHostName; + "", // localHostName; + 0, // remoteNodeId; + 0, // localNodeId; + false, // compression; + true, // checksum; + true, // signalId; + 0, // byteOrder; + + 2000, // prioASignalSize; + 2000, // prioBSignalSize; + 10 // Recv buf size +}; + +TransporterRegistry *tReg = 0; + +#ifndef OSE_DELTA +#include <signal.h> +#endif + +extern "C" +void +signalHandler(int signo){ +#ifndef OSE_DELTA + ::signal(13, signalHandler); +#endif + char buf[255]; + sprintf(buf,"Signal: %d\n", signo); + ndbout << buf << endl; +} + +void +usage(const char * progName){ + ndbout << "Usage: " << progName << " localNodeId localHostName" + << " remoteHostName" + << " [<loop count>] [<send buf size>] [<recv buf size>]" << endl; + ndbout << " localNodeId - {1,2}" << endl; +} + +typedef void (* CreateTransporterFunc)(void * conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendBuf, + int recvBuf); + +void +createOSETransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendBuf, + int recvBuf){ + + ndbout << "Creating OSE transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + OSE_TransporterConfiguration * conf = (OSE_TransporterConfiguration*)_conf; + + if(sendBuf != -1){ + conf->prioBSignalSize = sendBuf; + } + if(recvBuf != -1){ + conf->receiveBufferSize = recvBuf; + } + + ndbout << "\tSendBufferSize: " << conf->prioBSignalSize << endl; + ndbout << "\tReceiveBufferSize: " << conf->receiveBufferSize << endl; + + conf->localNodeId = localNodeId; + conf->localHostName = localHostName; + conf->remoteNodeId = remoteNodeId; + conf->remoteHostName = remoteHostName; + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + + +void +createSCITransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendbuf, + int recvbuf) { + + + ndbout << "Creating SCI transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + + SCI_TransporterConfiguration * conf = (SCI_TransporterConfiguration*)_conf; + + conf->remoteSciNodeId0= (Uint16)atoi(localHostName); + conf->remoteSciNodeId1= (Uint16)atoi(remoteHostName); + + + conf->localNodeId = localNodeId; + conf->remoteNodeId = remoteNodeId; + + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + +void +createSHMTransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendbuf, + int recvbuf) { + + + ndbout << "Creating SHM transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + + SHM_TransporterConfiguration * conf = (SHM_TransporterConfiguration*)_conf; + + + conf->localNodeId = localNodeId; + conf->remoteNodeId = remoteNodeId; + + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + + +void +createTCPTransporter(void * _conf, + NodeId localNodeId, + NodeId remoteNodeId, + const char * localHostName, + const char * remoteHostName, + int sendBuf, + int recvBuf){ + ndbout << "Creating TCP transporter from node " + << localNodeId << "(" << localHostName << ") to " + << remoteNodeId << "(" << remoteHostName << ")..." << endl;; + + TCP_TransporterConfiguration * conf = (TCP_TransporterConfiguration*)_conf; + + int port; + if(localNodeId == 1 && remoteNodeId == 2) port = basePortTCP + 0; + if(localNodeId == 1 && remoteNodeId == 3) port = basePortTCP + 1; + if(localNodeId == 2 && remoteNodeId == 1) port = basePortTCP + 0; + if(localNodeId == 2 && remoteNodeId == 3) port = basePortTCP + 2; + if(localNodeId == 3 && remoteNodeId == 1) port = basePortTCP + 1; + if(localNodeId == 3 && remoteNodeId == 2) port = basePortTCP + 2; + + if(sendBuf != -1){ + conf->sendBufferSize = sendBuf; + } + if(recvBuf != -1){ + conf->maxReceiveSize = recvBuf; + } + + ndbout << "\tSendBufferSize: " << conf->sendBufferSize << endl; + ndbout << "\tReceiveBufferSize: " << conf->maxReceiveSize << endl; + + conf->localNodeId = localNodeId; + conf->localHostName = localHostName; + conf->remoteNodeId = remoteNodeId; + conf->remoteHostName = remoteHostName; + conf->port = port; + bool res = tReg->createTransporter(conf); + if(res) + ndbout << "... -- Success " << endl; + else + ndbout << "... -- Failure " << endl; +} + +struct TestPhase { + int signalSize; + int noOfSignals; + int noOfSignalSent; + int noOfSignalReceived; + NDB_TICKS startTime; + NDB_TICKS stopTime; + + NDB_TICKS startTimePrioA; + NDB_TICKS stopTimePrioA; + NDB_TICKS totTimePrioA; + int bytesSentBeforePrioA; + NDB_TICKS accTime; + int loopCount; + Uint64 sendLenBytes, sendCount; + Uint64 recvLenBytes, recvCount; +}; + +TestPhase testSpec[] = { + { 1, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 1, 10000, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 1, 10000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 1, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 8, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 8, 10000, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 8, 10000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 8, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 16, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 16, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 16, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 16, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 24, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of size 1 word + ,{ 24, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of size 1 word + ,{ 24, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of size 1 word + ,{ 24, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of size 1 word + + ,{ 0, 10, 0,0, 0,0,0,0,0,0,0 } // 10 signals of random size + ,{ 0, 100, 0,0, 0,0,0,0,0,0,0 } // 100 signals of random size + ,{ 0, 1000, 0,0, 0,0,0,0,0,0,0 } // 1000 signals of random size + ,{ 0, 10000, 0,0, 0,0,0,0,0,0,0 } // 10000 signals of random size +}; + +const int noOfTests = sizeof(testSpec)/sizeof(TestPhase); + +SendStatus +sendSignalTo(NodeId nodeId, int signalSize, int prio){ + if(signalSize == 0) + signalSize = (rand() % 25) + 1; + + SignalHeader sh; + sh.theLength = signalSize; + sh.theVerId_signalNumber = rand(); + sh.theReceiversBlockNumber = rand(); + sh.theSendersBlockRef = rand(); + sh.theSendersSignalId = rand(); + sh.theSignalId = rand(); + sh.theTrace = rand(); + + Uint32 theData[25]; + for(int i = 0; i<signalSize; i++) + theData[i] = (i+1) * (Uint32)(&theData[i]); + + return tReg->prepareSend(&sh, prio, theData, nodeId); +} + +void +reportHeader(){ + ndbout << "#Sigs\tSz\tPayload\tTime\tSig/sec\tBps\t" + << "s len\tr len\tprioAtime\tbytesb4pA" << endl; +} + +void +printReport(TestPhase & p){ + if(p.accTime > 0) { + Uint32 secs = (p.accTime/p.loopCount)/1000; + Uint32 mill = (p.accTime/p.loopCount)%1000; + char st[255]; + if(secs > 0){ + sprintf(st, "%d.%.2ds", secs, (mill/10)); + } else { + sprintf(st, "%dms", mill); + } + + Uint32 sps = (1000*p.noOfSignals*p.loopCount)/p.accTime; + Uint32 bps = ((4000*p.noOfSignals)/p.accTime)*(p.loopCount*(p.signalSize+3)); + if(p.signalSize == 0) + ((4000*p.noOfSignals)/p.accTime)*(p.loopCount*(13+3)); + + char ssps[255]; + if(sps > 1000000){ + sps /= 1000000; + sprintf(ssps, "%dM", (int)sps); + } else if(sps > 1000){ + sps /= 1000; + sprintf(ssps, "%dk", (int)sps); + } else { + sprintf(ssps, "%d", (int)sps); + } + + char sbps[255]; + if(bps > 1000000){ + bps /= 1000000; + sprintf(sbps, "%dM", bps); + } else if(bps>1000){ + bps /= 1000; + sprintf(sbps, "%dk", bps); + } else { + sprintf(sbps, "%d", bps); + } + + char buf[255]; + if(p.signalSize != 0){ + snprintf(buf, 255, + "%d\t%d\t%d\t%s\t%s\t%s\t%d\t%d\t%d\t%d", + p.noOfSignals, + p.signalSize, + (4*p.signalSize), + st, + ssps, + sbps, + (int)(p.sendLenBytes / (p.sendCount == 0 ? 1 : p.sendCount)), + (int)(p.recvLenBytes / (p.recvCount == 0 ? 1 : p.recvCount)), + (int)(p.totTimePrioA / p.loopCount), + (int)(p.bytesSentBeforePrioA)); + } else { + snprintf(buf, 255, + "%d\trand\t4*rand\t%s\t%s\t%s\t%d\t%d\t%d\t%d", + p.noOfSignals, + st, + ssps, + sbps, + (int)(p.sendLenBytes / (p.sendCount == 0 ? 1 : p.sendCount)), + (int)(p.recvLenBytes / (p.recvCount == 0 ? 1 : p.recvCount)), + (int)(p.totTimePrioA / p.loopCount), + (int)(p.bytesSentBeforePrioA)); + + } + ndbout << buf << endl; + } +} + +int loopCount = 1; +int sendBufSz = -1; +int recvBufSz = -1; + +NDB_TICKS startSec=0; +NDB_TICKS stopSec=0; +Uint32 startMicro=0; +Uint32 stopMicro=0; +int timerStarted; +int timerStopped; + +bool isClient = false; +bool isConnected = false; +bool isStarted = false; +int currentPhase = 0; +TestPhase allPhases[noOfTests]; +Uint32 signalToEcho; +NDB_TICKS startTime, stopTime; + +void +client(NodeId remoteNodeId){ + isClient = true; + + currentPhase = 0; + memcpy(allPhases, testSpec, sizeof(testSpec)); + + int counter = 0; + + while(true){ + TestPhase * current = &allPhases[currentPhase]; + if(current->noOfSignals == current->noOfSignalSent && + current->noOfSignals == current->noOfSignalReceived){ + + /** + * Test phase done + */ + current->stopTime = NdbTick_CurrentMillisecond(); + current->accTime += (current->stopTime - current->startTime); + + NdbSleep_MilliSleep(500 / loopCount); + + current->startTime = NdbTick_CurrentMillisecond(); + + current->noOfSignalSent = 0; + current->noOfSignalReceived = 0; + + current->loopCount ++; + if(current->loopCount == loopCount){ + + printReport(allPhases[currentPhase]); + + currentPhase ++; + if(currentPhase == noOfTests){ + /** + * Now we are done + */ + break; + } + NdbSleep_MilliSleep(500); + current = &allPhases[currentPhase]; + current->startTime = NdbTick_CurrentMillisecond(); + } + } + int signalsLeft = current->noOfSignals - current->noOfSignalSent; + if(signalsLeft > 0){ + for(; signalsLeft > 1; signalsLeft--){ + if(sendSignalTo(remoteNodeId, current->signalSize, 1) == SEND_OK) { + current->noOfSignalSent++; + // ndbout << "sent prio b" << endl; + current->bytesSentBeforePrioA += (current->signalSize << 2); + } + else { + tReg->external_IO(10); + break; + } + } + //prio A + if(signalsLeft==1) { + NDB_TICKS sec = 0; + Uint32 micro=0; + int ret = NdbTick_CurrentMicrosecond(&sec,µ); + if(ret==0) + current->startTimePrioA = micro + sec*1000000; + if(sendSignalTo(remoteNodeId, current->signalSize, 0) == SEND_OK) { + current->noOfSignalSent++; + signalsLeft--; + } + else { + tReg->external_IO(10); + break; + } + } + } + + if(counter % 10 == 0) + tReg->checkConnections(); + tReg->external_IO(0); + counter++; + } +} + +void +server(){ + isClient = false; + + signalToEcho = 0; + for(int i = 0; i<noOfTests; i++) + signalToEcho += testSpec[i].noOfSignals; + + signalToEcho *= loopCount; + + while(signalToEcho > 0){ + tReg->checkConnections(); + for(int i = 0; i<10; i++) + tReg->external_IO(10); + } +} + +int +prioTransporterTest(TestType tt, const char * progName, + int argc, const char **argv){ + + loopCount = 100; + sendBufSz = -1; + recvBufSz = -1; + + isClient = false; + isConnected = false; + isStarted = false; + currentPhase = 0; + + signalHandler(0); + + if(argc < 4){ + usage(progName); + return 0; + } + + const NodeId localNodeId = atoi(argv[1]); + const char * localHostName = argv[2]; + const char * remoteHost1 = argv[3]; + + if(argc >= 5) + loopCount = atoi(argv[4]); + if(argc >= 6) + sendBufSz = atoi(argv[5]); + if(argc >= 7) + recvBufSz = atoi(argv[6]); + + if(localNodeId < 1 || localNodeId > 2){ + ndbout << "localNodeId = " << localNodeId << endl << endl; + usage(progName); + return 0; + } + + if(localNodeId == 1) + ndbout << "-- ECHO CLIENT --" << endl; + else + ndbout << "-- ECHO SERVER --" << endl; + + ndbout << "localNodeId: " << localNodeId << endl; + ndbout << "localHostName: " << localHostName << endl; + ndbout << "remoteHost1 (node " << (localNodeId == 1?2:1) << "): " + << remoteHost1 << endl; + ndbout << "Loop count: " << loopCount << endl; + ndbout << "-----------------" << endl; + + void * confTemplate = 0; + CreateTransporterFunc func = 0; + switch(tt){ + case TestTCP: + func = createTCPTransporter; + confTemplate = &tcpTemplate; + break; + case TestOSE: + func = createOSETransporter; + confTemplate = &oseTemplate; + break; + case TestSCI: + func = createSCITransporter; + confTemplate = &sciTemplate; + break; + case TestSHM: + func = createSHMTransporter; + confTemplate = &shmTemplate; + break; + default: + ndbout << "Unsupported transporter type" << endl; + return 0; + } + + ndbout << "Creating transporter registry" << endl; + tReg = new TransporterRegistry; + tReg->init(localNodeId); + + switch(localNodeId){ + case 1: + (* func)(confTemplate, 1, 2, localHostName, remoteHost1, + sendBufSz, recvBufSz); + break; + case 2: + (* func)(confTemplate, 2, 1, localHostName, remoteHost1, + sendBufSz, recvBufSz); + break; + } + + ndbout << "Doing startSending/startReceiving" << endl; + tReg->startSending(); + tReg->startReceiving(); + + ndbout << "Connecting" << endl; + tReg->setPerformState(PerformConnect); + tReg->checkConnections(); + + if(localNodeId == 1) + client(2); + else + server(); + + isStarted = false; + + ndbout << "Sleep 3 secs" << endl; + NdbSleep_SecSleep(3); + + ndbout << "Doing setPerformState(Disconnect)" << endl; + tReg->setPerformState(PerformDisconnect); + + ndbout << "Doing checkConnections()" << endl; + tReg->checkConnections(); + + ndbout << "Deleting transporter registry" << endl; + delete tReg; tReg = 0; + + return 0; +} + +NdbOut & operator <<(NdbOut & out, SignalHeader & sh){ + out << "-- Signal Header --" << endl; + out << "theLength: " << sh.theLength << endl; + out << "gsn: " << sh.theVerId_signalNumber << endl; + out << "recBlockNo: " << sh.theReceiversBlockNumber << endl; + out << "sendBlockRef: " << sh.theSendersBlockRef << endl; + out << "sendersSig: " << sh.theSendersSignalId << endl; + out << "theSignalId: " << sh.theSignalId << endl; + out << "trace: " << (int)sh.theTrace << endl; + return out; +} + +void +execute(SignalHeader * const header, Uint8 prio, Uint32 * const theData){ + const NodeId nodeId = refToNode(header->theSendersBlockRef); + NDB_TICKS sec = 0; + Uint32 micro=0; + int ret = NdbTick_CurrentMicrosecond(&sec,µ); + if(prio == 0 && isClient && ret == 0) { + allPhases[currentPhase].stopTimePrioA = micro + sec*1000000; + allPhases[currentPhase].totTimePrioA += + allPhases[currentPhase].stopTimePrioA - + allPhases[currentPhase].startTimePrioA; + } + if(ret!=0) + allPhases[currentPhase].totTimePrioA = -1; + + if(isClient){ + allPhases[currentPhase].noOfSignalReceived++; + } else { + int sleepTime = 10; + while(tReg->prepareSend(header, prio, theData, nodeId) != SEND_OK){ + ndbout << "Failed to echo" << sleepTime << endl; + NdbSleep_MilliSleep(sleepTime); + // sleepTime += 10; + } + + signalToEcho--; + } +} + +void +reportError(NodeId nodeId, TransporterError errorCode){ + char buf[255]; + sprintf(buf, "reportError (%d, %x) in perfTest", nodeId, errorCode); + ndbout << buf << endl; + if(errorCode & 0x8000){ + tReg->setPerformState(nodeId, PerformDisconnect); + } +} + +/** + * Report average send theLength in bytes (4096 last sends) + */ +void +reportSendLen(NodeId nodeId, Uint32 count, Uint64 bytes){ + allPhases[currentPhase].sendCount += count; + allPhases[currentPhase].sendLenBytes += bytes; + + if(!isClient){ + ndbout << "reportSendLen(" << nodeId << ", " + << (bytes/count) << ")" << endl; + } +} + +/** + * Report average receive theLength in bytes (4096 last receives) + */ +void +reportReceiveLen(NodeId nodeId, Uint32 count, Uint64 bytes){ + allPhases[currentPhase].recvCount += count; + allPhases[currentPhase].recvLenBytes += bytes; + + if(!isClient){ + ndbout << "reportReceiveLen(" << nodeId << ", " + << (bytes/count) << ")" << endl; + } +} + +/** + * Report connection established + */ +void +reportConnect(NodeId nodeId){ + char buf[255]; + sprintf(buf, "reportConnect(%d)", nodeId); + ndbout << buf << endl; + tReg->setPerformState(nodeId, PerformIO); + + if(!isStarted){ + isStarted = true; + startTime = NdbTick_CurrentMillisecond(); + if(isClient){ + reportHeader(); + allPhases[0].startTime = startTime; + } + } + else{ + // Resend signals that were lost when connection failed + TestPhase * current = &allPhases[currentPhase]; + current->noOfSignalSent = current->noOfSignalReceived; + } +} + +/** + * Report connection broken + */ +void +reportDisconnect(NodeId nodeId, Uint32 errNo){ + char buf[255]; + sprintf(buf, "reportDisconnect(%d)", nodeId); + ndbout << buf << endl; + + if(isStarted) + tReg->setPerformState(nodeId, PerformConnect); +} + + +int +checkJobBuffer() { + /** + * Check to see if jobbbuffers are starting to get full + * and if so call doJob + */ + return 0; +} diff --git a/ndb/src/common/transporter/priotest/prioTransporterTest.hpp b/ndb/src/common/transporter/priotest/prioTransporterTest.hpp new file mode 100644 index 00000000000..787a9f46433 --- /dev/null +++ b/ndb/src/common/transporter/priotest/prioTransporterTest.hpp @@ -0,0 +1,35 @@ +/* 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 */ + +#ifndef PRIO_TRANSPORTER_TEST_HPP +#define PRIO_TRANSPORTER_TEST_HPP + + +enum TestType { + TestTCP, + TestOSE, + TestSCI, + TestSHM +}; + +extern int basePortTCP; + +int prioTransporterTest(TestType tt, const char * pName, + int argc, const char **argv); + + + +#endif diff --git a/ndb/src/common/util/Base64.cpp b/ndb/src/common/util/Base64.cpp new file mode 100644 index 00000000000..5f4bbc8645a --- /dev/null +++ b/ndb/src/common/util/Base64.cpp @@ -0,0 +1,111 @@ +/* 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 <stdio.h> +#include <string.h> +#include <Base64.hpp> + +static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +int +base64_encode(UtilBuffer &src, BaseString &dst) { + char *s = (char *)src.get_data(); + int i = 0; + + while(i < src.length()) { + int c; + c = s[i++]; + c <<= 8; + + if(i < src.length()) + c += s[i]; + c <<= 8; + i++; + + if(i < src.length()) + c += s[i]; + i++; + + dst.append(base64_table[(c >> 18) & 0x3f]); + dst.append(base64_table[(c >> 12) & 0x3f]); + + if(i > (src.length() + 1)) + dst.append('='); + else + dst.append(base64_table[(c >> 6) & 0x3f]); + + if(i > src.length()) + dst.append('='); + else + dst.append(base64_table[(c >> 0) & 0x3f]); + } + return 0; +} + +static inline int +pos(char c) { + return strchr(base64_table, c) - base64_table; +} + + +int +base64_decode(BaseString &src, UtilBuffer &dst) { + size_t size; + size = (src.length() * 3) / 4; + size_t i = 0; + const char *s = src.c_str(); + while(i < size) { + int c = 0; + int mark = 0; + c += pos(*s++); + c <<= 6; + i++; + + c += pos(*s++); + c <<= 6; + i++; + + if(*s != '=') + c += pos(*s++); + else { + size--; + mark++; + } + c <<= 6; + i++; + + if(*s != '=') + c += pos(*s++); + else { + size--; + mark++; + } + /* c <<= 6; */ + i++; + + char b[3]; + + + b[0] = (c >> 16) & 0xff; + b[1] = (c >> 8) & 0xff; + b[2] = (c >> 0) & 0xff; + + dst.append((void *)b, 3-mark); + } + return 0; +} diff --git a/ndb/src/common/util/BaseString.cpp b/ndb/src/common/util/BaseString.cpp new file mode 100644 index 00000000000..1b0eaa1b83c --- /dev/null +++ b/ndb/src/common/util/BaseString.cpp @@ -0,0 +1,418 @@ +/* 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 */ + +/* -*- c-basic-offset: 4; -*- */ +#include <string.h> +#include <NdbStdio.h> +#include <stdarg.h> +#include "BaseString.hpp" +#include <stdlib.h> + +BaseString::BaseString() +{ + m_chr = new char[1]; + m_chr[0] = 0; + m_len = 0; +} + +BaseString::BaseString(const char* s) +{ + const size_t n = strlen(s); + m_chr = new char[n + 1]; + memcpy(m_chr, s, n + 1); + m_len = n; +} + +BaseString::BaseString(const BaseString& str) +{ + const char* const s = str.m_chr; + const size_t n = str.m_len; + char* t = new char[n + 1]; + memcpy(t, s, n + 1); + m_chr = t; + m_len = n; +} + +BaseString::~BaseString() +{ + delete[] m_chr; +} + +BaseString& +BaseString::assign(const char* s) +{ + const size_t n = strlen(s); + char* t = new char[n + 1]; + memcpy(t, s, n + 1); + delete[] m_chr; + m_chr = t; + m_len = n; + return *this; +} + +BaseString& +BaseString::assign(const char* s, size_t n) +{ + char* t = new char[n + 1]; + memcpy(t, s, n); + t[n] = 0; + delete[] m_chr; + m_chr = t; + m_len = n; + return *this; +} + +BaseString& +BaseString::assign(const BaseString& str, size_t n) +{ + if (n > str.m_len) + n = str.m_len; + return assign(str.m_chr, n); +} + +BaseString& +BaseString::append(const char* s) +{ + const size_t n = strlen(s); + char* t = new char[m_len + n + 1]; + memcpy(t, m_chr, m_len); + memcpy(t + m_len, s, n + 1); + delete[] m_chr; + m_chr = t; + m_len += n; + return *this; +} + +BaseString& +BaseString::append(char c) { + return appfmt("%c", c); +} + +BaseString& +BaseString::append(const BaseString& str) +{ + return append(str.m_chr); +} + +BaseString& +BaseString::append(const Vector<BaseString> &vector, + const BaseString &separator) { + for(size_t i=0;i<vector.size(); i++) { + append(vector[i]); + if(i<vector.size()-1) + append(separator); + } + return *this; +} + +BaseString& +BaseString::assfmt(const char *fmt, ...) +{ + char buf[1]; + va_list ap; + int l; + + /* Figure out how long the formatted string will be. A small temporary + * buffer is used, because I don't trust all implementations to work + * when called as vsnprintf(NULL, 0, ...). + */ + va_start(ap, fmt); + l = vsnprintf(buf, sizeof(buf), fmt, ap) + 1; + va_end(ap); + if(l > (int)m_len) { + delete[] m_chr; + m_chr = new char[l]; + } + va_start(ap, fmt); + vsnprintf(m_chr, l, fmt, ap); + va_end(ap); + m_len = strlen(m_chr); + return *this; +} + +BaseString& +BaseString::appfmt(const char *fmt, ...) +{ + char buf[1]; + va_list ap; + int l; + + /* Figure out how long the formatted string will be. A small temporary + * buffer is used, because I don't trust all implementations to work + * when called as vsnprintf(NULL, 0, ...). + */ + va_start(ap, fmt); + l = vsnprintf(buf, sizeof(buf), fmt, ap) + 1; + va_end(ap); + char *tmp = new char[l]; + va_start(ap, fmt); + vsnprintf(tmp, l, fmt, ap); + va_end(ap); + append(tmp); + delete[] tmp; + return *this; +} + +BaseString& +BaseString::operator=(const BaseString& str) +{ + if (this != &str) { + this->assign(str); + } + return *this; +} + +int +BaseString::split(Vector<BaseString> &v, + const BaseString &separator, + int maxSize) const { + char *str = strdup(m_chr); + int i, start, len, num = 0; + len = strlen(str); + for(start = i = 0; + (i <= len) && ( (maxSize<0) || ((int)v.size()<=maxSize-1) ); + i++) { + if(strchr(separator.c_str(), str[i]) || i == len) { + if(maxSize < 0 || (int)v.size() < maxSize-1) + str[i] = '\0'; + v.push_back(BaseString(str+start)); + num++; + start = i+1; + } + } + free(str); + + return num; +} + +ssize_t +BaseString::indexOf(char c) { + char *p; + p = strchr(m_chr, c); + if(p == NULL) + return -1; + return (ssize_t)(p-m_chr); +} + +ssize_t +BaseString::lastIndexOf(char c) { + char *p; + p = strrchr(m_chr, c); + if(p == NULL) + return -1; + return (ssize_t)(p-m_chr); +} + +BaseString +BaseString::substr(ssize_t start, ssize_t stop) { + if(stop < 0) + stop = length(); + ssize_t len = stop-start; + if(len <= 0) + return BaseString(""); + BaseString s; + s.assign(m_chr+start, len); + return s; +} + +static bool +iswhite(char c) { + switch(c) { + case ' ': + case '\t': + return true; + default: + return false; + } + /* NOTREACHED */ +} + +char ** +BaseString::argify(const char *argv0, const char *src) { + Vector<char *> vargv; + + if(argv0 != NULL) + vargv.push_back(strdup(argv0)); + + char *tmp = new char[strlen(src)+1]; + char *dst = tmp; + const char *end = src + strlen(src); + /* Copy characters from src to destination, while compacting them + * so that all whitespace is compacted and replaced by a NUL-byte. + * At the same time, add pointers to strings in the vargv vector. + * When whitespace is detected, the characters '"' and '\' are honored, + * to make it possible to give arguments containing whitespace. + * The semantics of '"' and '\' match that of most Unix shells. + */ + while(src < end && *src) { + /* Skip initial whitespace */ + while(src < end && *src && iswhite(*src)) + src++; + + char *begin = dst; + while(src < end && *src) { + /* Handle '"' quotation */ + if(*src == '"') { + src++; + while(src < end && *src && *src != '"') { + if(*src == '\\') + src++; + *dst++ = *src++; + } + src++; + if(src >= end) + goto end; + } + + /* Handle '\' */ + if(*src == '\\') + src++; + else if(iswhite(*src)) + break; + + /* Actually copy characters */ + *dst++ = *src++; + } + + /* Make sure the string is properly terminated */ + *dst++ = '\0'; + src++; + + vargv.push_back(strdup(begin)); + } + end: + + delete[] tmp; + vargv.push_back(NULL); + + /* Convert the C++ Vector into a C-vector of strings, suitable for + * calling execv(). + */ + char **argv = (char **)malloc(sizeof(*argv) * (vargv.size())); + if(argv == NULL) + return NULL; + + for(size_t i = 0; i < vargv.size(); i++){ + argv[i] = vargv[i]; + } + + return argv; +} + +BaseString& +BaseString::trim(const char * delim){ + trim(m_chr, delim); + m_len = strlen(m_chr); + return * this; +} + +char* +BaseString::trim(char * str, const char * delim){ + int len = strlen(str) - 1; + for(; len > 0 && strchr(delim, str[len]); len--); + + int pos = 0; + for(; pos <= len && strchr(delim, str[pos]); pos++); + + if(pos > len){ + str[0] = 0; + return 0; + } else { + memmove(str, &str[pos], len - pos + 1); + str[len-pos+1] = 0; + } + + return str; +} + + +#ifdef TEST_BASE_STRING +#include <assert.h> + +/* +g++ -g -Wall -o tbs -DTEST_BASE_STRING -I$NDB_TOP/include/util \ + -I$NDB_TOP/include/portlib BaseString.cpp +valgrind ./tbs +*/ + +int main() +{ + BaseString s("abc"); + BaseString t(s); + s.assign("def"); + t.append("123"); + assert(s == "def"); + assert(t == "abc123"); + s.assign(""); + t.assign(""); + for (unsigned i = 0; i < 1000; i++) { + s.append("xyz"); + t.assign(s); + assert(strlen(t.c_str()) % 3 == 0); + } + + { + BaseString s(":123:abc:;:foo:"); + Vector<BaseString> v; + assert(s.split(v, ":;") == 7); + + assert(v[0] == ""); + assert(v[1] == "123"); + assert(v[2] == "abc"); + assert(v[3] == ""); + assert(v[4] == ""); + assert(v[5] == "foo"); + assert(v[6] == ""); + } + + { + BaseString s(":123:abc:foo:bar"); + Vector<BaseString> v; + assert(s.split(v, ":;", 4) == 4); + + assert(v[0] == ""); + assert(v[1] == "123"); + assert(v[2] == "abc"); + assert(v[3] == "foo:bar"); + + BaseString n; + n.append(v, "()"); + assert(n == "()123()abc()foo:bar"); + n = ""; + n.append(v); + assert(n == " 123 abc foo:bar"); + } + + { + assert(BaseString("hamburger").substr(4,2) == ""); + assert(BaseString("hamburger").substr(3) == "burger"); + assert(BaseString("hamburger").substr(4,8) == "urge"); + assert(BaseString("smiles").substr(1,5) == "mile"); + assert(BaseString("012345").indexOf('2') == 2); + assert(BaseString("hej").indexOf('X') == -1); + } + + { + assert(BaseString(" 1").trim(" ") == "1"); + assert(BaseString("1 ").trim(" ") == "1"); + assert(BaseString(" 1 ").trim(" ") == "1"); + assert(BaseString("abc\t\n\r kalleabc\t\r\n").trim("abc\t\r\n ") == "kalle"); + assert(BaseString(" ").trim(" ") == ""); + } + return 0; +} + +#endif diff --git a/ndb/src/common/util/File.cpp b/ndb/src/common/util/File.cpp new file mode 100644 index 00000000000..ad72b41835d --- /dev/null +++ b/ndb/src/common/util/File.cpp @@ -0,0 +1,207 @@ +/* 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 <File.hpp> + +#include <errno.h> +#include <string.h> +#include <sys/stat.h> + +#if defined NDB_OSE || defined NDB_SOFTOSE +#include <unistd.h> +#endif + +#include <NdbOut.hpp> + +// +// PUBLIC +// + +bool +File::exists(const char* aFileName) +{ + bool rc = true; + + struct stat stmp; + if (::stat(aFileName, &stmp) != 0) + { + rc = false; + } + + /* + File f; + if (!f.open(aFileName, "r")) + { + rc = (errno == ENOENT ? false : true); + } + else + { + f.close(); + } + */ + return rc; +} + +long +File::size(FILE* f) +{ + long cur_pos = 0, length = 0; + + cur_pos = ::ftell(f); + ::fseek(f, 0, SEEK_END); + length = ::ftell(f); + ::fseek(f, cur_pos, SEEK_SET); // restore original position + + return length; +} + +bool +File::rename(const char* currFileName, const char* newFileName) +{ + return ::rename(currFileName, newFileName) == 0 ? true : false; +} +bool +File::remove(const char* aFileName) +{ + return ::remove(aFileName) == 0 ? true : false; +} + +File::File() : + m_file(NULL), + m_fileMode("r") +{ +} + +File::File(const char* aFileName, const char* mode) : + m_file(NULL), + m_fileMode(mode) +{ + ::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); +} + +bool +File::open() +{ + return open(m_fileName, m_fileMode); +} + +bool +File::open(const char* aFileName, const char* mode) +{ + if(m_fileName != aFileName){ + /** + * Only copy if it's not the same string + */ + ::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); + } + m_fileMode = mode; + bool rc = true; + if ((m_file = ::fopen(m_fileName, m_fileMode))== NULL) + { + rc = false; + } + + return rc; +} +File::~File() +{ + close(); +} + +bool +File::remove() +{ + // Close the file first! + close(); + return File::remove(m_fileName); +} + +bool +File::close() +{ + bool rc = true; + if (m_file != NULL) + { + ::fflush(m_file); + rc = (::fclose(m_file) == 0 ? true : false); + m_file = NULL; // Try again? + } + + return rc; +} + +int +File::read(void* buf, size_t itemSize, size_t nitems) const +{ + return ::fread(buf, itemSize, nitems, m_file); +} + +int +File::readChar(char* buf, long start, long length) const +{ + return ::fread((void*)&buf[start], 1, length, m_file); +} + +int +File::readChar(char* buf) +{ + return readChar(buf, 0, strlen(buf)); +} + +int +File::write(const void* buf, size_t size, size_t nitems) +{ + return ::fwrite(buf, size, nitems, m_file); +} + +int +File::writeChar(const char* buf, long start, long length) +{ + return ::fwrite((const void*)&buf[start], sizeof(char), length, m_file); +} + +int +File::writeChar(const char* buf) +{ + return writeChar(buf, 0, ::strlen(buf)); +} + +long +File::size() const +{ + return File::size(m_file); +} + +const char* +File::getName() const +{ + return m_fileName; +} + +int +File::flush() const +{ +#if defined NDB_OSE || defined NDB_SOFTOSE + ::fflush(m_file); + return ::fsync(::fileno(m_file)); +#else + return 0; +#endif +} + +// +// PRIVATE +// diff --git a/ndb/src/common/util/InputStream.cpp b/ndb/src/common/util/InputStream.cpp new file mode 100644 index 00000000000..c52b594225d --- /dev/null +++ b/ndb/src/common/util/InputStream.cpp @@ -0,0 +1,61 @@ +/* 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 "InputStream.hpp" +#include <socket_io.h> +#include <assert.h> +#include <string.h> + +FileInputStream Stdin(stdin); + +FileInputStream::FileInputStream(FILE * file) + : f(file) { +} + +char* +FileInputStream::gets(char * buf, int bufLen){ + if(!feof(f)){ + return fgets(buf, bufLen, f); + } + return 0; +} + +SocketInputStream::SocketInputStream(NDB_SOCKET_TYPE socket, + unsigned readTimeout) + : m_socket(socket) { + m_timeout = readTimeout; +} + +char* +SocketInputStream::gets(char * buf, int bufLen) { + buf[0] = 77; + assert(bufLen >= 2); + int res = readln_socket(m_socket, m_timeout, buf, bufLen - 1); + if(res == -1) + return 0; + if(res == 0 && buf[0] == 77){ // select return 0 + buf[0] = 0; + } else if(res == 0 && buf[0] == 0){ // only newline + buf[0] = '\n'; + buf[1] = 0; + } else { + int len = strlen(buf); + buf[len + 1] = '\0'; + buf[len] = '\n'; + } + return buf; +} diff --git a/ndb/src/common/util/Makefile b/ndb/src/common/util/Makefile new file mode 100644 index 00000000000..e400bb12d29 --- /dev/null +++ b/ndb/src/common/util/Makefile @@ -0,0 +1,36 @@ +include .defs.mk + +TYPE := util + +PIC_ARCHIVE := Y +ARCHIVE_TARGET := general + +SOURCES = File.cpp md5_hash.cpp Properties.cpp socket_io.cpp \ + SimpleProperties.cpp Parser.cpp InputStream.cpp SocketServer.cpp \ + OutputStream.cpp NdbOut.cpp BaseString.cpp Base64.cpp \ + NdbSqlUtil.cpp + +SOURCES.c = uucode.c random.c getarg.c version.c + +ifeq ($(NDB_OS), OSE) + SOURCES += NdbErrHnd.cpp +endif +ifeq ($(NDB_OS), OSE) + SOURCES += NdbErrHnd.cpp +endif +ifdef NDB_STRDUP + SOURCES.c += strdup.c +endif +ifdef NDB_STRLCAT + SOURCES.c += strlcat.c +endif +ifdef NDB_STRLCPY + SOURCES.c += strlcpy.c +endif + +DIRS := testSimpleProperties + +include $(NDB_TOP)/Epilogue.mk + +testNdbSqlUtil: NdbSqlUtil.cpp + $(CC) -o $@ NdbSqlUtil.cpp $(CCFLAGS) -DNDB_SQL_UTIL_TEST -L$(NDB_TOP)/lib -lportlib -lgeneral diff --git a/ndb/src/common/util/NdbErrHnd.cpp b/ndb/src/common/util/NdbErrHnd.cpp new file mode 100644 index 00000000000..53df5d702ca --- /dev/null +++ b/ndb/src/common/util/NdbErrHnd.cpp @@ -0,0 +1,493 @@ +/* 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 */ + + +#if defined NDB_OSE || defined NDB_SOFTOSE + +#include <NdbOut.hpp> +#include <NdbStdio.h> +#include <ndb_types.h> + +#include "ose.h" +#include "ose_err.h" +#include "osetypes.h" + + +#define BUFSIZE 100 + +typedef struct { + char header1[BUFSIZE]; + char header2[BUFSIZE]; + char error_code_line[BUFSIZE]; + char subcode_line[BUFSIZE]; + char product_line[BUFSIZE]; + char header_file_line[BUFSIZE]; + char extra_line[BUFSIZE]; + char user_called_line[BUFSIZE]; + char current_process_id_line[BUFSIZE]; + char current_process_name_line[BUFSIZE]; + char file_line[BUFSIZE]; + char line_line[BUFSIZE]; + char err_hnd_file[BUFSIZE]; +} Error_message; + +char assert_line[BUFSIZE]; +char unknown_signal_line[BUFSIZE]; +char signal_number_line[BUFSIZE]; +char sender_line[BUFSIZE]; +char receiver_line[BUFSIZE]; + +extern "C" OSBOOLEAN ndb_err_hnd(bool user_called, + Uint32 error_code, + Uint32 extra) +{ + static Error_message error_message; + bool error_handled; + Uint32 subcode; + + char* subcode_mnemonic; + char* product_name; + char* file_name; + + /*The subcode (bit 16 - 30) is extracted from error_code */ + subcode = (error_code & 0x7fff0000) >> 16; + + if (user_called) { + switch (subcode) { + case 0x0050 : + subcode_mnemonic= "OSE_PRH_PLS"; + product_name= "Program Loader"; + file_name = "prherr.h"; + break; + case 0x0051 : + subcode_mnemonic = "OSE_PRH_START_PRH"; + product_name= "start_prh"; + file_name= " start_prh.c"; + break; + case 0x0052 : + subcode_mnemonic= "OSE_PRH_ASF"; + product_name= "Archive Server"; + file_name = "prherr.h"; + break; + case 0x0058 : + case 0x4058 : + case 0x3fff : + case 0x8058 : + subcode_mnemonic= "OSE_MMS_EBASE"; + product_name= "MMS"; + file_name= "mms_err.h"; + break; + /*Link Handler G3***************************************/ + case 0x0060 : + case 0x8060 : + subcode_mnemonic= "OSE_GLH_EBASE"; + product_name= "General Link Handler"; + file_name= "glherr.h"; + break; + case 0x0064 : + case 0x8064 : + subcode_mnemonic= "OSE_GPL_EBASE"; + product_name= "General Protocol Link Handler"; + file_name= "gplerr.h"; + break; + case 0x0066 : + case 0x8066 : + subcode_mnemonic= "OSE_UDPPDR_EBASE"; + product_name= "UDP driver for GPL"; + file_name= "udppdrerr.h"; + break; + case 0x0067 : + case 0x8067 : + subcode_mnemonic= "OSE_SERPDR_EBASE"; + product_name= "Serial driver for GPL"; + file_name= "serpdrerr.h"; + break; + case 0x0068 : + case 0x8068 : + subcode_mnemonic= "OSE_ETHPDR_EBASE"; + product_name= "Ethernet driver for GPL"; + file_name= "ethpdrerr.h"; + break; + /*Link handler G4***************************************/ + case 0x0061 : + subcode_mnemonic= "OSE_OTL_EBASE"; + product_name= "OSE Transport Layer"; + file_name= "otlerr.h"; + break; + case 0x0062 : + subcode_mnemonic= "OSE_LALUDP_EBASE"; + product_name= "Link Adaption Layer for UDP"; + file_name= "header file unknown"; + break; + /*Internet Utilities************************************/ + case 0x0069 : + subcode_mnemonic= "OSE_TFTPD"; + product_name= "TFTP server"; + file_name= "inetutilerr.h"; + break; + case 0x006a : + subcode_mnemonic= "OSE_TELUDPD"; + product_name= "TELNET/UDP server"; + file_name= "inetutilerr.h"; + break; + case 0x006b : + subcode_mnemonic= "OSE_FTPD"; + product_name= "FTP server"; + file_name= "inetutilerr.h"; + break; + case 0x006c : + subcode_mnemonic= "OSE_TELNETD"; + product_name= "TELNET server"; + file_name= "inetutilerr.h"; + break; + case 0x006d : + subcode_mnemonic= "OSE_SURFER"; + product_name= "OSE System Surfer"; + file_name= "inetutilerr.h"; + break; + case 0x006e : + subcode_mnemonic= "OSE_BOOTP"; + product_name= "BOOTP client"; + file_name= "inetutilerr.h"; + break; + case 0x006f : + switch((error_code & 0x0000f000)){ + case 0x00000000 : + subcode_mnemonic= "OSE_RES"; + product_name= "DNS resolver"; + file_name= "inetutilerr.h"; + break; + case 0x00001000 : + subcode_mnemonic= "OSE_DHCPC"; + product_name= "DHCP client"; + file_name= "inetutilerr.h"; + break; + case 0x00002000 : + subcode_mnemonic= "OSE_FTP"; + product_name= "FTP client"; + file_name= "inetutilerr.h"; + break; + default : + subcode_mnemonic= "Unknown error"; + product_name= "unknown product"; + file_name = "header file unknown"; + break; + } + break; + case 0x00c2 : + subcode_mnemonic= "OSE_DNS"; + product_name= "DNS server"; + file_name= "dns_err.h"; + break; + /*INET**************************/ + case 0x0070 : + subcode_mnemonic= "INET_ERRBASE"; + product_name= "Internet Protocols (INET)"; + file_name= "ineterr.h"; + break; + case 0x0071 : + subcode_mnemonic= "WEBS_ERRBASE"; + product_name= "Web Server (WEBS)"; + file_name= "webserr.h"; + break; + case 0x0072 : + subcode_mnemonic= "SNMP"; + product_name= "SNMP"; + file_name= "header file unknown"; + break; + case 0x0073 : + subcode_mnemonic= "STP_BRIDGE"; + product_name= "STP bridge"; + file_name= "header file unknown"; + break; + case 0x0200 : + case 0x0201 : + case 0x0202 : + case 0x0203 : + case 0x0204 : + case 0x0205 : + case 0x0206 : + case 0x0207 : + case 0x0208 : + case 0x0209 : + case 0x020a : + case 0x020b : + case 0x020c : + case 0x020d : + case 0x020e : + case 0x020f : + subcode_mnemonic = "INETINIT_ERR_BASE"; + product_name = "INET"; + file_name = "startinet.c"; + break; + /*Miscellanous******************************************/ + case 0x0082 : + subcode_mnemonic= "OSE_HEAP_EBASE"; + product_name= "Heap Manager"; + file_name= "heap_err.h"; + break; + case 0x0088 : + subcode_mnemonic= "OSE_BSP"; + product_name= "Board Support Package"; + file_name= "bsperr.h"; + break; + case 0x008a : + subcode_mnemonic= "OSE_TOSV_EBASE"; + product_name= "Time Out Server"; + file_name= "tosverr.h"; + break; + case 0x008b : + subcode_mnemonic= "OSE_RTC_EBASE"; + product_name= "Real Time Clock"; + file_name= "rtcerr.h"; + break; + case 0x008d : + case 0x808d : + subcode_mnemonic= "OSENS_ERR_BASE"; + product_name= "Name Server"; + file_name= "osens_err.h"; + break; + case 0x008e : + subcode_mnemonic= "PMD_ERR_BASE"; + product_name= "Post Mortem Dump"; + file_name= "pmderr.h"; + break; + /*Embedded File System***********************************/ + case 0x0090 : + subcode_mnemonic= "OSE_EFS_COMMON"; + product_name= "EFS common"; + file_name= "efs_err.h"; + break; + case 0x0091 : + subcode_mnemonic= "OSE_EFS_FLIB"; + product_name= "EFS function library"; + file_name= "efs_err.h"; + break; + case 0x0092 : + subcode_mnemonic= "OSE_EFS_SERDD"; + product_name= "EFS serdd"; + file_name= "efs_err.h"; + break; + case 0x0093 : + subcode_mnemonic= "OSE_EFS_SHELL"; + product_name= "OSE shell"; + file_name= "efs_err.h"; + break; + case 0x0094 : + subcode_mnemonic= "OSE_EFS_STARTEFS"; + product_name= "EFS startefs.c"; + file_name= "efs_err.h"; + break; + /*Debugger related***************************************/ + case 0x00a0 : + subcode_mnemonic= "DBGSERVER_ERR_BASE"; + product_name= "Debug server for Illuminator"; + file_name= "degservererr.h"; + break; + case 0x00b2 : + subcode_mnemonic= "OSE_MDM"; + product_name= "Multi INDRT monitor"; + file_name= "header file unknown"; + break; + /*Miscellanous*******************************************/ + case 0x00c0 : + subcode_mnemonic= "OSE_POTS_EBASE"; + product_name= "POTS tutorial example"; + file_name= "pots_err.h"; + break; + case 0x00c1 : + subcode_mnemonic= "OSE_PTH_ECODE_BASE"; + product_name= "Pthreads"; + file_name= "pthread_err.h"; + break; + case 0x00c3 : + subcode_mnemonic= "OSE_NTP_EBASE"; + product_name= "OSE NTP/SNTP"; + file_name= "ntp_err.h"; + break; + case 0x00c4 : + subcode_mnemonic= "TRILLIUM_BASE"; + product_name= "Trillium OSE port"; + file_name= "sk_ss.c"; + break; + case 0x00c5 : + subcode_mnemonic= "OSE_OSECPP_EBASE"; + product_name= "C++ Support with libosecpp.a"; + file_name= "cpp_err.h"; + break; + case 0x00c6 : + subcode_mnemonic= "OSE_RIP_ERR_BASE"; + product_name= "OSE RIP"; + file_name= "oserip.h"; + break; + /*Unknown error_code*************************************/ + default : + subcode_mnemonic= "Unknown error"; + product_name= "unknown product"; + file_name = "header file unknown"; + break; + } + } else { + /* user_called = 0, i.e. reported by the kernel */ + subcode_mnemonic= "OSE_KRN"; + product_name= "Kernel"; + file_name = "ose_err.h"; + } + + snprintf (error_message.header1, + BUFSIZE, + "This is the OSE Example System Error handler\r\n"); + + snprintf (error_message.err_hnd_file, + BUFSIZE, + "located in: " __FILE__ "\r\n"); + + snprintf (error_message.header2, + BUFSIZE, + "An Error has been reported:\r\n"); + + if (user_called == (OSBOOLEAN) 0 ) { + snprintf(error_message.user_called_line, + BUFSIZE, + "user_called: 0x%x (Error detected by the kernel)\r\n", + user_called); + } + else { + snprintf(error_message.user_called_line, + BUFSIZE, + "user_called: 0x%x (Error detected by an application)\r\n", + user_called); + } + + snprintf (error_message.error_code_line, + BUFSIZE, + "error code: 0x%08x\r\n", + error_code); + + snprintf (error_message.subcode_line, + BUFSIZE, + " subcode: %s (0x%08x)\r\n", + subcode_mnemonic, + ( subcode << 16)); + + snprintf (error_message.product_line, + BUFSIZE, + " product: %s\r\n", + product_name); + + snprintf (error_message.header_file_line, + BUFSIZE, + " header file: %s\r\n", + file_name); + + snprintf (error_message.extra_line, + BUFSIZE, + "extra: 0x%08x\r\n", + extra); + + if (error_code != OSE_ENO_KERN_SPACE || user_called){ + struct OS_pcb *pcb = get_pcb(current_process()); + const char *process_name = &pcb->strings[pcb->name]; + + snprintf(error_message.current_process_id_line, + BUFSIZE, + "Current Process: 0x%08x\r\n", + current_process()); + + snprintf(error_message.current_process_name_line, + BUFSIZE, + "Process Name: %s\r\n", + process_name); + + snprintf(error_message.file_line, + BUFSIZE, + "File: %s\r\n", + &pcb->strings[pcb->file]); + + snprintf(error_message.line_line, + BUFSIZE, + "Line: %d\r\n", + pcb->line); + + free_buf((union SIGNAL **)&pcb); + } + + if ( !(((error_code & OSE_EFATAL_MASK) != 0) && (user_called == 0))){ + /* If the error is reported by the kernel and the fatal flag is set, + * dbgprintf can't be trusted */ + ndbout << error_message.header1; + ndbout << error_message.err_hnd_file; + ndbout << error_message.header2; + ndbout << error_message.user_called_line; + ndbout << error_message.error_code_line; + ndbout << error_message.subcode_line; + ndbout << error_message.product_line; + ndbout << error_message.header_file_line; + ndbout << error_message.extra_line; + ndbout << error_message.current_process_id_line; + ndbout << error_message.current_process_name_line; + ndbout << error_message.file_line; + ndbout << error_message.line_line; + ndbout << endl; + } + + if(user_called){ + switch (error_code) { + /* Check for assertion failure (see oseassert.h and assert.c). */ + case (OSERRCODE) 0xffffffff: + { + if(extra != 0){ + char *expr = ((char **)extra)[0]; + char *file = ((char **)extra)[1]; + unsigned line = ((unsigned *)extra)[2]; + snprintf(assert_line, BUFSIZE, "Assertion Failed: %s:%u: %s\r\n", file, line, expr); + ndbout << assert_line; + } + } + /* Check for unknown signal */ + case (OSERRCODE) 0xfffffffe: + { + union SIGNAL *sig = (union SIGNAL *)extra; + SIGSELECT signo = *(SIGSELECT*)sig; + PROCESS rcv_ = current_process(); + PROCESS snd_ = sender(&sig); + struct OS_pcb *rcv = get_pcb(rcv_); + const char *rcv_name = &rcv->strings[rcv->name]; + struct OS_pcb *snd = get_pcb(snd_); + const char *snd_name = &snd->strings[snd->name]; + snprintf(unknown_signal_line, BUFSIZE, + "Unknown Signal Received\r\n"); + snprintf(unknown_signal_line, BUFSIZE, + "Signal Number: 0x%08lx\r\n", signo); + snprintf(unknown_signal_line, BUFSIZE, + "Sending Process: 0x%08lx (%s))\r\n", snd_, snd_name); + snprintf(unknown_signal_line, BUFSIZE, + "Receiving Process: 0x%08lx (%s))\r\n", rcv_, rcv_name); + free_buf((union SIGNAL **)&rcv); + free_buf((union SIGNAL **)&snd); } + ndbout << unknown_signal_line; + ndbout << signal_number_line; + ndbout << sender_line; + ndbout << receiver_line; + } /* switch */ + } /* if */ + + /* Zero means the error has not been fixed by the error handler. */ + error_handled = 0; + return error_handled; +} + +#endif diff --git a/ndb/src/common/util/NdbOut.cpp b/ndb/src/common/util/NdbOut.cpp new file mode 100644 index 00000000000..2624bfa04bd --- /dev/null +++ b/ndb/src/common/util/NdbOut.cpp @@ -0,0 +1,175 @@ +/* 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 "NdbOut.hpp" +#include <NdbStdio.h> +#include <stdarg.h> +#include <NdbUnistd.h> +#include <string.h> +#include <OutputStream.hpp> + +static FileOutputStream ndbouts_fileoutputstream(stdout); +NdbOut ndbout(ndbouts_fileoutputstream); + +static const char * fms[] = { + "%d", "0x%02x", // Int8 + "%u", "0x%02x", // Uint8 + "%d", "0x%04x", // Int16 + "%u", "0x%04x", // Uint16 + "%d", "0x%08x", // Int32 + "%u", "0x%08x", // Uint32 + "%lld", "0x%016llx", // Int64 + "%llu", "0x%016llx" // Uint64 + "%llu", "0x%016llx" // UintPtr +}; + +NdbOut& +NdbOut::operator<<(Int8 v) { m_out->print(fms[0+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Uint8 v) { m_out->print(fms[2+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Int16 v) { m_out->print(fms[4+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Uint16 v) { m_out->print(fms[6+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Int32 v) { m_out->print(fms[8+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(Uint32 v) { m_out->print(fms[10+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(Int64 v) { m_out->print(fms[12+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(Uint64 v) { m_out->print(fms[14+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(unsigned long int v) { return *this << (Uint64) v; } + +NdbOut& +NdbOut::operator<<(const char* val){ m_out->print("%s", val); return * this; } +NdbOut& +NdbOut::operator<<(const void* val){ m_out->print("%p", val); return * this; } +NdbOut& +NdbOut::operator<<(BaseString &val){ return *this << val.c_str(); } + +NdbOut& +NdbOut::operator<<(float val){ m_out->print("%f", (double)val); return * this;} +NdbOut& +NdbOut::operator<<(double val){ m_out->print("%f", val); return * this; } + +NdbOut& NdbOut::endline() +{ + isHex = 0; // Reset hex to normal, if user forgot this + m_out->println(""); + m_out->flush(); + return *this; +} + +NdbOut& NdbOut::flushline() +{ + m_out->flush(); + return *this; +} + +NdbOut& NdbOut::setHexFormat(int _format) +{ + isHex = (_format == 0 ? 0 : 1); + return *this; +} + +NdbOut::NdbOut(OutputStream & out) + : m_out(& out) +{ + isHex = 0; +} + +NdbOut::~NdbOut() +{ +} + +void +NdbOut::print(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf; + va_end(ap); +} + +void +NdbOut::println(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf << endl; + va_end(ap); +} + +extern "C" +void +ndbout_c(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf << endl; + va_end(ap); +} + +FilteredNdbOut::FilteredNdbOut(OutputStream & out, + int threshold, int level) + : NdbOut(out) { + m_level = level; + m_threshold = threshold; + m_org = &out; + m_null = new NullOutputStream(); + setLevel(level); +} + +FilteredNdbOut::~FilteredNdbOut(){ + delete m_null; +} + +void +FilteredNdbOut::setLevel(int i){ + m_level = i; + if(m_level >= m_threshold){ + m_out = m_org; + } else { + m_out = m_null; + } +} + +void +FilteredNdbOut::setThreshold(int i){ + m_threshold = i; + setLevel(m_level); +} + +int +FilteredNdbOut::getLevel() const { + return m_level; +} +int +FilteredNdbOut::getThreshold() const { + return m_threshold; +} + diff --git a/ndb/src/common/util/NdbSqlUtil.cpp b/ndb/src/common/util/NdbSqlUtil.cpp new file mode 100644 index 00000000000..dba7012cc0f --- /dev/null +++ b/ndb/src/common/util/NdbSqlUtil.cpp @@ -0,0 +1,351 @@ +/* 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 <NdbSqlUtil.hpp> + +int +NdbSqlUtil::char_compare(const char* s1, unsigned n1, + const char* s2, unsigned n2, bool padded) +{ + int c1 = 0; + int c2 = 0; + unsigned i = 0; + while (i < n1 || i < n2) { + c1 = i < n1 ? s1[i] : padded ? 0x20 : 0; + c2 = i < n2 ? s2[i] : padded ? 0x20 : 0; + if (c1 != c2) + break; + i++; + } + return c1 - c2; +} + +bool +NdbSqlUtil::char_like(const char* s1, unsigned n1, + const char* s2, unsigned n2, bool padded) +{ + int c1 = 0; + int c2 = 0; + unsigned i1 = 0; + unsigned i2 = 0; + while (i1 < n1 || i2 < n2) { + c1 = i1 < n1 ? s1[i1] : padded ? 0x20 : 0; + c2 = i2 < n2 ? s2[i2] : padded ? 0x20 : 0; + if (c2 == '%') { + while (i2 + 1 < n2 && s2[i2 + 1] == '%') { + i2++; + } + unsigned m = 0; + while (m <= n1 - i1) { + if (char_like(s1 + i1 + m, n1 -i1 - m, + s2 + i2 + 1, n2 - i2 - 1, padded)) + return true; + m++; + } + return false; + } + if (c2 == '_') { + if (c1 == 0) + return false; + } else { + if (c1 != c2) + return false; + } + i1++; + i2++; + } + return i1 == n2 && i2 == n2; +} + +/** + * Data types. + */ + +const NdbSqlUtil::Type +NdbSqlUtil::m_typeList[] = { + { + Type::Undefined, + NULL + }, + { + Type::Tinyint, + cmpTinyint + }, + { + Type::Tinyunsigned, + cmpTinyunsigned + }, + { + Type::Smallint, + cmpSmallint + }, + { + Type::Smallunsigned, + cmpSmallunsigned + }, + { + Type::Mediumint, + NULL // cmpMediumint + }, + { + Type::Mediumunsigned, + NULL // cmpMediumunsigned + }, + { + Type::Int, + cmpInt + }, + { + Type::Unsigned, + cmpUnsigned + }, + { + Type::Bigint, + cmpBigint + }, + { + Type::Bigunsigned, + cmpBigunsigned + }, + { + Type::Float, + cmpFloat + }, + { + Type::Double, + cmpDouble + }, + { + Type::Decimal, + NULL // cmpDecimal + }, + { + Type::Char, + cmpChar + }, + { + Type::Varchar, + cmpVarchar + }, + { + Type::Binary, + NULL // cmpBinary + }, + { + Type::Varbinary, + NULL // cmpVarbinary + }, + { + Type::Datetime, + cmpDatetime + }, + { + Type::Timespec, + NULL // cmpTimespec + } +}; + +const NdbSqlUtil::Type& +NdbSqlUtil::type(Uint32 typeId) +{ + if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) && + m_typeList[typeId].m_typeId != Type::Undefined) { + return m_typeList[typeId]; + } + return m_typeList[Type::Undefined]; +} + +// compare + +int +NdbSqlUtil::cmpTinyint(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Tinyint, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpTinyunsigned(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Tinyunsigned, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpSmallint(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Smallint, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpSmallunsigned(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Smallunsigned, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpMediumint(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Mediumint, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpMediumunsigned(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Mediumunsigned, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpInt(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Int, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpUnsigned(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Unsigned, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpBigint(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Bigint, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpBigunsigned(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Bigunsigned, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpFloat(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Float, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpDouble(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Double, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpDecimal(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Decimal, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpChar(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Char, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpVarchar(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Varchar, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpBinary(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Binary, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpVarbinary(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Varbinary, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpDatetime(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Datetime, p1, p2, full, size); +} + +int +NdbSqlUtil::cmpTimespec(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size) +{ + return cmp(Type::Timespec, p1, p2, full, size); +} + +#ifdef NDB_SQL_UTIL_TEST + +#include <assert.h> +#include <NdbTick.h> +#include <NdbOut.hpp> + +struct Testcase { + int op; // 1=compare 2=like + int res; + const char* s1; + const char* s2; + int pad; +}; +const Testcase testcase[] = { + { 2, 1, "abc", "abc", 0 }, + { 2, 1, "abc", "abc%", 0 }, + { 2, 1, "abcdef", "abc%", 0 }, + { 2, 1, "abcdefabcdefabcdef", "abc%", 0 }, + { 2, 1, "abcdefabcdefabcdef", "abc%f", 0 }, + { 2, 0, "abcdefabcdefabcdef", "abc%z", 0 }, + { 2, 1, "abcdefabcdefabcdef", "%f", 0 }, + { 2, 1, "abcdef", "a%b%c%d%e%f", 0 }, + { 0, 0, 0, 0 } +}; + +int +main(int argc, char** argv) +{ + unsigned count = argc > 1 ? atoi(argv[1]) : 1000000; + ndbout_c("count = %u", count); + assert(count != 0); + for (const Testcase* t = testcase; t->s1 != 0; t++) { + ndbout_c("%d = '%s' %s '%s' pad=%d", + t->res, t->s1, t->op == 1 ? "comp" : "like", t->s2); + NDB_TICKS x1 = NdbTick_CurrentMillisecond(); + unsigned n1 = strlen(t->s1); + unsigned n2 = strlen(t->s2); + for (unsigned i = 0; i < count; i++) { + if (t->op == 1) { + int res = NdbSqlUtil::char_compare(t->s1, n1, t->s2, n2, t->pad); + assert(res == t->res); + continue; + } + if (t->op == 2) { + int res = NdbSqlUtil::char_like(t->s1, n1, t->s2, n2, t->pad); + assert(res == t->res); + continue; + } + assert(false); + } + NDB_TICKS x2 = NdbTick_CurrentMillisecond(); + if (x2 < x1) + x2 = x1; + double usec = 1000000.0 * double(x2 - x1) / double(count); + ndbout_c("time %.0f usec per call", usec); + } + // quick check + for (unsigned i = 0; i < sizeof(m_typeList) / sizeof(m_typeList[0]); i++) { + const NdbSqlUtil::Type& t = m_typeList[i]; + assert(t.m_typeId == i); + } + return 0; +} + +#endif diff --git a/ndb/src/common/util/OutputStream.cpp b/ndb/src/common/util/OutputStream.cpp new file mode 100644 index 00000000000..1143fe00fd1 --- /dev/null +++ b/ndb/src/common/util/OutputStream.cpp @@ -0,0 +1,98 @@ +/* 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 <OutputStream.hpp> +#include <stdarg.h> +#include <socket_io.h> + +FileOutputStream::FileOutputStream(FILE * file){ + f = file; +} + +int +FileOutputStream::print(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret; +} + +int +FileOutputStream::println(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret + fprintf(f, "\n"); +} + +SocketOutputStream::SocketOutputStream(NDB_SOCKET_TYPE socket, + unsigned timeout){ + m_socket = socket; + m_timeout = timeout; +} + +int +SocketOutputStream::print(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vprint_socket(m_socket, m_timeout, fmt, ap); + va_end(ap); + return ret; +} +int +SocketOutputStream::println(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vprintln_socket(m_socket, m_timeout, fmt, ap); + va_end(ap); + return ret; +} + +#ifdef NDB_SOFTOSE +#include <dbgprintf.h> +int +SoftOseOutputStream::print(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + else + buf[0] = 0; + va_end(ap); + dbgprintf(buf); +} + +int +SoftOseOutputStream::println(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + vsnprintf(buf, sizeof(buf)-1, fmt, ap); + else + buf[0] = 0; + va_end(ap); + + strcat(buf, "\n\r"); + dbgprintf(buf); +} +#endif diff --git a/ndb/src/common/util/Parser.cpp b/ndb/src/common/util/Parser.cpp new file mode 100644 index 00000000000..d5c23fe14c1 --- /dev/null +++ b/ndb/src/common/util/Parser.cpp @@ -0,0 +1,349 @@ +/* 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 "Parser.hpp" +#include <stdio.h> +#include <NdbOut.hpp> +#include <string.h> +#include <Properties.hpp> +#include <assert.h> +#include <Base64.hpp> + +#define DEBUG(x) ndbout << x << endl; + +static void trim(char * str); + +class ParseInputStream : public InputStream { +public: + ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#'); + + char* gets(char * buf, int bufLen); + void push_back(const char *); +private: + InputStream & in; + char * buffer; +}; + +ParseInputStream::ParseInputStream(InputStream & _in, + bool /* unused */, + char /* unused */) + : in(_in){ + buffer = 0; +} + +char* +ParseInputStream::gets(char * buf, int bufLen){ + if(buffer != 0){ + strncpy(buf, buffer, bufLen); + free(buffer); + buffer = 0; + return buf; + } + char *t = in.gets(buf, bufLen); + return t; +} + +void +ParseInputStream::push_back(const char * str){ + if(buffer != 0) + abort(); + buffer = strdup(str); +} + +ParserImpl::ParserImpl(const DummyRow * rows, InputStream & in, + bool b_cmd, bool b_empty, bool b_iarg) + : m_rows(rows), input(* new ParseInputStream(in)) +{ + m_breakOnCmd = b_cmd; + m_breakOnEmpty = b_empty; + m_breakOnInvalidArg = b_iarg; +} + +ParserImpl::~ParserImpl(){ + delete & input; +} + +static +bool +Empty(const char * str){ + if(str == 0) + return true; + const int len = strlen(str); + if(len == 0) + return false; + for(int i = 0; i<len; i++) + if(str[i] != ' ' && str[i] != '\t' && str[i] != '\n') + return false; + return true; +} + +static +bool +Eof(const char * str) { return str == 0;} + +static +void +trim(char * str){ + if(str == NULL) + return; + int len = strlen(str); + for(len--; str[len] == '\n' || str[len] == ' ' || str[len] == '\t'; len--) + str[len] = 0; + + int pos = 0; + while(str[pos] == ' ' || str[pos] == '\t') + pos++; + + if(str[pos] == '\"' && str[len] == '\"') { + pos++; + str[len] = 0; + len--; + } + + memmove(str, &str[pos], len - pos + 2); +} + +static +bool +split(char * buf, char ** name, char ** value){ + + * value = strchr(buf, ':'); + if(* value == 0) + * value = strchr(buf, '='); + + + if(* value == 0){ + return false; + } + (* value)[0] = 0; + * value = (* value + 1); + * name = buf; + + trim(* name); + trim(* value); + + return true; +} + +bool +ParserImpl::run(Context * ctx, const class Properties ** pDst, + volatile bool * stop) const { + * pDst = 0; + bool ownStop = false; + if(stop == 0) + stop = &ownStop; + + ctx->m_aliasUsed.clear(); + + const unsigned sz = sizeof(ctx->m_tokenBuffer); + ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); + if(Eof(ctx->m_currentToken)){ + ctx->m_status = Parser<Dummy>::Eof; + return false; + } + + if(ctx->m_currentToken[0] == 0){ + ctx->m_status = Parser<Dummy>::NoLine; + return false; + } + + if(Empty(ctx->m_currentToken)){ + ctx->m_status = Parser<Dummy>::EmptyLine; + return false; + } + + trim(ctx->m_currentToken); + ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows); + if(ctx->m_currentCmd == 0){ + ctx->m_status = Parser<Dummy>::UnknownCommand; + return false; + } + + Properties * p = new Properties(); + + bool invalidArgument = false; + ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); + + while((! * stop) && + !Eof(ctx->m_currentToken) && + !Empty(ctx->m_currentToken)){ + if(ctx->m_currentToken[0] != 0){ + trim(ctx->m_currentToken); + if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){ + delete p; + invalidArgument = true; + break; + } + } + ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); + } + + if(invalidArgument){ + char buf[sz]; + char * tmp; + if(!m_breakOnInvalidArg){ + do { + tmp = input.gets(buf, sz); + } while((! * stop) && !Eof(tmp) && !Empty(tmp)); + } + return false; + } + + if(* stop){ + delete p; + ctx->m_status = Parser<Dummy>::ExternalStop; + return false; + } + + if(!checkMandatory(ctx, p)){ + ctx->m_status = Parser<Dummy>::MissingMandatoryArgument; + delete p; + return false; + } + + /** + * Add alias to properties + */ + for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){ + const ParserRow<Dummy> * alias = ctx->m_aliasUsed[i]; + Properties tmp; + tmp.put("name", alias->name); + tmp.put("realName", alias->realName); + p->put("$ALIAS", i, &tmp); + } + p->put("$ALIAS", ctx->m_aliasUsed.size()); + + ctx->m_status = Parser<Dummy>::Ok; + * pDst = p; + return true; +} + +const ParserImpl::DummyRow* +ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){ + const char * name = buf; + const DummyRow * tmp = &rows[0]; + while(tmp->name != 0 && name != 0){ + if(strcmp(tmp->name, name) == 0){ + if(tmp->type == DummyRow::Cmd) + return tmp; + if(tmp->type == DummyRow::CmdAlias){ + if(ctx != 0) + ctx->m_aliasUsed.push_back(tmp); + name = tmp->realName; + tmp = &rows[0]; + continue; + } + } + tmp++; + } + return 0; +} + +const ParserImpl::DummyRow* +ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){ + const char * name = buf; + const DummyRow * tmp = &rows[0]; + while(tmp->name != 0){ + const DummyRow::Type t = tmp->type; + if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias) + break; + if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){ + if(tmp->type == DummyRow::Arg){ + return tmp; + } + if(tmp->type == DummyRow::ArgAlias){ + if(ctx != 0) + ctx->m_aliasUsed.push_back(tmp); + name = tmp->realName; + tmp = &rows[0]; + continue; + } + } + tmp++; + } + return 0; +} + +bool +ParserImpl::parseArg(Context * ctx, + char * buf, + const DummyRow * rows, + Properties * p){ + char * name; + char * value; + if(!split(buf, &name, &value)){ + ctx->m_status = Parser<Dummy>::InvalidArgumentFormat; + return false; + } + const DummyRow * arg = matchArg(ctx, name, rows); + if(arg == 0){ + ctx->m_status = Parser<Dummy>::UnknownArgument; + return false; + } + + switch(arg->argType){ + case DummyRow::String: + if(p->put(arg->name, value)) + return true; + break; + case DummyRow::Int:{ + Uint32 i; + int c = sscanf(value, "%u", &i); + if(c != 1){ + ctx->m_status = Parser<Dummy>::TypeMismatch; + return false; + } + if(p->put(arg->name, i)) + return true; + break; + } + + case DummyRow::Properties: { + Properties *sp = new Properties(); + BaseString v(value); + UtilBuffer b; + base64_decode(v, b); + sp->unpack((const Uint32 *)b.get_data(), b.length()); + break; + } + default: + ctx->m_status = Parser<Dummy>::UnknownArgumentType; + return false; + } + if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){ + ctx->m_status = Parser<Dummy>::ArgumentGivenTwice; + return false; + } + + abort(); +} + +bool +ParserImpl::checkMandatory(Context* ctx, const Properties* props){ + const DummyRow * tmp = &ctx->m_currentCmd[1]; + while(tmp->name != 0 && tmp->type == DummyRow::Arg){ + if(tmp->argRequired == ParserRow<Dummy>::Mandatory && + !props->contains(tmp->name)){ + ctx->m_status = Parser<Dummy>::MissingMandatoryArgument; + ctx->m_currentArg = tmp; + return false; + } + tmp++; + } + return true; +} + diff --git a/ndb/src/common/util/Properties.cpp b/ndb/src/common/util/Properties.cpp new file mode 100644 index 00000000000..4841d6e5e9e --- /dev/null +++ b/ndb/src/common/util/Properties.cpp @@ -0,0 +1,1019 @@ +/* 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 <Properties.hpp> + +#include <NdbTCP.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <NdbString.h> + +#include <NdbOut.hpp> + +/** + * Note has to be a multiple of 4 bytes + */ +const char Properties::version[] = { 2, 0, 0, 1, 1, 1, 1, 4 }; + +/** + * PropertyImpl + */ +struct PropertyImpl{ + PropertiesType valueType; + const char * name; + void * value; + + ~PropertyImpl(); + PropertyImpl(const char * name, Uint32 value); + PropertyImpl(const char * name, const char * value); + PropertyImpl(const char * name, const Properties * value); + + static PropertyImpl * copyPropertyImpl(const PropertyImpl &); +}; + +/** + * PropertiesImpl + */ +class PropertiesImpl { + PropertiesImpl(const PropertiesImpl &); // Not implemented + PropertiesImpl& operator=(const PropertiesImpl&); // Not implemented +public: + PropertiesImpl(Properties *); + PropertiesImpl(Properties *, const PropertiesImpl &); + ~PropertiesImpl(); + + Properties * properties; + + Uint32 size; + Uint32 items; + PropertyImpl **content; + + bool m_insensitive; + int (* compare)(const char *s1, const char *s2); + + void grow(int sizeToAdd); + + PropertyImpl * get(const char * name) const; + PropertyImpl * put(PropertyImpl *); + void remove(const char * name); + + Uint32 getPackedSize(Uint32 pLen) const; + bool pack(Uint32 *& buf, const char * prefix, Uint32 prefixLen) const; + bool unpack(const Uint32 * buf, Uint32 &bufLen, Properties * top, int items); + + Uint32 getTotalItems() const; + + void setErrno(Uint32 pErr, Uint32 osErr = 0){ + properties->setErrno(pErr, osErr); + } + + const char * getProps(const char * name, const PropertiesImpl ** impl) const; + const char * getPropsPut(const char * name, PropertiesImpl ** impl); +}; + +/** + * Methods for Property + */ +Property::Property(const char * name, Uint32 value){ + impl = new PropertyImpl(name, value); +} + +Property::Property(const char * name, const char * value){ + impl = new PropertyImpl(name, value); +} + +Property::Property(const char * name, const class Properties * value){ + impl = new PropertyImpl(name, value); + + ((Properties*)impl->value)->setCaseInsensitiveNames(value->getCaseInsensitiveNames()); +} + +Property::~Property(){ + delete impl; +} + +/** + * Methods for Properties + */ +Properties::Properties(){ + parent = 0; + impl = new PropertiesImpl(this); +} + +Properties::Properties(const Properties & org){ + parent = 0; + impl = new PropertiesImpl(this, * org.impl); +} + +Properties::Properties(const Property * anArray, int arrayLen){ + impl = new PropertiesImpl(this); + + put(anArray, arrayLen); +} + +Properties::~Properties(){ + clear(); + delete impl; +} + +void +Properties::put(const Property * anArray, int arrayLen){ + if(anArray == 0) + return; + for(int i = 0; i<arrayLen; i++) + impl->put(anArray[i].impl); +} + +template <class T> +bool +put(PropertiesImpl * impl, const char * name, T value, bool replace){ + if(name == 0){ + impl->setErrno(E_PROPERTIES_INVALID_NAME); + return false; + } + + PropertiesImpl * tmp = 0; + const char * short_name = impl->getPropsPut(name, &tmp); + + if(tmp == 0){ + impl->setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(tmp->get(short_name) != 0){ + if(replace){ + tmp->remove(short_name); + } else { + impl->setErrno(E_PROPERTIES_ELEMENT_ALREADY_EXISTS); + return false; + } + } + return tmp->put(new PropertyImpl(short_name, value)); +} + +bool +Properties::put(const char * name, Uint32 value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::put(const char * name, const char * value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::put(const char * name, const Properties * value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::getTypeOf(const char * name, PropertiesType * type) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + setErrno(E_PROPERTIES_OK); + * type = nvp->valueType; + return true; +} + +bool +Properties::contains(const char * name) const { + PropertyImpl * nvp = impl->get(name); + return nvp != 0; +} + +bool +Properties::get(const char * name, Uint32 * value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_Uint32){ + * value = * (Uint32 *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::get(const char * name, const char ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_char){ + * value = (const char *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::get(const char * name, BaseString& value) const { + const char *tmp = ""; + bool ret; + ret = get(name, &tmp); + value.assign(tmp); + return ret; +} + +bool +Properties::get(const char * name, const Properties ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + if(nvp->valueType == PropertiesType_Properties){ + * value = (const Properties *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::getCopy(const char * name, char ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_char){ + * value = strdup((const char *)nvp->value); + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::getCopy(const char * name, Properties ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_Properties){ + * value = new Properties(* (const Properties *)nvp->value); + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +void +Properties::clear(){ + while(impl->items > 0) + impl->remove(impl->content[0]->name); +} + +void +Properties::remove(const char * name) { + impl->remove(name); +} + +void +Properties::print(FILE * out, const char * prefix) const{ + char buf[1024]; + if(prefix == 0) + buf[0] = 0; + else + strncpy(buf, prefix, 1024); + + for(unsigned int i = 0; i<impl->items; i++){ + switch(impl->content[i]->valueType){ + case PropertiesType_Uint32: + fprintf(out, "%s%s = (Uint32) %d\n", buf, impl->content[i]->name, + *(Uint32 *)impl->content[i]->value); + break; + case PropertiesType_char: + fprintf(out, "%s%s = (char*) \"%s\"\n", buf, impl->content[i]->name, + (char *)impl->content[i]->value); + break; + case PropertiesType_Properties: + char buf2 [1024]; + snprintf(buf2, sizeof(buf2), "%s%s%c",buf, impl->content[i]->name, + Properties::delimiter); + ((Properties *)impl->content[i]->value)->print(out, buf2); + break; + } + } +} + +Properties::Iterator::Iterator(const Properties* prop) : + m_prop(prop), + m_iterator(0) { +} + +const char* +Properties::Iterator::first() { + m_iterator = 0; + return next(); +} + +const char* +Properties::Iterator::next() { + if (m_iterator < m_prop->impl->items) + return m_prop->impl->content[m_iterator++]->name; + else + return NULL; +} + +Uint32 +Properties::getPackedSize() const { + Uint32 sz = 0; + + sz += sizeof(version); // Version id of properties object + sz += 4; // No Of Items + sz += 4; // Checksum + + return sz + impl->getPackedSize(0); +} + +static +Uint32 +computeChecksum(const Uint32 * buf, Uint32 words){ + Uint32 sum = 0; + for(unsigned int i = 0; i<words; i++) + sum ^= htonl(buf[i]); + + return sum; +} + +bool +Properties::pack(Uint32 * buf) const { + Uint32 * bufStart = buf; + + memcpy(buf, version, sizeof(version)); + + // Note that version must be a multiple of 4 + buf += (sizeof(version) / 4); + + * buf = htonl(impl->getTotalItems()); + buf++; + bool res = impl->pack(buf, "", 0); + if(!res) + return res; + + * buf = htonl(computeChecksum(bufStart, (buf - bufStart))); + + return true; +} + +bool +Properties::unpack(const Uint32 * buf, Uint32 bufLen){ + const Uint32 * bufStart = buf; + Uint32 bufLenOrg = bufLen; + + if(bufLen < sizeof(version)){ + setErrno(E_PROPERTIES_INVALID_BUFFER_TO_SHORT); + return false; + } + + if(memcmp(buf, version, sizeof(version)) != 0){ + setErrno(E_PROPERTIES_INVALID_VERSION_WHILE_UNPACKING); + return false; + } + bufLen -= sizeof(version); + + // Note that version must be a multiple of 4 + buf += (sizeof(version) / 4); + + if(bufLen < 4){ + setErrno(E_PROPERTIES_INVALID_BUFFER_TO_SHORT); + return false; + } + + Uint32 totalItems = ntohl(* buf); + buf++; bufLen -= 4; + bool res = impl->unpack(buf, bufLen, this, totalItems); + if(!res) + return res; + + Uint32 sum = computeChecksum(bufStart, (bufLenOrg-bufLen)/4); + if(sum != ntohl(bufStart[(bufLenOrg-bufLen)/4])){ + setErrno(E_PROPERTIES_INVALID_CHECKSUM); + return false; + } + return true; +} + +/** + * Methods for PropertiesImpl + */ +PropertiesImpl::PropertiesImpl(Properties * p){ + this->properties = p; + items = 0; + size = 25; + content = new PropertyImpl * [size]; + this->m_insensitive = false; + this->compare = strcmp; +} + +PropertiesImpl::PropertiesImpl(Properties * p, const PropertiesImpl & org){ + this->properties = p; + this->size = org.size; + this->items = org.items; + this->m_insensitive = org.m_insensitive; + this->compare = org.compare; + content = new PropertyImpl * [size]; + for(unsigned int i = 0; i<items; i++){ + content[i] = PropertyImpl::copyPropertyImpl(* org.content[i]); + } +} + +PropertiesImpl::~PropertiesImpl(){ + for(unsigned int i = 0; i<items; i++) + delete content[i]; + delete [] content; +} + +void +PropertiesImpl::grow(int sizeToAdd){ + PropertyImpl ** newContent = new PropertyImpl * [size + sizeToAdd]; + memcpy(newContent, content, items * sizeof(PropertyImpl *)); + delete [] content; + content = newContent; + size += sizeToAdd; +} + +PropertyImpl * +PropertiesImpl::get(const char * name) const { + const PropertiesImpl * tmp = 0; + const char * short_name = getProps(name, &tmp); + if(tmp == 0){ + return 0; + } + + for(unsigned int i = 0; i<tmp->items; i++) + if((* compare)(tmp->content[i]->name, short_name) == 0) + return tmp->content[i]; + return 0; +} + +PropertyImpl * +PropertiesImpl::put(PropertyImpl * nvp){ + if(items == size) + grow(size); + content[items] = nvp; + + items ++; + + if(nvp->valueType == PropertiesType_Properties){ + ((Properties*)nvp->value)->parent = properties; + } + return nvp; +} + +void +PropertiesImpl::remove(const char * name){ + for(unsigned int i = 0; i<items; i++){ + if((* compare)(content[i]->name, name) == 0){ + delete content[i]; + memmove(&content[i], &content[i+1], (items-i-1)*sizeof(PropertyImpl *)); + items --; + return; + } + } +} + +Uint32 +PropertiesImpl::getTotalItems() const { + int ret = 0; + for(unsigned int i = 0; i<items; i++) + if(content[i]->valueType == PropertiesType_Properties){ + ret += ((Properties*)content[i]->value)->impl->getTotalItems(); + } else { + ret ++; + } + return ret; +} + +const char * +PropertiesImpl::getProps(const char * name, + const PropertiesImpl ** impl) const { + const char * ret = name; + const char * tmp = strchr(name, Properties::delimiter); + if(tmp == 0){ + * impl = this; + return ret; + } else { + Uint32 sz = tmp - name; + char * tmp2 = (char*)malloc(sz + 1); + memcpy(tmp2, name, sz); + tmp2[sz] = 0; + + PropertyImpl * nvp = get(tmp2); + + free(tmp2); + + if(nvp == 0){ + * impl = 0; + return 0; + } + if(nvp->valueType != PropertiesType_Properties){ + * impl = 0; + return name; + } + return ((Properties*)nvp->value)->impl->getProps(tmp+1, impl); + } +} + +const char * +PropertiesImpl::getPropsPut(const char * name, + PropertiesImpl ** impl) { + const char * ret = name; + const char * tmp = strchr(name, Properties::delimiter); + if(tmp == 0){ + * impl = this; + return ret; + } else { + Uint32 sz = tmp - name; + char * tmp2 = (char*)malloc(sz + 1); + memcpy(tmp2, name, sz); + tmp2[sz] = 0; + + PropertyImpl * nvp = get(tmp2); + + if(nvp == 0){ + Properties * tmpP = new Properties(); + PropertyImpl * tmpPI = new PropertyImpl(tmp2, tmpP); + PropertyImpl * nvp = put(tmpPI); + + delete tmpP; + free(tmp2); + return ((Properties*)nvp->value)->impl->getPropsPut(tmp+1, impl); + } + free(tmp2); + if(nvp->valueType != PropertiesType_Properties){ + * impl = 0; + return name; + } + return ((Properties*)nvp->value)->impl->getPropsPut(tmp+1, impl); + } +} + +int +mod4(unsigned int i){ + int res = i + (4 - (i % 4)); + return res; +} + +Uint32 +PropertiesImpl::getPackedSize(Uint32 pLen) const { + Uint32 sz = 0; + for(unsigned int i = 0; i<items; i++){ + if(content[i]->valueType == PropertiesType_Properties){ + Properties * p = (Properties*)content[i]->value; + sz += p->impl->getPackedSize(pLen+strlen(content[i]->name)+1); + } else { + sz += 4; // Type + sz += 4; // Name Len + sz += 4; // Value Len + sz += mod4(pLen + strlen(content[i]->name)); // Name + if(content[i]->valueType == PropertiesType_char){ + sz += mod4(strlen((char *)content[i]->value)); + } else if(content[i]->valueType == PropertiesType_Uint32){ + sz += mod4(4); + } else { + assert(0); + } + } + } + return sz; +} + +struct CharBuf { + char * buffer; + Uint32 bufLen; + Uint32 contentLen; + + CharBuf(){ + buffer = 0; + bufLen = 0; + contentLen = 0; + } + + ~CharBuf(){ + free(buffer); + } + + void clear() { contentLen = 0;} + bool add(const char * str, Uint32 strLen){ + if(!expand(contentLen + strLen + 1)) + return false; + memcpy(&buffer[contentLen], str, strLen); + contentLen += strLen; + buffer[contentLen] = 0; + return true; + } + + bool add(char c){ + return add(&c, 1); + } + + bool expand(Uint32 newSize){ + if(newSize >= bufLen){ + + char * tmp = (char*)malloc(newSize + 1024); + memset(tmp, 0, newSize + 1024); + if(tmp == 0) + return false; + if(contentLen > 0) + memcpy(tmp, buffer, contentLen); + if(buffer != 0) + free(buffer); + buffer = tmp; + bufLen = newSize + 1024; + } + return true; + } +}; + +bool +PropertiesImpl::pack(Uint32 *& buf, const char * prefix, Uint32 pLen) const { + CharBuf charBuf; + + for(unsigned int i = 0; i<items; i++){ + const int strLenName = strlen(content[i]->name); + + if(content[i]->valueType == PropertiesType_Properties){ + charBuf.clear(); + if(!charBuf.add(prefix, pLen)){ + properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING, + errno); + return false; + } + + if(!charBuf.add(content[i]->name, strLenName)){ + properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING, + errno); + return false; + } + + if(!charBuf.add(Properties::delimiter)){ + properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING, + errno); + return false; + } + + if(!((Properties*)(content[i]->value))->impl->pack(buf, + charBuf.buffer, + charBuf.contentLen)){ + + return false; + } + continue; + } + + Uint32 valLenData = 0; + Uint32 valLenWrite = 0; + Uint32 sz = 4 + 4 + 4 + mod4(pLen + strLenName); + switch(content[i]->valueType){ + case PropertiesType_Uint32: + valLenData = 4; + break; + case PropertiesType_char: + valLenData = strlen((char *)content[i]->value); + break; + case PropertiesType_Properties: + assert(0); + } + valLenWrite = mod4(valLenData); + sz += valLenWrite; + + * (buf + 0) = htonl(content[i]->valueType); + * (buf + 1) = htonl(pLen + strLenName); + * (buf + 2) = htonl(valLenData); + + char * valBuf = (char*)(buf + 3); + char * nameBuf = (char*)(buf + 3 + (valLenWrite / 4)); + + memset(valBuf, 0, sz-12); + + switch(content[i]->valueType){ + case PropertiesType_Uint32: + * (Uint32 *)valBuf = htonl(* (Uint32 *)content[i]->value); + break; + case PropertiesType_char: + memcpy(valBuf, content[i]->value, strlen((char*)content[i]->value)); + break; + case PropertiesType_Properties: + assert(0); + } + if(pLen > 0) + memcpy(nameBuf, prefix, pLen); + memcpy(nameBuf + pLen, content[i]->name, strLenName); + + buf += (sz / 4); + } + + return true; +} + +bool +PropertiesImpl::unpack(const Uint32 * buf, Uint32 &bufLen, Properties * top, + int _items){ + CharBuf charBuf; + while(_items > 0){ + Uint32 tmp[3]; + + if(bufLen <= 12){ + top->setErrno(E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING); + return false; + } + + tmp[0] = ntohl(buf[0]); + tmp[1] = ntohl(buf[1]); + tmp[2] = ntohl(buf[2]); + buf += 3; + bufLen -= 12; + + PropertiesType pt = (PropertiesType)tmp[0]; + Uint32 nameLen = tmp[1]; + Uint32 valueLen = tmp[2]; + Uint32 nameLenRead = mod4(nameLen); + Uint32 valueLenRead = mod4(valueLen); + + Uint32 sz = nameLenRead + valueLenRead; + if(bufLen < sz){ + top->setErrno(E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING); + return false; + } + + if(!charBuf.expand(sz)){ + top->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_UNPACKING, errno); + return false; + } + + memcpy(charBuf.buffer, buf, sz); + buf += (sz / 4); + bufLen -= sz ; + + char * valBuf = charBuf.buffer; + char * nameBuf = charBuf.buffer + valueLenRead; + + nameBuf[nameLen] = 0; + valBuf[valueLen] = 0; + + bool res3 = false; + switch(pt){ + case PropertiesType_Uint32: + res3 = top->put(nameBuf, ntohl(* (Uint32 *)valBuf), true); + break; + case PropertiesType_char: + res3 = top->put(nameBuf, valBuf, true); + break; + case PropertiesType_Properties: + assert(0); + } + if(res3 != true){ + return false; + } + _items--; + } + return true; +} + +PropertyImpl::~PropertyImpl(){ + free((char*)name); + switch(valueType){ + case PropertiesType_Uint32: + delete (Uint32 *)value; + break; + case PropertiesType_char: + free((char *)value); + break; + case PropertiesType_Properties: + delete (Properties *)value; + break; + } +} + +PropertyImpl * +PropertyImpl::copyPropertyImpl(const PropertyImpl & org){ + switch(org.valueType){ + case PropertiesType_Uint32: + return new PropertyImpl(org.name, * (Uint32 *)org.value); + break; + case PropertiesType_char: + return new PropertyImpl(org.name, (char *)org.value); + break; + case PropertiesType_Properties: + return new PropertyImpl(org.name, (Properties *)org.value); + break; + default: + assert(0); + } + return 0; +} + +PropertyImpl::PropertyImpl(const char * _name, Uint32 _value){ + this->name = strdup(_name); + this->value = new Uint32; + * ((Uint32 *)this->value) = _value; + this->valueType = PropertiesType_Uint32; +} + +PropertyImpl::PropertyImpl(const char * _name, const char * _value){ + this->name = strdup(_name); + this->value = strdup(_value); + this->valueType = PropertiesType_char; + +} + +PropertyImpl::PropertyImpl(const char * _name, const Properties * _value){ + this->name = strdup(_name); + this->value = new Properties(* _value); + this->valueType = PropertiesType_Properties; +} + +const Uint32 E_PROPERTIES_OK = 0; +const Uint32 E_PROPERTIES_INVALID_NAME = 1; +const Uint32 E_PROPERTIES_NO_SUCH_ELEMENT = 2; +const Uint32 E_PROPERTIES_INVALID_TYPE = 3; +const Uint32 E_PROPERTIES_ELEMENT_ALREADY_EXISTS = 4; + +const Uint32 E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING = 5; +const Uint32 E_PROPERTIES_INVALID_VERSION_WHILE_UNPACKING = 6; +const Uint32 E_PROPERTIES_INVALID_BUFFER_TO_SHORT = 7; +const Uint32 E_PROPERTIES_ERROR_MALLOC_WHILE_UNPACKING = 8; +const Uint32 E_PROPERTIES_INVALID_CHECKSUM = 9; +const Uint32 E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING = 10; + +/** + * These are methods that used to be inline + * + * But Diab 4.1f could not compile -release with to many inlines + */ +void +Properties::setErrno(Uint32 pErr, Uint32 osErr) const { + if(parent != 0){ + parent->setErrno(pErr, osErr); + return ; + } + + /** + * propErrno & osErrno used to be mutable, + * but diab didn't know what mutable meant. + */ + *((Uint32*)&propErrno) = pErr; + *((Uint32*)&osErrno) = osErr; +} + +/** + * Inlined get/put(name, no, ...) - methods + */ + +bool +Properties::put(const char * name, Uint32 no, Uint32 val, bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + + +bool +Properties::put(const char * name, Uint32 no, const char * val, bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + + +bool +Properties::put(const char * name, Uint32 no, const Properties * val, + bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + + +bool +Properties::getTypeOf(const char * name, Uint32 no, + PropertiesType * type) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = getTypeOf(tmp, type); + free(tmp); + return res; +} + +bool +Properties::contains(const char * name, Uint32 no) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = contains(tmp); + free(tmp); + return res; +} + +bool +Properties::get(const char * name, Uint32 no, Uint32 * value) const{ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::get(const char * name, Uint32 no, const char ** value) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::get(const char * name, Uint32 no, const Properties ** value) const{ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::getCopy(const char * name, Uint32 no, char ** value) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = getCopy(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::getCopy(const char * name, Uint32 no, Properties ** value) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = getCopy(tmp, value); + free(tmp); + return res; +} + +void +Properties::setCaseInsensitiveNames(bool value){ + impl->m_insensitive = value; + if(value) + impl->compare = strcasecmp; + else + impl->compare = strcmp; +} + +bool +Properties::getCaseInsensitiveNames() const { + return impl->m_insensitive; +} diff --git a/ndb/src/common/util/SimpleProperties.cpp b/ndb/src/common/util/SimpleProperties.cpp new file mode 100644 index 00000000000..a118478ba6c --- /dev/null +++ b/ndb/src/common/util/SimpleProperties.cpp @@ -0,0 +1,509 @@ +/* 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 <SimpleProperties.hpp> +#include <stdlib.h> +#include <NdbString.h> +#include <NdbOut.hpp> +#include <NdbTCP.h> +#include <assert.h> +#include <UtilBuffer.hpp> + +bool +SimpleProperties::Writer::first(){ + return reset(); +} + +bool +SimpleProperties::Writer::add(Uint16 key, Uint32 value){ + Uint32 head = Uint32Value; + head <<= 16; + head += key; + if(!putWord(htonl(head))) + return false; + + return putWord(htonl(value)); +} + +bool +SimpleProperties::Writer::add(Uint16 key, const char * value){ + Uint32 head = StringValue; + head <<= 16; + head += key; + if(!putWord(htonl(head))) + return false; + Uint32 strLen = strlen(value) + 1; // Including NULL-byte + if(!putWord(htonl(strLen))) + return false; + + const Uint32 valLen = (strLen + 3) / 4; + return putWords((Uint32*)value, valLen); +} + +bool +SimpleProperties::Writer::add(Uint16 key, const void* value, int len){ + Uint32 head = BinaryValue; + head <<= 16; + head += key; + if(!putWord(htonl(head))) + return false; + if(!putWord(htonl(len))) + return false; + + const Uint32 valLen = (len + 3) / 4; + return putWords((Uint32*)value, valLen); +} + +SimpleProperties::Reader::Reader(){ + m_itemLen = 0; +} + +bool +SimpleProperties::Reader::first(){ + reset(); + m_itemLen = 0; + return readValue(); +} + +bool +SimpleProperties::Reader::next(){ + return readValue(); +} + +bool +SimpleProperties::Reader::valid() const { + return m_type != InvalidValue; +} + +Uint16 +SimpleProperties::Reader::getKey() const{ + return m_key; +} + +Uint16 +SimpleProperties::Reader::getValueLen() const { + switch(m_type){ + case Uint32Value: + return 4; + case StringValue: + case BinaryValue: + return m_strLen; + case InvalidValue: + return 0; + } + return 0; +} + +SimpleProperties::ValueType +SimpleProperties::Reader::getValueType() const { + return m_type; +} + +Uint32 +SimpleProperties::Reader::getUint32() const { + return m_ui32_value; +} + +char * +SimpleProperties::Reader::getString(char * dst) const { + if(peekWords((Uint32*)dst, m_itemLen)) + return dst; + return 0; +} + +bool +SimpleProperties::Reader::readValue(){ + if(!step(m_itemLen)){ + m_type = InvalidValue; + return false; + } + + Uint32 tmp; + if(!getWord(&tmp)){ + m_type = InvalidValue; + return false; + } + + tmp = ntohl(tmp); + m_key = tmp & 0xFFFF; + m_type = (SimpleProperties::ValueType)(tmp >> 16); + switch(m_type){ + case Uint32Value: + m_itemLen = 1; + if(!peekWord(&m_ui32_value)) + return false; + m_ui32_value = ntohl(m_ui32_value); + return true; + case StringValue: + case BinaryValue: + if(!getWord(&tmp)) + return false; + m_strLen = ntohl(tmp); + m_itemLen = (m_strLen + 3)/4; + return true; + default: + m_itemLen = 0; + m_type = InvalidValue; + return false; + } +} + +SimpleProperties::UnpackStatus +SimpleProperties::unpack(Reader & it, void * dst, + const SP2StructMapping _map[], Uint32 mapSz, + bool ignoreMinMax, + bool ignoreUnknownKeys){ + do { + if(!it.valid()) + break; + + bool found = false; + Uint16 key = it.getKey(); + for(Uint32 i = 0; i<mapSz; i++){ + if(key == _map[i].Key){ + found = true; + if(_map[i].Type == InvalidValue) + return Break; + if(_map[i].Type != it.getValueType()) + return TypeMismatch; + + char * _dst = (char *)dst; + _dst += _map[i].Offset; + + switch(it.getValueType()){ + case Uint32Value:{ + const Uint32 val = it.getUint32(); + if(!ignoreMinMax){ + if(val < _map[i].minValue) + return ValueTooLow; + if(val > _map[i].maxValue) + return ValueTooHigh; + } + * ((Uint32 *)_dst) = val; + break; + } + case BinaryValue: + case StringValue:{ + unsigned len = it.getValueLen(); + if(len < _map[i].minValue) + return ValueTooLow; + if(len > _map[i].maxValue) + return ValueTooHigh; + it.getString(_dst); + break; + } + default: + abort(); + } + break; + } + } + if(!found && !ignoreUnknownKeys) + return UnknownKey; + } while(it.next()); + + return Eof; +} + +SimpleProperties::UnpackStatus +SimpleProperties::pack(Writer & it, const void * __src, + const SP2StructMapping _map[], Uint32 mapSz, + bool ignoreMinMax){ + + const char * _src = (const char *)__src; + + for(Uint32 i = 0; i<mapSz; i++){ + bool ok = false; + const char * src = _src + _map[i].Offset; + switch(_map[i].Type){ + case SimpleProperties::InvalidValue: + ok = true; + break; + case SimpleProperties::Uint32Value:{ + Uint32 val = * ((Uint32*)src); + if(!ignoreMinMax){ + if(val < _map[i].minValue) + return ValueTooLow; + if(val > _map[i].maxValue) + return ValueTooHigh; + } + ok = it.add(_map[i].Key, val); + } + break; + case SimpleProperties::BinaryValue:{ + const char * src_len = _src + _map[i].Length_Offset; + Uint32 len = *((Uint32*)src_len); + if(!ignoreMinMax){ + if(len == _map[i].maxValue) + return ValueTooHigh; + } + ok = it.add(_map[i].Key, src, len); + break; + } + case SimpleProperties::StringValue: + if(!ignoreMinMax){ + size_t len = strlen(src); + if(len == _map[i].maxValue) + return ValueTooHigh; + } + ok = it.add(_map[i].Key, src); + break; + } + if(!ok) + return OutOfMemory; + } + + return Eof; +} + +void +SimpleProperties::Reader::printAll(NdbOut& ndbout){ + char tmp[1024]; + for(first(); valid(); next()){ + switch(getValueType()){ + case SimpleProperties::Uint32Value: + ndbout << "Key: " << getKey() + << " value(" << getValueLen() << ") : " + << getUint32() << endl; + break; + case SimpleProperties::BinaryValue: + case SimpleProperties::StringValue: + if(getValueLen() < 1024){ + getString(tmp); + ndbout << "Key: " << getKey() + << " value(" << getValueLen() << ") : " + << "\"" << tmp << "\"" << endl; + } else { + ndbout << "Key: " << getKey() + << " value(" << getValueLen() << ") : " + << "\"" << "<TOO LONG>" << "\"" << endl; + + } + break; + default: + ndbout << "Unknown type for key: " << getKey() + << " type: " << getValueType() << endl; + } + } +} + +SimplePropertiesLinearReader::SimplePropertiesLinearReader +(const Uint32 * src, Uint32 len){ + m_src = src; + m_len = len; + m_pos = 0; + first(); +} + +void +SimplePropertiesLinearReader::reset() { + m_pos = 0; +} + +bool +SimplePropertiesLinearReader::step(Uint32 len){ + m_pos += len; + return m_pos < m_len; +} + +bool +SimplePropertiesLinearReader::getWord(Uint32 * dst) { + if(m_pos<m_len){ + * dst = m_src[m_pos++]; + return true; + } + return false; +} + +bool +SimplePropertiesLinearReader::peekWord(Uint32 * dst) const { + if(m_pos<m_len){ + * dst = m_src[m_pos]; + return true; + } + return false; +} + +bool +SimplePropertiesLinearReader::peekWords(Uint32 * dst, Uint32 len) const { + if(m_pos + len <= m_len){ + memcpy(dst, &m_src[m_pos], 4 * len); + return true; + } + return false; +} + +LinearWriter::LinearWriter(Uint32 * src, Uint32 len){ + m_src = src; + m_len = len; + reset(); +} + +bool LinearWriter::reset() { m_pos = 0; return m_len > 0;} + +bool +LinearWriter::putWord(Uint32 val){ + if(m_pos < m_len){ + m_src[m_pos++] = val; + return true; + } + return false; +} + +bool +LinearWriter::putWords(const Uint32 * src, Uint32 len){ + if(m_pos + len <= m_len){ + memcpy(&m_src[m_pos], src, 4 * len); + m_pos += len; + return true; + } + return false; +} + +Uint32 +LinearWriter::getWordsUsed() const { return m_pos;} + +UtilBufferWriter::UtilBufferWriter(UtilBuffer & b) + : m_buf(b) +{ + reset(); +} + +bool UtilBufferWriter::reset() { m_buf.clear(); return true;} + +bool +UtilBufferWriter::putWord(Uint32 val){ + return (m_buf.append(&val, 4) == 0); +} + +bool +UtilBufferWriter::putWords(const Uint32 * src, Uint32 len){ + return (m_buf.append(src, 4 * len) == 0); +} + +Uint32 +UtilBufferWriter::getWordsUsed() const { return m_buf.length() / 4;} + +#if 0 +LinearPagesReader::LinearPagesReader(const Uint32 * base, + Uint32 pageSize, + Uint32 headerSize, + Uint32 noOfPages, + Uint32 len){ + m_base = base; + m_pageSz = pageSize; + m_noOfPages = noOfPages; + m_pageHeaderSz = headerSize; + m_len = len; + reset(); +} + +void +LinearPagesReader::reset() { m_pos = 0;} + +bool +LinearPagesReader::step(Uint32 len){ + m_pos += len; + return m_pos < m_len; +} + +bool +LinearPagesReader::getWord(Uint32 * dst) { + if(m_pos<m_len){ + * dst = m_base[getPos(m_pos++)]; + return true; + } + return false; +} + +bool +LinearPagesReader::peekWord(Uint32 * dst) const { + if(m_pos<m_len){ + * dst = m_base[getPos(m_pos)]; + return true; + } + return false; +} + +bool +LinearPagesReader::peekWords(Uint32 * dst, Uint32 len) const { + if(m_pos + len <= m_len){ + for(Uint32 i = 0; i<len; i++) + * (dst + i) = m_base[getPos(m_pos + i)]; + return true; + } + return false; +} + +Uint32 +LinearPagesReader::getPos(Uint32 pos) const { + const Uint32 sz = (m_pageSz - m_pageHeaderSz); + Uint32 no = pos / sz; + Uint32 in = pos % sz; + return no * m_pageSz + m_pageHeaderSz + in; +} + +LinearPagesWriter::LinearPagesWriter(Uint32 * base, + Uint32 pageSize, + Uint32 noOfPages, + Uint32 headerSize){ + m_base = base; + m_pageSz = pageSize; + m_noOfPages = noOfPages; + m_pageHeaderSz = headerSize; + m_len = noOfPages * (pageSize - headerSize); + reset(); +} + +bool +LinearPagesWriter::putWord(Uint32 val){ + if(m_pos < m_len){ + m_base[getPos(m_pos++)] = val; + return true; + } + return false; +} + +bool +LinearPagesWriter::putWords(const Uint32 * src, Uint32 len){ + if(m_pos + len <= m_len){ + for(Uint32 i = 0; i<len; i++) + m_base[getPos(m_pos++)] = src[i]; + return true; + } + return false; +} + +#if 0 +Uint32 +LinearPagesWriter::getWordsUsed() const { + return getPos(m_pos); +} +#endif + +Uint32 +LinearPagesWriter::getPagesUsed() const { + return m_pos / (m_pageSz - m_pageHeaderSz); +} + +Uint32 +LinearPagesWriter::getPos(Uint32 pos) const { + const Uint32 sz = (m_pageSz - m_pageHeaderSz); + Uint32 no = pos / sz; + Uint32 in = pos % sz; + return no * m_pageSz + m_pageHeaderSz + in; +} +#endif diff --git a/ndb/src/common/util/SocketServer.cpp b/ndb/src/common/util/SocketServer.cpp new file mode 100644 index 00000000000..39f46eceed9 --- /dev/null +++ b/ndb/src/common/util/SocketServer.cpp @@ -0,0 +1,307 @@ +/* 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 "SocketServer.hpp" + +#include <NdbTCP.h> +#include <string.h> +#include <NdbOut.hpp> +#include <NdbThread.h> +#include <NdbSleep.h> + +#include <stdio.h> +#include <assert.h> + +#define DEBUG(x) ndbout << x << endl; + +SocketServer::SocketServer(int maxSessions) : + m_sessions(10), + m_services(5) +{ + m_thread = 0; + m_stopThread = false; + m_maxSessions = maxSessions; +} + +SocketServer::~SocketServer() { + for(unsigned i = 0; i<m_sessions.size(); i++){ + delete m_sessions[i].m_session; + } + for(unsigned i = 0; i<m_services.size(); i++){ + delete m_services[i].m_service; + } +} + +bool +SocketServer::tryBind(unsigned short port, const char * intface) const { + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(port); + + if(intface != 0){ + if(Ndb_getInAddr(&servaddr.sin_addr, intface)) + return false; + } + + const NDB_SOCKET_TYPE sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == NDB_INVALID_SOCKET) { + return false; + } + + const int on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == -1) { + NDB_CLOSE_SOCKET(sock); + return false; + } + + if (bind(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) { + NDB_CLOSE_SOCKET(sock); + return false; + } + + NDB_CLOSE_SOCKET(sock); + return true; +} + +bool +SocketServer::setup(SocketServer::Service * service, + unsigned short port, + const char * intface){ + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(port); + + if(intface != 0){ + if(Ndb_getInAddr(&servaddr.sin_addr, intface)) + return false; + } + + const NDB_SOCKET_TYPE sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == NDB_INVALID_SOCKET) { + return false; + } + + const int on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == -1) { + NDB_CLOSE_SOCKET(sock); + return false; + } + + if (bind(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) { + NDB_CLOSE_SOCKET(sock); + return false; + } + + if (listen(sock, m_maxSessions) == -1){ + NDB_CLOSE_SOCKET(sock); + return false; + } + + ServiceInstance i; + i.m_socket = sock; + i.m_service = service; + m_services.push_back(i); + return true; +} + +void +SocketServer::doAccept(){ + fd_set readSet, exceptionSet; + FD_ZERO(&readSet); + FD_ZERO(&exceptionSet); + + m_services.lock(); + int maxSock = 0; + for (unsigned i = 0; i < m_services.size(); i++){ + const NDB_SOCKET_TYPE s = m_services[i].m_socket; + FD_SET(s, &readSet); + FD_SET(s, &exceptionSet); + maxSock = (maxSock > s ? maxSock : s); + } + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if(select(maxSock + 1, &readSet, 0, &exceptionSet, &timeout) > 0){ + for (unsigned i = 0; i < m_services.size(); i++){ + ServiceInstance & si = m_services[i]; + + if(FD_ISSET(si.m_socket, &readSet)){ + + NDB_SOCKET_TYPE childSock = accept(si.m_socket, 0, 0); + if(childSock == NDB_INVALID_SOCKET){ + continue; + } + + SessionInstance s; + s.m_service = si.m_service; + s.m_session = si.m_service->newSession(childSock); + if(s.m_session != 0){ + m_sessions.push_back(s); + startSession(m_sessions.back()); + } + + continue; + } + + if(FD_ISSET(si.m_socket, &exceptionSet)){ + DEBUG("socket in the exceptionSet"); + continue; + } + } + } + m_services.unlock(); +} + +extern "C" +void* +socketServerThread_C(void* _ss){ + SocketServer * ss = (SocketServer *)_ss; + + ss->doRun(); + + NdbThread_Exit(0); + return 0; +} + +void +SocketServer::startServer(){ + m_threadLock.lock(); + if(m_thread == 0 && m_stopThread == false){ + m_thread = NdbThread_Create(socketServerThread_C, + (void**)this, + 32768, + "NdbSockServ", + NDB_THREAD_PRIO_LOW); + } + m_threadLock.unlock(); +} + +void +SocketServer::stopServer(){ + m_threadLock.lock(); + if(m_thread != 0){ + m_stopThread = true; + + void * res; + NdbThread_WaitFor(m_thread, &res); + NdbThread_Destroy(&m_thread); + m_thread = 0; + } + m_threadLock.unlock(); +} + +void +SocketServer::doRun(){ + + while(!m_stopThread){ + checkSessions(); + if(m_sessions.size() < m_maxSessions){ + doAccept(); + } else { + NdbSleep_MilliSleep(200); + } + } +} + +void +SocketServer::startSession(SessionInstance & si){ + si.m_thread = NdbThread_Create(sessionThread_C, + (void**)si.m_session, + 32768, + "NdbSock_Session", + NDB_THREAD_PRIO_LOW); +} + +static +bool +transfer(NDB_SOCKET_TYPE sock){ +#if defined NDB_OSE || defined NDB_SOFTOSE + const PROCESS p = current_process(); + const size_t ps = sizeof(PROCESS); + int res = setsockopt(sock, SOL_SOCKET, SO_OSEOWNER, &p, ps); + if(res != 0){ + ndbout << "Failed to transfer ownership of socket" << endl; + return false; + } +#endif + return true; +} + +void +SocketServer::checkSessions(){ + for(int i = m_sessions.size() - 1; i >= 0; i--){ + if(m_sessions[i].m_session->m_stopped){ + if(m_sessions[i].m_thread != 0){ + void* ret; + NdbThread_WaitFor(m_sessions[i].m_thread, &ret); + NdbThread_Destroy(&m_sessions[i].m_thread); + } + m_sessions[i].m_session->stopSession(); + delete m_sessions[i].m_session; + m_sessions.erase(i); + } + } +} + +void +SocketServer::stopSessions(bool wait){ + for(int i = m_sessions.size() - 1; i>=0; i--) + m_sessions[i].m_session->m_stop = true; + + for(int i = m_services.size() - 1; i>=0; i--) + m_services[i].m_service->stopSessions(); + + if(wait){ + while(m_sessions.size() > 0){ + checkSessions(); + NdbSleep_MilliSleep(100); + } + } +} + +/***** Session code ******/ + +extern "C" +void* +sessionThread_C(void* _sc){ + SocketServer::Session * si = (SocketServer::Session *)_sc; + + if(!transfer(si->m_socket)){ + si->m_stopped = true; + NdbThread_Exit(0); + return 0; + } + + if(!si->m_stop){ + si->m_stopped = false; + si->runSession(); + } else { + NDB_CLOSE_SOCKET(si->m_socket); + } + + si->m_stopped = true; + NdbThread_Exit(0); + return 0; +} diff --git a/ndb/src/common/util/filetest/FileUnitTest.cpp b/ndb/src/common/util/filetest/FileUnitTest.cpp new file mode 100644 index 00000000000..ebcca26d3d2 --- /dev/null +++ b/ndb/src/common/util/filetest/FileUnitTest.cpp @@ -0,0 +1,238 @@ +/* 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 "FileUnitTest.hpp" +#include <File.hpp> + +#include <NdbOut.hpp> +#include <assert.h> + +typedef bool (*TESTFUNC)(const char*); + +typedef const char TESTNAME; +typedef struct +{ + const char* name; + TESTFUNC test; +}Tests; + +static Tests testCases[] = { {"Create/Write", &FileUnitTest::testWrite}, + {"Read", &FileUnitTest::testRead}, + {"Exists", &FileUnitTest::testExists}, + {"File Size", &FileUnitTest::testSize}, + {"Rename", &FileUnitTest::testRename}, + {"Remove", &FileUnitTest::testRemove} }; + +static int testFailed = 0; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + ndbout << "Usage: filetest <filename>" << endl; + return 0; + } + const char* fileName = argv[1]; + + int testCount = (sizeof(testCases) / sizeof(Tests)); + ndbout << "Starting " << testCount << " tests..." << endl; + for (int i = 0; i < testCount; i++) + { + ndbout << "-- " << " Test " << i + 1 + << " [" << testCases[i].name << "] --" << endl; + if (testCases[i].test(fileName)) + { + ndbout << "-- Passed --" << endl; + } + else + { + ndbout << "-- Failed -- " << endl; + } + + } + ndbout << endl << "-- " << testCount - testFailed << " passed, " + << testFailed << " failed --" << endl; + return 0; +} + + +bool +FileUnitTest::testWrite(const char* aFileName) +{ + bool rc = true; + File f; + if (f.open(aFileName, "w")) + { + f.writeChar("ABABABABABAB ABBABAB ABBABA ABAB JKH KJHA JHHAHAH..."); + f.writeChar("12129791242 1298371923 912738912 378129837128371128132...\n"); + f.close(); + } + else + { + error("testWrite failed: "); + rc = false; + } + return rc; +} + +bool +FileUnitTest::testRead(const char* aFileName) +{ + bool rc = true; + // Read file + File f; + if (f.open(aFileName, "r")) + { + long size = f.size(); + ndbout << "File size = " << size << endl; + ndbout << "Allocating buf of " << size << " bytes" << endl; + char* buf = new char[size]; + buf[size - 1] = '\0'; + int r = 0; + while ((r = f.readChar(buf, r, size)) > 0) + { + ndbout << "Read(" << r << "):" << buf << endl; + } + f.close(); + delete buf; + } + else + { + error("readTest failed: "); + rc = false; + } + return rc; +} + +bool +FileUnitTest::testExists(const char* aFileName) +{ + bool rc = true; + if (File::exists(aFileName)) + { + if (File::exists("ThisFileShouldnotbe.txt")) + { + rc = false; + error("testExists failed, the file should NOT be found."); + } + } + else + { + rc = false; + error("testExists failed, the file should exist."); + } + + return rc; +} + + +bool +FileUnitTest::testSize(const char* aFileName) +{ + bool rc = true; + File f; + if (f.open(aFileName, "r")) + { + long size = f.size(); + if (size <= 0) + { + rc = false; + error("testSize failed, size is <= 0"); + } + ndbout << "File size = " << size << endl; + } + else + { + rc = false; + error("testSize failed, could no open file."); + } + f.close(); + return rc; +} + +bool +FileUnitTest::testRename(const char* aFileName) +{ + bool rc = true; + if (File::rename(aFileName, "filetest_new.txt")) + { + if (!File::exists("filetest_new.txt")) + { + rc = false; + error("testRename failed, new file does not exists."); + } + else + { + ndbout << "Renamed " << aFileName << " to filetest_new.txt" << endl; + } + } + else + { + rc = false; + error("testRename failed, unable to rename file."); + } + + return rc; +} + +bool +FileUnitTest::testRemove(const char* aFileName) +{ + bool rc = true; + File f; + if (f.open("filetest_new.txt", "r")) + { + if (!f.remove()) + { + rc = false; + error("testRemove failed, could not remove file."); + } + else + { + if (File::exists("filetest_new")) + { + rc = false; + error("testRemove failed, file was not removed, it still exists."); + } + } + } // (f.open("filetest_new", "r")) + else + { + rc = false; + error("testRemove failed, could not read the file."); + } + + return rc; +} + +void +FileUnitTest::error(const char* msg) +{ + testFailed++; + ndbout << "Test failed: " << msg << endl; + perror("Errno msg"); +} + + +FileUnitTest::FileUnitTest() +{ + +} + +FileUnitTest::~FileUnitTest() +{ + +} diff --git a/ndb/src/common/util/filetest/FileUnitTest.hpp b/ndb/src/common/util/filetest/FileUnitTest.hpp new file mode 100644 index 00000000000..a589615e9b2 --- /dev/null +++ b/ndb/src/common/util/filetest/FileUnitTest.hpp @@ -0,0 +1,41 @@ +/* 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 */ + +#ifndef FILEUNITTEST_H +#define FILEUNITTEST_H + +/** + * Unit test of File. + * + * @version #@ $Id: FileUnitTest.hpp,v 1.1 2002/03/13 18:09:03 eyualex Exp $ + */ +class FileUnitTest +{ +public: + static bool testWrite(const char* aFileName); + static bool testRead(const char* aFileName); + static bool testExists(const char* aFileName); + static bool testSize(const char* aFileName); + static bool testRename(const char* aFileName); + static bool testRemove(const char* aFileName); + + static void error(const char* msg); +private: + FileUnitTest(); + ~FileUnitTest(); + +}; +#endif diff --git a/ndb/src/common/util/filetest/Makefile b/ndb/src/common/util/filetest/Makefile new file mode 100644 index 00000000000..fe1842921f9 --- /dev/null +++ b/ndb/src/common/util/filetest/Makefile @@ -0,0 +1,14 @@ +include .defs.mk + +TYPE := + +BIN_TARGET := filetest +BIN_TARGET_ARCHIVES := portlib general + +SOURCES := FileUnitTest.cpp + +CCFLAGS_LOC += -I$(NDB_TOP)/include/logger -I$(NDB_TOP)/include/portlib + +include $(NDB_TOP)/Epilogue.mk + + diff --git a/ndb/src/common/util/getarg.3 b/ndb/src/common/util/getarg.3 new file mode 100644 index 00000000000..43aae5d7b31 --- /dev/null +++ b/ndb/src/common/util/getarg.3 @@ -0,0 +1,315 @@ +.\" Copyright (c) 1999 Kungliga Tekniska Högskolan +.\" $KTH: getarg.3,v 1.1.4.1 2001/07/26 19:54:45 lha Exp $ +.Dd September 24, 1999 +.Dt GETARG 3 +.Os ROKEN +.Sh NAME +.Nm getarg , +.Nm arg_printusage +.Nd collect command line options +.Sh SYNOPSIS +.Fd #include <getarg.h> + +.Ft int +.Fn getarg "struct getargs *args" "size_t num_args" "int argc" "char **argv" "int *optind" + +.Ft void +.Fn arg_printusage "struct getargs *args" "size_t num_args" "const char *progname" "const char *extra_string" + +.Sh DESCRIPTION +.Fn getarg +collects any command line options given to a program in an easily used way. +.Fn arg_printusage +pretty-prints the available options, with a short help text. +.Pp +.Fa args +is the option specification to use, and it's an array of +.Fa struct getargs +elements. +.Fa num_args +is the size of +.Fa args +(in elements). +.Fa argc +and +.Fa argv +are the argument count and argument vector to extract option from. +.Fa optind +is a pointer to an integer where the index to the last processed +argument is stored, it must be initialised to the first index (minus +one) to process (normally 0) before the first call. +.Pp +.Fa arg_printusage +take the same +.Fa args +and +.Fa num_args +as getarg; +.Fa progname is the name of the program (to be used in the help text), and +.Fa extra_string +is a string to print after the actual options to indicate more +arguments. The usefulness of this function is realised only be people +who has used programs that has help strings that doesn't match what +the code does. +.Pp +The +.Fa getargs +struct has the following elements. + +.Bd -literal +struct getargs{ + const char *long_name; + char short_name; + enum { arg_integer, + arg_string, + arg_flag, + arg_negative_flag, + arg_strings, + arg_double, + arg_collect + } type; + void *value; + const char *help; + const char *arg_help; +}; +.Ed +.Pp +.Fa long_name +is the long name of the option, it can be +.Dv NULL , +if you don't want a long name. +.Fa short_name +is the characted to use as short option, it can be zero. If the option +has a value the +.Fa value +field gets filled in with that value interpreted as specified by the +.Fa type +field. +.Fa help +is a longer help string for the option as a whole, if it's +.Dv NULL +the help text for the option is omitted (but it's still displayed in +the synopsis). +.Fa arg_help +is a description of the argument, if +.Dv NULL +a default value will be used, depending on the type of the option: +.Pp +.Bl -hang -width arg_negative_flag +.It arg_integer +the argument is a signed integer, and +.Fa value +should point to an +.Fa int . +.It Fa arg_string +the argument is a string, and +.Fa value +should point to a +.Fa char* . +.It Fa arg_flag +the argument is a flag, and +.Fa value +should point to a +.Fa int . +It gets filled in with either zero or one, depending on how the option +is given, the normal case beeing one. Note that if the option isn't +given, the value isn't altered, so it should be initialised to some +useful default. +.It Fa arg_negative_flag +this is the same as +.Fa arg_flag +but it reverses the meaning of the flag (a given short option clears +the flag), and the synopsis of a long option is negated. +.It Fa arg_strings +the argument can be given multiple times, and the values are collected +in an array; +.Fa value +should be a pointer to a +.Fa struct getarg_strings +structure, which holds a length and a string pointer. +.It Fa arg_double +argument is a double precision floating point value, and +.Fa value +should point to a +.Fa double . +.It Fa arg_collect +allows more fine-grained control of the option parsing process. +.Fa value +should be a pointer to a +.Fa getarg_collect_info +structure: +.Bd -literal +typedef int (*getarg_collect_func)(int short_opt, + int argc, + char **argv, + int *optind, + int *optarg, + void *data); + +typedef struct getarg_collect_info { + getarg_collect_func func; + void *data; +} getarg_collect_info; +.Ed +.Pp +With the +.Fa func +member set to a function to call, and +.Fa data +to some application specific data. The parameters to the collect function are: +.Bl -inset +.It Fa short_flag +non-zero if this call is via a short option flag, zero otherwise +.It Fa argc , argv +the whole argument list +.It Fa optind +pointer to the index in argv where the flag is +.It Fa optarg +pointer to the index in argv[*optind] where the flag name starts +.It Fa data +application specific data +.El +.Pp +You can modify +.Fa *optind , +and +.Fa *optarg , +but to do this correct you (more or less) have to know about the inner +workings of getarg. + +You can skip parts of arguments by increasing +.Fa *optarg +(you could +implement the +.Fl z Ns Ar 3 +set of flags from +.Nm gzip +with this), or whole argument strings by increasing +.Fa *optind +(let's say you want a flag +.Fl c Ar x y z +to specify a coordinate); if you also have to set +.Fa *optarg +to a sane value. +.Pp +The collect function should return one of +.Dv ARG_ERR_NO_MATCH , ARG_ERR_BAD_ARG , ARG_ERR_NO_ARG +on error, zero otherwise. +.Pp +For your convenience there is a function, +.Fn getarg_optarg , +that returns the traditional argument string, and you pass it all +arguments, sans data, that where given to the collection function. +.Pp +Don't use this more this unless you absolutely have to. +.El +.Pp +Option parsing is similar to what +.Xr getopt +uses. Short options without arguments can be compressed +.Pf ( Fl xyz +is the same as +.Fl x y z ) , +and short +options with arguments take these as either the rest of the +argv-string or as the next option +.Pf ( Fl o Ns Ar foo , +or +.Fl o Ar foo ) . +.Pp +Long option names are prefixed with -- (double dash), and the value +with a = (equal), +.Fl -foo= Ns Ar bar . +Long option flags can either be specified as they are +.Pf ( Fl -help ) , +or with an (boolean parsable) option +.Pf ( Fl -help= Ns Ar yes , +.Fl -help= Ns Ar true , +or similar), or they can also be negated +.Pf ( Fl -no-help +is the same as +.Fl -help= Ns no ) , +and if you're really confused you can do it multiple times +.Pf ( Fl -no-no-help= Ns Ar false , +or even +.Fl -no-no-help= Ns Ar maybe ) . +.Sh EXAMPLE +.Bd -literal +#include <stdio.h> +#include <string.h> +#include <getarg.h> + +char *source = "Ouagadougou"; +char *destination; +int weight; +int include_catalog = 1; +int help_flag; + +struct getargs args[] = { + { "source", 's', arg_string, &source, + "source of shippment", "city" }, + { "destination", 'd', arg_string, &destination, + "destination of shippment", "city" }, + { "weight", 'w', arg_integer, &weight, + "weight of shippment", "tons" }, + { "catalog", 'c', arg_negative_flag, &include_catalog, + "include product catalog" }, + { "help", 'h', arg_flag, &help_flag } +}; + +int num_args = sizeof(args) / sizeof(args[0]); /* number of elements in args */ + +const char *progname = "ship++"; + +int +main(int argc, char **argv) +{ + int optind = 0; + if (getarg(args, num_args, argc, argv, &optind)) { + arg_printusage(args, num_args, progname, "stuff..."); + exit (1); + } + if (help_flag) { + arg_printusage(args, num_args, progname, "stuff..."); + exit (0); + } + if (destination == NULL) { + fprintf(stderr, "%s: must specify destination\n", progname); + exit(1); + } + if (strcmp(source, destination) == 0) { + fprintf(stderr, "%s: destination must be different from source\n"); + exit(1); + } + /* include more stuff here ... */ + exit(2); +} +.Ed +.Pp +The output help output from this program looks like this: +.Bd -literal +$ ship++ --help +Usage: ship++ [--source=city] [-s city] [--destination=city] [-d city] + [--weight=tons] [-w tons] [--no-catalog] [-c] [--help] [-h] stuff... +-s city, --source=city source of shippment +-d city, --destination=city destination of shippment +-w tons, --weight=tons weight of shippment +-c, --no-catalog include product catalog +.Ed + +.Sh BUGS +It should be more flexible, so it would be possible to use other more +complicated option syntaxes, such as what +.Xr ps 1 , +and +.Xr tar 1 , +uses, or the AFS model where you can skip the flag names as long as +the options come in the correct order. +.Pp +Options with multiple arguments should be handled better. +.Pp +Should be integreated with SL. +.Pp +It's very confusing that the struct you pass in is called getargS. +.Sh SEE ALSO +.Xr getopt 3 diff --git a/ndb/src/common/util/getarg.3.ps b/ndb/src/common/util/getarg.3.ps new file mode 100644 index 00000000000..146fb8e4961 --- /dev/null +++ b/ndb/src/common/util/getarg.3.ps @@ -0,0 +1,458 @@ +%!PS-Adobe-3.0 +%%Creator: groff version 1.15 +%%CreationDate: Thu Nov 7 12:53:13 2002 +%%DocumentNeededResources: font Times-Roman +%%+ font Times-Bold +%%+ font Courier-Bold +%%+ font Courier-Oblique +%%+ font Symbol +%%+ font Courier +%%DocumentSuppliedResources: procset grops 1.15 0 +%%Pages: 4 +%%PageOrder: Ascend +%%Orientation: Portrait +%%EndComments +%%BeginProlog +%%BeginResource: procset grops 1.15 0 +/setpacking where{ +pop +currentpacking +true setpacking +}if +/grops 120 dict dup begin +/SC 32 def +/A/show load def +/B{0 SC 3 -1 roll widthshow}bind def +/C{0 exch ashow}bind def +/D{0 exch 0 SC 5 2 roll awidthshow}bind def +/E{0 rmoveto show}bind def +/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def +/G{0 rmoveto 0 exch ashow}bind def +/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/I{0 exch rmoveto show}bind def +/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def +/K{0 exch rmoveto 0 exch ashow}bind def +/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/M{rmoveto show}bind def +/N{rmoveto 0 SC 3 -1 roll widthshow}bind def +/O{rmoveto 0 exch ashow}bind def +/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/Q{moveto show}bind def +/R{moveto 0 SC 3 -1 roll widthshow}bind def +/S{moveto 0 exch ashow}bind def +/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/SF{ +findfont exch +[exch dup 0 exch 0 exch neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/MF{ +findfont +[5 2 roll +0 3 1 roll +neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/level0 0 def +/RES 0 def +/PL 0 def +/LS 0 def +/MANUAL{ +statusdict begin/manualfeed true store end +}bind def +/PLG{ +gsave newpath clippath pathbbox grestore +exch pop add exch pop +}bind def +/BP{ +/level0 save def +1 setlinecap +1 setlinejoin +72 RES div dup scale +LS{ +90 rotate +}{ +0 PL translate +}ifelse +1 -1 scale +}bind def +/EP{ +level0 restore +showpage +}bind def +/DA{ +newpath arcn stroke +}bind def +/SN{ +transform +.25 sub exch .25 sub exch +round .25 add exch round .25 add exch +itransform +}bind def +/DL{ +SN +moveto +SN +lineto stroke +}bind def +/DC{ +newpath 0 360 arc closepath +}bind def +/TM matrix def +/DE{ +TM currentmatrix pop +translate scale newpath 0 0 .5 0 360 arc closepath +TM setmatrix +}bind def +/RC/rcurveto load def +/RL/rlineto load def +/ST/stroke load def +/MT/moveto load def +/CL/closepath load def +/FL{ +currentgray exch setgray fill setgray +}bind def +/BL/fill load def +/LW/setlinewidth load def +/RE{ +findfont +dup maxlength 1 index/FontName known not{1 add}if dict begin +{ +1 index/FID ne{def}{pop pop}ifelse +}forall +/Encoding exch def +dup/FontName exch def +currentdict end definefont pop +}bind def +/DEFS 0 def +/EBEGIN{ +moveto +DEFS begin +}bind def +/EEND/end load def +/CNT 0 def +/level1 0 def +/PBEGIN{ +/level1 save def +translate +div 3 1 roll div exch scale +neg exch neg exch translate +0 setgray +0 setlinecap +1 setlinewidth +0 setlinejoin +10 setmiterlimit +[]0 setdash +/setstrokeadjust where{ +pop +false setstrokeadjust +}if +/setoverprint where{ +pop +false setoverprint +}if +newpath +/CNT countdictstack def +userdict begin +/showpage{}def +}bind def +/PEND{ +clear +countdictstack CNT sub{end}repeat +level1 restore +}bind def +end def +/setpacking where{ +pop +setpacking +}if +%%EndResource +%%IncludeResource: font Times-Roman +%%IncludeResource: font Times-Bold +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier-Oblique +%%IncludeResource: font Symbol +%%IncludeResource: font Courier +grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 +def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron +/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent +/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen +/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon +/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O +/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex +/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y +/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft +/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl +/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut +/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash +/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen +/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft +/logicalnot/minus/registered/macron/degree/plusminus/twosuperior +/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior +/ordmasculine/guilsinglright/onequarter/onehalf/threequarters +/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE +/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn +/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla +/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis +/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash +/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def +/Courier@0 ENC0/Courier RE/Courier-Oblique@0 ENC0/Courier-Oblique RE +/Courier-Bold@0 ENC0/Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE +/Times-Roman@0 ENC0/Times-Roman RE +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF(GET)72 48 Q -.834(ARG \( 3 \))-.93 F +(OpenBSD Programmer')111.062 E 2.5(sM)-.55 G 108.562(anual GET)-2.5 F +-.834(ARG \( 3 \))-.93 F/F1 10/Times-Bold@0 SF -.2(NA)72 108 S(ME).2 E +/F2 10/Courier-Bold@0 SF(getarg)102 120 Q F0(,)A F2(arg_printusage)2.5 E +F0 2.5<ad63>2.5 G(ollect command line options)-2.5 E F1(SYNOPSIS)72 144 +Q F2(#include <getarg.h>)102 156 Q/F3 10/Courier-Oblique@0 SF(int)102 +186 Q F2(getarg)102 198 Q F0(\()A F3(struct getargs)A/F4 10/Symbol SF(*) +6 E F3(args)A F0(,)1.666 E F3(size_t num_args)4.166 E F0(,)1.666 E F3 +(int argc)4.166 E F0(,)1.666 E F3(char)4.166 E F4(**)6 E F3(argv)A F0(,) +1.666 E F3(int)151.666 210 Q F4(*)6 E F3(optind)A F0(\);)A F3(void)102 +240 Q F2(arg_printusage)102 252 Q F0(\()A F3(struct getargs)A F4(*)6 E +F3(args)A F0(,)1.666 E F3(size_t num_args)4.166 E F0(,)1.666 E F3 +(const char)4.166 E F4(*)6 E F3(progname)A F0(,)1.666 E F3(const char) +151.666 264 Q F4(*)6 E F3(extra_string)A F0(\);)A F1(DESCRIPTION)72 300 +Q F2(getarg)102 312 Q F0 2.721 1.666(\(\) c)D 6.053(ollects an)-1.666 F +8.553(yc)-.15 G 6.053(ommand line options gi)-8.553 F -.15(ve)-.25 G +8.552(nt).15 G 8.552(oap)-8.552 G 6.052(rogram in an easily used w) +-8.552 F(ay)-.1 E(.)-.65 E F2(arg_printusage)102 324 Q F0 -3.332 1.666 +(\(\) p)D(retty-prints the a)-1.666 E -.25(va)-.2 G +(ilable options, with a short help te).25 E(xt.)-.15 E F3(args)102 342 Q +F0 .855(is the option speci\214cation to use, and it')3.355 F 3.356(sa) +-.55 G 3.356(na)-3.356 G .856(rray of)-3.356 F F3 .856(struct getargs) +3.356 F F0(elements.)3.356 E F3(num_args)5.856 E F0(is)3.356 E .344 +(the size of)102 354 R F3(args)2.844 E F0 .344(\(in elements\).)2.844 F +F3(argc)5.344 E F0(and)2.844 E F3(argv)2.844 E F0 .344(are the ar)2.844 +F .344(gument count and ar)-.18 F .344(gument v)-.18 F .344(ector to e) +-.15 F .343(xtract op-)-.15 F 1.127(tion from.)102 366 R F3(optind)6.127 +E F0 1.127(is a pointer to an inte)3.627 F 1.127(ger where the inde)-.15 +F 3.627(xt)-.15 G 3.628(ot)-3.627 G 1.128(he last processed ar)-3.628 F +1.128(gument is stored, it)-.18 F +(must be initialised to the \214rst inde)102 378 Q 2.5(x\()-.15 G +(minus one\) to process \(normally 0\) before the \214rst call.)-2.5 E +F3(arg_printusage)102 396 Q F0(tak)4.178 E 4.178(et)-.1 G 1.678(he same) +-4.178 F F3(args)4.178 E F0(and)4.178 E F3(num_args)4.178 E F0 1.678 +(as getar)4.178 F(g;)-.18 E F3 1.677(progname is the name of)4.178 F +6.381(the program \(to be)102 408 R F0(progname0)12.381 E F3(0)12.381 E +F0(progname1)A F3(1)12.381 E F0(progname2)A F3(2)12.382 E F0(progname3)A +F3(3)12.382 E F0(progname4)A F3(4)102 420 Q F0(progname5)A F3 +(extra_string)3.404 E F0 .904 +(is a string to print after the actual options to indicate more ar)3.404 +F .904(guments. The)-.18 F .025(usefulness of this function is realised\ + only be people who has used programs that has help strings that doesn') +102 432 R(t)-.18 E(match what the code does.)102 444 Q(The)102 462 Q F3 +(getargs)2.5 E F0(struct has the follo)2.5 E(wing elements.)-.25 E/F5 10 +/Courier@0 SF(struct getargs{)102 504 Q(const char)126 516 Q F4(*)6 E F5 +(long_name;)A(char short_name;)126 528 Q(enum { arg_integer,)126 540 Q +(arg_string,)165 552 Q(arg_flag,)165 564 Q(arg_negative_flag,)165 576 Q +(arg_strings,)165 588 Q(arg_double,)165 600 Q(arg_collect)168 612 Q 6 +(}t)126 624 S(ype;)-6 E(void)126 636 Q F4(*)6 E F5(value;)A(const char) +126 648 Q F4(*)6 E F5(help;)A(const char)126 660 Q F4(*)6 E F5 +(arg_help;)A(};)102 672 Q F3(long_name)102 690 Q F0 .207 +(is the long name of the option, it can be)2.707 F F5(NULL)2.706 E F0 +2.706(,i)C 2.706(fy)-2.706 G .206(ou don')-2.706 F 2.706(tw)-.18 G .206 +(ant a long name.)-2.806 F F3(short_name)5.206 E F0 .397(is the charact\ +ed to use as short option, it can be zero. If the option has a v)102 702 +R .398(alue the)-.25 F F3(value)2.898 E F0 .398 +(\214eld gets \214lled in)2.898 F -.4(RO)77 750 S 152.325(KEN September) +.4 F(24, 1999)2.5 E(1)188.865 E EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF(GET)72 48 Q -.834(ARG \( 3 \))-.93 F +(OpenBSD Programmer')111.062 E 2.5(sM)-.55 G 108.562(anual GET)-2.5 F +-.834(ARG \( 3 \))-.93 F .737(with that v)102 96 R .737 +(alue interpreted as speci\214ed by the)-.25 F/F1 10/Courier-Oblique@0 +SF(type)3.237 E F0(\214eld.)3.237 E F1(help)5.737 E F0 .737 +(is a longer help string for the option as a)3.237 F 2.833 +(whole, if it')102 108 R(s)-.55 E/F2 10/Courier@0 SF(NULL)5.333 E F0 +2.833(the help te)5.333 F 2.833(xt for the option is omitted \(b)-.15 F +2.834(ut it')-.2 F 5.334(ss)-.55 G 2.834 +(till displayed in the synopsis\).)-5.334 F F1(arg_help)102 120 Q F0 +.391(is a description of the ar)2.891 F .391(gument, if)-.18 F F2(NULL) +2.891 E F0 2.891(ad)2.891 G(ef)-2.891 E .39(ault v)-.1 F .39 +(alue will be used, depending on the type of)-.25 F(the option:)102 132 +Q(ar)102 150 Q(g_inte)-.18 E 59.29(ger the)-.15 F(ar)2.5 E +(gument is a signed inte)-.18 E(ger)-.15 E 2.5(,a)-.4 G(nd)-2.5 E F1 +(value)2.5 E F0(should point to an)2.5 E F1(int)2.5 E F0(.)A F1 +(arg_string)102 168 Q F0(the ar)47 E(gument is a string, and)-.18 E F1 +(value)2.5 E F0(should point to a)2.5 E F1(char)2.5 E/F3 10/Symbol SF(*) +A F0(.)A F1(arg_flag)102 186 Q F0 .4(the ar)59 F .4 +(gument is a \215ag, and)-.18 F F1(value)2.9 E F0 .4(should point to a) +2.9 F F1(int)2.9 E F0 2.9(.I)C 2.9(tg)-2.9 G .4 +(ets \214lled in with ei-)-2.9 F 1.154 +(ther zero or one, depending on ho)209 198 R 3.654(wt)-.25 G 1.153 +(he option is gi)-3.654 F -.15(ve)-.25 G 1.153 +(n, the normal case beeing).15 F .526(one. Note that if the option isn') +209 210 R 3.026(tg)-.18 G -2.15 -.25(iv e)-3.026 H .526(n, the v).25 F +.526(alue isn')-.25 F 3.026(ta)-.18 G .527(ltered, so it should be ini-) +-3.026 F(tialised to some useful def)209 222 Q(ault.)-.1 E F1 +(arg_negative_flag)102 240 Q F0 .058(this is the same as)2.558 F F1 +(arg_flag)2.558 E F0 -.2(bu)2.558 G 2.558(ti).2 G 2.558(tr)-2.558 G +-2.15 -.25(ev e)-2.558 H .057(rses the meaning of the \215ag \(a gi).25 +F -.15(ve)-.25 G 2.557(ns).15 G(hort)-2.557 E +(option clears the \215ag\), and the synopsis of a long option is ne)209 +252 Q -.05(ga)-.15 G(ted.).05 E F1(arg_strings)102 270 Q F0 .195(the ar) +41 F .195(gument can be gi)-.18 F -.15(ve)-.25 G 2.695(nm).15 G .195 +(ultiple times, and the v)-2.695 F .195 +(alues are collected in an array;)-.25 F F1(value)209 282 Q F0 .947 +(should be a pointer to a)3.447 F F1 .947(struct getarg_strings)3.447 F +F0 .947(structure, which)3.447 F(holds a length and a string pointer)209 +294 Q(.)-.55 E F1(arg_double)102 312 Q F0(ar)47 E .538 +(gument is a double precision \215oating point v)-.18 F .539(alue, and) +-.25 F F1(value)3.039 E F0 .539(should point to a)3.039 F F1(double)209 +324 Q F0(.)A F1(arg_collect)102 342 Q F0(allo)41 E .345 +(ws more \214ne-grained control of the option parsing process.)-.25 F F1 +(value)5.344 E F0 .344(should be)2.844 F 2.5(ap)209 354 S(ointer to a) +-2.5 E F1(getarg_collect_info)2.5 E F0(structure:)2.5 E F2 +(typedef int \()209 372 Q F3(*)A F2 +(getarg_collect_func\)\(int short_opt,)A(int argc,)407 384 Q(char)407 +396 Q F3(**)6 E F2(argv,)A(int)407 408 Q F3(*)6 E F2(optind,)A(int)407 +420 Q F3(*)6 E F2(optarg,)A(void)407 432 Q F3(*)6 E F2(data\);)A +(typedef struct getarg_collect_info {)209 456 Q +(getarg_collect_func func;)233 468 Q(void)233 480 Q F3(*)6 E F2(data;)A +6(}g)209 492 S(etarg_collect_info;)-6 E F0 -.4(Wi)209 510 S 1.018 +(th the).4 F F1(func)3.518 E F0 1.019 +(member set to a function to call, and)3.518 F F1(data)3.519 E F0 1.019 +(to some application)3.519 F +(speci\214c data. The parameters to the collect function are:)209 522 Q +F1(short_flag)209 540 Q F0 +(non-zero if this call is via a short option \215ag, zero otherwise)2.5 +E F1(argc)209 558 Q F0(,)A F1(argv)6 E F0(the whole ar)2.5 E +(gument list)-.18 E F1(optind)209 576 Q F0(pointer to the inde)2.5 E 2.5 +(xi)-.15 G 2.5(na)-2.5 G -.18(rg)-2.5 G 2.5(vw).18 G(here the \215ag is) +-2.5 E F1(optarg)209 594 Q F0(pointer to the inde)2.5 E 2.5(xi)-.15 G +2.5(na)-2.5 G -.18(rg)-2.5 G(v[).18 E F3(*)A F0 +(optind] where the \215ag name starts)A F1(data)209 612 Q F0 +(application speci\214c data)2.5 E -1.1(Yo)209 630 S 3.915(uc)1.1 G +1.415(an modify)-3.915 F F3(*)3.915 E F1(optind)A F0 3.915(,a)C(nd) +-3.915 E F3(*)3.915 E F1(optarg)A F0 3.915(,b)C 1.414 +(ut to do this correct you \(more or)-4.115 F(less\) ha)209 642 Q .3 +-.15(ve t)-.2 H 2.5(ok).15 G(no)-2.5 E 2.5(wa)-.25 G(bout the inner w) +-2.5 E(orkings of getar)-.1 E(g.)-.18 E -1.1(Yo)209 666 S 3.604(uc)1.1 G +1.104(an skip parts of ar)-3.604 F 1.105(guments by increasing)-.18 F F3 +(*)3.605 E F1(optarg)A F0 1.105(\(you could implement)3.605 F(the)209 +678 Q/F4 10/Courier-Bold@0 SF<ad7a>4.567 E F1(3)A F0 .401 +(set of \215ags from)2.901 F F4(gzip)2.9 E F0 .4 +(with this\), or whole ar)2.9 F .4(gument strings by increas-)-.18 F +(ing)209 690 Q F3(*)3.275 E F1(optind)A F0(\(let')3.275 E 3.276(ss)-.55 +G .776(ay you w)-3.276 F .776(ant a \215ag)-.1 F F4<ad63>4.942 E F1 +6.776(xyz)6.776 G F0 .776(to specify a coordinate\); if)-3.5 F +(you also ha)209 702 Q .3 -.15(ve t)-.2 H 2.5(os).15 G(et)-2.5 E F3(*) +2.5 E F1(optarg)A F0(to a sane v)2.5 E(alue.)-.25 E -.4(RO)77 750 S +152.325(KEN September).4 F(24, 1999)2.5 E(2)188.865 E EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF(GET)72 48 Q -.834(ARG \( 3 \))-.93 F +(OpenBSD Programmer')111.062 E 2.5(sM)-.55 G 108.562(anual GET)-2.5 F +-.834(ARG \( 3 \))-.93 F 9.449 +(The collect function should return one of)209 96 R/F1 10/Courier@0 SF +(ARG_ERR_NO_MATCH)11.948 E F0(,)A F1(ARG_ERR_BAD_ARG)209 108 Q F0(,)A F1 +(ARG_ERR_NO_ARG)6 E F0(on error)2.5 E 2.5(,z)-.4 G(ero otherwise.)-2.5 E +-.15(Fo)209 126 S 4.042(ry).15 G 1.542(our con)-4.042 F -.15(ve)-.4 G +1.542(nience there is a function,).15 F/F2 10/Courier-Bold@0 SF +(getarg_optarg)4.042 E F0 1.542(\(\), that returns the)B 1.251 +(traditional ar)209 138 R 1.251(gument string, and you pass it all ar) +-.18 F 1.251(guments, sans data, that where)-.18 F(gi)209 150 Q -.15(ve) +-.25 G 2.5(nt).15 G 2.5(ot)-2.5 G(he collection function.)-2.5 E(Don') +209 168 Q 2.5(tu)-.18 G(se this more this unless you absolutely ha)-2.5 +E .3 -.15(ve t)-.2 H(o.).15 E .213(Option parsing is similar to what)102 +186 R F1(getopt)2.713 E F0 .214(uses. Short options without ar)2.714 F +.214(guments can be compressed \()-.18 F F2(\255xyz)1.666 E F0 .207 +(is the same as)102 198 R F2 1.873<ad7820ad7920ad7a>4.373 F F0 .207 +(\), and short options with ar)B .207(guments tak)-.18 F 2.706(et)-.1 G +.206(hese as either the rest of the ar)-2.706 F(gv-string)-.18 E +(or as the ne)102 210 Q(xt option \()-.15 E F2<ad6f>1.666 E/F3 10 +/Courier-Oblique@0 SF(foo)A F0 2.5(,o)C(r)-2.5 E F2<ad6f>4.166 E F3(foo) +6 E F0(\).)A .78(Long option names are pre\214x)102 228 R .781 +(ed with -- \(double dash\), and the v)-.15 F .781 +(alue with a = \(equal\),)-.25 F F2(\255-foo=)4.947 E F3(bar)A F0 3.281 +(.L)C(ong)-3.281 E 3.815 +(option \215ags can either be speci\214ed as the)102 240 R 6.315(ya)-.15 +G 3.815(re \()-6.315 F F2(\255-help)1.666 E F0 3.815 +(\), or with an \(boolean parsable\) option)B(\()102 252 Q F2 +(\255-help=)1.666 E F3(yes)A F0(,)A F2(\255-help=)5.659 E F3(true)A F0 +3.993(,o)C 3.993(rs)-3.993 G 1.493(imilar\), or the)-3.993 F 3.993(yc) +-.15 G 1.493(an also be ne)-3.993 F -.05(ga)-.15 G 1.493(ted \().05 F F2 +(\255-no-help)1.666 E F0 1.493(is the same as)3.993 F F2(\255-help=) +103.666 264 Q F0 1.363(no\), and if you')B 1.362 +(re really confused you can do it multiple times \()-.5 F F2 +(\255-no-no-help=)1.666 E F3(false)A F0 3.862(,o)C(r)-3.862 E -2.15 -.25 +(ev e)102 276 T(n).25 E F2(\255-no-no-help=)4.166 E F3(maybe)A F0(\).)A +/F4 10/Times-Bold@0 SF(EXAMPLE)72 300 Q F1(#include <stdio.h>)102 330 Q +(#include <string.h>)102 342 Q(#include <getarg.h>)102 354 Q(char)102 +378 Q/F5 10/Symbol SF(*)6 E F1(source = "Ouagadougou";)A(char)102 390 Q +F5(*)6 E F1(destination;)A(int weight;)102 402 Q +(int include_catalog = 1;)102 414 Q(int help_flag;)102 426 Q +(struct getargs args[] = {)102 450 Q 6({")126 462 S 30(source", 's',)-6 +F 6(arg_string, &source,)6 F("source of shippment", "city" },)138 474 Q +6({")126 486 S(destination", 'd', arg_string,)-6 E(&destination,)12 E +("destination of shippment", "city" },)138 498 Q 6({")126 510 S 30 +(weight", 'w',)-6 F(arg_integer, &weight,)6 E +("weight of shippment", "tons" },)138 522 Q 6({")126 534 S 24 +(catalog", 'c',)-6 F(arg_negative_flag, &include_catalog,)6 E +("include product catalog" },)138 546 Q 6({")126 558 S 42(help", 'h',)-6 +F(arg_flag, &help_flag })6 E(};)102 570 Q +(int num_args = sizeof\(args\) / sizeof\(args[0]\); /)102 594 Q F5(*)A +F1(number of elements in args)6 E F5(*)6 E F1(/)A(const char)102 618 Q +F5(*)6 E F1(progname = "ship++";)A(int)102 642 Q(main\(int argc, char) +102 654 Q F5(**)6 E F1(argv\))A({)102 666 Q(int optind = 0;)126 678 Q +(if \(getarg\(args, num_args, argc, argv, &optind\)\) {)126 690 Q +(arg_printusage\(args, num_args, progname, "stuff..."\);)147 702 Q F0 +-.4(RO)77 750 S 152.325(KEN September).4 F(24, 1999)2.5 E(3)188.865 E EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF(GET)72 48 Q -.834(ARG \( 3 \))-.93 F +(OpenBSD Programmer')111.062 E 2.5(sM)-.55 G 108.562(anual GET)-2.5 F +-.834(ARG \( 3 \))-.93 F/F1 10/Courier@0 SF(exit \(1\);)147 96 Q(})126 +108 Q(if \(help_flag\) {)126 120 Q +(arg_printusage\(args, num_args, progname, "stuff..."\);)147 132 Q +(exit \(0\);)147 144 Q(})126 156 Q(if \(destination == NULL\) {)126 168 +Q(fprintf\(stderr, "%s: must specify destination0, progname\);)147 180 Q +(exit\(1\);)147 192 Q(})126 204 Q +(if \(strcmp\(source, destination\) == 0\) {)126 216 Q +(fprintf\(stderr, "%s: destination must be different from source0\);)147 +228 Q(exit\(1\);)147 240 Q(})126 252 Q(/)126 264 Q/F2 10/Symbol SF(*)A +F1(include more stuff here ...)6 E F2(*)6 E F1(/)A(exit\(2\);)126 276 Q +(})102 288 Q F0(The output help output from this program looks lik)102 +306 Q 2.5(et)-.1 G(his:)-2.5 E F1 6($s)102 324 S(hip++ --help)-6 E +(Usage: ship++ [--source=city] [-s city] [--destination=city] [-d city]) +102 336 Q +([--weight=tons] [-w tons] [--no-catalog] [-c] [--help] [-h] stuff...) +120 348 Q(-s city, --source=city)102 360 Q(source of shippment)36 E +(-d city, --destination=city destination of shippment)102 372 Q +(-w tons, --weight=tons)102 384 Q(weight of shippment)36 E +(-c, --no-catalog)102 396 Q(include product catalog)72 E/F3 10 +/Times-Bold@0 SF -.1(BU)72 432 S(GS).1 E F0 .9(It should be more \215e) +102 444 R .9(xible, so it w)-.15 F .901 +(ould be possible to use other more complicated option syntax)-.1 F .901 +(es, such as)-.15 F(what)102 456 Q F1(ps)3.167 E F0 .667(\(1\), and)B F1 +(tar)3.167 E F0 .666(\(1\), uses, or the AFS model where you can skip t\ +he \215ag names as long as the options)B(come in the correct order)102 +468 Q(.)-.55 E(Options with multiple ar)102 486 Q +(guments should be handled better)-.18 E(.)-.55 E(Should be inte)102 504 +Q(greated with SL.)-.15 E(It')102 522 Q 2.5(sv)-.55 G +(ery confusing that the struct you pass in is called getar)-2.65 E(gS.) +-.18 E F3 1.666(SEE ALSO)72 546 R F1(getopt)102 558 Q F0(\(3\))A -.4(RO) +77 750 S 152.325(KEN September).4 F(24, 1999)2.5 E(4)188.865 E EP +%%Trailer +end +%%EOF diff --git a/ndb/src/common/util/getarg.c b/ndb/src/common/util/getarg.c new file mode 100644 index 00000000000..5f792437a65 --- /dev/null +++ b/ndb/src/common/util/getarg.c @@ -0,0 +1,599 @@ +/* -*- c-basic-offset: 4; -*- */ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ndb_types.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$KTH: getarg.c,v 1.23 2000/09/01 21:25:54 lha Exp $"); +#endif + +#include <NdbStdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> +#include "getarg.h" + +#define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag) + +#ifndef HAVE_STRLCPY +extern size_t strlcpy (char *dst, const char *src, size_t dst_sz); +#endif /* !HAVE_STRLCPY */ + +#ifndef HAVE_STRLCAT +extern size_t strlcat (char *dst, const char *src, size_t dst_sz); +#endif /* !HAVE_STRLCAT */ + +#ifndef max +#define max(a, b) (a) > (b) ? (a) : (b) +#endif + +#ifdef HAVE___PROGNAME +extern char *__progname; +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +char * +strupr(char *str) +{ + char *s; + + for(s = str; *s; s++) + *s = toupper(*s); + return str; +} + +static size_t +print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg) +{ + const char *s; + + *string = '\0'; + + if (ISFLAG(*arg) || (!longp && arg->type == arg_counter)) + return 0; + + if(mdoc){ + if(longp) + strlcat(string, "= Ns", len); + strlcat(string, " Ar ", len); + }else + if (longp) + strlcat (string, "=", len); + else + strlcat (string, " ", len); + + if (arg->arg_help) + s = arg->arg_help; + else if (arg->type == arg_integer || arg->type == arg_counter) + s = "integer"; + else if (arg->type == arg_string) + s = "string"; + else if (arg->type == arg_double) + s = "float"; + else + s = "<undefined>"; + + strlcat(string, s, len); + return 1 + strlen(s); +} + +#ifdef GETARGMANDOC +static void +mandoc_template(struct getargs *args, + size_t num_args, + const char *progname, + const char *extra_string) +{ + size_t i; + char timestr[64], cmd[64]; + char buf[128]; + const char *p; + time_t t; + + printf(".\\\" Things to fix:\n"); + printf(".\\\" * correct section, and operating system\n"); + printf(".\\\" * remove Op from mandatory flags\n"); + printf(".\\\" * use better macros for arguments (like .Pa for files)\n"); + printf(".\\\"\n"); + t = time(NULL); + strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t)); + printf(".Dd %s\n", timestr); + p = strrchr(progname, '/'); + if(p) p++; else p = progname; + strlcpy(cmd, p, sizeof(cmd)); + strupr(cmd); + + printf(".Dt %s SECTION\n", cmd); + printf(".Os OPERATING_SYSTEM\n"); + printf(".Sh NAME\n"); + printf(".Nm %s\n", p); + printf(".Nd\n"); + printf("in search of a description\n"); + printf(".Sh SYNOPSIS\n"); + printf(".Nm\n"); + for(i = 0; i < num_args; i++){ + /* we seem to hit a limit on number of arguments if doing + short and long flags with arguments -- split on two lines */ + if(ISFLAG(args[i]) || + args[i].short_name == 0 || args[i].long_name == NULL) { + printf(".Op "); + + if(args[i].short_name) { + print_arg(buf, sizeof(buf), 1, 0, args + i); + printf("Fl %c%s", args[i].short_name, buf); + if(args[i].long_name) + printf(" | "); + } + if(args[i].long_name) { + print_arg(buf, sizeof(buf), 1, 1, args + i); + printf("Fl -%s%s%s", + args[i].type == arg_negative_flag ? "no-" : "", + args[i].long_name, buf); + } + printf("\n"); + } else { + print_arg(buf, sizeof(buf), 1, 0, args + i); + printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf); + print_arg(buf, sizeof(buf), 1, 1, args + i); + printf(".Fl -%s%s Oc\n.Xc\n", args[i].long_name, buf); + } + /* + if(args[i].type == arg_strings) + fprintf (stderr, "..."); + */ + } + if (extra_string && *extra_string) + printf (".Ar %s\n", extra_string); + printf(".Sh DESCRIPTION\n"); + printf("Supported options:\n"); + printf(".Bl -tag -width Ds\n"); + for(i = 0; i < num_args; i++){ + printf(".It Xo\n"); + if(args[i].short_name){ + printf(".Fl %c", args[i].short_name); + print_arg(buf, sizeof(buf), 1, 0, args + i); + printf("%s", buf); + if(args[i].long_name) + printf(" Ns ,"); + printf("\n"); + } + if(args[i].long_name){ + printf(".Fl -%s%s", + args[i].type == arg_negative_flag ? "no-" : "", + args[i].long_name); + print_arg(buf, sizeof(buf), 1, 1, args + i); + printf("%s\n", buf); + } + printf(".Xc\n"); + if(args[i].help) + printf("%s\n", args[i].help); + /* + if(args[i].type == arg_strings) + fprintf (stderr, "..."); + */ + } + printf(".El\n"); + printf(".\\\".Sh ENVIRONMENT\n"); + printf(".\\\".Sh FILES\n"); + printf(".\\\".Sh EXAMPLES\n"); + printf(".\\\".Sh DIAGNOSTICS\n"); + printf(".\\\".Sh SEE ALSO\n"); + printf(".\\\".Sh STANDARDS\n"); + printf(".\\\".Sh HISTORY\n"); + printf(".\\\".Sh AUTHORS\n"); + printf(".\\\".Sh BUGS\n"); +} +#endif /* GETARGMANDOC */ + +static int +check_column(FILE *f, int col, int len, int columns) +{ + if(col + len > columns) { + fprintf(f, "\n"); + col = fprintf(f, " "); + } + return col; +} + +void +arg_printusage (struct getargs *args, + size_t num_args, + const char *progname, + const char *extra_string) +{ + unsigned int i; + size_t max_len = 0; + char buf[128]; + int col = 0, columns; + +#ifdef HAVE___PROGNAME + if (progname == NULL) + progname = __progname; +#endif + if (progname == NULL) + progname = ""; + +#ifdef GETARGMANDOC + if(getenv("GETARGMANDOC")){ + mandoc_template(args, num_args, progname, extra_string); + return; + } +#endif + + columns = 80; /* Always assume that the window is 80 chars wide */ + col = 0; + col += fprintf (stderr, "Usage: %s", progname); + for (i = 0; i < num_args; ++i) { + size_t len = 0; + + if (args[i].long_name) { + buf[0] = '\0'; + strlcat(buf, "[--", sizeof(buf)); + len += 2; + if(args[i].type == arg_negative_flag) { + strlcat(buf, "no-", sizeof(buf)); + len += 3; + } + strlcat(buf, args[i].long_name, sizeof(buf)); + len += strlen(args[i].long_name); + len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), + 0, 1, &args[i]); + strlcat(buf, "]", sizeof(buf)); + if(args[i].type == arg_strings) + strlcat(buf, "...", sizeof(buf)); + col = check_column(stderr, col, strlen(buf) + 1, columns); + col += fprintf(stderr, " %s", buf); + } + if (args[i].short_name) { + snprintf(buf, sizeof(buf), "[-%c", args[i].short_name); + len += 2; + len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), + 0, 0, &args[i]); + strlcat(buf, "]", sizeof(buf)); + if(args[i].type == arg_strings) + strlcat(buf, "...", sizeof(buf)); + col = check_column(stderr, col, strlen(buf) + 1, columns); + col += fprintf(stderr, " %s", buf); + } + if (args[i].long_name && args[i].short_name) + len += 2; /* ", " */ + max_len = max(max_len, len); + } + if (extra_string) { + col = check_column(stderr, col, strlen(extra_string) + 1, columns); + fprintf (stderr, " %s\n", extra_string); + } else + fprintf (stderr, "\n"); + for (i = 0; i < num_args; ++i) { + if (args[i].help) { + size_t count = 0; + + if (args[i].short_name) { + count += fprintf (stderr, "-%c", args[i].short_name); + print_arg (buf, sizeof(buf), 0, 0, &args[i]); + count += fprintf(stderr, "%s", buf); + } + if (args[i].short_name && args[i].long_name) + count += fprintf (stderr, ", "); + if (args[i].long_name) { + count += fprintf (stderr, "--"); + if (args[i].type == arg_negative_flag) + count += fprintf (stderr, "no-"); + count += fprintf (stderr, "%s", args[i].long_name); + print_arg (buf, sizeof(buf), 0, 1, &args[i]); + count += fprintf(stderr, "%s", buf); + } + while(count++ <= max_len) + putc (' ', stderr); + fprintf (stderr, "%s\n", args[i].help); + } + } +} + +static void +add_string(getarg_strings *s, char *value) +{ + s->strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings)); + s->strings[s->num_strings] = value; + s->num_strings++; +} + +static int +arg_match_long(struct getargs *args, size_t num_args, + char *argv, int argc, const char **rargv, int *optind) +{ + unsigned int i; + const char *optarg = NULL; + int negate = 0; + int partial_match = 0; + struct getargs *partial = NULL; + struct getargs *current = NULL; + int argv_len; + char *p; + + argv_len = strlen(argv); + p = strchr (argv, '='); + if (p != NULL) + argv_len = p - argv; + + for (i = 0; i < num_args; ++i) { + if(args[i].long_name) { + int len = strlen(args[i].long_name); + char *p = argv; + int p_len = argv_len; + negate = 0; + + for (;;) { + if (strncmp (args[i].long_name, p, p_len) == 0) { + if(p_len == len) + current = &args[i]; + else { + ++partial_match; + partial = &args[i]; + } + optarg = p + p_len; + } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) { + negate = !negate; + p += 3; + p_len -= 3; + continue; + } + break; + } + if (current) + break; + } + } + if (current == NULL) { + if (partial_match == 1) + current = partial; + else + return ARG_ERR_NO_MATCH; + } + + if(*optarg == '\0' + && !ISFLAG(*current) + && current->type != arg_collect + && current->type != arg_counter) + return ARG_ERR_NO_MATCH; + switch(current->type){ + case arg_integer: + { + int tmp; + if(sscanf(optarg + 1, "%d", &tmp) != 1) + return ARG_ERR_BAD_ARG; + *(int*)current->value = tmp; + return 0; + } + case arg_string: + { + *(char**)current->value = optarg + 1; + return 0; + } + case arg_strings: + { + add_string((getarg_strings*)current->value, optarg + 1); + return 0; + } + case arg_flag: + case arg_negative_flag: + { + int *flag = current->value; + if(*optarg == '\0' || + strcmp(optarg + 1, "yes") == 0 || + strcmp(optarg + 1, "true") == 0){ + *flag = !negate; + return 0; + } else if (*optarg && strcmp(optarg + 1, "maybe") == 0) { + *flag = rand() & 1; + } else { + *flag = negate; + return 0; + } + return ARG_ERR_BAD_ARG; + } + case arg_counter : + { + int val; + + if (*optarg == '\0') + val = 1; + else { + char *endstr; + + val = strtol (optarg, &endstr, 0); + if (endstr == optarg) + return ARG_ERR_BAD_ARG; + } + *(int *)current->value += val; + return 0; + } + case arg_double: + { + double tmp; + if(sscanf(optarg + 1, "%lf", &tmp) != 1) + return ARG_ERR_BAD_ARG; + *(double*)current->value = tmp; + return 0; + } + case arg_collect:{ + struct getarg_collect_info *c = current->value; + int o = argv - rargv[*optind]; + return (*c->func)(FALSE, argc, rargv, optind, &o, c->data); + } + + default: + abort (); + } +} + +static int +arg_match_short (struct getargs *args, size_t num_args, + char *argv, int argc, const char **rargv, int *optind) +{ + int j, k; + + for(j = 1; j > 0 && j < (int)strlen(rargv[*optind]); j++) { + for(k = 0; k < (int)num_args; k++) { + char *optarg; + + if(args[k].short_name == 0) + continue; + if(argv[j] == args[k].short_name) { + if(args[k].type == arg_flag) { + *(int*)args[k].value = 1; + break; + } + if(args[k].type == arg_negative_flag) { + *(int*)args[k].value = 0; + break; + } + if(args[k].type == arg_counter) { + ++*(int *)args[k].value; + break; + } + if(args[k].type == arg_collect) { + struct getarg_collect_info *c = args[k].value; + + if((*c->func)(TRUE, argc, rargv, optind, &j, c->data)) + return ARG_ERR_BAD_ARG; + break; + } + + if(argv[j + 1]) + optarg = &argv[j + 1]; + else { + ++*optind; + optarg = rargv[*optind]; + } + if(optarg == NULL) { + --*optind; + return ARG_ERR_NO_ARG; + } + if(args[k].type == arg_integer) { + int tmp; + if(sscanf(optarg, "%d", &tmp) != 1) + return ARG_ERR_BAD_ARG; + *(int*)args[k].value = tmp; + return 0; + } else if(args[k].type == arg_string) { + *(char**)args[k].value = optarg; + return 0; + } else if(args[k].type == arg_strings) { + add_string((getarg_strings*)args[k].value, optarg); + return 0; + } else if(args[k].type == arg_double) { + double tmp; + if(sscanf(optarg, "%lf", &tmp) != 1) + return ARG_ERR_BAD_ARG; + *(double*)args[k].value = tmp; + return 0; + } + return ARG_ERR_BAD_ARG; + } + } + if (k == (int)num_args) + return ARG_ERR_NO_MATCH; + } + return 0; +} + +int +getarg(struct getargs *args, size_t num_args, + int argc, const char **argv, int *optind) +{ + int i; + int ret = 0; + + srand (time(NULL)); + (*optind)++; + for(i = *optind; i < argc; i++) { + if(argv[i][0] != '-') + break; + if(argv[i][1] == '-'){ + if(argv[i][2] == 0){ + i++; + break; + } + ret = arg_match_long (args, num_args, argv[i] + 2, + argc, argv, &i); + } else { + ret = arg_match_short (args, num_args, argv[i], + argc, argv, &i); + } + if(ret) + break; + } + *optind = i; + return ret; +} + + +#if TEST +int foo_flag = 2; +int flag1 = 0; +int flag2 = 0; +int bar_int; +char *baz_string; + +struct getargs args[] = { + { NULL, '1', arg_flag, &flag1, "one", NULL }, + { NULL, '2', arg_flag, &flag2, "two", NULL }, + { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL }, + { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"}, + { "baz", 'x', arg_string, &baz_string, "baz", "name" }, +}; + +int main(int argc, char **argv) +{ + int optind = 0; + while(getarg(args, 5, argc, argv, &optind)) + printf("Bad arg: %s\n", argv[optind]); + printf("flag1 = %d\n", flag1); + printf("flag2 = %d\n", flag2); + printf("foo_flag = %d\n", foo_flag); + printf("bar_int = %d\n", bar_int); + printf("baz_flag = %s\n", baz_string); + arg_printusage (args, 5, argv[0], "nothing here"); +} +#endif diff --git a/ndb/src/common/util/getarg.cat3 b/ndb/src/common/util/getarg.cat3 new file mode 100644 index 00000000000..31685510537 --- /dev/null +++ b/ndb/src/common/util/getarg.cat3 @@ -0,0 +1,237 @@ +GETARG(3) OpenBSD Programmer's Manual GETARG(3) + +NNAAMMEE + ggeettaarrgg, aarrgg__pprriinnttuussaaggee - collect command line options + +SSYYNNOOPPSSIISS + ##iinncclluuddee <<ggeettaarrgg..hh>> + + + _i_n_t + ggeettaarrgg(_s_t_r_u_c_t _g_e_t_a_r_g_s _*_a_r_g_s, _s_i_z_e___t _n_u_m___a_r_g_s, _i_n_t _a_r_g_c, _c_h_a_r _*_*_a_r_g_v, + _i_n_t _*_o_p_t_i_n_d); + + + _v_o_i_d + aarrgg__pprriinnttuussaaggee(_s_t_r_u_c_t _g_e_t_a_r_g_s _*_a_r_g_s, _s_i_z_e___t _n_u_m___a_r_g_s, + _c_o_n_s_t _c_h_a_r _*_p_r_o_g_n_a_m_e, _c_o_n_s_t _c_h_a_r _*_e_x_t_r_a___s_t_r_i_n_g); + + +DDEESSCCRRIIPPTTIIOONN + ggeettaarrgg() collects any command line options given to a program in an easi + ly used way. aarrgg__pprriinnttuussaaggee() pretty-prints the available options, with + a short help text. + + _a_r_g_s is the option specification to use, and it's an array of _s_t_r_u_c_t + _g_e_t_a_r_g_s elements. _n_u_m___a_r_g_s is the size of _a_r_g_s (in elements). _a_r_g_c and + _a_r_g_v are the argument count and argument vector to extract option from. + _o_p_t_i_n_d is a pointer to an integer where the index to the last processed + argument is stored, it must be initialised to the first index (minus one) + to process (normally 0) before the first call. + + _a_r_g___p_r_i_n_t_u_s_a_g_e take the same _a_r_g_s and _n_u_m___a_r_g_s as getarg; _p_r_o_g_n_a_m_e _i_s _t_h_e + _n_a_m_e _o_f _t_h_e _p_r_o_g_r_a_m _(_t_o _b_e progname0 _0progname1 _1progname2 _2progname3 + _3progname4 _4progname5 _e_x_t_r_a___s_t_r_i_n_g is a string to print after the actual + options to indicate more arguments. The usefulness of this function is + realised only be people who has used programs that has help strings that + doesn't match what the code does. + + The _g_e_t_a_r_g_s struct has the following elements. + + + struct getargs{ + const char *long_name; + char short_name; + enum { arg_integer, + arg_string, + arg_flag, + arg_negative_flag, + arg_strings, + arg_double, + arg_collect + } type; + void *value; + const char *help; + const char *arg_help; + }; + + _l_o_n_g___n_a_m_e is the long name of the option, it can be NULL, if you don't + want a long name. _s_h_o_r_t___n_a_m_e is the characted to use as short option, it + can be zero. If the option has a value the _v_a_l_u_e field gets filled in + with that value interpreted as specified by the _t_y_p_e field. _h_e_l_p is a + longer help string for the option as a whole, if it's NULL the help text + for the option is omitted (but it's still displayed in the synopsis). + _a_r_g___h_e_l_p is a description of the argument, if NULL a default value will + be used, depending on the type of the option: + + + arg_integer the argument is a signed integer, and _v_a_l_u_e should + point to an _i_n_t. + + _a_r_g___s_t_r_i_n_g the argument is a string, and _v_a_l_u_e should point to a + _c_h_a_r_*. + + _a_r_g___f_l_a_g the argument is a flag, and _v_a_l_u_e should point to a + _i_n_t. It gets filled in with either zero or one, de + pending on how the option is given, the normal case + beeing one. Note that if the option isn't given, the + value isn't altered, so it should be initialised to + some useful default. + + _a_r_g___n_e_g_a_t_i_v_e___f_l_a_g this is the same as _a_r_g___f_l_a_g but it reverses the mean + ing of the flag (a given short option clears the + flag), and the synopsis of a long option is negated. + + _a_r_g___s_t_r_i_n_g_s the argument can be given multiple times, and the val + ues are collected in an array; _v_a_l_u_e should be a + pointer to a _s_t_r_u_c_t _g_e_t_a_r_g___s_t_r_i_n_g_s structure, which + holds a length and a string pointer. + + _a_r_g___d_o_u_b_l_e argument is a double precision floating point value, + and _v_a_l_u_e should point to a _d_o_u_b_l_e. + + _a_r_g___c_o_l_l_e_c_t allows more fine-grained control of the option parsing + process. _v_a_l_u_e should be a pointer to a + _g_e_t_a_r_g___c_o_l_l_e_c_t___i_n_f_o structure: + + typedef int (*getarg_collect_func)(int short_opt, + int argc, + char **argv, + int *optind, + int *optarg, + void *data); + + typedef struct getarg_collect_info { + getarg_collect_func func; + void *data; + } getarg_collect_info; + + With the _f_u_n_c member set to a function to call, and + _d_a_t_a to some application specific data. The parameters + to the collect function are: + + _s_h_o_r_t___f_l_a_g non-zero if this call is via a short option + flag, zero otherwise + + _a_r_g_c, _a_r_g_v the whole argument list + + _o_p_t_i_n_d pointer to the index in argv where the flag is + + _o_p_t_a_r_g pointer to the index in argv[*optind] where the + flag name starts + + _d_a_t_a application specific data + + You can modify _*_o_p_t_i_n_d, and _*_o_p_t_a_r_g, but to do this + correct you (more or less) have to know about the in + ner workings of getarg. + + You can skip parts of arguments by increasing _*_o_p_t_a_r_g + (you could implement the --zz_3 set of flags from ggzziipp + with this), or whole argument strings by increasing + _*_o_p_t_i_n_d (let's say you want a flag --cc _x _y _z to specify + a coordinate); if you also have to set _*_o_p_t_a_r_g to a + sane value. + + The collect function should return one of + ARG_ERR_NO_MATCH, ARG_ERR_BAD_ARG, ARG_ERR_NO_ARG on + error, zero otherwise. + + For your convenience there is a function, + ggeettaarrgg__ooppttaarrgg(), that returns the traditional argument + string, and you pass it all arguments, sans data, that + where given to the collection function. + + Don't use this more this unless you absolutely have + to. + + Option parsing is similar to what getopt uses. Short options without ar + guments can be compressed (--xxyyzz is the same as --xx --yy --zz), and short op + tions with arguments take these as either the rest of the argv-string or + as the next option (--oo_f_o_o, or --oo _f_o_o). + + Long option names are prefixed with -- (double dash), and the value with + a = (equal), ----ffoooo==_b_a_r. Long option flags can either be specified as they + are (----hheellpp), or with an (boolean parsable) option (----hheellpp==_y_e_s, + ----hheellpp==_t_r_u_e, or similar), or they can also be negated (----nnoo--hheellpp is the + same as ----hheellpp==no), and if you're really confused you can do it multiple + times (----nnoo--nnoo--hheellpp==_f_a_l_s_e, or even ----nnoo--nnoo--hheellpp==_m_a_y_b_e). + +EEXXAAMMPPLLEE + #include <stdio.h> + #include <string.h> + #include <getarg.h> + + char *source = "Ouagadougou"; + char *destination; + int weight; + int include_catalog = 1; + int help_flag; + + struct getargs args[] = { + { "source", 's', arg_string, &source, + "source of shippment", "city" }, + { "destination", 'd', arg_string, &destination, + "destination of shippment", "city" }, + { "weight", 'w', arg_integer, &weight, + "weight of shippment", "tons" }, + { "catalog", 'c', arg_negative_flag, &include_catalog, + "include product catalog" }, + { "help", 'h', arg_flag, &help_flag } + }; + + int num_args = sizeof(args) / sizeof(args[0]); /* number of elements in args */ + + const char *progname = "ship++"; + + int + main(int argc, char **argv) + { + int optind = 0; + if (getarg(args, num_args, argc, argv, &optind)) { + arg_printusage(args, num_args, progname, "stuff..."); + exit (1); + } + if (help_flag) { + arg_printusage(args, num_args, progname, "stuff..."); + exit (0); + } + if (destination == NULL) { + fprintf(stderr, "%s: must specify destination0, progname); + exit(1); + } + if (strcmp(source, destination) == 0) { + fprintf(stderr, "%s: destination must be different from source0); + exit(1); + } + /* include more stuff here ... */ + exit(2); + } + + The output help output from this program looks like this: + + $ ship++ --help + Usage: ship++ [--source=city] [-s city] [--destination=city] [-d city] + [--weight=tons] [-w tons] [--no-catalog] [-c] [--help] [-h] stuff... + -s city, --source=city source of shippment + -d city, --destination=city destination of shippment + -w tons, --weight=tons weight of shippment + -c, --no-catalog include product catalog + + +BBUUGGSS + It should be more flexible, so it would be possible to use other more + complicated option syntaxes, such as what ps(1), and tar(1), uses, or the + AFS model where you can skip the flag names as long as the options come + in the correct order. + + Options with multiple arguments should be handled better. + + Should be integreated with SL. + + It's very confusing that the struct you pass in is called getargS. + +SSEEEE AALLSSOO + getopt(3) + + ROKEN September 24, 1999 4 diff --git a/ndb/src/common/util/md5_hash.cpp b/ndb/src/common/util/md5_hash.cpp new file mode 100644 index 00000000000..5e28edcf8fa --- /dev/null +++ b/ndb/src/common/util/md5_hash.cpp @@ -0,0 +1,235 @@ +/* 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 "md5_hash.hpp" + +#ifdef WORDS_BIGENDIAN +#define HIGHFIRST 1 +#endif + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * The code has been modified by Mikael Ronstroem to handle + * calculating a hash value of a key that is always a multiple + * of 4 bytes long. Word 0 of the calculated 4-word hash value + * is returned as the hash value. + */ + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (Uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(Uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(Uint32 buf[4], Uint32 const in[16]) +{ + register Uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +Uint32 md5_hash(const Uint64* keybuf, Uint32 no_of_32_words) +{ +/* + * This is the external interface of the module + * It is assumed that keybuf is placed on 8 byte + * alignment. + */ + Uint32 i; + Uint32 buf[4]; + Uint64 transform64_buf[8]; + Uint32* transform32_buf; + Uint32 len = no_of_32_words << 2; + const Uint64* key64buf = (const Uint64*)keybuf; + const Uint32* key32buf = (const Uint32*)keybuf; + + transform32_buf = (Uint32*)&transform64_buf[0]; + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + while (no_of_32_words >= 16) { + transform64_buf[0] = key64buf[0]; + transform64_buf[1] = key64buf[1]; + transform64_buf[2] = key64buf[2]; + transform64_buf[3] = key64buf[3]; + transform64_buf[4] = key64buf[4]; + transform64_buf[5] = key64buf[5]; + transform64_buf[6] = key64buf[6]; + transform64_buf[7] = key64buf[7]; + no_of_32_words -= 16; + key64buf += 8; + byteReverse((unsigned char *)transform32_buf, 16); + MD5Transform(buf, transform32_buf); + } + + key32buf = (const Uint32*)key64buf; + transform64_buf[0] = 0; + transform64_buf[1] = 0; + transform64_buf[2] = 0; + transform64_buf[3] = 0; + transform64_buf[4] = 0; + transform64_buf[5] = 0; + transform64_buf[6] = 0; + transform64_buf[7] = (Uint64)len; + + for (i = 0; i < no_of_32_words; i++) + transform32_buf[i] = key32buf[i]; + transform32_buf[no_of_32_words] = 0x80000000; + + if (no_of_32_words < 14) { + byteReverse((unsigned char *)transform32_buf, 16); + MD5Transform(buf, transform32_buf); + } else { + if (no_of_32_words == 14) + transform32_buf[15] = 0; + MD5Transform(buf, transform32_buf); + transform64_buf[0] = 0; + transform64_buf[1] = 0; + transform64_buf[2] = 0; + transform64_buf[3] = 0; + transform64_buf[4] = 0; + transform64_buf[5] = 0; + transform64_buf[6] = 0; + transform64_buf[7] = (Uint64)len; + byteReverse((unsigned char *)transform32_buf, 16); + MD5Transform(buf, transform32_buf); + } + return buf[0]; +} + diff --git a/ndb/src/common/util/random.c b/ndb/src/common/util/random.c new file mode 100644 index 00000000000..91da19572e2 --- /dev/null +++ b/ndb/src/common/util/random.c @@ -0,0 +1,292 @@ +/* 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 */ + +/*************************************************************** +* I N C L U D E D F I L E S * +***************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/types.h> + +#ifndef NDB_WIN32 +#include <sys/time.h> +#endif + +#include <ndb_types.h> +#include <NdbOut.hpp> + +#include <random.h> + +/*************************************************************** +* L O C A L C O N S T A N T S * +***************************************************************/ + +/*************************************************************** +* L O C A L D A T A S T R U C T U R E S * +***************************************************************/ + +typedef struct { + unsigned short int x[3]; /* Current state. */ + unsigned short int a[3]; /* Factor in congruential formula. */ + unsigned short int c; /* Additive const. in congruential formula. */ + int init; /* Flag for initializing. */ +}DRand48Data; + +/*************************************************************** +* L O C A L F U N C T I O N S * +***************************************************************/ + +static void shuffleSequence(RandomSequence *seq); + +/*************************************************************** +* L O C A L D A T A * +***************************************************************/ + +static DRand48Data dRand48Data; + +/*************************************************************** +* P U B L I C D A T A * +***************************************************************/ + + +/*************************************************************** +**************************************************************** +* L O C A L F U N C T I O N S C O D E S E C T I O N * +**************************************************************** +***************************************************************/ + +static void localRandom48Init(long int seedval, DRand48Data *buffer) +{ + /* The standards say we only have 32 bits. */ + if (sizeof (long int) > 4) + seedval &= 0xffffffffl; + +#if USHRT_MAX == 0xffffU + buffer->x[2] = seedval >> 16; + buffer->x[1] = seedval & 0xffffl; + buffer->x[0] = 0x330e; + + buffer->a[2] = 0x5; + buffer->a[1] = 0xdeec; + buffer->a[0] = 0xe66d; +#else + buffer->x[2] = seedval; + buffer->x[1] = 0x330e0000UL; + buffer->x[0] = 0; + + buffer->a[2] = 0x5deecUL; + buffer->a[1] = 0xe66d0000UL; + buffer->a[0] = 0; +#endif + + buffer->c = 0xb; + buffer->init = 1; +} + +static void localRandom48(DRand48Data *buffer, long int *result) +{ + Uint64 X; + Uint64 a; + Uint64 loc_result; + + /*--------------------------------------*/ + /* Initialize buffer, if not yet done. */ + /*--------------------------------------*/ + if (!buffer->init) { +#if (USHRT_MAX == 0xffffU) + buffer->a[2] = 0x5; + buffer->a[1] = 0xdeec; + buffer->a[0] = 0xe66d; +#else + buffer->a[2] = 0x5deecUL; + buffer->a[1] = 0xe66d0000UL; + buffer->a[0] = 0; +#endif + buffer->c = 0xb; + buffer->init = 1; + } + + /* Do the real work. We choose a data type which contains at least + 48 bits. Because we compute the modulus it does not care how + many bits really are computed. */ + + if (sizeof (unsigned short int) == 2) { + X = (Uint64)buffer->x[2] << 32 | + (Uint64)buffer->x[1] << 16 | + buffer->x[0]; + a = ((Uint64)buffer->a[2] << 32 | + (Uint64)buffer->a[1] << 16 | + buffer->a[0]); + + loc_result = X * a + buffer->c; + + buffer->x[0] = loc_result & 0xffff; + buffer->x[1] = (loc_result >> 16) & 0xffff; + buffer->x[2] = (loc_result >> 32) & 0xffff; + } + else { + X = (Uint64)buffer->x[2] << 16 | + buffer->x[1] >> 16; + a = (Uint64)buffer->a[2] << 16 | + buffer->a[1] >> 16; + + loc_result = X * a + buffer->c; + + buffer->x[0] = loc_result >> 16 & 0xffffffffl; + buffer->x[1] = loc_result << 16 & 0xffff0000l; + } + + /*--------------------*/ + /* Store the result. */ + /*--------------------*/ + if (sizeof (unsigned short int) == 2) + *result = buffer->x[2] << 15 | buffer->x[1] >> 1; + else + *result = buffer->x[2] >> 1; +} + +static void shuffleSequence(RandomSequence *seq) +{ + int i; + int j; + unsigned int tmp; + + if( !seq ) return; + + for(i = 0; i < seq->length; i++ ) { + j = myRandom48(seq->length); + if( i != j ) { + tmp = seq->values[i]; + seq->values[i] = seq->values[j]; + seq->values[j] = tmp; + } + } +} + + +/*************************************************************** +**************************************************************** +* P U B L I C F U N C T I O N S C O D E S E C T I O N * +**************************************************************** +***************************************************************/ + + +double getTps(unsigned int count, double timeValue) +{ + double f; + + if( timeValue != 0.0 ) + f = count / timeValue; + else + f = 0.0; + + return(f); +} + +/*----------------------------*/ +/* Random Sequences Functions */ +/*----------------------------*/ +int initSequence(RandomSequence *seq, SequenceValues *inputValues) +{ + unsigned int i; + unsigned int j; + unsigned int totalLength; + unsigned int index; + + if( !seq || !inputValues ) return(-1); + + /*------------------------------------*/ + /* Find the total length of the array */ + /*------------------------------------*/ + totalLength = 0; + + for(i = 0; inputValues[i].length != 0; i++) + totalLength += inputValues[i].length; + + if( totalLength == 0 ) return(-1); + + seq->length = totalLength; + seq->values = calloc(totalLength, sizeof(unsigned int)); + + if( seq->values == 0 ) return(-1); + + /*----------------------*/ + /* set the array values */ + /*----------------------*/ + index = 0; + + for(i = 0; inputValues[i].length != 0; i++) { + for(j = 0; j < inputValues[i].length; j++ ) { + seq->values[index] = inputValues[i].value; + index++; + } + } + + shuffleSequence(seq); + + seq->currentIndex = 0; + + return(0); +} + +unsigned int getNextRandom(RandomSequence *seq) +{ + unsigned int nextValue; + + nextValue = seq->values[seq->currentIndex]; + + seq->currentIndex++; + + if(seq->currentIndex == seq->length){ + seq->currentIndex = 0; + shuffleSequence(seq); + } + + return nextValue; +} + +void printSequence(RandomSequence *seq, unsigned int numPerRow) +{ + int i; + + if( !seq ) return; + + for(i = 0; i<seq->length; i++) { + ndbout_c("%d ", seq->values[i]); + + if((i+1) % numPerRow == 0) + ndbout_c(""); + } + + if(i % numPerRow != 0) + ndbout_c(""); +} + +void myRandom48Init(long int seedval) +{ + localRandom48Init(seedval, &dRand48Data); +} + +long int myRandom48(unsigned int maxValue) +{ + long int result; + + localRandom48(&dRand48Data, &result); + + return(result % maxValue); +} diff --git a/ndb/src/common/util/socket_io.cpp b/ndb/src/common/util/socket_io.cpp new file mode 100644 index 00000000000..878a9059512 --- /dev/null +++ b/ndb/src/common/util/socket_io.cpp @@ -0,0 +1,284 @@ +/* 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 <NdbTCP.h> +#include <socket_io.h> +#include <stdarg.h> +#include <string.h> +#include <NdbStdio.h> +#include <NdbOut.hpp> +#include <NdbString.h> + +extern "C" +int +read_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + char * buf, int buflen){ + if(buflen < 1) + return 0; + + fd_set readset; + FD_ZERO(&readset); + FD_SET(socket, &readset); + + struct timeval timeout; + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + + const int selectRes = select(socket + 1, &readset, 0, 0, &timeout); + if(selectRes == 0) + return 0; + + if(selectRes == -1){ + return -1; + } + + return recv(socket, &buf[0], buflen, 0); +} + +extern "C" +int +readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + char * buf, int buflen){ + if(buflen <= 1) + return 0; + + fd_set readset; + FD_ZERO(&readset); + FD_SET(socket, &readset); + + struct timeval timeout; + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + + const int selectRes = select(socket + 1, &readset, 0, 0, &timeout); + if(selectRes == 0) + return 0; + + if(selectRes == -1){ + return -1; + } + + int pos = 0; buf[pos] = 0; + while(true){ + const int t = recv(socket, &buf[pos], 1, 0); + if(t != 1){ + return -1; + } + if(buf[pos] == '\n'){ + buf[pos] = 0; + + if(pos > 0 && buf[pos-1] == '\r'){ + pos--; + buf[pos] = 0; + } + + return pos; + } + pos++; + if(pos == (buflen - 1)){ + buf[pos] = 0; + return buflen; + } + + FD_ZERO(&readset); + FD_SET(socket, &readset); + timeout.tv_sec = 1; + timeout.tv_usec = 0; // 1 s + const int selectRes = select(socket + 1, &readset, 0, 0, &timeout); + if(selectRes != 1){ + return -1; + } + } +} + +extern "C" +int +write_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char buf[], int len){ + fd_set writeset; + FD_ZERO(&writeset); + FD_SET(socket, &writeset); + struct timeval timeout; + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + + const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout); + if(selectRes != 1){ + return -1; + } + + const char * tmp = &buf[0]; + while(len > 0){ + const int w = send(socket, tmp, len, 0); + if(w == -1){ + return -1; + } + len -= w; + tmp += w; + + if(len == 0) + break; + + FD_ZERO(&writeset); + FD_SET(socket, &writeset); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout); + if(selectRes != 1){ + return -1; + } + } + + return 0; +} + +extern "C" +int +print_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + int ret = vprint_socket(socket, timeout_millis, fmt, ap); + va_end(ap); + + return ret; +} + +extern "C" +int +println_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + int ret = vprintln_socket(socket, timeout_millis, fmt, ap); + va_end(ap); + return ret; +} + +extern "C" +int +vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, va_list ap){ + char buf[1000]; + char *buf2 = buf; + size_t size = sizeof(buf); + + if (fmt != 0) { + size = vsnprintf(buf, sizeof(buf), fmt, ap); + /* Check if the output was truncated */ + if(size >= sizeof(buf)) { + buf2 = (char *)malloc(size+1); + if(buf2 == NULL) + return -1; + vsnprintf(buf2, size, fmt, ap); + } else + size = sizeof(buf); + } else + buf[0] = 0; + + int ret = write_socket(socket, timeout_millis, buf2, strlen(buf2)); + if(buf2 != buf) + free(buf2); + return ret; +} + +extern "C" +int +vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, va_list ap){ + char buf[1000]; + char *buf2 = buf; + size_t size = sizeof(buf); + + if (fmt != 0) { + size = vsnprintf(buf, sizeof(buf)-1, fmt, ap); + /* Check if the output was truncated */ + if(size >= sizeof(buf)) { + buf2 = (char *)malloc(size+2); + if(buf2 == NULL) + return -1; + vsnprintf(buf2, size, fmt, ap); + } else + size = sizeof(buf); + } else + buf[0] = 0; + strlcat(buf2, "\n", size+2); + + int ret = write_socket(socket, timeout_millis, buf2, strlen(buf2)); + if(buf2 != buf) + free(buf2); + return ret; +} + +#ifdef NDB_WIN32 + +class INIT_WINSOCK2 +{ +public: + INIT_WINSOCK2(void); + ~INIT_WINSOCK2(void); + +private: + bool m_bAcceptable; +}; + +INIT_WINSOCK2 g_init_winsock2; + +INIT_WINSOCK2::INIT_WINSOCK2(void) +: m_bAcceptable(false) +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 2 ); + + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + m_bAcceptable = false; + } + + /* Confirm that the WinSock DLL supports 2.2.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.2 in addition to 2.2, it will still return */ + /* 2.2 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 2 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + WSACleanup( ); + m_bAcceptable = false; + } + + /* The WinSock DLL is acceptable. Proceed. */ + m_bAcceptable = true; +} + +INIT_WINSOCK2::~INIT_WINSOCK2(void) +{ + if(m_bAcceptable) + { + m_bAcceptable = false; + WSACleanup(); + } +} + +#endif + diff --git a/ndb/src/common/util/strdup.c b/ndb/src/common/util/strdup.c new file mode 100644 index 00000000000..5291be86b0f --- /dev/null +++ b/ndb/src/common/util/strdup.c @@ -0,0 +1,28 @@ +/* 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 <stdlib.h> + +#ifndef HAVE_STRDUP +char * +strdup(const char *s){ + void *p2; + p2 = malloc(strlen(s)+1); + strcpy(p2, s); + return p2; +} +#endif diff --git a/ndb/src/common/util/strlcat.c b/ndb/src/common/util/strlcat.c new file mode 100644 index 00000000000..ccff15da27f --- /dev/null +++ b/ndb/src/common/util/strlcat.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1995 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <ndb_types.h> + +/* RCSID("$KTH: strlcat.c,v 1.1 2000/08/16 01:23:47 lha Exp $"); */ + +//#include <NdbString.h> + +#ifndef HAVE_STRLCAT +size_t +strlcat (char *dst, const char *src, size_t dst_sz) +{ + size_t len = strlen(dst); + + return len + strlcpy (dst + len, src, dst_sz - len); +} +#endif diff --git a/ndb/src/common/util/strlcpy.c b/ndb/src/common/util/strlcpy.c new file mode 100644 index 00000000000..9a3048081ca --- /dev/null +++ b/ndb/src/common/util/strlcpy.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1995 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <ndb_types.h> + +/* RCSID("$KTH: strlcpy.c,v 1.1 2000/08/16 01:23:48 lha Exp $"); */ + +#ifndef HAVE_STRLCPY + +#ifdef NDB_WIN32 +#include <string.h> +#endif + +size_t +strlcpy (char *dst, const char *src, size_t dst_sz) +{ + size_t n; + char *p; + + for (p = dst, n = 0; + n + 1 < dst_sz && *src != '\0'; + ++p, ++src, ++n) + *p = *src; + *p = '\0'; + if (*src == '\0') + return n; + else + return n + strlen (src); +} + +#endif diff --git a/ndb/src/common/util/testProperties/Makefile b/ndb/src/common/util/testProperties/Makefile new file mode 100644 index 00000000000..00b4465b69d --- /dev/null +++ b/ndb/src/common/util/testProperties/Makefile @@ -0,0 +1,12 @@ +include .defs.mk + +TYPE := + +BIN_TARGET := keso +BIN_TARGET_ARCHIVES := portlib general + +SOURCES := testProperties.cpp + +CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/util) + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/util/testProperties/testProperties.cpp b/ndb/src/common/util/testProperties/testProperties.cpp new file mode 100644 index 00000000000..4a2999b89c1 --- /dev/null +++ b/ndb/src/common/util/testProperties/testProperties.cpp @@ -0,0 +1,203 @@ +/* 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 "Properties.hpp" +#include <NdbOut.hpp> +#include <stdlib.h> +#include <string.h> + +#include "uucode.h" + +bool +writeToFile(const Properties & p, const char * fname, bool uu = true){ + Uint32 sz = p.getPackedSize(); + char * buffer = (char*)malloc(sz); + + FILE * f = fopen(fname, "wb"); + bool res = p.pack((Uint32*)buffer); + if(res != true){ + ndbout << "Error packing" << endl; + ndbout << "p.getPropertiesErrno() = " << p.getPropertiesErrno() << endl; + ndbout << "p.getOSErrno() = " << p.getOSErrno() << endl; + } + if(uu) + uuencode(buffer, sz, f); + else { + fwrite(buffer, 1, sz, f); + } + + fclose(f); + free(buffer); + return res; +} + +bool +readFromFile(Properties & p, const char *fname, bool uu = true){ + Uint32 sz = 30000; + char * buffer = (char*)malloc(sz); + FILE * f = fopen(fname, "rb"); + if(uu) + uudecode(f, buffer, sz); + else + fread(buffer, 1, sz, f); + fclose(f); + bool res = p.unpack((Uint32*)buffer, sz); + if(res != true){ + ndbout << "Error unpacking" << endl; + ndbout << "p.getPropertiesErrno() = " << p.getPropertiesErrno() << endl; + ndbout << "p.getOSErrno() = " << p.getOSErrno() << endl; + } + free(buffer); + return res; +} + +Property defs[] = { + Property("Rolf", 123) + ,Property("Keso", "Kent") +}; + + +void putALot(Properties & tmp){ + int i = 123; + tmp.put("LockPagesInMainMemory", i++); + tmp.put("SleepWhenIdle", i++); + tmp.put("NoOfSignalsToExecuteBetweenCommunicationInterfacePoll", i++); + tmp.put("TimeBetweenWatchDogCheck", i++); + tmp.put("StopOnError", i++); + + tmp.put("MaxNoOfConcurrentOperations", i++); + tmp.put("MaxNoOfConcurrentTransactions", i++); + tmp.put("MemorySpaceIndexes", i++); + tmp.put("MemorySpaceTuples", i++); + tmp.put("MemoryDiskPages", i++); + tmp.put("NoOfFreeDiskClusters", i++); + tmp.put("NoOfDiskClusters", i++); + + tmp.put("TimeToWaitAlive", i++); + tmp.put("HeartbeatIntervalDbDb", i++); + tmp.put("HeartbeatIntervalDbApi", i++); + tmp.put("TimeBetweenInactiveTransactionAbortCheck", i++); + + tmp.put("TimeBetweenLocalCheckpoints", i++); + tmp.put("TimeBetweenGlobalCheckpoints", i++); + tmp.put("NoOfFragmentLogFiles", i++); + tmp.put("NoOfConcurrentCheckpointsDuringRestart", i++); + tmp.put("TransactionInactiveTimeBeforeAbort", i++); + tmp.put("NoOfConcurrentProcessesHandleTakeover", i++); + + tmp.put("NoOfConcurrentCheckpointsAfterRestart", i++); + + tmp.put("NoOfDiskPagesToDiskDuringRestartTUP", i++); + tmp.put("NoOfDiskPagesToDiskAfterRestartTUP", i++); + tmp.put("NoOfDiskPagesToDiskDuringRestartACC", i++); + tmp.put("NoOfDiskPagesToDiskAfterRestartACC", i++); + + tmp.put("NoOfDiskClustersPerDiskFile", i++); + tmp.put("NoOfDiskFiles", i++); + + // Always found + tmp.put("NoOfReplicas", 33); + tmp.put("MaxNoOfAttributes", 34); + tmp.put("MaxNoOfTables", 35); +} + +int +main(void){ + Properties p; + + p.put("Kalle", 1); + p.put("Ank1", "anka"); + p.put("Ank2", "anka"); + p.put("Ank3", "anka"); + p.put("Ank4", "anka"); + putALot(p); + + //p.put(defs, 2); + Properties tmp; + tmp.put("Type", "TCP"); + tmp.put("OwnNodeId", 1); + tmp.put("RemoteNodeId", 2); + tmp.put("OwnHostName", "local"); + tmp.put("RemoteHostName", "remote"); + + tmp.put("SendSignalId", 1); + tmp.put("Compression", (Uint32)false); + tmp.put("Checksum", 1); + + tmp.put("SendBufferSize", 2000); + tmp.put("MaxReceiveSize", 1000); + + tmp.put("PortNumber", 1233); + putALot(tmp); + + p.put("Connection", 1, &tmp); + + p.put("NoOfConnections", 2); + p.put("NoOfConnection2", 2); + + p.put("kalle", 3); + p.put("anka", "kalle"); + + Properties p2; + p2.put("kalle", "anka"); + + p.put("prop", &p2); + + p.put("Connection", 2, &tmp); + + p.put("Connection", 3, &tmp); + + p.put("Connection", 4, &tmp); + /* + */ + + Uint32 a = 99; + const char * b; + const Properties * p3; + Properties * p4; + + bool bb = p.get("kalle", &a); + bool cc = p.get("anka", &b); + bool dd = p.get("prop", &p3); + if(p.getCopy("prop", &p4)) + delete p4; + + p2.put("p2", &p2); + + p.put("prop2", &p2); + /* */ + + p.print(stdout, "testing 1: "); + + writeToFile(p, "A_1"); + writeToFile(p, "B_1", false); + + Properties r1; + readFromFile(r1, "A_1"); + writeToFile(r1, "A_3"); + + //r1.print(stdout, "testing 2: "); + Properties r2; + readFromFile(r2, "A_1"); + writeToFile(r2, "A_4"); + + Properties r3; + readFromFile(r3, "B_1", false); + writeToFile(r3, "A_5"); + r3.print(stdout, "testing 3: "); + + return 0; +} diff --git a/ndb/src/common/util/testSimpleProperties/Makefile b/ndb/src/common/util/testSimpleProperties/Makefile new file mode 100644 index 00000000000..89d33fa8dd8 --- /dev/null +++ b/ndb/src/common/util/testSimpleProperties/Makefile @@ -0,0 +1,12 @@ +include .defs.mk + +TYPE := util + +BIN_TARGET := sp_test +BIN_TARGET_ARCHIVES := portlib general + +SOURCES := sp_test.cpp + +CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/util) + +include $(NDB_TOP)/Epilogue.mk diff --git a/ndb/src/common/util/testSimpleProperties/sp_test.cpp b/ndb/src/common/util/testSimpleProperties/sp_test.cpp new file mode 100644 index 00000000000..d6dbe2a1502 --- /dev/null +++ b/ndb/src/common/util/testSimpleProperties/sp_test.cpp @@ -0,0 +1,95 @@ +/* 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 "SimpleProperties.hpp" +#include <NdbOut.hpp> +#include <assert.h> +#include <stdio.h> + +Uint32 page[8192]; + +int writer(); +int reader(Uint32 *, Uint32 len); +int unpack(Uint32 *, Uint32 len); + +int main(){ + int len = writer(); + reader(page, len); + unpack(page, len); + + return 0; +} + +int +writer(){ + LinearWriter w(&page[0], 8192); + + w.first(); + w.add(1, 2); + w.add(7, 3); + w.add(3, "jonas"); + w.add(5, "0123456789"); + w.add(7, 4); + w.add(3, "e cool"); + w.add(5, "9876543210"); + + ndbout_c("WordsUsed = %d", w.getWordsUsed()); + + return w.getWordsUsed(); +} + +int +reader(Uint32 * pages, Uint32 len){ + SimplePropertiesLinearReader it(pages, len); + + it.printAll(ndbout); + return 0; +} + +struct Test { + Uint32 val1; + Uint32 val7; + char val3[100]; + Test() : val1(0xFFFFFFFF), val7(0xFFFFFFFF) { sprintf(val3, "bad");} +}; + +static const +SimpleProperties::SP2StructMapping +test_map [] = { + { 1, offsetof(Test, val1), SimpleProperties::Uint32Value, 0, ~0 }, + { 7, offsetof(Test, val7), SimpleProperties::Uint32Value, 0, ~0 }, + { 3, offsetof(Test, val3), SimpleProperties::StringValue, 0, sizeof(100) }, + { 5, 0, SimpleProperties::InvalidValue, 0, 0 } +}; + +static unsigned +test_map_sz = sizeof(test_map)/sizeof(test_map[0]); + +int +unpack(Uint32 * pages, Uint32 len){ + Test test; + SimplePropertiesLinearReader it(pages, len); + SimpleProperties::UnpackStatus status; + while((status = SimpleProperties::unpack(it, &test, test_map, test_map_sz, + true, false)) == SimpleProperties::Break){ + ndbout << "test.val1 = " << test.val1 << endl; + ndbout << "test.val7 = " << test.val7 << endl; + ndbout << "test.val3 = " << test.val3 << endl; + it.next(); + } + assert(status == SimpleProperties::Eof); + return 0; +} diff --git a/ndb/src/common/util/uucode.c b/ndb/src/common/util/uucode.c new file mode 100644 index 00000000000..f862d982204 --- /dev/null +++ b/ndb/src/common/util/uucode.c @@ -0,0 +1,235 @@ +/* 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 <stdio.h> +#include <string.h> + +/* ENC is the basic 1 character encoding function to make a char printing */ +/* DEC is single character decode */ +#define ENC(c) ((c) ? ((c) & 077) + ' ': '`') +#define DEC(c) (((c) - ' ') & 077) + +/* + * copy from in to out, encoding as you go along. + */ +void +uuencode(const char * data, int dataLen, FILE * out) +{ + int ch, n; + const char *p = data; + + fprintf(out, "begin\n"); + + while (dataLen > 0){ + n = dataLen > 45 ? 45 : dataLen; + dataLen -= n; + ch = ENC(n); + if (putc(ch, out) == EOF) + break; + for (; n > 0; n -= 3, p += 3) { + char p_0 = * p; + char p_1 = 0; + char p_2 = 0; + + if(n >= 2){ + p_1 = p[1]; + } + if(n >= 3){ + p_2 = p[2]; + } + + ch = p_0 >> 2; + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + ch = ((p_0 << 4) & 060) | ((p_1 >> 4) & 017); + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + ch = ((p_1 << 2) & 074) | ((p_2 >> 6) & 03); + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + ch = p_2 & 077; + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + } + if (putc('\n', out) == EOF) + break; + } + ch = ENC('\0'); + putc(ch, out); + putc('\n', out); + fprintf(out, "end\n"); +} + +int +uudecode(FILE * input, char * outBuf, int bufLen){ + int n; + char ch, *p, returnCode; + char buf[255]; + + returnCode = 0; + /* search for header line */ + do { + if (!fgets(buf, sizeof(buf), input)) { + return 1; + } + } while (strncmp(buf, "begin", 5)); + + /* for each input line */ + for (;;) { + if (!fgets(p = buf, sizeof(buf), input)) { + return 1; + } + /* + * `n' is used to avoid writing out all the characters + * at the end of the file. + */ + if ((n = DEC(*p)) <= 0) + break; + if(n >= bufLen){ + returnCode = 1; + break; + } + for (++p; n > 0; p += 4, n -= 3) + if (n >= 3) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; + } else { + if (n >= 1) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; + } + if (n >= 2) { + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; + } + if (n >= 3) { + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; + } + } + } + if (!fgets(buf, sizeof(buf), input) || strcmp(buf, "end\n")) { + return 1; + } + return returnCode; +} + +int +uuencode_mem(char * dst, const char * data, int dataLen) +{ + int sz = 0; + + int ch, n; + const char *p = data; + + while (dataLen > 0){ + n = dataLen > 45 ? 45 : dataLen; + dataLen -= n; + ch = ENC(n); + * dst = ch; dst++; sz++; + for (; n > 0; n -= 3, p += 3) { + char p_0 = * p; + char p_1 = 0; + char p_2 = 0; + + if(n >= 2){ + p_1 = p[1]; + } + if(n >= 3){ + p_2 = p[2]; + } + + ch = p_0 >> 2; + ch = ENC(ch); + * dst = ch; dst++; sz++; + + ch = ((p_0 << 4) & 060) | ((p_1 >> 4) & 017); + ch = ENC(ch); + * dst = ch; dst++; sz++; + + ch = ((p_1 << 2) & 074) | ((p_2 >> 6) & 03); + ch = ENC(ch); + * dst = ch; dst++; sz++; + + ch = p_2 & 077; + ch = ENC(ch); + * dst = ch; dst++; sz++; + } + + * dst = '\n'; dst++; sz++; + } + ch = ENC('\0'); + * dst = ch; dst++; sz++; + + * dst = '\n'; dst++; sz++; + * dst = 0; dst++; sz++; + + return sz; +} + +int +uudecode_mem(char * outBuf, int bufLen, const char * src){ + int n; + char ch; + int sz = 0; + const char * p = src; + + /* + * `n' is used to avoid writing out all the characters + * at the end of the file. + */ + if ((n = DEC(*p)) <= 0) + return 0; + if(n >= bufLen){ + return -1; + } + for (++p; n > 0; p += 4, n -= 3){ + if (n >= 3) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; sz++; + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; sz++; + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; sz++; + } else { + if (n >= 1) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; sz++; + } + if (n >= 2) { + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; sz++; + } + if (n >= 3) { + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; sz++; + } + } + } + return sz; +} + + + diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c new file mode 100644 index 00000000000..d220a06850a --- /dev/null +++ b/ndb/src/common/util/version.c @@ -0,0 +1,224 @@ +/* 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 <stdio.h> +#include <string.h> +#include <ndb_types.h> +#include <ndb_version.h> +#include <version.h> + +Uint32 getMajor(Uint32 version) { + return (version >> 16) & 0xFF; +} + +Uint32 getMinor(Uint32 version) { + return (version >> 8) & 0xFF; +} + +Uint32 getBuild(Uint32 version) { + return (version >> 0) & 0xFF; +} + +Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build) { + return MAKE_VERSION(major, minor, build); + +} + +char * getVersionString(Uint32 version, char * status) { + char buff[100]; + snprintf(buff, sizeof(buff), + "Version %d.%d.%d (%s)", + getMajor(version), + getMinor(version), + getBuild(version), + status); + + return strdup(buff); +} + +typedef enum { + UG_Null, + UG_Range, + UG_Exact +} UG_MatchType; + +struct NdbUpGradeCompatible { + Uint32 ownVersion; + Uint32 otherVersion; + UG_MatchType matchType; +}; + +//#define TEST_VERSION + +#ifndef TEST_VERSION +struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { + { NDB_VERSION_D , MAKE_VERSION(NDB_VERSION_MAJOR,NDB_VERSION_MINOR,2), UG_Range }, + { 0, 0, UG_Null } +}; + +struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = { + { 0, 0, UG_Null } +}; + +void ndbSetOwnVersion() {} + +#else // testing purposes + +struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { + { MAKE_VERSION(4,1,5), MAKE_VERSION(4,1,0), UG_Range }, + { MAKE_VERSION(3,6,9), MAKE_VERSION(3,6,1), UG_Range }, + { MAKE_VERSION(3,6,2), MAKE_VERSION(3,6,1), UG_Range }, + { MAKE_VERSION(3,5,7), MAKE_VERSION(3,5,0), UG_Range }, + { MAKE_VERSION(3,5,1), MAKE_VERSION(3,5,0), UG_Range }, + { NDB_VERSION_D , MAKE_VERSION(NDB_VERSION_MAJOR,NDB_VERSION_MINOR,2), UG_Range }, + { 0, 0, UG_Null } +}; + +struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = { + { MAKE_VERSION(4,1,5), MAKE_VERSION(3,6,9), UG_Exact }, + { MAKE_VERSION(3,6,2), MAKE_VERSION(3,5,7), UG_Exact }, + { MAKE_VERSION(3,5,1), NDB_VERSION_D , UG_Exact }, + { 0, 0, UG_Null } +}; + + +Uint32 ndbOwnVersionTesting = 0; +void +ndbSetOwnVersion() { + char buf[256]; + if (NdbEnv_GetEnv("NDB_SETVERSION", buf, sizeof(buf))) { + Uint32 _v1,_v2,_v3; + if (sscanf(buf, "%u.%u.%u", &_v1, &_v2, &_v3) == 3) { + ndbOwnVersionTesting = MAKE_VERSION(_v1,_v2,_v3); + ndbout_c("Testing: Version set to 0x%x", ndbOwnVersionTesting); + } + } +} + +#endif + +void ndbPrintVersion() +{ + printf("Version: %u.%u.%u\n", + getMajor(ndbGetOwnVersion()), + getMinor(ndbGetOwnVersion()), + getBuild(ndbGetOwnVersion())); +} + +Uint32 +ndbGetOwnVersion() +{ +#ifndef TEST_VERSION + return NDB_VERSION_D; +#else // testing purposes + if (ndbOwnVersionTesting == 0) + return NDB_VERSION_D; + else + return ndbOwnVersionTesting; +#endif +} + +int +ndbSearchUpgradeCompatibleTable(Uint32 ownVersion, Uint32 otherVersion, + struct NdbUpGradeCompatible table[]) +{ + int i; + for (i = 0; table[i].ownVersion != 0 && table[i].otherVersion != 0; i++) { + if (table[i].ownVersion == ownVersion || + table[i].ownVersion == ~0) { + switch (table[i].matchType) { + case UG_Range: + if (otherVersion >= table[i].otherVersion){ + return 1; + } + break; + case UG_Exact: + if (otherVersion == table[i].otherVersion){ + return 1; + } + break; + default: + break; + } + } + } + return 0; +} + +int +ndbCompatible(Uint32 ownVersion, Uint32 otherVersion, struct NdbUpGradeCompatible table[]) +{ + if (otherVersion >= ownVersion) { + return 1; + } + return ndbSearchUpgradeCompatibleTable(ownVersion, otherVersion, table); +} + +int +ndbCompatible_full(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible(ownVersion, otherVersion, ndbCompatibleTable_full); +} + +int +ndbCompatible_upgrade(Uint32 ownVersion, Uint32 otherVersion) +{ + if (ndbCompatible_full(ownVersion, otherVersion)) + return 1; + return ndbCompatible(ownVersion, otherVersion, ndbCompatibleTable_upgrade); +} + +int +ndbCompatible_mgmt_ndb(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} + +int +ndbCompatible_mgmt_api(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} + +int +ndbCompatible_ndb_mgmt(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_full(ownVersion, otherVersion); +} + +int +ndbCompatible_api_mgmt(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_full(ownVersion, otherVersion); +} + +int +ndbCompatible_api_ndb(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_full(ownVersion, otherVersion); +} + +int +ndbCompatible_ndb_api(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} + +int +ndbCompatible_ndb_ndb(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} |