1 /* Copyright (c) 2003-2007 MySQL AB
2    Use is subject to license terms
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */
16 
17 #include "Cmvmi.hpp"
18 
19 #include <Configuration.hpp>
20 #include <kernel_types.h>
21 #include <TransporterRegistry.hpp>
22 #include <NdbOut.hpp>
23 #include <NdbMem.h>
24 
25 #include <SignalLoggerManager.hpp>
26 #include <FastScheduler.hpp>
27 
28 #define DEBUG(x) { ndbout << "CMVMI::" << x << endl; }
29 
30 #include <signaldata/TestOrd.hpp>
31 #include <signaldata/EventReport.hpp>
32 #include <signaldata/TamperOrd.hpp>
33 #include <signaldata/StartOrd.hpp>
34 #include <signaldata/CloseComReqConf.hpp>
35 #include <signaldata/SetLogLevelOrd.hpp>
36 #include <signaldata/EventSubscribeReq.hpp>
37 #include <signaldata/DumpStateOrd.hpp>
38 #include <signaldata/DisconnectRep.hpp>
39 
40 #include <EventLogger.hpp>
41 #include <TimeQueue.hpp>
42 
43 #include <NdbSleep.h>
44 #include <SafeCounter.hpp>
45 
46 // Used here only to print event reports on stdout/console.
47 EventLogger g_eventLogger;
48 extern int simulate_error_during_shutdown;
49 
Cmvmi(Block_context & ctx)50 Cmvmi::Cmvmi(Block_context& ctx) :
51   SimulatedBlock(CMVMI, ctx)
52   ,subscribers(subscriberPool)
53 {
54   BLOCK_CONSTRUCTOR(Cmvmi);
55 
56   Uint32 long_sig_buffer_size;
57   const ndb_mgm_configuration_iterator * p =
58     m_ctx.m_config.getOwnConfigIterator();
59   ndbrequire(p != 0);
60 
61   ndb_mgm_get_int_parameter(p, CFG_DB_LONG_SIGNAL_BUFFER,
62 			    &long_sig_buffer_size);
63 
64   long_sig_buffer_size= long_sig_buffer_size / 256;
65   g_sectionSegmentPool.setSize(long_sig_buffer_size,
66                                false,true,true,CFG_DB_LONG_SIGNAL_BUFFER);
67 
68   // Add received signals
69   addRecSignal(GSN_CONNECT_REP, &Cmvmi::execCONNECT_REP);
70   addRecSignal(GSN_DISCONNECT_REP, &Cmvmi::execDISCONNECT_REP);
71 
72   addRecSignal(GSN_NDB_TAMPER,  &Cmvmi::execNDB_TAMPER, true);
73   addRecSignal(GSN_SET_LOGLEVELORD,  &Cmvmi::execSET_LOGLEVELORD);
74   addRecSignal(GSN_EVENT_REP,  &Cmvmi::execEVENT_REP);
75   addRecSignal(GSN_STTOR,  &Cmvmi::execSTTOR);
76   addRecSignal(GSN_READ_CONFIG_REQ,  &Cmvmi::execREAD_CONFIG_REQ);
77   addRecSignal(GSN_CLOSE_COMREQ,  &Cmvmi::execCLOSE_COMREQ);
78   addRecSignal(GSN_ENABLE_COMORD,  &Cmvmi::execENABLE_COMORD);
79   addRecSignal(GSN_OPEN_COMREQ,  &Cmvmi::execOPEN_COMREQ);
80   addRecSignal(GSN_TEST_ORD,  &Cmvmi::execTEST_ORD);
81 
82   addRecSignal(GSN_TAMPER_ORD,  &Cmvmi::execTAMPER_ORD);
83   addRecSignal(GSN_STOP_ORD,  &Cmvmi::execSTOP_ORD);
84   addRecSignal(GSN_START_ORD,  &Cmvmi::execSTART_ORD);
85   addRecSignal(GSN_EVENT_SUBSCRIBE_REQ,
86                &Cmvmi::execEVENT_SUBSCRIBE_REQ);
87 
88   addRecSignal(GSN_DUMP_STATE_ORD, &Cmvmi::execDUMP_STATE_ORD);
89 
90   addRecSignal(GSN_TESTSIG, &Cmvmi::execTESTSIG);
91   addRecSignal(GSN_NODE_START_REP, &Cmvmi::execNODE_START_REP, true);
92 
93   subscriberPool.setSize(5);
94 
95   const ndb_mgm_configuration_iterator * db = m_ctx.m_config.getOwnConfigIterator();
96   for(unsigned j = 0; j<LogLevel::LOGLEVEL_CATEGORIES; j++){
97     Uint32 logLevel;
98     if(!ndb_mgm_get_int_parameter(db, CFG_MIN_LOGLEVEL+j, &logLevel)){
99       clogLevel.setLogLevel((LogLevel::EventCategory)j,
100 			    logLevel);
101     }
102   }
103 
104   ndb_mgm_configuration_iterator * iter = m_ctx.m_config.getClusterConfigIterator();
105   for(ndb_mgm_first(iter); ndb_mgm_valid(iter); ndb_mgm_next(iter)){
106     jam();
107     Uint32 nodeId;
108     Uint32 nodeType;
109 
110     ndbrequire(!ndb_mgm_get_int_parameter(iter,CFG_NODE_ID, &nodeId));
111     ndbrequire(!ndb_mgm_get_int_parameter(iter,CFG_TYPE_OF_SECTION,&nodeType));
112 
113     switch(nodeType){
114     case NodeInfo::DB:
115       c_dbNodes.set(nodeId);
116       break;
117     case NodeInfo::API:
118     case NodeInfo::MGM:
119       break;
120     default:
121       ndbrequire(false);
122     }
123     setNodeInfo(nodeId).m_type = nodeType;
124   }
125 
126   setNodeInfo(getOwnNodeId()).m_connected = true;
127   setNodeInfo(getOwnNodeId()).m_version = ndbGetOwnVersion();
128 }
129 
~Cmvmi()130 Cmvmi::~Cmvmi()
131 {
132   m_shared_page_pool.clear();
133 }
134 
135 #ifdef ERROR_INSERT
136 NodeBitmask c_error_9000_nodes_mask;
137 extern Uint32 MAX_RECEIVED_SIGNALS;
138 #endif
139 
execNDB_TAMPER(Signal * signal)140 void Cmvmi::execNDB_TAMPER(Signal* signal)
141 {
142   jamEntry();
143   SET_ERROR_INSERT_VALUE(signal->theData[0]);
144   if(ERROR_INSERTED(9999)){
145     CRASH_INSERTION(9999);
146   }
147 
148   if(ERROR_INSERTED(9998)){
149     while(true) NdbSleep_SecSleep(1);
150   }
151 
152   if(ERROR_INSERTED(9997)){
153     ndbrequire(false);
154   }
155 
156 #ifndef NDB_WIN32
157   if(ERROR_INSERTED(9996)){
158     simulate_error_during_shutdown= SIGSEGV;
159     ndbrequire(false);
160   }
161 
162   if(ERROR_INSERTED(9995)){
163     simulate_error_during_shutdown= SIGSEGV;
164     kill(getpid(), SIGABRT);
165   }
166 #endif
167 
168 #ifdef ERROR_INSERT
169   if (signal->theData[0] == 9003)
170   {
171     if (MAX_RECEIVED_SIGNALS < 1024)
172     {
173       MAX_RECEIVED_SIGNALS = 1024;
174     }
175     else
176     {
177       MAX_RECEIVED_SIGNALS = 1 + (rand() % 128);
178     }
179     ndbout_c("MAX_RECEIVED_SIGNALS: %d", MAX_RECEIVED_SIGNALS);
180     CLEAR_ERROR_INSERT_VALUE;
181   }
182 #endif
183 }//execNDB_TAMPER()
184 
execSET_LOGLEVELORD(Signal * signal)185 void Cmvmi::execSET_LOGLEVELORD(Signal* signal)
186 {
187   SetLogLevelOrd * const llOrd = (SetLogLevelOrd *)&signal->theData[0];
188   LogLevel::EventCategory category;
189   Uint32 level;
190   jamEntry();
191 
192   for(unsigned int i = 0; i<llOrd->noOfEntries; i++){
193     category = (LogLevel::EventCategory)(llOrd->theData[i] >> 16);
194     level = llOrd->theData[i] & 0xFFFF;
195 
196     clogLevel.setLogLevel(category, level);
197   }
198 }//execSET_LOGLEVELORD()
199 
execEVENT_REP(Signal * signal)200 void Cmvmi::execEVENT_REP(Signal* signal)
201 {
202   //-----------------------------------------------------------------------
203   // This message is sent to report any types of events in NDB.
204   // Based on the log level they will be either ignored or
205   // reported. Currently they are printed, but they will be
206   // transferred to the management server for further distribution
207   // to the graphical management interface.
208   //-----------------------------------------------------------------------
209   EventReport * const eventReport = (EventReport *)&signal->theData[0];
210   Ndb_logevent_type eventType = eventReport->getEventType();
211   Uint32 nodeId= eventReport->getNodeId();
212   if (nodeId == 0)
213   {
214     nodeId= refToNode(signal->getSendersBlockRef());
215     eventReport->setNodeId(nodeId);
216   }
217 
218   jamEntry();
219 
220   /**
221    * If entry is not found
222    */
223   Uint32 threshold;
224   LogLevel::EventCategory eventCategory;
225   Logger::LoggerLevel severity;
226   EventLoggerBase::EventTextFunction textF;
227   if (EventLoggerBase::event_lookup(eventType,eventCategory,threshold,severity,textF))
228     return;
229 
230   SubscriberPtr ptr;
231   for(subscribers.first(ptr); ptr.i != RNIL; subscribers.next(ptr)){
232     if(ptr.p->logLevel.getLogLevel(eventCategory) < threshold){
233       continue;
234     }
235 
236     sendSignal(ptr.p->blockRef, GSN_EVENT_REP, signal, signal->length(), JBB);
237   }
238 
239   if(clogLevel.getLogLevel(eventCategory) < threshold){
240     return;
241   }
242 
243   // Print the event info
244   g_eventLogger.log(eventReport->getEventType(), signal->theData);
245 
246   return;
247 }//execEVENT_REP()
248 
249 void
execEVENT_SUBSCRIBE_REQ(Signal * signal)250 Cmvmi::execEVENT_SUBSCRIBE_REQ(Signal * signal){
251   EventSubscribeReq * subReq = (EventSubscribeReq *)&signal->theData[0];
252   Uint32 senderRef = signal->getSendersBlockRef();
253   SubscriberPtr ptr;
254   jamEntry();
255   DBUG_ENTER("Cmvmi::execEVENT_SUBSCRIBE_REQ");
256 
257   /**
258    * Search for subcription
259    */
260   for(subscribers.first(ptr); ptr.i != RNIL; subscribers.next(ptr)){
261     if(ptr.p->blockRef == subReq->blockRef)
262       break;
263   }
264 
265   if(ptr.i == RNIL){
266     /**
267      * Create a new one
268      */
269     if(subscribers.seize(ptr) == false){
270       sendSignal(senderRef, GSN_EVENT_SUBSCRIBE_REF, signal, 1, JBB);
271       return;
272     }
273     ptr.p->logLevel.clear();
274     ptr.p->blockRef = subReq->blockRef;
275   }
276 
277   if(subReq->noOfEntries == 0){
278     /**
279      * Cancel subscription
280      */
281     subscribers.release(ptr.i);
282   } else {
283     /**
284      * Update subscription
285      */
286     LogLevel::EventCategory category;
287     Uint32 level = 0;
288     for(Uint32 i = 0; i<subReq->noOfEntries; i++){
289       category = (LogLevel::EventCategory)(subReq->theData[i] >> 16);
290       level = subReq->theData[i] & 0xFFFF;
291       ptr.p->logLevel.setLogLevel(category, level);
292       DBUG_PRINT("info",("entry %d: level=%d, category= %d", i, level, category));
293     }
294   }
295 
296   signal->theData[0] = ptr.i;
297   sendSignal(senderRef, GSN_EVENT_SUBSCRIBE_CONF, signal, 1, JBB);
298   DBUG_VOID_RETURN;
299 }
300 
301 void
cancelSubscription(NodeId nodeId)302 Cmvmi::cancelSubscription(NodeId nodeId){
303 
304   SubscriberPtr ptr;
305   subscribers.first(ptr);
306 
307   while(ptr.i != RNIL){
308     Uint32 i = ptr.i;
309     BlockReference blockRef = ptr.p->blockRef;
310 
311     subscribers.next(ptr);
312 
313     if(refToNode(blockRef) == nodeId){
314       subscribers.release(i);
315     }
316   }
317 }
318 
sendSTTORRY(Signal * signal)319 void Cmvmi::sendSTTORRY(Signal* signal)
320 {
321   jam();
322   signal->theData[3] = 1;
323   signal->theData[4] = 3;
324   signal->theData[5] = 8;
325   signal->theData[6] = 255;
326   sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 7, JBB);
327 }//Cmvmi::sendSTTORRY
328 
329 
330 void
execREAD_CONFIG_REQ(Signal * signal)331 Cmvmi::execREAD_CONFIG_REQ(Signal* signal)
332 {
333   jamEntry();
334 
335   const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
336 
337   Uint32 ref = req->senderRef;
338   Uint32 senderData = req->senderData;
339 
340   const ndb_mgm_configuration_iterator * p =
341     m_ctx.m_config.getOwnConfigIterator();
342   ndbrequire(p != 0);
343 
344   Uint64 page_buffer = 64*1024*1024;
345   ndb_mgm_get_int64_parameter(p, CFG_DB_DISK_PAGE_BUFFER_MEMORY, &page_buffer);
346 
347   Uint32 pages = 0;
348   pages += page_buffer / GLOBAL_PAGE_SIZE; // in pages
349   pages += LCP_RESTORE_BUFFER;
350   m_global_page_pool.setSize(pages + 64, true);
351 
352   Uint64 shared_mem = 8*1024*1024;
353   ndb_mgm_get_int64_parameter(p, CFG_DB_SGA, &shared_mem);
354   shared_mem /= GLOBAL_PAGE_SIZE;
355   if (shared_mem)
356   {
357     Resource_limit rl;
358     rl.m_min = 0;
359     rl.m_max = shared_mem;
360     rl.m_resource_id = 0;
361     m_ctx.m_mm.set_resource_limit(rl);
362   }
363 
364   ndbrequire(m_ctx.m_mm.init());
365   {
366     void* ptr = m_ctx.m_mm.get_memroot();
367     m_shared_page_pool.set((GlobalPage*)ptr, ~0);
368   }
369 
370   ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
371   conf->senderRef = reference();
372   conf->senderData = senderData;
373   sendSignal(ref, GSN_READ_CONFIG_CONF, signal,
374 	     ReadConfigConf::SignalLength, JBB);
375 }
376 
execSTTOR(Signal * signal)377 void Cmvmi::execSTTOR(Signal* signal)
378 {
379   Uint32 theStartPhase  = signal->theData[1];
380 
381   jamEntry();
382   if (theStartPhase == 1){
383     jam();
384 
385     if(m_ctx.m_config.lockPagesInMainMemory() == 1)
386     {
387       int res = NdbMem_MemLockAll(0);
388       if(res != 0){
389 	g_eventLogger.warning("Failed to memlock pages");
390 	warningEvent("Failed to memlock pages");
391       }
392     }
393 
394     sendSTTORRY(signal);
395     return;
396   } else if (theStartPhase == 3) {
397     jam();
398     globalData.activateSendPacked = 1;
399     sendSTTORRY(signal);
400   } else if (theStartPhase == 8){
401     /*---------------------------------------------------*/
402     /* Open com to API + REP nodes                       */
403     /*---------------------------------------------------*/
404     signal->theData[0] = 0; // no answer
405     signal->theData[1] = 0; // no id
406     signal->theData[2] = NodeInfo::API;
407     execOPEN_COMREQ(signal);
408     globalData.theStartLevel = NodeState::SL_STARTED;
409     sendSTTORRY(signal);
410   }
411 }
412 
execCLOSE_COMREQ(Signal * signal)413 void Cmvmi::execCLOSE_COMREQ(Signal* signal)
414 {
415   // Close communication with the node and halt input/output from
416   // other blocks than QMGR
417 
418   CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
419 
420   const BlockReference userRef = closeCom->xxxBlockRef;
421   Uint32 failNo = closeCom->failNo;
422 //  Uint32 noOfNodes = closeCom->noOfNodes;
423 
424   jamEntry();
425   for (unsigned i = 0; i < MAX_NODES; i++)
426   {
427     if(NodeBitmask::get(closeCom->theNodes, i))
428     {
429       jam();
430 
431       //-----------------------------------------------------
432       // Report that the connection to the node is closed
433       //-----------------------------------------------------
434       signal->theData[0] = NDB_LE_CommunicationClosed;
435       signal->theData[1] = i;
436       sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
437 
438       globalTransporterRegistry.setIOState(i, HaltIO);
439       globalTransporterRegistry.do_disconnect(i);
440     }
441   }
442 
443   if (failNo != 0)
444   {
445     jam();
446     signal->theData[0] = userRef;
447     signal->theData[1] = failNo;
448     sendSignal(QMGR_REF, GSN_CLOSE_COMCONF, signal, 19, JBA);
449   }
450 }
451 
execOPEN_COMREQ(Signal * signal)452 void Cmvmi::execOPEN_COMREQ(Signal* signal)
453 {
454   // Connect to the specifed NDB node, only QMGR allowed communication
455   // so far with the node
456 
457   const BlockReference userRef = signal->theData[0];
458   Uint32 tStartingNode = signal->theData[1];
459   Uint32 tData2 = signal->theData[2];
460   jamEntry();
461 
462   const Uint32 len = signal->getLength();
463   if(len == 2)
464   {
465 #ifdef ERROR_INSERT
466     if (! ((ERROR_INSERTED(9000) || ERROR_INSERTED(9002))
467 	   && c_error_9000_nodes_mask.get(tStartingNode)))
468 #endif
469     {
470       if (globalData.theStartLevel != NodeState::SL_STARTED &&
471           (getNodeInfo(tStartingNode).m_type != NodeInfo::DB &&
472            getNodeInfo(tStartingNode).m_type != NodeInfo::MGM))
473       {
474         jam();
475         goto done;
476       }
477 
478       globalTransporterRegistry.do_connect(tStartingNode);
479       globalTransporterRegistry.setIOState(tStartingNode, HaltIO);
480 
481       //-----------------------------------------------------
482       // Report that the connection to the node is opened
483       //-----------------------------------------------------
484       signal->theData[0] = NDB_LE_CommunicationOpened;
485       signal->theData[1] = tStartingNode;
486       sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
487       //-----------------------------------------------------
488     }
489   } else {
490     for(unsigned int i = 1; i < MAX_NODES; i++ )
491     {
492       jam();
493       if (i != getOwnNodeId() && getNodeInfo(i).m_type == tData2)
494       {
495 	jam();
496 
497 #ifdef ERROR_INSERT
498 	if ((ERROR_INSERTED(9000) || ERROR_INSERTED(9002))
499 	    && c_error_9000_nodes_mask.get(i))
500 	  continue;
501 #endif
502 
503 	globalTransporterRegistry.do_connect(i);
504 	globalTransporterRegistry.setIOState(i, HaltIO);
505 
506 	signal->theData[0] = NDB_LE_CommunicationOpened;
507 	signal->theData[1] = i;
508 	sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
509       }
510     }
511   }
512 
513 done:
514   if (userRef != 0) {
515     jam();
516     signal->theData[0] = tStartingNode;
517     signal->theData[1] = tData2;
518     sendSignal(userRef, GSN_OPEN_COMCONF, signal, len - 1,JBA);
519   }
520 }
521 
execENABLE_COMORD(Signal * signal)522 void Cmvmi::execENABLE_COMORD(Signal* signal)
523 {
524   // Enable communication with all our NDB blocks to this node
525 
526   Uint32 tStartingNode = signal->theData[0];
527   globalTransporterRegistry.setIOState(tStartingNode, NoHalt);
528   setNodeInfo(tStartingNode).m_connected = true;
529     //-----------------------------------------------------
530   // Report that the version of the node
531   //-----------------------------------------------------
532   signal->theData[0] = NDB_LE_ConnectedApiVersion;
533   signal->theData[1] = tStartingNode;
534   signal->theData[2] = getNodeInfo(tStartingNode).m_version;
535 
536   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
537   //-----------------------------------------------------
538 
539   jamEntry();
540 }
541 
execDISCONNECT_REP(Signal * signal)542 void Cmvmi::execDISCONNECT_REP(Signal *signal)
543 {
544   const DisconnectRep * const rep = (DisconnectRep *)&signal->theData[0];
545   const Uint32 hostId = rep->nodeId;
546   const Uint32 errNo  = rep->err;
547 
548   jamEntry();
549 
550   setNodeInfo(hostId).m_connected = false;
551   setNodeInfo(hostId).m_connectCount++;
552   const NodeInfo::NodeType type = getNodeInfo(hostId).getType();
553   ndbrequire(type != NodeInfo::INVALID);
554 
555   sendSignal(QMGR_REF, GSN_DISCONNECT_REP, signal,
556              DisconnectRep::SignalLength, JBA);
557 
558   cancelSubscription(hostId);
559 
560   signal->theData[0] = NDB_LE_Disconnected;
561   signal->theData[1] = hostId;
562   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
563 }
564 
execCONNECT_REP(Signal * signal)565 void Cmvmi::execCONNECT_REP(Signal *signal){
566   const Uint32 hostId = signal->theData[0];
567   jamEntry();
568 
569   const NodeInfo::NodeType type = (NodeInfo::NodeType)getNodeInfo(hostId).m_type;
570   ndbrequire(type != NodeInfo::INVALID);
571   globalData.m_nodeInfo[hostId].m_version = 0;
572   globalData.m_nodeInfo[hostId].m_signalVersion = 0;
573 
574   if(type == NodeInfo::DB || globalData.theStartLevel >= NodeState::SL_STARTED){
575     jam();
576 
577     /**
578      * Inform QMGR that client has connected
579      */
580 
581     signal->theData[0] = hostId;
582     sendSignal(QMGR_REF, GSN_CONNECT_REP, signal, 1, JBA);
583   } else if(globalData.theStartLevel == NodeState::SL_CMVMI ||
584             globalData.theStartLevel == NodeState::SL_STARTING) {
585     jam();
586     /**
587      * Someone connected before start was finished
588      */
589     if(type == NodeInfo::MGM){
590       jam();
591       signal->theData[0] = hostId;
592       sendSignal(QMGR_REF, GSN_CONNECT_REP, signal, 1, JBA);
593     } else {
594       /**
595        * Dont allow api nodes to connect
596        */
597       ndbout_c("%d %d %d", hostId, type, globalData.theStartLevel);
598       abort();
599       globalTransporterRegistry.do_disconnect(hostId);
600     }
601   }
602 
603   /* Automatically subscribe events for MGM nodes.
604    */
605   if(type == NodeInfo::MGM){
606     jam();
607     globalTransporterRegistry.setIOState(hostId, NoHalt);
608   }
609 
610   //------------------------------------------
611   // Also report this event to the Event handler
612   //------------------------------------------
613   signal->theData[0] = NDB_LE_Connected;
614   signal->theData[1] = hostId;
615   signal->header.theLength = 2;
616 
617   execEVENT_REP(signal);
618 }
619 
620 #ifdef VM_TRACE
621 void
modifySignalLogger(bool allBlocks,BlockNumber bno,TestOrd::Command cmd,TestOrd::SignalLoggerSpecification spec)622 modifySignalLogger(bool allBlocks, BlockNumber bno,
623                    TestOrd::Command cmd,
624                    TestOrd::SignalLoggerSpecification spec){
625   SignalLoggerManager::LogMode logMode;
626 
627   /**
628    * Mapping between SignalLoggerManager::LogMode and
629    *                 TestOrd::SignalLoggerSpecification
630    */
631   switch(spec){
632   case TestOrd::InputSignals:
633     logMode = SignalLoggerManager::LogIn;
634     break;
635   case TestOrd::OutputSignals:
636     logMode = SignalLoggerManager::LogOut;
637     break;
638   case TestOrd::InputOutputSignals:
639     logMode = SignalLoggerManager::LogInOut;
640     break;
641   default:
642     return;
643     break;
644   }
645 
646   switch(cmd){
647   case TestOrd::On:
648     globalSignalLoggers.logOn(allBlocks, bno, logMode);
649     break;
650   case TestOrd::Off:
651     globalSignalLoggers.logOff(allBlocks, bno, logMode);
652     break;
653   case TestOrd::Toggle:
654     globalSignalLoggers.logToggle(allBlocks, bno, logMode);
655     break;
656   case TestOrd::KeepUnchanged:
657     // Do nothing
658     break;
659   }
660   globalSignalLoggers.flushSignalLog();
661 }
662 #endif
663 
664 void
execTEST_ORD(Signal * signal)665 Cmvmi::execTEST_ORD(Signal * signal){
666   jamEntry();
667 
668 #ifdef VM_TRACE
669   TestOrd * const testOrd = (TestOrd *)&signal->theData[0];
670 
671   TestOrd::Command cmd;
672 
673   {
674     /**
675      * Process Trace command
676      */
677     TestOrd::TraceSpecification traceSpec;
678 
679     testOrd->getTraceCommand(cmd, traceSpec);
680     unsigned long traceVal = traceSpec;
681     unsigned long currentTraceVal = globalSignalLoggers.getTrace();
682     switch(cmd){
683     case TestOrd::On:
684       currentTraceVal |= traceVal;
685       break;
686     case TestOrd::Off:
687       currentTraceVal &= (~traceVal);
688       break;
689     case TestOrd::Toggle:
690       currentTraceVal ^= traceVal;
691       break;
692     case TestOrd::KeepUnchanged:
693       // Do nothing
694       break;
695     }
696     globalSignalLoggers.setTrace(currentTraceVal);
697   }
698 
699   {
700     /**
701      * Process Log command
702      */
703     TestOrd::SignalLoggerSpecification logSpec;
704     BlockNumber bno;
705     unsigned int loggers = testOrd->getNoOfSignalLoggerCommands();
706 
707     if(loggers == (unsigned)~0){ // Apply command to all blocks
708       testOrd->getSignalLoggerCommand(0, bno, cmd, logSpec);
709       modifySignalLogger(true, bno, cmd, logSpec);
710     } else {
711       for(unsigned int i = 0; i<loggers; i++){
712         testOrd->getSignalLoggerCommand(i, bno, cmd, logSpec);
713         modifySignalLogger(false, bno, cmd, logSpec);
714       }
715     }
716   }
717 
718   {
719     /**
720      * Process test command
721      */
722     testOrd->getTestCommand(cmd);
723     switch(cmd){
724     case TestOrd::On:{
725       SET_GLOBAL_TEST_ON;
726     }
727     break;
728     case TestOrd::Off:{
729       SET_GLOBAL_TEST_OFF;
730     }
731     break;
732     case TestOrd::Toggle:{
733       TOGGLE_GLOBAL_TEST_FLAG;
734     }
735     break;
736     case TestOrd::KeepUnchanged:
737       // Do nothing
738       break;
739     }
740     globalSignalLoggers.flushSignalLog();
741   }
742 
743 #endif
744 }
745 
execSTOP_ORD(Signal * signal)746 void Cmvmi::execSTOP_ORD(Signal* signal)
747 {
748   jamEntry();
749   globalData.theRestartFlag = perform_stop;
750 }//execSTOP_ORD()
751 
752 void
execSTART_ORD(Signal * signal)753 Cmvmi::execSTART_ORD(Signal* signal) {
754 
755   StartOrd * const startOrd = (StartOrd *)&signal->theData[0];
756   jamEntry();
757 
758   Uint32 tmp = startOrd->restartInfo;
759   if(StopReq::getPerformRestart(tmp)){
760     jam();
761     /**
762      *
763      */
764     NdbRestartType type = NRT_Default;
765     if(StopReq::getNoStart(tmp) && StopReq::getInitialStart(tmp))
766       type = NRT_NoStart_InitialStart;
767     if(StopReq::getNoStart(tmp) && !StopReq::getInitialStart(tmp))
768       type = NRT_NoStart_Restart;
769     if(!StopReq::getNoStart(tmp) && StopReq::getInitialStart(tmp))
770       type = NRT_DoStart_InitialStart;
771     if(!StopReq::getNoStart(tmp)&&!StopReq::getInitialStart(tmp))
772       type = NRT_DoStart_Restart;
773     NdbShutdown(NST_Restart, type);
774   }
775 
776   if(globalData.theRestartFlag == system_started){
777     jam()
778     /**
779      * START_ORD received when already started(ignored)
780      */
781     //ndbout << "START_ORD received when already started(ignored)" << endl;
782     return;
783   }
784 
785   if(globalData.theRestartFlag == perform_stop){
786     jam()
787     /**
788      * START_ORD received when stopping(ignored)
789      */
790     //ndbout << "START_ORD received when stopping(ignored)" << endl;
791     return;
792   }
793 
794   if(globalData.theStartLevel == NodeState::SL_NOTHING){
795     jam();
796     globalData.theStartLevel = NodeState::SL_CMVMI;
797     /**
798      * Open connections to management servers
799      */
800     for(unsigned int i = 1; i < MAX_NODES; i++ ){
801       if (getNodeInfo(i).m_type == NodeInfo::MGM){
802         if(!globalTransporterRegistry.is_connected(i)){
803           globalTransporterRegistry.do_connect(i);
804           globalTransporterRegistry.setIOState(i, NoHalt);
805         }
806       }
807     }
808 
809     EXECUTE_DIRECT(QMGR, GSN_START_ORD, signal, 1);
810     return ;
811   }
812 
813   if(globalData.theStartLevel == NodeState::SL_CMVMI){
814     jam();
815 
816     if(m_ctx.m_config.lockPagesInMainMemory() == 2)
817     {
818       int res = NdbMem_MemLockAll(1);
819       if(res != 0)
820       {
821 	g_eventLogger.warning("Failed to memlock pages");
822 	warningEvent("Failed to memlock pages");
823       }
824       else
825       {
826 	g_eventLogger.info("Locked future allocations");
827       }
828     }
829 
830     globalData.theStartLevel  = NodeState::SL_STARTING;
831     globalData.theRestartFlag = system_started;
832     /**
833      * StartLevel 1
834      *
835      * Do Restart
836      */
837 
838     // Disconnect all nodes as part of the system restart.
839     // We need to ensure that we are starting up
840     // without any connected nodes.
841     for(unsigned int i = 1; i < MAX_NODES; i++ ){
842       if (i != getOwnNodeId() && getNodeInfo(i).m_type != NodeInfo::MGM){
843         globalTransporterRegistry.do_disconnect(i);
844         globalTransporterRegistry.setIOState(i, HaltIO);
845       }
846     }
847 
848     /**
849      * Start running startphases
850      */
851     sendSignal(NDBCNTR_REF, GSN_START_ORD, signal, 1, JBA);
852     return;
853   }
854 }//execSTART_ORD()
855 
execTAMPER_ORD(Signal * signal)856 void Cmvmi::execTAMPER_ORD(Signal* signal)
857 {
858   jamEntry();
859   // TODO We should maybe introduce a CONF and REF signal
860   // to be able to indicate if we really introduced an error.
861 #ifdef ERROR_INSERT
862   TamperOrd* const tamperOrd = (TamperOrd*)&signal->theData[0];
863   signal->theData[2] = 0;
864   signal->theData[1] = tamperOrd->errorNo;
865   signal->theData[0] = 5;
866   sendSignal(DBDIH_REF, GSN_DIHNDBTAMPER, signal, 3,JBB);
867 #endif
868 
869 }//execTAMPER_ORD()
870 
871 #ifdef VM_TRACE
872 class RefSignalTest {
873 public:
874   enum ErrorCode {
875     OK = 0,
876     NF_FakeErrorREF = 7
877   };
878   Uint32 senderRef;
879   Uint32 senderData;
880   Uint32 errorCode;
881 };
882 #endif
883 
884 
885 static int iii;
886 
887 static
888 int
recurse(char * buf,int loops,int arg)889 recurse(char * buf, int loops, int arg){
890   char * tmp = (char*)alloca(arg);
891   printf("tmp = %p\n", tmp);
892   for(iii = 0; iii<arg; iii += 1024){
893     tmp[iii] = (iii % 23 + (arg & iii));
894   }
895 
896   if(loops == 0)
897     return tmp[345];
898   else
899     return tmp[arg/loops] + recurse(tmp, loops - 1, arg);
900 }
901 
902 void
execDUMP_STATE_ORD(Signal * signal)903 Cmvmi::execDUMP_STATE_ORD(Signal* signal)
904 {
905 
906   sendSignal(QMGR_REF, GSN_DUMP_STATE_ORD,    signal, signal->length(), JBB);
907   sendSignal(NDBCNTR_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
908   sendSignal(DBTC_REF, GSN_DUMP_STATE_ORD,    signal, signal->length(), JBB);
909   sendSignal(DBDIH_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
910   sendSignal(DBDICT_REF, GSN_DUMP_STATE_ORD,  signal, signal->length(), JBB);
911   sendSignal(DBLQH_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
912   sendSignal(DBTUP_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
913   sendSignal(DBACC_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
914   sendSignal(NDBFS_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
915   sendSignal(BACKUP_REF, GSN_DUMP_STATE_ORD,  signal, signal->length(), JBB);
916   sendSignal(DBUTIL_REF, GSN_DUMP_STATE_ORD,  signal, signal->length(), JBB);
917   sendSignal(SUMA_REF, GSN_DUMP_STATE_ORD,    signal, signal->length(), JBB);
918   sendSignal(TRIX_REF, GSN_DUMP_STATE_ORD,    signal, signal->length(), JBB);
919   sendSignal(DBTUX_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
920   sendSignal(LGMAN_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
921   sendSignal(TSMAN_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
922   sendSignal(PGMAN_REF, GSN_DUMP_STATE_ORD,   signal, signal->length(), JBB);
923 
924   /**
925    *
926    * Here I can dump CMVMI state if needed
927    */
928   if(signal->theData[0] == 13){
929 #if 0
930     int loop = 100;
931     int len = (10*1024*1024);
932     if(signal->getLength() > 1)
933       loop = signal->theData[1];
934     if(signal->getLength() > 2)
935       len = signal->theData[2];
936 
937     ndbout_c("recurse(%d loop, %dkb per recurse)", loop, len/1024);
938     int a = recurse(0, loop, len);
939     ndbout_c("after...%d", a);
940 #endif
941   }
942 
943   DumpStateOrd * const & dumpState = (DumpStateOrd *)&signal->theData[0];
944   Uint32 arg = dumpState->args[0];
945   if (arg == DumpStateOrd::CmvmiDumpConnections){
946     for(unsigned int i = 1; i < MAX_NODES; i++ ){
947       const char* nodeTypeStr = "";
948       switch(getNodeInfo(i).m_type){
949       case NodeInfo::DB:
950 	nodeTypeStr = "DB";
951 	break;
952       case NodeInfo::API:
953 	nodeTypeStr = "API";
954 	break;
955       case NodeInfo::MGM:
956 	nodeTypeStr = "MGM";
957 	break;
958       case NodeInfo::INVALID:
959 	nodeTypeStr = 0;
960 	break;
961       default:
962 	nodeTypeStr = "<UNKNOWN>";
963       }
964 
965       if(nodeTypeStr == 0)
966 	continue;
967 
968       infoEvent("Connection to %d (%s) %s",
969                 i,
970                 nodeTypeStr,
971                 globalTransporterRegistry.getPerformStateString(i));
972     }
973   }
974 
975   if (arg == DumpStateOrd::CmvmiDumpSubscriptions)
976   {
977     SubscriberPtr ptr;
978     subscribers.first(ptr);
979     g_eventLogger.info("List subscriptions:");
980     while(ptr.i != RNIL)
981     {
982       g_eventLogger.info("Subscription: %u, nodeId: %u, ref: 0x%x",
983                          ptr.i,  refToNode(ptr.p->blockRef), ptr.p->blockRef);
984       for(Uint32 i = 0; i < LogLevel::LOGLEVEL_CATEGORIES; i++)
985       {
986         Uint32 level = ptr.p->logLevel.getLogLevel((LogLevel::EventCategory)i);
987         g_eventLogger.info("Category %u Level %u", i, level);
988       }
989       subscribers.next(ptr);
990     }
991   }
992 
993   if (arg == DumpStateOrd::CmvmiDumpLongSignalMemory){
994     infoEvent("Cmvmi: g_sectionSegmentPool size: %d free: %d",
995 	      g_sectionSegmentPool.getSize(),
996 	      g_sectionSegmentPool.getNoOfFree());
997   }
998 
999   if (dumpState->args[0] == 1000)
1000   {
1001     Uint32 len = signal->getLength();
1002     if (signal->getLength() == 1)
1003     {
1004       signal->theData[1] = 0;
1005       signal->theData[2] = ~0;
1006       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 3, JBB);
1007       return;
1008     }
1009     Uint32 id = signal->theData[1];
1010     Resource_limit rl;
1011     if (!m_ctx.m_mm.get_resource_limit(id, rl))
1012       len = 2;
1013     else
1014     {
1015       if (rl.m_min || rl.m_curr || rl.m_max)
1016 	infoEvent("Resource %d min: %d max: %d curr: %d",
1017 		  id, rl.m_min, rl.m_max, rl.m_curr);
1018     }
1019 
1020     if (len == 3)
1021     {
1022       signal->theData[0] = 1000;
1023       signal->theData[1] = id+1;
1024       signal->theData[2] = ~0;
1025       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 3, JBB);
1026     }
1027     return;
1028   }
1029 
1030   if (arg == DumpStateOrd::CmvmiSetRestartOnErrorInsert)
1031   {
1032     if(signal->getLength() == 1)
1033     {
1034       Uint32 val = (Uint32)NRT_NoStart_Restart;
1035       const ndb_mgm_configuration_iterator * p =
1036 	m_ctx.m_config.getOwnConfigIterator();
1037       ndbrequire(p != 0);
1038 
1039       if(!ndb_mgm_get_int_parameter(p, CFG_DB_STOP_ON_ERROR_INSERT, &val))
1040       {
1041         m_ctx.m_config.setRestartOnErrorInsert(val);
1042       }
1043     }
1044     else
1045     {
1046       m_ctx.m_config.setRestartOnErrorInsert(signal->theData[1]);
1047     }
1048   }
1049 
1050   if (arg == DumpStateOrd::CmvmiTestLongSigWithDelay) {
1051     unsigned i;
1052     Uint32 loopCount = dumpState->args[1];
1053     const unsigned len0 = 11;
1054     const unsigned len1 = 123;
1055     Uint32 sec0[len0];
1056     Uint32 sec1[len1];
1057     for (i = 0; i < len0; i++)
1058       sec0[i] = i;
1059     for (i = 0; i < len1; i++)
1060       sec1[i] = 16 * i;
1061     Uint32* sig = signal->getDataPtrSend();
1062     sig[0] = reference();
1063     sig[1] = 20; // test type
1064     sig[2] = 0;
1065     sig[3] = 0;
1066     sig[4] = loopCount;
1067     sig[5] = len0;
1068     sig[6] = len1;
1069     sig[7] = 0;
1070     LinearSectionPtr ptr[3];
1071     ptr[0].p = sec0;
1072     ptr[0].sz = len0;
1073     ptr[1].p = sec1;
1074     ptr[1].sz = len1;
1075     sendSignal(reference(), GSN_TESTSIG, signal, 8, JBB, ptr, 2);
1076   }
1077 
1078 #ifdef ERROR_INSERT
1079   if (arg == 9000 || arg == 9002)
1080   {
1081     SET_ERROR_INSERT_VALUE(arg);
1082     for (Uint32 i = 1; i<signal->getLength(); i++)
1083       c_error_9000_nodes_mask.set(signal->theData[i]);
1084   }
1085 
1086   if (arg == 9001)
1087   {
1088     CLEAR_ERROR_INSERT_VALUE;
1089     if (signal->getLength() == 1 || signal->theData[1])
1090     {
1091       for (Uint32 i = 0; i<MAX_NODES; i++)
1092       {
1093 	if (c_error_9000_nodes_mask.get(i))
1094 	{
1095 	  signal->theData[0] = 0;
1096 	  signal->theData[1] = i;
1097 	  EXECUTE_DIRECT(CMVMI, GSN_OPEN_COMREQ, signal, 2);
1098 	}
1099       }
1100     }
1101     c_error_9000_nodes_mask.clear();
1102   }
1103 #endif
1104 
1105 #ifdef VM_TRACE
1106 #if 0
1107   {
1108     SafeCounterManager mgr(* this); mgr.setSize(1);
1109     SafeCounterHandle handle;
1110 
1111     {
1112       SafeCounter tmp(mgr, handle);
1113       tmp.init<RefSignalTest>(CMVMI, GSN_TESTSIG, /* senderData */ 13);
1114       tmp.setWaitingFor(3);
1115       ndbrequire(!tmp.done());
1116       ndbout_c("Allocted");
1117     }
1118     ndbrequire(!handle.done());
1119     {
1120       SafeCounter tmp(mgr, handle);
1121       tmp.clearWaitingFor(3);
1122       ndbrequire(tmp.done());
1123       ndbout_c("Deallocted");
1124     }
1125     ndbrequire(handle.done());
1126   }
1127 #endif
1128 #endif
1129 
1130   if (arg == 9999)
1131   {
1132     Uint32 delay = 1000;
1133     switch(signal->getLength()){
1134     case 1:
1135       break;
1136     case 2:
1137       delay = signal->theData[1];
1138       break;
1139     default:{
1140       Uint32 dmin = signal->theData[1];
1141       Uint32 dmax = signal->theData[2];
1142       delay = dmin + (rand() % (dmax - dmin));
1143       break;
1144     }
1145     }
1146 
1147     signal->theData[0] = 9999;
1148     if (delay == 0)
1149     {
1150       execNDB_TAMPER(signal);
1151     }
1152     else if (delay < 10)
1153     {
1154       sendSignal(reference(), GSN_NDB_TAMPER, signal, 1, JBB);
1155     }
1156     else
1157     {
1158       sendSignalWithDelay(reference(), GSN_NDB_TAMPER, signal, delay, 1);
1159     }
1160   }
1161 }//Cmvmi::execDUMP_STATE_ORD()
1162 
1163 void
execNODE_START_REP(Signal * signal)1164 Cmvmi::execNODE_START_REP(Signal* signal)
1165 {
1166 #ifdef ERROR_INSERT
1167   if (ERROR_INSERTED(9002) && signal->theData[0] == getOwnNodeId())
1168   {
1169     signal->theData[0] = 9001;
1170     execDUMP_STATE_ORD(signal);
1171   }
1172 #endif
1173 }
1174 
1175 BLOCK_FUNCTIONS(Cmvmi)
1176 
1177 static Uint32 g_print;
1178 static LinearSectionPtr g_test[3];
1179 
1180 void
execTESTSIG(Signal * signal)1181 Cmvmi::execTESTSIG(Signal* signal){
1182   Uint32 i;
1183   /**
1184    * Test of SafeCounter
1185    */
1186   jamEntry();
1187 
1188   if(!assembleFragments(signal)){
1189     jam();
1190     return;
1191   }
1192 
1193   Uint32 ref = signal->theData[0];
1194   Uint32 testType = signal->theData[1];
1195   Uint32 fragmentLength = signal->theData[2];
1196   g_print = signal->theData[3];
1197 //  Uint32 returnCount = signal->theData[4];
1198   Uint32 * secSizes = &signal->theData[5];
1199 
1200   if(g_print){
1201     SignalLoggerManager::printSignalHeader(stdout,
1202 					   signal->header,
1203 					   0,
1204 					   getOwnNodeId(),
1205 					   true);
1206     ndbout_c("-- Fixed section --");
1207     for(i = 0; i<signal->length(); i++){
1208       fprintf(stdout, "H'0x%.8x ", signal->theData[i]);
1209       if(((i + 1) % 6) == 0)
1210 	fprintf(stdout, "\n");
1211     }
1212     fprintf(stdout, "\n");
1213 
1214     for(i = 0; i<signal->header.m_noOfSections; i++){
1215       SegmentedSectionPtr ptr(0,0,0);
1216       ndbout_c("-- Section %d --", i);
1217       signal->getSection(ptr, i);
1218       ndbrequire(ptr.p != 0);
1219       print(ptr, stdout);
1220       ndbrequire(ptr.sz == secSizes[i]);
1221     }
1222   }
1223 
1224   /**
1225    * Validate length:s
1226    */
1227   for(i = 0; i<signal->header.m_noOfSections; i++){
1228     SegmentedSectionPtr ptr;
1229     signal->getSection(ptr, i);
1230     ndbrequire(ptr.p != 0);
1231     ndbrequire(ptr.sz == secSizes[i]);
1232   }
1233 
1234   /**
1235    * Testing send with delay.
1236    */
1237   if (testType == 20) {
1238     if (signal->theData[4] == 0) {
1239       releaseSections(signal);
1240       return;
1241     }
1242     signal->theData[4]--;
1243     sendSignalWithDelay(reference(), GSN_TESTSIG, signal, 100, 8);
1244     return;
1245   }
1246 
1247   NodeReceiverGroup rg(CMVMI, c_dbNodes);
1248 
1249   if(signal->getSendersBlockRef() == ref){
1250     /**
1251      * Signal from API (not via NodeReceiverGroup)
1252      */
1253     if((testType % 2) == 1){
1254       signal->theData[4] = 1;
1255     } else {
1256       signal->theData[1] --;
1257       signal->theData[4] = rg.m_nodes.count();
1258     }
1259   }
1260 
1261   switch(testType){
1262   case 1:
1263     sendSignal(ref, GSN_TESTSIG,  signal, signal->length(), JBB);
1264     break;
1265   case 2:
1266     sendSignal(rg, GSN_TESTSIG,  signal, signal->length(), JBB);
1267     break;
1268   case 3:
1269   case 4:{
1270     LinearSectionPtr ptr[3];
1271     const Uint32 secs = signal->getNoOfSections();
1272     for(i = 0; i<secs; i++){
1273       SegmentedSectionPtr sptr(0,0,0);
1274       signal->getSection(sptr, i);
1275       ptr[i].sz = sptr.sz;
1276       ptr[i].p = new Uint32[sptr.sz];
1277       copy(ptr[i].p, sptr);
1278     }
1279 
1280     if(testType == 3){
1281       sendSignal(ref, GSN_TESTSIG,  signal, signal->length(), JBB, ptr, secs);
1282     } else {
1283       sendSignal(rg, GSN_TESTSIG,  signal, signal->length(), JBB, ptr, secs);
1284     }
1285     for(Uint32 i = 0; i<secs; i++){
1286       delete[] ptr[i].p;
1287     }
1288     break;
1289   }
1290   case 5:
1291   case 6:{
1292 
1293     NodeReceiverGroup tmp;
1294     if(testType == 5){
1295       tmp  = ref;
1296     } else {
1297       tmp = rg;
1298     }
1299 
1300     FragmentSendInfo fragSend;
1301     sendFirstFragment(fragSend,
1302 		      tmp,
1303 		      GSN_TESTSIG,
1304 		      signal,
1305 		      signal->length(),
1306 		      JBB,
1307 		      fragmentLength);
1308     int count = 1;
1309     while(fragSend.m_status != FragmentSendInfo::SendComplete){
1310       count++;
1311       if(g_print)
1312 	ndbout_c("Sending fragment %d", count);
1313       sendNextSegmentedFragment(signal, fragSend);
1314     }
1315     break;
1316   }
1317   case 7:
1318   case 8:{
1319     LinearSectionPtr ptr[3];
1320     const Uint32 secs = signal->getNoOfSections();
1321     for(i = 0; i<secs; i++){
1322       SegmentedSectionPtr sptr(0,0,0);
1323       signal->getSection(sptr, i);
1324       ptr[i].sz = sptr.sz;
1325       ptr[i].p = new Uint32[sptr.sz];
1326       copy(ptr[i].p, sptr);
1327     }
1328 
1329     NodeReceiverGroup tmp;
1330     if(testType == 7){
1331       tmp  = ref;
1332     } else {
1333       tmp = rg;
1334     }
1335 
1336     FragmentSendInfo fragSend;
1337     sendFirstFragment(fragSend,
1338 		      tmp,
1339 		      GSN_TESTSIG,
1340 		      signal,
1341 		      signal->length(),
1342 		      JBB,
1343 		      ptr,
1344 		      secs,
1345 		      fragmentLength);
1346 
1347     int count = 1;
1348     while(fragSend.m_status != FragmentSendInfo::SendComplete){
1349       count++;
1350       if(g_print)
1351 	ndbout_c("Sending fragment %d", count);
1352       sendNextLinearFragment(signal, fragSend);
1353     }
1354 
1355     for(i = 0; i<secs; i++){
1356       delete[] ptr[i].p;
1357     }
1358     break;
1359   }
1360   case 9:
1361   case 10:{
1362 
1363     Callback m_callBack;
1364     m_callBack.m_callbackFunction =
1365       safe_cast(&Cmvmi::sendFragmentedComplete);
1366 
1367     if(testType == 9){
1368       m_callBack.m_callbackData = 9;
1369       sendFragmentedSignal(ref,
1370 			   GSN_TESTSIG, signal, signal->length(), JBB,
1371 			   m_callBack,
1372 			   fragmentLength);
1373     } else {
1374       m_callBack.m_callbackData = 10;
1375       sendFragmentedSignal(rg,
1376 			   GSN_TESTSIG, signal, signal->length(), JBB,
1377 			   m_callBack,
1378 			   fragmentLength);
1379     }
1380     break;
1381   }
1382   case 11:
1383   case 12:{
1384 
1385     const Uint32 secs = signal->getNoOfSections();
1386     memset(g_test, 0, sizeof(g_test));
1387     for(i = 0; i<secs; i++){
1388       SegmentedSectionPtr sptr(0,0,0);
1389       signal->getSection(sptr, i);
1390       g_test[i].sz = sptr.sz;
1391       g_test[i].p = new Uint32[sptr.sz];
1392       copy(g_test[i].p, sptr);
1393     }
1394 
1395 
1396     Callback m_callBack;
1397     m_callBack.m_callbackFunction =
1398       safe_cast(&Cmvmi::sendFragmentedComplete);
1399 
1400     if(testType == 11){
1401       m_callBack.m_callbackData = 11;
1402       sendFragmentedSignal(ref,
1403 			   GSN_TESTSIG, signal, signal->length(), JBB,
1404 			   g_test, secs,
1405 			   m_callBack,
1406 			   fragmentLength);
1407     } else {
1408       m_callBack.m_callbackData = 12;
1409       sendFragmentedSignal(rg,
1410 			   GSN_TESTSIG, signal, signal->length(), JBB,
1411 			   g_test, secs,
1412 			   m_callBack,
1413 			   fragmentLength);
1414     }
1415     break;
1416   }
1417   case 13:{
1418     ndbrequire(signal->getNoOfSections() == 0);
1419     Uint32 loop = signal->theData[9];
1420     if(loop > 0){
1421       signal->theData[9] --;
1422       sendSignal(CMVMI_REF, GSN_TESTSIG, signal, signal->length(), JBB);
1423       return;
1424     }
1425     sendSignal(ref, GSN_TESTSIG, signal, signal->length(), JBB);
1426     return;
1427   }
1428   case 14:{
1429     Uint32 count = signal->theData[8];
1430     signal->theData[10] = count * rg.m_nodes.count();
1431     for(i = 0; i<count; i++){
1432       sendSignal(rg, GSN_TESTSIG, signal, signal->length(), JBB);
1433     }
1434     return;
1435   }
1436 
1437   default:
1438     ndbrequire(false);
1439   }
1440   return;
1441 }
1442 
1443 void
sendFragmentedComplete(Signal * signal,Uint32 data,Uint32 returnCode)1444 Cmvmi::sendFragmentedComplete(Signal* signal, Uint32 data, Uint32 returnCode){
1445   if(g_print)
1446     ndbout_c("sendFragmentedComplete: %d", data);
1447   if(data == 11 || data == 12){
1448     for(Uint32 i = 0; i<3; i++){
1449       if(g_test[i].p != 0)
1450 	delete[] g_test[i].p;
1451     }
1452   }
1453 }
1454