summaryrefslogtreecommitdiff
path: root/ndb/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/src/common')
-rw-r--r--ndb/src/common/Makefile15
-rw-r--r--ndb/src/common/debugger/BlockNames.cpp39
-rw-r--r--ndb/src/common/debugger/DebuggerNames.cpp154
-rw-r--r--ndb/src/common/debugger/EventLogger.cpp1454
-rw-r--r--ndb/src/common/debugger/GrepError.cpp133
-rw-r--r--ndb/src/common/debugger/LogLevel.cpp29
-rw-r--r--ndb/src/common/debugger/Makefile11
-rw-r--r--ndb/src/common/debugger/SignalLoggerManager.cpp513
-rw-r--r--ndb/src/common/debugger/signaldata/AccLock.cpp75
-rw-r--r--ndb/src/common/debugger/signaldata/AlterIndx.cpp35
-rw-r--r--ndb/src/common/debugger/signaldata/AlterTab.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/AlterTable.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/AlterTrig.cpp51
-rw-r--r--ndb/src/common/debugger/signaldata/BackupImpl.cpp142
-rw-r--r--ndb/src/common/debugger/signaldata/BackupSignalData.cpp129
-rw-r--r--ndb/src/common/debugger/signaldata/CloseComReqConf.cpp53
-rw-r--r--ndb/src/common/debugger/signaldata/ContinueB.cpp36
-rw-r--r--ndb/src/common/debugger/signaldata/CopyGCI.cpp58
-rw-r--r--ndb/src/common/debugger/signaldata/CreateEvnt.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/CreateFragmentation.cpp56
-rw-r--r--ndb/src/common/debugger/signaldata/CreateIndx.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/CreateTrig.cpp120
-rw-r--r--ndb/src/common/debugger/signaldata/DictTabInfo.cpp153
-rw-r--r--ndb/src/common/debugger/signaldata/DihContinueB.cpp217
-rw-r--r--ndb/src/common/debugger/signaldata/DihSwitchReplicaReq.cpp48
-rw-r--r--ndb/src/common/debugger/signaldata/DisconnectRep.cpp30
-rw-r--r--ndb/src/common/debugger/signaldata/DropIndx.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/DropTab.cpp50
-rw-r--r--ndb/src/common/debugger/signaldata/DropTrig.cpp89
-rw-r--r--ndb/src/common/debugger/signaldata/FailRep.cpp31
-rw-r--r--ndb/src/common/debugger/signaldata/FireTrigOrd.cpp56
-rw-r--r--ndb/src/common/debugger/signaldata/FsAppendReq.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/FsCloseReq.cpp40
-rw-r--r--ndb/src/common/debugger/signaldata/FsConf.cpp33
-rw-r--r--ndb/src/common/debugger/signaldata/FsOpenReq.cpp59
-rw-r--r--ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp85
-rw-r--r--ndb/src/common/debugger/signaldata/FsRef.cpp75
-rw-r--r--ndb/src/common/debugger/signaldata/GCPSave.cpp78
-rwxr-xr-xndb/src/common/debugger/signaldata/IndxAttrInfo.cpp31
-rwxr-xr-xndb/src/common/debugger/signaldata/IndxKeyInfo.cpp31
-rw-r--r--ndb/src/common/debugger/signaldata/LCP.cpp88
-rw-r--r--ndb/src/common/debugger/signaldata/LqhFrag.cpp61
-rw-r--r--ndb/src/common/debugger/signaldata/LqhKey.cpp161
-rw-r--r--ndb/src/common/debugger/signaldata/LqhTrans.cpp40
-rw-r--r--ndb/src/common/debugger/signaldata/Makefile32
-rw-r--r--ndb/src/common/debugger/signaldata/MasterLCP.cpp87
-rw-r--r--ndb/src/common/debugger/signaldata/NFCompleteRep.cpp44
-rw-r--r--ndb/src/common/debugger/signaldata/NdbSttor.cpp50
-rw-r--r--ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp38
-rw-r--r--ndb/src/common/debugger/signaldata/PackedSignal.cpp104
-rw-r--r--ndb/src/common/debugger/signaldata/PrepDropTab.cpp50
-rw-r--r--ndb/src/common/debugger/signaldata/PrepFailReqRef.cpp53
-rw-r--r--ndb/src/common/debugger/signaldata/ScanTab.cpp163
-rw-r--r--ndb/src/common/debugger/signaldata/SignalDataPrint.cpp254
-rw-r--r--ndb/src/common/debugger/signaldata/SignalDroppedRep.cpp34
-rw-r--r--ndb/src/common/debugger/signaldata/SignalNames.cpp673
-rw-r--r--ndb/src/common/debugger/signaldata/StartRec.cpp52
-rw-r--r--ndb/src/common/debugger/signaldata/SumaImpl.cpp167
-rw-r--r--ndb/src/common/debugger/signaldata/SystemError.cpp41
-rw-r--r--ndb/src/common/debugger/signaldata/TcIndx.cpp159
-rw-r--r--ndb/src/common/debugger/signaldata/TcKeyConf.cpp59
-rw-r--r--ndb/src/common/debugger/signaldata/TcKeyRef.cpp28
-rw-r--r--ndb/src/common/debugger/signaldata/TcKeyReq.cpp114
-rw-r--r--ndb/src/common/debugger/signaldata/TcRollbackRep.cpp28
-rw-r--r--ndb/src/common/debugger/signaldata/TrigAttrInfo.cpp53
-rw-r--r--ndb/src/common/debugger/signaldata/TupAccess.cpp131
-rw-r--r--ndb/src/common/debugger/signaldata/TupCommit.cpp28
-rw-r--r--ndb/src/common/debugger/signaldata/TupKey.cpp50
-rw-r--r--ndb/src/common/debugger/signaldata/TuxMaint.cpp45
-rw-r--r--ndb/src/common/debugger/signaldata/UtilDelete.cpp65
-rw-r--r--ndb/src/common/debugger/signaldata/UtilExecute.cpp59
-rw-r--r--ndb/src/common/debugger/signaldata/UtilLock.cpp158
-rw-r--r--ndb/src/common/debugger/signaldata/UtilPrepare.cpp64
-rw-r--r--ndb/src/common/debugger/signaldata/UtilSequence.cpp67
-rw-r--r--ndb/src/common/debugger/signaldata/print.awk55
-rw-r--r--ndb/src/common/editline/MANIFEST15
-rw-r--r--ndb/src/common/editline/Makefile18
-rw-r--r--ndb/src/common/editline/README53
-rw-r--r--ndb/src/common/editline/complete.c211
-rw-r--r--ndb/src/common/editline/editline.3178
-rw-r--r--ndb/src/common/editline/editline.c1514
-rw-r--r--ndb/src/common/editline/editline_internal.h47
-rw-r--r--ndb/src/common/editline/editline_win32.c33
-rw-r--r--ndb/src/common/editline/sysunix.c143
-rw-r--r--ndb/src/common/editline/test/Makefile10
-rw-r--r--ndb/src/common/editline/test/testit.c59
-rw-r--r--ndb/src/common/editline/unix.h26
-rw-r--r--ndb/src/common/logger/ConsoleLogHandler.cpp68
-rw-r--r--ndb/src/common/logger/FileLogHandler.cpp241
-rw-r--r--ndb/src/common/logger/LogHandler.cpp142
-rw-r--r--ndb/src/common/logger/LogHandlerList.cpp183
-rw-r--r--ndb/src/common/logger/LogHandlerList.hpp93
-rw-r--r--ndb/src/common/logger/Logger.cpp358
-rw-r--r--ndb/src/common/logger/Makefile27
-rw-r--r--ndb/src/common/logger/SysLogHandler.cpp159
-rw-r--r--ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp165
-rw-r--r--ndb/src/common/logger/listtest/LogHandlerListUnitTest.hpp40
-rw-r--r--ndb/src/common/logger/listtest/Makefile14
-rw-r--r--ndb/src/common/logger/loggertest/LoggerUnitTest.cpp201
-rw-r--r--ndb/src/common/logger/loggertest/LoggerUnitTest.hpp49
-rw-r--r--ndb/src/common/logger/loggertest/Makefile16
-rw-r--r--ndb/src/common/mgmcommon/Config.cpp255
-rw-r--r--ndb/src/common/mgmcommon/Config.hpp86
-rw-r--r--ndb/src/common/mgmcommon/ConfigInfo.cpp2629
-rw-r--r--ndb/src/common/mgmcommon/ConfigInfo.hpp120
-rw-r--r--ndb/src/common/mgmcommon/ConfigRetriever.cpp514
-rw-r--r--ndb/src/common/mgmcommon/IPCConfig.cpp336
-rw-r--r--ndb/src/common/mgmcommon/InitConfigFileParser.cpp544
-rw-r--r--ndb/src/common/mgmcommon/InitConfigFileParser.hpp142
-rw-r--r--ndb/src/common/mgmcommon/LocalConfig.cpp308
-rw-r--r--ndb/src/common/mgmcommon/LocalConfig.hpp83
-rw-r--r--ndb/src/common/mgmcommon/Makefile26
-rw-r--r--ndb/src/common/mgmcommon/NdbConfig.c61
-rw-r--r--ndb/src/common/mgmcommon/printConfig/Makefile14
-rw-r--r--ndb/src/common/mgmcommon/printConfig/printConfig.cpp89
-rw-r--r--ndb/src/common/portlib/Makefile43
-rw-r--r--ndb/src/common/portlib/memtest/Makefile12
-rw-r--r--ndb/src/common/portlib/memtest/memtest.c245
-rw-r--r--ndb/src/common/portlib/memtest/munmaptest/Makefile14
-rw-r--r--ndb/src/common/portlib/memtest/munmaptest/munmaptest.cpp251
-rw-r--r--ndb/src/common/portlib/mmstest/mmslist.cpp103
-rw-r--r--ndb/src/common/portlib/mmstest/mmstest.cpp76
-rw-r--r--ndb/src/common/portlib/ose/Makefile31
-rw-r--r--ndb/src/common/portlib/ose/NdbCondition.c244
-rw-r--r--ndb/src/common/portlib/ose/NdbConditionOSE.h103
-rw-r--r--ndb/src/common/portlib/ose/NdbEnv.c55
-rw-r--r--ndb/src/common/portlib/ose/NdbHost.c55
-rw-r--r--ndb/src/common/portlib/ose/NdbMem.c183
-rw-r--r--ndb/src/common/portlib/ose/NdbMem_SoftOse.cpp53
-rw-r--r--ndb/src/common/portlib/ose/NdbMutex.c86
-rw-r--r--ndb/src/common/portlib/ose/NdbOut.cpp99
-rw-r--r--ndb/src/common/portlib/ose/NdbSleep.c36
-rw-r--r--ndb/src/common/portlib/ose/NdbTCP.c38
-rw-r--r--ndb/src/common/portlib/ose/NdbThread.c184
-rw-r--r--ndb/src/common/portlib/ose/NdbTick.c64
-rw-r--r--ndb/src/common/portlib/test/Makefile15
-rw-r--r--ndb/src/common/portlib/test/NdbPortLibTest.cpp621
-rw-r--r--ndb/src/common/portlib/unix/Makefile27
-rw-r--r--ndb/src/common/portlib/unix/NdbCondition.c179
-rw-r--r--ndb/src/common/portlib/unix/NdbDaemon.c170
-rw-r--r--ndb/src/common/portlib/unix/NdbEnv.c34
-rw-r--r--ndb/src/common/portlib/unix/NdbHost.c34
-rw-r--r--ndb/src/common/portlib/unix/NdbMem.c76
-rw-r--r--ndb/src/common/portlib/unix/NdbMutex.c93
-rw-r--r--ndb/src/common/portlib/unix/NdbSleep.c48
-rw-r--r--ndb/src/common/portlib/unix/NdbTCP.c60
-rw-r--r--ndb/src/common/portlib/unix/NdbThread.c119
-rw-r--r--ndb/src/common/portlib/unix/NdbTick.c110
-rw-r--r--ndb/src/common/portlib/win32/Makefile30
-rw-r--r--ndb/src/common/portlib/win32/NdbCondition.c184
-rw-r--r--ndb/src/common/portlib/win32/NdbDaemon.c44
-rw-r--r--ndb/src/common/portlib/win32/NdbEnv.c33
-rw-r--r--ndb/src/common/portlib/win32/NdbHost.c53
-rw-r--r--ndb/src/common/portlib/win32/NdbMem.c237
-rw-r--r--ndb/src/common/portlib/win32/NdbMutex.c78
-rw-r--r--ndb/src/common/portlib/win32/NdbSleep.c35
-rw-r--r--ndb/src/common/portlib/win32/NdbTCP.c39
-rw-r--r--ndb/src/common/portlib/win32/NdbThread.c118
-rw-r--r--ndb/src/common/portlib/win32/NdbTick.c64
-rw-r--r--ndb/src/common/transporter/Makefile62
-rw-r--r--ndb/src/common/transporter/OSE_Receiver.cpp360
-rw-r--r--ndb/src/common/transporter/OSE_Receiver.hpp119
-rw-r--r--ndb/src/common/transporter/OSE_Signals.hpp144
-rw-r--r--ndb/src/common/transporter/OSE_Transporter.cpp487
-rw-r--r--ndb/src/common/transporter/OSE_Transporter.hpp158
-rw-r--r--ndb/src/common/transporter/Packer.cpp502
-rw-r--r--ndb/src/common/transporter/Packer.hpp85
-rw-r--r--ndb/src/common/transporter/SCI_Transporter.cpp1006
-rw-r--r--ndb/src/common/transporter/SCI_Transporter.hpp390
-rw-r--r--ndb/src/common/transporter/SHM_Buffer.hpp217
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.cpp238
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.hpp156
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.unix.cpp179
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.win32.cpp172
-rw-r--r--ndb/src/common/transporter/SendBuffer.cpp89
-rw-r--r--ndb/src/common/transporter/SendBuffer.hpp191
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.cpp603
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.hpp290
-rw-r--r--ndb/src/common/transporter/Transporter.cpp147
-rw-r--r--ndb/src/common/transporter/Transporter.hpp177
-rw-r--r--ndb/src/common/transporter/TransporterInternalDefinitions.hpp323
-rw-r--r--ndb/src/common/transporter/TransporterRegistry.cpp1188
-rw-r--r--ndb/src/common/transporter/basictest/Makefile15
-rw-r--r--ndb/src/common/transporter/basictest/basicTransporterTest.cpp536
-rw-r--r--ndb/src/common/transporter/buddy.cpp328
-rw-r--r--ndb/src/common/transporter/buddy.hpp173
-rw-r--r--ndb/src/common/transporter/failoverSCI/Makefile18
-rw-r--r--ndb/src/common/transporter/failoverSCI/failoverSCI.cpp866
-rw-r--r--ndb/src/common/transporter/perftest/Makefile15
-rw-r--r--ndb/src/common/transporter/perftest/perfTransporterTest.cpp774
-rw-r--r--ndb/src/common/transporter/priotest/Makefile15
-rw-r--r--ndb/src/common/transporter/priotest/prioOSE/Makefile17
-rw-r--r--ndb/src/common/transporter/priotest/prioSCI/Makefile17
-rw-r--r--ndb/src/common/transporter/priotest/prioSCI/prioSCI.cpp29
-rw-r--r--ndb/src/common/transporter/priotest/prioSHM/Makefile13
-rw-r--r--ndb/src/common/transporter/priotest/prioSHM/prioSHM.cpp26
-rw-r--r--ndb/src/common/transporter/priotest/prioTCP/Makefile13
-rw-r--r--ndb/src/common/transporter/priotest/prioTCP/prioTCP.cpp26
-rw-r--r--ndb/src/common/transporter/priotest/prioTransporterTest.cpp768
-rw-r--r--ndb/src/common/transporter/priotest/prioTransporterTest.hpp35
-rw-r--r--ndb/src/common/util/Base64.cpp111
-rw-r--r--ndb/src/common/util/BaseString.cpp418
-rw-r--r--ndb/src/common/util/File.cpp207
-rw-r--r--ndb/src/common/util/InputStream.cpp61
-rw-r--r--ndb/src/common/util/Makefile36
-rw-r--r--ndb/src/common/util/NdbErrHnd.cpp493
-rw-r--r--ndb/src/common/util/NdbOut.cpp175
-rw-r--r--ndb/src/common/util/NdbSqlUtil.cpp351
-rw-r--r--ndb/src/common/util/OutputStream.cpp98
-rw-r--r--ndb/src/common/util/Parser.cpp349
-rw-r--r--ndb/src/common/util/Properties.cpp1019
-rw-r--r--ndb/src/common/util/SimpleProperties.cpp509
-rw-r--r--ndb/src/common/util/SocketServer.cpp307
-rw-r--r--ndb/src/common/util/filetest/FileUnitTest.cpp238
-rw-r--r--ndb/src/common/util/filetest/FileUnitTest.hpp41
-rw-r--r--ndb/src/common/util/filetest/Makefile14
-rw-r--r--ndb/src/common/util/getarg.3315
-rw-r--r--ndb/src/common/util/getarg.3.ps458
-rw-r--r--ndb/src/common/util/getarg.c599
-rw-r--r--ndb/src/common/util/getarg.cat3237
-rw-r--r--ndb/src/common/util/md5_hash.cpp235
-rw-r--r--ndb/src/common/util/random.c292
-rw-r--r--ndb/src/common/util/socket_io.cpp284
-rw-r--r--ndb/src/common/util/strdup.c28
-rw-r--r--ndb/src/common/util/strlcat.c52
-rw-r--r--ndb/src/common/util/strlcpy.c65
-rw-r--r--ndb/src/common/util/testProperties/Makefile12
-rw-r--r--ndb/src/common/util/testProperties/testProperties.cpp203
-rw-r--r--ndb/src/common/util/testSimpleProperties/Makefile12
-rw-r--r--ndb/src/common/util/testSimpleProperties/sp_test.cpp95
-rw-r--r--ndb/src/common/util/uucode.c235
-rw-r--r--ndb/src/common/util/version.c224
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 &param, 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 &param, 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 &param, 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 &section,
+ const BaseString &param,
+ 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 &section,
+ const BaseString &param,
+ 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, &section)) {
+ Properties newsection;
+ newsection.setCaseInsensitiveNames(true);
+ m_info.put(param._section, &newsection);
+ }
+
+ // Get copy of section
+ m_info.getCopy(param._section, &section);
+
+ // 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, &micros);
+ error = SendInterrupt(sdOne,localAdapterNo,localNodeId1,remoteNodeId1, DATA_TRANSFER_READY);
+ NdbTick_CurrentMicrosecond(&secs, &micros2);
+ 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,&micro);
+ 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,&micro);
+ 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);
+}