1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "Cmvmi.hpp"
26 
27 #include <Configuration.hpp>
28 #include <kernel_types.h>
29 #include <TransporterRegistry.hpp>
30 #include <NdbOut.hpp>
31 #include <NdbMem.h>
32 #include <NdbTick.h>
33 
34 #include <SignalLoggerManager.hpp>
35 #include <FastScheduler.hpp>
36 
37 #define DEBUG(x) { ndbout << "CMVMI::" << x << endl; }
38 
39 #include <signaldata/TestOrd.hpp>
40 #include <signaldata/EventReport.hpp>
41 #include <signaldata/TamperOrd.hpp>
42 #include <signaldata/StartOrd.hpp>
43 #include <signaldata/CloseComReqConf.hpp>
44 #include <signaldata/SetLogLevelOrd.hpp>
45 #include <signaldata/EventSubscribeReq.hpp>
46 #include <signaldata/DumpStateOrd.hpp>
47 #include <signaldata/DisconnectRep.hpp>
48 #include <signaldata/EnableCom.hpp>
49 #include <signaldata/RouteOrd.hpp>
50 #include <signaldata/DbinfoScan.hpp>
51 #include <signaldata/Sync.hpp>
52 #include <signaldata/AllocMem.hpp>
53 #include <signaldata/NodeStateSignalData.hpp>
54 #include <signaldata/GetConfig.hpp>
55 
56 #include <EventLogger.hpp>
57 #include <TimeQueue.hpp>
58 
59 #include <NdbSleep.h>
60 #include <SafeCounter.hpp>
61 
62 #define ZREPORT_MEMORY_USAGE 1000
63 
64 // Used here only to print event reports on stdout/console.
65 extern EventLogger * g_eventLogger;
66 extern int simulate_error_during_shutdown;
67 
68 // Index pages used by ACC instances
69 Uint32 g_acc_pages_used[1 + MAX_NDBMT_LQH_WORKERS];
70 
71 extern void mt_set_section_chunk_size();
72 
Cmvmi(Block_context & ctx)73 Cmvmi::Cmvmi(Block_context& ctx) :
74   SimulatedBlock(CMVMI, ctx)
75   ,subscribers(subscriberPool)
76 {
77   BLOCK_CONSTRUCTOR(Cmvmi);
78 
79   Uint32 long_sig_buffer_size;
80   const ndb_mgm_configuration_iterator * p =
81     m_ctx.m_config.getOwnConfigIterator();
82   ndbrequire(p != 0);
83 
84   ndb_mgm_get_int_parameter(p, CFG_DB_LONG_SIGNAL_BUFFER,
85 			    &long_sig_buffer_size);
86 
87   /* Ensure that aligned allocation will result in 64-bit
88    * aligned offset for theData
89    */
90   STATIC_ASSERT((sizeof(SectionSegment) % 8) == 0);
91   STATIC_ASSERT((offsetof(SectionSegment, theData) % 8) == 0);
92 
93   long_sig_buffer_size= long_sig_buffer_size / sizeof(SectionSegment);
94   g_sectionSegmentPool.setSize(long_sig_buffer_size,
95                                true,true,true,CFG_DB_LONG_SIGNAL_BUFFER);
96 
97   mt_set_section_chunk_size();
98 
99   // Add received signals
100   addRecSignal(GSN_CONNECT_REP, &Cmvmi::execCONNECT_REP);
101   addRecSignal(GSN_DISCONNECT_REP, &Cmvmi::execDISCONNECT_REP);
102 
103   addRecSignal(GSN_NDB_TAMPER,  &Cmvmi::execNDB_TAMPER, true);
104   addRecSignal(GSN_SET_LOGLEVELORD,  &Cmvmi::execSET_LOGLEVELORD);
105   addRecSignal(GSN_EVENT_REP,  &Cmvmi::execEVENT_REP);
106   addRecSignal(GSN_STTOR,  &Cmvmi::execSTTOR);
107   addRecSignal(GSN_READ_CONFIG_REQ,  &Cmvmi::execREAD_CONFIG_REQ);
108   addRecSignal(GSN_CLOSE_COMREQ,  &Cmvmi::execCLOSE_COMREQ);
109   addRecSignal(GSN_ENABLE_COMREQ,  &Cmvmi::execENABLE_COMREQ);
110   addRecSignal(GSN_OPEN_COMREQ,  &Cmvmi::execOPEN_COMREQ);
111   addRecSignal(GSN_TEST_ORD,  &Cmvmi::execTEST_ORD);
112 
113   addRecSignal(GSN_TAMPER_ORD,  &Cmvmi::execTAMPER_ORD);
114   addRecSignal(GSN_STOP_ORD,  &Cmvmi::execSTOP_ORD);
115   addRecSignal(GSN_START_ORD,  &Cmvmi::execSTART_ORD);
116   addRecSignal(GSN_EVENT_SUBSCRIBE_REQ,
117                &Cmvmi::execEVENT_SUBSCRIBE_REQ);
118 
119   addRecSignal(GSN_DUMP_STATE_ORD, &Cmvmi::execDUMP_STATE_ORD);
120 
121   addRecSignal(GSN_TESTSIG, &Cmvmi::execTESTSIG);
122   addRecSignal(GSN_NODE_START_REP, &Cmvmi::execNODE_START_REP, true);
123 
124   addRecSignal(GSN_CONTINUEB, &Cmvmi::execCONTINUEB);
125   addRecSignal(GSN_ROUTE_ORD, &Cmvmi::execROUTE_ORD);
126   addRecSignal(GSN_DBINFO_SCANREQ, &Cmvmi::execDBINFO_SCANREQ);
127 
128   addRecSignal(GSN_SYNC_REQ, &Cmvmi::execSYNC_REQ, true);
129   addRecSignal(GSN_SYNC_REF, &Cmvmi::execSYNC_REF);
130   addRecSignal(GSN_SYNC_CONF, &Cmvmi::execSYNC_CONF);
131 
132   addRecSignal(GSN_ALLOC_MEM_REF, &Cmvmi::execALLOC_MEM_REF);
133   addRecSignal(GSN_ALLOC_MEM_CONF, &Cmvmi::execALLOC_MEM_CONF);
134 
135   addRecSignal(GSN_GET_CONFIG_REQ, &Cmvmi::execGET_CONFIG_REQ);
136 
137   subscriberPool.setSize(5);
138   c_syncReqPool.setSize(5);
139 
140   const ndb_mgm_configuration_iterator * db = m_ctx.m_config.getOwnConfigIterator();
141   for(unsigned j = 0; j<LogLevel::LOGLEVEL_CATEGORIES; j++){
142     Uint32 logLevel;
143     if(!ndb_mgm_get_int_parameter(db, CFG_MIN_LOGLEVEL+j, &logLevel)){
144       clogLevel.setLogLevel((LogLevel::EventCategory)j,
145 			    logLevel);
146     }
147   }
148 
149   ndb_mgm_configuration_iterator * iter = m_ctx.m_config.getClusterConfigIterator();
150   for(ndb_mgm_first(iter); ndb_mgm_valid(iter); ndb_mgm_next(iter)){
151     jam();
152     Uint32 nodeId;
153     Uint32 nodeType;
154 
155     ndbrequire(!ndb_mgm_get_int_parameter(iter,CFG_NODE_ID, &nodeId));
156     ndbrequire(!ndb_mgm_get_int_parameter(iter,CFG_TYPE_OF_SECTION,&nodeType));
157 
158     switch(nodeType){
159     case NodeInfo::DB:
160       c_dbNodes.set(nodeId);
161       break;
162     case NodeInfo::API:
163     case NodeInfo::MGM:
164       break;
165     default:
166       ndbrequire(false);
167     }
168     setNodeInfo(nodeId).m_type = nodeType;
169   }
170 
171   setNodeInfo(getOwnNodeId()).m_connected = true;
172   setNodeInfo(getOwnNodeId()).m_version = ndbGetOwnVersion();
173   setNodeInfo(getOwnNodeId()).m_mysql_version = NDB_MYSQL_VERSION_D;
174 
175   c_memusage_report_frequency = 0;
176 
177   m_start_time = NdbTick_CurrentMillisecond() / 1000; // seconds
178 
179   bzero(g_acc_pages_used, sizeof(g_acc_pages_used));
180 
181 }
182 
~Cmvmi()183 Cmvmi::~Cmvmi()
184 {
185   m_shared_page_pool.clear();
186 }
187 
188 #ifdef ERROR_INSERT
189 NodeBitmask c_error_9000_nodes_mask;
190 extern Uint32 MAX_RECEIVED_SIGNALS;
191 #endif
192 
execNDB_TAMPER(Signal * signal)193 void Cmvmi::execNDB_TAMPER(Signal* signal)
194 {
195   jamEntry();
196   SET_ERROR_INSERT_VALUE(signal->theData[0]);
197   if(ERROR_INSERTED(9999)){
198     CRASH_INSERTION(9999);
199   }
200 
201   if(ERROR_INSERTED(9998)){
202     while(true) NdbSleep_SecSleep(1);
203   }
204 
205   if(ERROR_INSERTED(9997)){
206     ndbrequire(false);
207   }
208 
209 #ifndef NDB_WIN32
210   if(ERROR_INSERTED(9996)){
211     simulate_error_during_shutdown= SIGSEGV;
212     ndbrequire(false);
213   }
214 
215   if(ERROR_INSERTED(9995)){
216     simulate_error_during_shutdown= SIGSEGV;
217     kill(getpid(), SIGABRT);
218   }
219 #endif
220 
221 #ifdef ERROR_INSERT
222   if (signal->theData[0] == 9003)
223   {
224     if (MAX_RECEIVED_SIGNALS < 1024)
225     {
226       MAX_RECEIVED_SIGNALS = 1024;
227     }
228     else
229     {
230       MAX_RECEIVED_SIGNALS = 1 + (rand() % 128);
231     }
232     ndbout_c("MAX_RECEIVED_SIGNALS: %d", MAX_RECEIVED_SIGNALS);
233     CLEAR_ERROR_INSERT_VALUE;
234   }
235 #endif
236 }//execNDB_TAMPER()
237 
238 static Uint32 blocks[] =
239 {
240   QMGR_REF,
241   NDBCNTR_REF,
242   DBTC_REF,
243   DBDIH_REF,
244   DBDICT_REF,
245   DBLQH_REF,
246   DBTUP_REF,
247   DBACC_REF,
248   NDBFS_REF,
249   BACKUP_REF,
250   DBUTIL_REF,
251   SUMA_REF,
252   TRIX_REF,
253   DBTUX_REF,
254   LGMAN_REF,
255   TSMAN_REF,
256   PGMAN_REF,
257   DBINFO_REF,
258   DBSPJ_REF,
259   0
260 };
261 
262 void
execSYNC_REQ(Signal * signal)263 Cmvmi::execSYNC_REQ(Signal* signal)
264 {
265   jamEntry();
266   SyncReq req = * CAST_CONSTPTR(SyncReq, signal->getDataPtr());
267   Ptr<SyncRecord> ptr;
268   if (!c_syncReqPool.seize(ptr))
269   {
270     jam();
271     SyncRecord tmp;
272     ptr.p = &tmp;
273     tmp.m_senderRef = req.senderRef;
274     tmp.m_senderData = req.senderData;
275     tmp.m_prio = req.prio;
276     tmp.m_error = SyncRef::SR_OUT_OF_MEMORY;
277     sendSYNC_REP(signal, ptr);
278     return;
279   }
280 
281   ptr.p->m_senderRef = req.senderRef;
282   ptr.p->m_senderData = req.senderData;
283   ptr.p->m_prio = req.prio;
284   ptr.p->m_error = 0;
285 
286   SyncReq* out = CAST_PTR(SyncReq, signal->getDataPtrSend());
287   out->senderRef = reference();
288   out->senderData = ptr.i;
289   out->prio = ptr.p->m_prio;
290   Uint32 i = 0;
291   for (i = 0; blocks[i] != 0; i++)
292   {
293     sendSignal(blocks[i], GSN_SYNC_REQ, signal, SyncReq::SignalLength,
294                JobBufferLevel(ptr.p->m_prio));
295   }
296   ptr.p->m_cnt = i;
297 }
298 
299 void
execSYNC_CONF(Signal * signal)300 Cmvmi::execSYNC_CONF(Signal* signal)
301 {
302   jamEntry();
303   SyncConf conf = * CAST_CONSTPTR(SyncConf, signal->getDataPtr());
304 
305   Ptr<SyncRecord> ptr;
306   c_syncReqPool.getPtr(ptr, conf.senderData);
307   ndbrequire(ptr.p->m_cnt > 0);
308   ptr.p->m_cnt--;
309   if (ptr.p->m_cnt == 0)
310   {
311     jam();
312 
313     sendSYNC_REP(signal, ptr);
314     c_syncReqPool.release(ptr);
315   }
316 }
317 
318 void
execSYNC_REF(Signal * signal)319 Cmvmi::execSYNC_REF(Signal* signal)
320 {
321   jamEntry();
322   SyncRef ref = * CAST_CONSTPTR(SyncRef, signal->getDataPtr());
323 
324   Ptr<SyncRecord> ptr;
325   c_syncReqPool.getPtr(ptr, ref.senderData);
326   ndbrequire(ptr.p->m_cnt > 0);
327   ptr.p->m_cnt--;
328 
329   if (ptr.p->m_error == 0)
330   {
331     jam();
332     ptr.p->m_error = ref.errorCode;
333   }
334 
335   if (ptr.p->m_cnt == 0)
336   {
337     jam();
338 
339     sendSYNC_REP(signal, ptr);
340     c_syncReqPool.release(ptr);
341   }
342 }
343 
344 void
sendSYNC_REP(Signal * signal,Ptr<SyncRecord> ptr)345 Cmvmi::sendSYNC_REP(Signal * signal, Ptr<SyncRecord> ptr)
346 {
347   if (ptr.p->m_error == 0)
348   {
349     jam();
350     SyncConf* conf = CAST_PTR(SyncConf, signal->getDataPtrSend());
351     conf->senderRef = reference();
352     conf->senderData = ptr.p->m_senderData;
353     sendSignal(ptr.p->m_senderRef, GSN_SYNC_CONF, signal,
354                SyncConf::SignalLength,
355                JobBufferLevel(ptr.p->m_prio));
356   }
357   else
358   {
359     jam();
360     SyncRef* ref = CAST_PTR(SyncRef, signal->getDataPtrSend());
361     ref->senderRef = reference();
362     ref->senderData = ptr.p->m_senderData;
363     ref->errorCode = ptr.p->m_error;
364     sendSignal(ptr.p->m_senderRef, GSN_SYNC_REF, signal, SyncRef::SignalLength,
365                JobBufferLevel(ptr.p->m_prio));
366   }
367 }
368 
execSET_LOGLEVELORD(Signal * signal)369 void Cmvmi::execSET_LOGLEVELORD(Signal* signal)
370 {
371   SetLogLevelOrd * const llOrd = (SetLogLevelOrd *)&signal->theData[0];
372   LogLevel::EventCategory category;
373   Uint32 level;
374   jamEntry();
375 
376   for(unsigned int i = 0; i<llOrd->noOfEntries; i++){
377     category = (LogLevel::EventCategory)(llOrd->theData[i] >> 16);
378     level = llOrd->theData[i] & 0xFFFF;
379 
380     clogLevel.setLogLevel(category, level);
381   }
382 }//execSET_LOGLEVELORD()
383 
384 struct SavedEvent
385 {
386   Uint32 m_len;
387   Uint32 m_seq;
388   Uint32 m_time;
389   Uint32 m_data[25];
390 
391   STATIC_CONST( HeaderLength = 3 );
392 };
393 
394 static
395 struct SavedEventBuffer
396 {
SavedEventBufferSavedEventBuffer397   SavedEventBuffer() {
398     m_read_pos = m_write_pos = 0;
399     m_sequence = 0;
400     m_buffer_len = 0;
401     m_data = 0;
402   }
403 
initSavedEventBuffer404   void init(Uint32 bytes) {
405     if (bytes < 128)
406     {
407       return; // min size...unless set to 0
408     }
409     Uint32 words = bytes / 4;
410     m_data = new Uint32[words];
411     if (m_data)
412     {
413       m_buffer_len = words;
414     }
415   }
416 
417   Uint32 m_sequence;
418   Uint16 m_write_pos;
419   Uint16 m_read_pos;
420   Uint32 m_buffer_len;
421   Uint32 * m_data;
422 
423   void alloc(Uint32 len);
424   void purge();
425   void save(const Uint32 * theData, Uint32 len);
426 
427   Uint32 free() const;
428 
429   Uint32 m_scan_pos;
430   void startScan();
431   int scan(SavedEvent * dst, Uint32 filter[]);
432 } m_saved_event_buffer;
433 
434 void
alloc(Uint32 len)435 SavedEventBuffer::alloc(Uint32 len)
436 {
437   assert(m_buffer_len > 0);
438 
439   while (free() <= len)
440     purge();
441 }
442 
443 Uint32
free() const444 SavedEventBuffer::free() const
445 {
446   if (m_write_pos == m_read_pos)
447     return m_buffer_len;
448   else if (m_write_pos > m_read_pos)
449     return (m_buffer_len - m_write_pos) + m_read_pos;
450   else
451     return m_read_pos - m_write_pos;
452 }
453 
454 void
purge()455 SavedEventBuffer::purge()
456 {
457   const Uint32 * ptr = m_data + m_read_pos;
458   const SavedEvent * header = (SavedEvent*)ptr;
459   Uint32 len = SavedEvent::HeaderLength + header->m_len;
460   m_read_pos = (m_read_pos + len) % m_buffer_len;
461 }
462 
463 void
save(const Uint32 * theData,Uint32 len)464 SavedEventBuffer::save(const Uint32 * theData, Uint32 len)
465 {
466   if (m_buffer_len == 0)
467     return;
468 
469   Uint32 total = len + SavedEvent::HeaderLength;
470   alloc(total);
471 
472   SavedEvent s;
473   s.m_len = len; // size of SavedEvent
474   s.m_seq = m_sequence++;
475   s.m_time = (Uint32)time(0);
476   const Uint32 * src = (const Uint32*)&s;
477   Uint32 * dst = m_data + m_write_pos;
478 
479   Uint32 remain = m_buffer_len - m_write_pos;
480   if (remain >= total)
481   {
482     memcpy(dst, src, 4 * SavedEvent::HeaderLength);
483     memcpy(dst+SavedEvent::HeaderLength, theData, 4*len);
484   }
485   else
486   {
487     memcpy(s.m_data, theData, 4 * len);
488     memcpy(dst, src, 4 * remain);
489     memcpy(m_data, src + remain, 4 * (total - remain));
490   }
491   m_write_pos = (m_write_pos + total) % m_buffer_len;
492 }
493 
494 void
startScan()495 SavedEventBuffer::startScan()
496 {
497   m_scan_pos = m_read_pos;
498 }
499 
500 int
scan(SavedEvent * _dst,Uint32 filter[])501 SavedEventBuffer::scan(SavedEvent* _dst, Uint32 filter[])
502 {
503   Uint32 * dst = (Uint32*)_dst;
504   while (m_scan_pos != m_write_pos)
505   {
506     const Uint32 * ptr = m_data + m_scan_pos;
507     SavedEvent * s = (SavedEvent*)ptr;
508     assert(s->m_len <= 25);
509     Uint32 total = s->m_len + SavedEvent::HeaderLength;
510     if (m_scan_pos + total <= m_buffer_len)
511     {
512       memcpy(dst, s, 4 * total);
513     }
514     else
515     {
516       Uint32 remain = m_buffer_len - m_scan_pos;
517       memcpy(dst, s, 4 * remain);
518       memcpy(dst + remain, m_data, 4 * (total - remain));
519     }
520     m_scan_pos = (m_scan_pos + total) % m_buffer_len;
521     return 1;
522   }
523   return 0;
524 }
525 
execEVENT_REP(Signal * signal)526 void Cmvmi::execEVENT_REP(Signal* signal)
527 {
528   //-----------------------------------------------------------------------
529   // This message is sent to report any types of events in NDB.
530   // Based on the log level they will be either ignored or
531   // reported. Currently they are printed, but they will be
532   // transferred to the management server for further distribution
533   // to the graphical management interface.
534   //-----------------------------------------------------------------------
535   EventReport * const eventReport = (EventReport *)&signal->theData[0];
536   Ndb_logevent_type eventType = eventReport->getEventType();
537   Uint32 nodeId= eventReport->getNodeId();
538   if (nodeId == 0)
539   {
540     nodeId= refToNode(signal->getSendersBlockRef());
541 
542     if (nodeId == 0)
543     {
544       /* Event reporter supplied no node id,
545        * assume it was local
546        */
547       nodeId= getOwnNodeId();
548     }
549 
550     eventReport->setNodeId(nodeId);
551   }
552 
553   jamEntry();
554 
555   /**
556    * If entry is not found
557    */
558   Uint32 threshold;
559   LogLevel::EventCategory eventCategory;
560   Logger::LoggerLevel severity;
561   EventLoggerBase::EventTextFunction textF;
562   if (EventLoggerBase::event_lookup(eventType,eventCategory,threshold,severity,textF))
563     return;
564 
565   SubscriberPtr ptr;
566   for(subscribers.first(ptr); ptr.i != RNIL; subscribers.next(ptr)){
567     if(ptr.p->logLevel.getLogLevel(eventCategory) < threshold){
568       continue;
569     }
570 
571     sendSignal(ptr.p->blockRef, GSN_EVENT_REP, signal, signal->length(), JBB);
572   }
573 
574   m_saved_event_buffer.save(signal->theData, signal->getLength());
575 
576   if(clogLevel.getLogLevel(eventCategory) < threshold){
577     return;
578   }
579 
580   // Print the event info
581   g_eventLogger->log(eventReport->getEventType(),
582                      signal->theData, signal->getLength(), 0, 0);
583 
584   return;
585 }//execEVENT_REP()
586 
587 void
execEVENT_SUBSCRIBE_REQ(Signal * signal)588 Cmvmi::execEVENT_SUBSCRIBE_REQ(Signal * signal){
589   EventSubscribeReq * subReq = (EventSubscribeReq *)&signal->theData[0];
590   Uint32 senderRef = signal->getSendersBlockRef();
591   SubscriberPtr ptr;
592   jamEntry();
593   DBUG_ENTER("Cmvmi::execEVENT_SUBSCRIBE_REQ");
594 
595   /**
596    * Search for subcription
597    */
598   for(subscribers.first(ptr); ptr.i != RNIL; subscribers.next(ptr)){
599     if(ptr.p->blockRef == subReq->blockRef)
600       break;
601   }
602 
603   if(ptr.i == RNIL){
604     /**
605      * Create a new one
606      */
607     if(subscribers.seize(ptr) == false){
608       sendSignal(senderRef, GSN_EVENT_SUBSCRIBE_REF, signal, 1, JBB);
609       return;
610     }
611     ptr.p->logLevel.clear();
612     ptr.p->blockRef = subReq->blockRef;
613   }
614 
615   if(subReq->noOfEntries == 0){
616     /**
617      * Cancel subscription
618      */
619     subscribers.release(ptr.i);
620   } else {
621     /**
622      * Update subscription
623      */
624     LogLevel::EventCategory category;
625     Uint32 level = 0;
626     for(Uint32 i = 0; i<subReq->noOfEntries; i++){
627       category = (LogLevel::EventCategory)(subReq->theData[i] >> 16);
628       level = subReq->theData[i] & 0xFFFF;
629       ptr.p->logLevel.setLogLevel(category, level);
630       DBUG_PRINT("info",("entry %d: level=%d, category= %d", i, level, category));
631     }
632   }
633 
634   signal->theData[0] = ptr.i;
635   sendSignal(senderRef, GSN_EVENT_SUBSCRIBE_CONF, signal, 1, JBB);
636   DBUG_VOID_RETURN;
637 }
638 
639 void
cancelSubscription(NodeId nodeId)640 Cmvmi::cancelSubscription(NodeId nodeId){
641 
642   SubscriberPtr ptr;
643   subscribers.first(ptr);
644 
645   while(ptr.i != RNIL){
646     Uint32 i = ptr.i;
647     BlockReference blockRef = ptr.p->blockRef;
648 
649     subscribers.next(ptr);
650 
651     if(refToNode(blockRef) == nodeId){
652       subscribers.release(i);
653     }
654   }
655 }
656 
sendSTTORRY(Signal * signal)657 void Cmvmi::sendSTTORRY(Signal* signal)
658 {
659   jam();
660   signal->theData[3] = 1;
661   signal->theData[4] = 3;
662   signal->theData[5] = 8;
663   signal->theData[6] = 255;
664   sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 7, JBB);
665 }//Cmvmi::sendSTTORRY
666 
667 
668 static Uint32 f_accpages = 0;
669 extern Uint32 compute_acc_32kpages(const ndb_mgm_configuration_iterator * p);
670 
671 static Uint32 f_read_config_ref = 0;
672 static Uint32 f_read_config_data = 0;
673 
674 void
execREAD_CONFIG_REQ(Signal * signal)675 Cmvmi::execREAD_CONFIG_REQ(Signal* signal)
676 {
677   jamEntry();
678 
679   const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
680 
681   Uint32 ref = req->senderRef;
682   Uint32 senderData = req->senderData;
683 
684   const ndb_mgm_configuration_iterator * p =
685     m_ctx.m_config.getOwnConfigIterator();
686   ndbrequire(p != 0);
687 
688   {
689     void* ptr = m_ctx.m_mm.get_memroot();
690     m_shared_page_pool.set((GlobalPage*)ptr, ~0);
691   }
692 
693   f_accpages = compute_acc_32kpages(p);
694 
695   Uint32 eventlog = 4096;
696   ndb_mgm_get_int_parameter(p, CFG_DB_EVENTLOG_BUFFER_SIZE, &eventlog);
697   m_saved_event_buffer.init(eventlog);
698 
699   c_memusage_report_frequency = 0;
700   ndb_mgm_get_int_parameter(p, CFG_DB_MEMREPORT_FREQUENCY,
701                             &c_memusage_report_frequency);
702 
703   Uint32 late_alloc = 1;
704   ndb_mgm_get_int_parameter(p, CFG_DB_LATE_ALLOC,
705                             &late_alloc);
706   if (late_alloc)
707   {
708     jam();
709     f_read_config_ref = ref;
710     f_read_config_data = senderData;
711 
712 
713     AllocMemReq * req = CAST_PTR(AllocMemReq, signal->getDataPtrSend());
714     req->senderData = 0;
715     req->senderRef = reference();
716     req->requestInfo = AllocMemReq::RT_MAP;
717     if (m_ctx.m_config.lockPagesInMainMemory())
718     {
719       req->requestInfo |= AllocMemReq::RT_MEMLOCK;
720     }
721 
722     req->bytes_hi = 0;
723     req->bytes_lo = 0;
724     sendSignal(NDBFS_REF, GSN_ALLOC_MEM_REQ, signal,
725                AllocMemReq::SignalLength, JBB);
726 
727     /**
728      * Assume this takes time...
729      *   Set sp0 complete (even though it hasn't) but it makes
730      *   ndb_mgm -e "show" show starting instead of not-started
731      */
732     {
733       NodeStateRep * rep = CAST_PTR(NodeStateRep, signal->getDataPtrSend());
734       NodeState newState(NodeState::SL_STARTING, 0,
735                          NodeState::ST_ILLEGAL_TYPE);
736       rep->nodeState = newState;
737       rep->nodeState.masterNodeId = 0;
738       rep->nodeState.setNodeGroup(0);
739       sendSignal(QMGR_REF, GSN_NODE_STATE_REP, signal,
740                  NodeStateRep::SignalLength, JBB);
741     }
742     return;
743   }
744 
745   init_global_page_pool();
746 
747   ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
748   conf->senderRef = reference();
749   conf->senderData = senderData;
750   sendSignal(ref, GSN_READ_CONFIG_CONF, signal,
751 	     ReadConfigConf::SignalLength, JBB);
752 }
753 
754 void
init_global_page_pool()755 Cmvmi::init_global_page_pool()
756 {
757   /**
758    * This subroutine takes page from m_shared_page_pool and
759    *   moves them into m_global_page_pool
760    *   (that is currently used by pgman(dbtup) and restore
761    */
762   void* ptr = m_ctx.m_mm.get_memroot();
763   m_global_page_pool.set((GlobalPage*)ptr, ~0);
764 
765   Resource_limit rl;
766   ndbrequire(m_ctx.m_mm.get_resource_limit(RG_DISK_PAGE_BUFFER, rl));
767   while (rl.m_max)
768   {
769     Uint32 ptrI;
770     Uint32 cnt = rl.m_max;
771     m_ctx.m_mm.alloc_pages(RG_DISK_PAGE_BUFFER, &ptrI, &cnt, 1);
772     ndbrequire(cnt);
773     for (Uint32 i = 0; i<cnt; i++)
774     {
775       Ptr<GlobalPage> pagePtr;
776       m_shared_page_pool.getPtr(pagePtr, ptrI + i);
777       m_global_page_pool.release(pagePtr);
778     }
779     rl.m_max -= cnt;
780   }
781 }
782 
execSTTOR(Signal * signal)783 void Cmvmi::execSTTOR(Signal* signal)
784 {
785   Uint32 theStartPhase  = signal->theData[1];
786 
787   jamEntry();
788   if (theStartPhase == 1){
789     jam();
790 
791     if (m_ctx.m_config.lockPagesInMainMemory())
792     {
793       jam();
794       /**
795        * Notify watchdog that we're locking memory...
796        *   which can be equally "heavy" as allocating it
797        */
798       refresh_watch_dog(9);
799       int res = NdbMem_MemLockAll(1);
800       if (res != 0)
801       {
802         char buf[100];
803         BaseString::snprintf(buf, sizeof(buf),
804                              "Failed to memlock pages, error: %d (%s)",
805                              errno, strerror(errno));
806         g_eventLogger->warning("%s", buf);
807         warningEvent("%s", buf);
808       }
809       else
810       {
811         g_eventLogger->info("Using locked memory");
812       }
813     }
814 
815     /**
816      * Install "normal" watchdog value
817      */
818     {
819       Uint32 db_watchdog_interval = 0;
820       const ndb_mgm_configuration_iterator * p =
821         m_ctx.m_config.getOwnConfigIterator();
822       ndb_mgm_get_int_parameter(p, CFG_DB_WATCHDOG_INTERVAL,
823                                 &db_watchdog_interval);
824       ndbrequire(db_watchdog_interval);
825       update_watch_dog_timer(db_watchdog_interval);
826     }
827 
828     /**
829      * Start auto-mem reporting
830      */
831     signal->theData[0] = ZREPORT_MEMORY_USAGE;
832     signal->theData[1] = 0;
833     signal->theData[2] = 0;
834     signal->theData[3] = 0;
835     execCONTINUEB(signal);
836 
837     sendSTTORRY(signal);
838     return;
839   } else if (theStartPhase == 3) {
840     jam();
841     globalData.activateSendPacked = 1;
842     sendSTTORRY(signal);
843   } else if (theStartPhase == 8){
844 #ifdef ERROR_INSERT
845     if (ERROR_INSERTED(9004))
846     {
847       Uint32 len = signal->getLength();
848       Uint32 db = c_dbNodes.find(0);
849       if (db == getOwnNodeId())
850         db = c_dbNodes.find(db);
851       Uint32 i = c_error_9000_nodes_mask.find(0);
852       Uint32 tmp[25];
853       memcpy(tmp, signal->theData, sizeof(tmp));
854       signal->theData[0] = i;
855       sendSignal(calcQmgrBlockRef(db),GSN_API_FAILREQ, signal, 1, JBA);
856       ndbout_c("stopping %u using %u", i, db);
857       CLEAR_ERROR_INSERT_VALUE;
858       memcpy(signal->theData, tmp, sizeof(tmp));
859       sendSignalWithDelay(reference(), GSN_STTOR,
860                           signal, 100, len);
861       return;
862     }
863 #endif
864     globalData.theStartLevel = NodeState::SL_STARTED;
865     sendSTTORRY(signal);
866   }
867 }
868 
execCLOSE_COMREQ(Signal * signal)869 void Cmvmi::execCLOSE_COMREQ(Signal* signal)
870 {
871   // Close communication with the node and halt input/output from
872   // other blocks than QMGR
873 
874   CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
875 
876   const BlockReference userRef = closeCom->xxxBlockRef;
877   Uint32 requestType = closeCom->requestType;
878   Uint32 failNo = closeCom->failNo;
879 //  Uint32 noOfNodes = closeCom->noOfNodes;
880 
881   jamEntry();
882   for (unsigned i = 0; i < MAX_NODES; i++)
883   {
884     if(NodeBitmask::get(closeCom->theNodes, i))
885     {
886       jam();
887 
888       //-----------------------------------------------------
889       // Report that the connection to the node is closed
890       //-----------------------------------------------------
891       signal->theData[0] = NDB_LE_CommunicationClosed;
892       signal->theData[1] = i;
893       sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
894 
895       globalTransporterRegistry.setIOState(i, HaltIO);
896       globalTransporterRegistry.do_disconnect(i);
897     }
898   }
899   if (requestType != CloseComReqConf::RT_NO_REPLY)
900   {
901     ndbassert((requestType == CloseComReqConf::RT_API_FAILURE) ||
902               ((requestType == CloseComReqConf::RT_NODE_FAILURE) &&
903                (failNo != 0)));
904     jam();
905     CloseComReqConf* closeComConf = (CloseComReqConf *)signal->getDataPtrSend();
906     closeComConf->xxxBlockRef = userRef;
907     closeComConf->requestType = requestType;
908     closeComConf->failNo = failNo;
909 
910     /* Note assumption that noOfNodes and theNodes
911      * bitmap is not trampled above
912      * signals received from the remote node.
913      */
914     sendSignal(QMGR_REF, GSN_CLOSE_COMCONF, signal, 19, JBA);
915   }
916 }
917 
execOPEN_COMREQ(Signal * signal)918 void Cmvmi::execOPEN_COMREQ(Signal* signal)
919 {
920   // Connect to the specifed NDB node, only QMGR allowed communication
921   // so far with the node
922 
923   const BlockReference userRef = signal->theData[0];
924   Uint32 tStartingNode = signal->theData[1];
925   Uint32 tData2 = signal->theData[2];
926   jamEntry();
927 
928   const Uint32 len = signal->getLength();
929   if(len == 2)
930   {
931 #ifdef ERROR_INSERT
932     if (! ((ERROR_INSERTED(9000) || ERROR_INSERTED(9002))
933 	   && c_error_9000_nodes_mask.get(tStartingNode)))
934 #endif
935     {
936       globalTransporterRegistry.do_connect(tStartingNode);
937       globalTransporterRegistry.setIOState(tStartingNode, HaltIO);
938 
939       //-----------------------------------------------------
940       // Report that the connection to the node is opened
941       //-----------------------------------------------------
942       signal->theData[0] = NDB_LE_CommunicationOpened;
943       signal->theData[1] = tStartingNode;
944       sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
945       //-----------------------------------------------------
946     }
947   } else {
948     for(unsigned int i = 1; i < MAX_NODES; i++ )
949     {
950       jam();
951       if (i != getOwnNodeId() && getNodeInfo(i).m_type == tData2)
952       {
953 	jam();
954 
955 #ifdef ERROR_INSERT
956 	if ((ERROR_INSERTED(9000) || ERROR_INSERTED(9002))
957 	    && c_error_9000_nodes_mask.get(i))
958 	  continue;
959 #endif
960 	globalTransporterRegistry.do_connect(i);
961 	globalTransporterRegistry.setIOState(i, HaltIO);
962 
963 	signal->theData[0] = NDB_LE_CommunicationOpened;
964 	signal->theData[1] = i;
965 	sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
966       }
967     }
968   }
969 
970   if (userRef != 0)
971   {
972     jam();
973     signal->theData[0] = tStartingNode;
974     signal->theData[1] = tData2;
975     sendSignal(userRef, GSN_OPEN_COMCONF, signal, len - 1,JBA);
976   }
977 }
978 
execENABLE_COMREQ(Signal * signal)979 void Cmvmi::execENABLE_COMREQ(Signal* signal)
980 {
981   jamEntry();
982   const EnableComReq *enableComReq = (const EnableComReq *)signal->getDataPtr();
983 
984   /* Need to copy out signal data to not clobber it with sendSignal(). */
985   Uint32 senderRef = enableComReq->m_senderRef;
986   Uint32 senderData = enableComReq->m_senderData;
987   Uint32 nodes[NodeBitmask::Size];
988   MEMCOPY_NO_WORDS(nodes, enableComReq->m_nodeIds, NodeBitmask::Size);
989 
990   /* Enable communication with all our NDB blocks to these nodes. */
991   Uint32 search_from = 0;
992   for (;;)
993   {
994     Uint32 tStartingNode = NodeBitmask::find(nodes, search_from);
995     if (tStartingNode == NodeBitmask::NotFound)
996       break;
997     search_from = tStartingNode + 1;
998 
999     globalTransporterRegistry.setIOState(tStartingNode, NoHalt);
1000     setNodeInfo(tStartingNode).m_connected = true;
1001 
1002     //-----------------------------------------------------
1003     // Report that the version of the node
1004     //-----------------------------------------------------
1005     signal->theData[0] = NDB_LE_ConnectedApiVersion;
1006     signal->theData[1] = tStartingNode;
1007     signal->theData[2] = getNodeInfo(tStartingNode).m_version;
1008     signal->theData[3] = getNodeInfo(tStartingNode).m_mysql_version;
1009 
1010     sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB);
1011     //-----------------------------------------------------
1012   }
1013 
1014   EnableComConf *enableComConf = (EnableComConf *)signal->getDataPtrSend();
1015   enableComConf->m_senderRef = reference();
1016   enableComConf->m_senderData = senderData;
1017   MEMCOPY_NO_WORDS(enableComConf->m_nodeIds, nodes, NodeBitmask::Size);
1018   sendSignal(senderRef, GSN_ENABLE_COMCONF, signal,
1019              EnableComConf::SignalLength, JBA);
1020 }
1021 
execDISCONNECT_REP(Signal * signal)1022 void Cmvmi::execDISCONNECT_REP(Signal *signal)
1023 {
1024   const DisconnectRep * const rep = (DisconnectRep *)&signal->theData[0];
1025   const Uint32 hostId = rep->nodeId;
1026   jamEntry();
1027 
1028   setNodeInfo(hostId).m_connected = false;
1029   setNodeInfo(hostId).m_connectCount++;
1030   const NodeInfo::NodeType type = getNodeInfo(hostId).getType();
1031   ndbrequire(type != NodeInfo::INVALID);
1032 
1033   sendSignal(QMGR_REF, GSN_DISCONNECT_REP, signal,
1034              DisconnectRep::SignalLength, JBA);
1035 
1036   cancelSubscription(hostId);
1037 
1038   signal->theData[0] = NDB_LE_Disconnected;
1039   signal->theData[1] = hostId;
1040   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
1041 }
1042 
execCONNECT_REP(Signal * signal)1043 void Cmvmi::execCONNECT_REP(Signal *signal){
1044   const Uint32 hostId = signal->theData[0];
1045   jamEntry();
1046 
1047   const NodeInfo::NodeType type = (NodeInfo::NodeType)getNodeInfo(hostId).m_type;
1048   ndbrequire(type != NodeInfo::INVALID);
1049   globalData.m_nodeInfo[hostId].m_version = 0;
1050   globalData.m_nodeInfo[hostId].m_mysql_version = 0;
1051 
1052   /**
1053    * Inform QMGR that client has connected
1054    */
1055   signal->theData[0] = hostId;
1056   if (ERROR_INSERTED(9005))
1057   {
1058     sendSignalWithDelay(QMGR_REF, GSN_CONNECT_REP, signal, 50, 1);
1059   }
1060   else
1061   {
1062     sendSignal(QMGR_REF, GSN_CONNECT_REP, signal, 1, JBA);
1063   }
1064 
1065   /* Automatically subscribe events for MGM nodes.
1066    */
1067   if(type == NodeInfo::MGM)
1068   {
1069     jam();
1070     globalTransporterRegistry.setIOState(hostId, NoHalt);
1071   }
1072 
1073   //------------------------------------------
1074   // Also report this event to the Event handler
1075   //------------------------------------------
1076   signal->theData[0] = NDB_LE_Connected;
1077   signal->theData[1] = hostId;
1078   signal->header.theLength = 2;
1079 
1080   execEVENT_REP(signal);
1081 }
1082 
1083 #ifdef VM_TRACE
1084 void
modifySignalLogger(bool allBlocks,BlockNumber bno,TestOrd::Command cmd,TestOrd::SignalLoggerSpecification spec)1085 modifySignalLogger(bool allBlocks, BlockNumber bno,
1086                    TestOrd::Command cmd,
1087                    TestOrd::SignalLoggerSpecification spec){
1088   SignalLoggerManager::LogMode logMode;
1089 
1090   /**
1091    * Mapping between SignalLoggerManager::LogMode and
1092    *                 TestOrd::SignalLoggerSpecification
1093    */
1094   switch(spec){
1095   case TestOrd::InputSignals:
1096     logMode = SignalLoggerManager::LogIn;
1097     break;
1098   case TestOrd::OutputSignals:
1099     logMode = SignalLoggerManager::LogOut;
1100     break;
1101   case TestOrd::InputOutputSignals:
1102     logMode = SignalLoggerManager::LogInOut;
1103     break;
1104   default:
1105     return;
1106     break;
1107   }
1108 
1109   switch(cmd){
1110   case TestOrd::On:
1111     globalSignalLoggers.logOn(allBlocks, bno, logMode);
1112     break;
1113   case TestOrd::Off:
1114     globalSignalLoggers.logOff(allBlocks, bno, logMode);
1115     break;
1116   case TestOrd::Toggle:
1117     globalSignalLoggers.logToggle(allBlocks, bno, logMode);
1118     break;
1119   case TestOrd::KeepUnchanged:
1120     // Do nothing
1121     break;
1122   }
1123   globalSignalLoggers.flushSignalLog();
1124 }
1125 #endif
1126 
1127 void
execTEST_ORD(Signal * signal)1128 Cmvmi::execTEST_ORD(Signal * signal){
1129   jamEntry();
1130 
1131 #ifdef VM_TRACE
1132   TestOrd * const testOrd = (TestOrd *)&signal->theData[0];
1133 
1134   TestOrd::Command cmd;
1135 
1136   {
1137     /**
1138      * Process Trace command
1139      */
1140     TestOrd::TraceSpecification traceSpec;
1141 
1142     testOrd->getTraceCommand(cmd, traceSpec);
1143     unsigned long traceVal = traceSpec;
1144     unsigned long currentTraceVal = globalSignalLoggers.getTrace();
1145     switch(cmd){
1146     case TestOrd::On:
1147       currentTraceVal |= traceVal;
1148       break;
1149     case TestOrd::Off:
1150       currentTraceVal &= (~traceVal);
1151       break;
1152     case TestOrd::Toggle:
1153       currentTraceVal ^= traceVal;
1154       break;
1155     case TestOrd::KeepUnchanged:
1156       // Do nothing
1157       break;
1158     }
1159     globalSignalLoggers.setTrace(currentTraceVal);
1160   }
1161 
1162   {
1163     /**
1164      * Process Log command
1165      */
1166     TestOrd::SignalLoggerSpecification logSpec;
1167     BlockNumber bno;
1168     unsigned int loggers = testOrd->getNoOfSignalLoggerCommands();
1169 
1170     if(loggers == (unsigned)~0){ // Apply command to all blocks
1171       testOrd->getSignalLoggerCommand(0, bno, cmd, logSpec);
1172       modifySignalLogger(true, bno, cmd, logSpec);
1173     } else {
1174       for(unsigned int i = 0; i<loggers; i++){
1175         testOrd->getSignalLoggerCommand(i, bno, cmd, logSpec);
1176         modifySignalLogger(false, bno, cmd, logSpec);
1177       }
1178     }
1179   }
1180 
1181   {
1182     /**
1183      * Process test command
1184      */
1185     testOrd->getTestCommand(cmd);
1186     switch(cmd){
1187     case TestOrd::On:{
1188       SET_GLOBAL_TEST_ON;
1189     }
1190     break;
1191     case TestOrd::Off:{
1192       SET_GLOBAL_TEST_OFF;
1193     }
1194     break;
1195     case TestOrd::Toggle:{
1196       TOGGLE_GLOBAL_TEST_FLAG;
1197     }
1198     break;
1199     case TestOrd::KeepUnchanged:
1200       // Do nothing
1201       break;
1202     }
1203     globalSignalLoggers.flushSignalLog();
1204   }
1205 
1206 #endif
1207 }
1208 
execSTOP_ORD(Signal * signal)1209 void Cmvmi::execSTOP_ORD(Signal* signal)
1210 {
1211   jamEntry();
1212   globalData.theRestartFlag = perform_stop;
1213 }//execSTOP_ORD()
1214 
1215 void
execSTART_ORD(Signal * signal)1216 Cmvmi::execSTART_ORD(Signal* signal) {
1217   StartOrd * const startOrd = (StartOrd *)&signal->theData[0];
1218   jamEntry();
1219 
1220   Uint32 tmp = startOrd->restartInfo;
1221   if(StopReq::getPerformRestart(tmp)){
1222     jam();
1223     /**
1224      *
1225      */
1226     NdbRestartType type = NRT_Default;
1227     if(StopReq::getNoStart(tmp) && StopReq::getInitialStart(tmp))
1228       type = NRT_NoStart_InitialStart;
1229     if(StopReq::getNoStart(tmp) && !StopReq::getInitialStart(tmp))
1230       type = NRT_NoStart_Restart;
1231     if(!StopReq::getNoStart(tmp) && StopReq::getInitialStart(tmp))
1232       type = NRT_DoStart_InitialStart;
1233     if(!StopReq::getNoStart(tmp)&&!StopReq::getInitialStart(tmp))
1234       type = NRT_DoStart_Restart;
1235     NdbShutdown(0, NST_Restart, type);
1236   }
1237 
1238   if(globalData.theRestartFlag == system_started){
1239     jam();
1240     /**
1241      * START_ORD received when already started(ignored)
1242      */
1243     //ndbout << "START_ORD received when already started(ignored)" << endl;
1244     return;
1245   }
1246 
1247   if(globalData.theRestartFlag == perform_stop){
1248     jam();
1249     /**
1250      * START_ORD received when stopping(ignored)
1251      */
1252     //ndbout << "START_ORD received when stopping(ignored)" << endl;
1253     return;
1254   }
1255 
1256   if(globalData.theStartLevel == NodeState::SL_NOTHING)
1257   {
1258     jam();
1259 
1260     for(unsigned int i = 1; i < MAX_NODES; i++ )
1261     {
1262       if (getNodeInfo(i).m_type == NodeInfo::MGM)
1263       {
1264         jam();
1265         globalTransporterRegistry.do_connect(i);
1266       }
1267     }
1268 
1269     globalData.theStartLevel = NodeState::SL_CMVMI;
1270     sendSignal(QMGR_REF, GSN_START_ORD, signal, 1, JBA);
1271     return ;
1272   }
1273 
1274   if(globalData.theStartLevel == NodeState::SL_CMVMI)
1275   {
1276     jam();
1277 
1278     globalData.theStartLevel  = NodeState::SL_STARTING;
1279     globalData.theRestartFlag = system_started;
1280     /**
1281      * StartLevel 1
1282      *
1283      * Do Restart
1284      */
1285 
1286     // Disconnect all nodes as part of the system restart.
1287     // We need to ensure that we are starting up
1288     // without any connected nodes.
1289     for(unsigned int i = 1; i < MAX_NODES; i++ )
1290     {
1291       if (i != getOwnNodeId() && getNodeInfo(i).m_type != NodeInfo::MGM)
1292       {
1293         globalTransporterRegistry.do_disconnect(i);
1294         globalTransporterRegistry.setIOState(i, HaltIO);
1295       }
1296     }
1297 
1298     CRASH_INSERTION(9994);
1299 
1300     /**
1301      * Start running startphases
1302      */
1303     sendSignal(NDBCNTR_REF, GSN_START_ORD, signal, 1, JBA);
1304     return;
1305   }
1306 }//execSTART_ORD()
1307 
execTAMPER_ORD(Signal * signal)1308 void Cmvmi::execTAMPER_ORD(Signal* signal)
1309 {
1310   jamEntry();
1311   // TODO We should maybe introduce a CONF and REF signal
1312   // to be able to indicate if we really introduced an error.
1313 #ifdef ERROR_INSERT
1314   TamperOrd* const tamperOrd = (TamperOrd*)&signal->theData[0];
1315   Uint32 errNo = tamperOrd->errorNo;
1316 
1317   if (errNo == 0)
1318   {
1319     jam();
1320     signal->theData[0] = 0;
1321     for (Uint32 i = 0; blocks[i] != 0; i++)
1322     {
1323       sendSignal(blocks[i], GSN_NDB_TAMPER, signal, 1, JBB);
1324     }
1325     return;
1326   }
1327 
1328   Uint32 tuserblockref = 0;
1329   if (errNo < 1000)
1330   {
1331     /*--------------------------------------------------------------------*/
1332     // Insert errors into QMGR.
1333     /*--------------------------------------------------------------------*/
1334     jam();
1335     tuserblockref = QMGR_REF;
1336   }
1337   else if (errNo < 2000)
1338   {
1339     /*--------------------------------------------------------------------*/
1340     // Insert errors into NDBCNTR.
1341     /*--------------------------------------------------------------------*/
1342     jam();
1343     tuserblockref = NDBCNTR_REF;
1344   }
1345   else if (errNo < 3000)
1346   {
1347     /*--------------------------------------------------------------------*/
1348     // Insert errors into NDBFS.
1349     /*--------------------------------------------------------------------*/
1350     jam();
1351     tuserblockref = NDBFS_REF;
1352   }
1353   else if (errNo < 4000)
1354   {
1355     /*--------------------------------------------------------------------*/
1356     // Insert errors into DBACC.
1357     /*--------------------------------------------------------------------*/
1358     jam();
1359     tuserblockref = DBACC_REF;
1360   }
1361   else if (errNo < 5000)
1362   {
1363     /*--------------------------------------------------------------------*/
1364     // Insert errors into DBTUP.
1365     /*--------------------------------------------------------------------*/
1366     jam();
1367     tuserblockref = DBTUP_REF;
1368   }
1369   else if (errNo < 6000)
1370   {
1371     /*---------------------------------------------------------------------*/
1372     // Insert errors into DBLQH.
1373     /*---------------------------------------------------------------------*/
1374     jam();
1375     tuserblockref = DBLQH_REF;
1376   }
1377   else if (errNo < 7000)
1378   {
1379     /*---------------------------------------------------------------------*/
1380     // Insert errors into DBDICT.
1381     /*---------------------------------------------------------------------*/
1382     jam();
1383     tuserblockref = DBDICT_REF;
1384   }
1385   else if (errNo < 8000)
1386   {
1387     /*---------------------------------------------------------------------*/
1388     // Insert errors into DBDIH.
1389     /*--------------------------------------------------------------------*/
1390     jam();
1391     tuserblockref = DBDIH_REF;
1392   }
1393   else if (errNo < 9000)
1394   {
1395     /*--------------------------------------------------------------------*/
1396     // Insert errors into DBTC.
1397     /*--------------------------------------------------------------------*/
1398     jam();
1399     tuserblockref = DBTC_REF;
1400   }
1401   else if (errNo < 10000)
1402   {
1403     /*--------------------------------------------------------------------*/
1404     // Insert errors into CMVMI.
1405     /*--------------------------------------------------------------------*/
1406     jam();
1407     tuserblockref = CMVMI_REF;
1408   }
1409   else if (errNo < 11000)
1410   {
1411     jam();
1412     tuserblockref = BACKUP_REF;
1413   }
1414   else if (errNo < 12000)
1415   {
1416     // DBUTIL_REF ?
1417     jam();
1418   }
1419   else if (errNo < 13000)
1420   {
1421     jam();
1422     tuserblockref = DBTUX_REF;
1423   }
1424   else if (errNo < 14000)
1425   {
1426     jam();
1427     tuserblockref = SUMA_REF;
1428   }
1429   else if (errNo < 15000)
1430   {
1431     jam();
1432     tuserblockref = DBDICT_REF;
1433   }
1434   else if (errNo < 16000)
1435   {
1436     jam();
1437     tuserblockref = LGMAN_REF;
1438   }
1439   else if (errNo < 17000)
1440   {
1441     jam();
1442     tuserblockref = TSMAN_REF;
1443   }
1444   else if (errNo < 18000)
1445   {
1446     jam();
1447     tuserblockref = DBSPJ_REF;
1448   }
1449   else if (errNo < 19000)
1450   {
1451     jam();
1452     tuserblockref = TRIX_REF;
1453   }
1454   else if (errNo < 30000)
1455   {
1456     /*--------------------------------------------------------------------*/
1457     // Ignore errors in the 20000-range.
1458     /*--------------------------------------------------------------------*/
1459     jam();
1460     return;
1461   }
1462   else if (errNo < 40000)
1463   {
1464     jam();
1465     /*--------------------------------------------------------------------*/
1466     // Redirect errors to master DIH in the 30000-range.
1467     /*--------------------------------------------------------------------*/
1468 
1469     /**
1470      * since CMVMI doesnt keep track of master,
1471      * send to local DIH
1472      */
1473     signal->theData[0] = 5;
1474     signal->theData[1] = errNo;
1475     signal->theData[2] = 0;
1476     sendSignal(DBDIH_REF, GSN_DIHNDBTAMPER, signal, 3, JBB);
1477     return;
1478   }
1479   else if (errNo < 50000)
1480   {
1481     jam();
1482 
1483     /**
1484      * since CMVMI doesnt keep track of master,
1485      * send to local DIH
1486      */
1487     signal->theData[0] = 5;
1488     signal->theData[1] = errNo;
1489     signal->theData[2] = 0;
1490     sendSignal(DBDIH_REF, GSN_DIHNDBTAMPER, signal, 3, JBB);
1491     return;
1492   }
1493 
1494   ndbassert(tuserblockref != 0); // mapping missing ??
1495   if (tuserblockref != 0)
1496   {
1497     signal->theData[0] = errNo;
1498     sendSignal(tuserblockref, GSN_NDB_TAMPER, signal, 1, JBB);
1499   }
1500 #endif
1501 }//execTAMPER_ORD()
1502 
1503 #ifdef VM_TRACE
1504 class RefSignalTest {
1505 public:
1506   enum ErrorCode {
1507     OK = 0,
1508     NF_FakeErrorREF = 7
1509   };
1510   Uint32 senderRef;
1511   Uint32 senderData;
1512   Uint32 errorCode;
1513 };
1514 #endif
1515 
1516 
1517 static int iii;
1518 
1519 static
1520 int
recurse(char * buf,int loops,int arg)1521 recurse(char * buf, int loops, int arg){
1522   char * tmp = (char*)alloca(arg);
1523   printf("tmp = %p\n", tmp);
1524   for(iii = 0; iii<arg; iii += 1024){
1525     tmp[iii] = (iii % 23 + (arg & iii));
1526   }
1527 
1528   if(loops == 0)
1529     return tmp[345];
1530   else
1531     return tmp[arg/loops] + recurse(tmp, loops - 1, arg);
1532 }
1533 
1534 #define check_block(block,val) \
1535 (((val) >= DumpStateOrd::_ ## block ## Min) && ((val) <= DumpStateOrd::_ ## block ## Max))
1536 
1537 void
execDUMP_STATE_ORD(Signal * signal)1538 Cmvmi::execDUMP_STATE_ORD(Signal* signal)
1539 {
1540   jamEntry();
1541   Uint32 val = signal->theData[0];
1542   if (val >= DumpStateOrd::OneBlockOnly)
1543   {
1544     if (check_block(Backup, val))
1545     {
1546       sendSignal(BACKUP_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
1547     }
1548     else if (check_block(TC, val))
1549     {
1550     }
1551     else if (check_block(LQH, val))
1552     {
1553       sendSignal(DBLQH_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
1554     }
1555     return;
1556   }
1557 
1558   for (Uint32 i = 0; blocks[i] != 0; i++)
1559   {
1560     sendSignal(blocks[i], GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
1561   }
1562 
1563   /**
1564    *
1565    * Here I can dump CMVMI state if needed
1566    */
1567   if(signal->theData[0] == 13){
1568 #if 0
1569     int loop = 100;
1570     int len = (10*1024*1024);
1571     if(signal->getLength() > 1)
1572       loop = signal->theData[1];
1573     if(signal->getLength() > 2)
1574       len = signal->theData[2];
1575 
1576     ndbout_c("recurse(%d loop, %dkb per recurse)", loop, len/1024);
1577     int a = recurse(0, loop, len);
1578     ndbout_c("after...%d", a);
1579 #endif
1580   }
1581 
1582   DumpStateOrd * const & dumpState = (DumpStateOrd *)&signal->theData[0];
1583   Uint32 arg = dumpState->args[0];
1584   if (arg == DumpStateOrd::CmvmiDumpConnections){
1585     for(unsigned int i = 1; i < MAX_NODES; i++ ){
1586       const char* nodeTypeStr = "";
1587       switch(getNodeInfo(i).m_type){
1588       case NodeInfo::DB:
1589 	nodeTypeStr = "DB";
1590 	break;
1591       case NodeInfo::API:
1592 	nodeTypeStr = "API";
1593 	break;
1594       case NodeInfo::MGM:
1595 	nodeTypeStr = "MGM";
1596 	break;
1597       case NodeInfo::INVALID:
1598 	nodeTypeStr = 0;
1599 	break;
1600       default:
1601 	nodeTypeStr = "<UNKNOWN>";
1602       }
1603 
1604       if(nodeTypeStr == 0)
1605 	continue;
1606 
1607       infoEvent("Connection to %d (%s) %s",
1608                 i,
1609                 nodeTypeStr,
1610                 globalTransporterRegistry.getPerformStateString(i));
1611     }
1612   }
1613 
1614   if (arg == DumpStateOrd::CmvmiDumpSubscriptions)
1615   {
1616     SubscriberPtr ptr;
1617     subscribers.first(ptr);
1618     g_eventLogger->info("List subscriptions:");
1619     while(ptr.i != RNIL)
1620     {
1621       g_eventLogger->info("Subscription: %u, nodeId: %u, ref: 0x%x",
1622                           ptr.i,  refToNode(ptr.p->blockRef), ptr.p->blockRef);
1623       for(Uint32 i = 0; i < LogLevel::LOGLEVEL_CATEGORIES; i++)
1624       {
1625         Uint32 level = ptr.p->logLevel.getLogLevel((LogLevel::EventCategory)i);
1626         g_eventLogger->info("Category %u Level %u", i, level);
1627       }
1628       subscribers.next(ptr);
1629     }
1630   }
1631 
1632   if (arg == DumpStateOrd::CmvmiDumpLongSignalMemory){
1633     infoEvent("Cmvmi: g_sectionSegmentPool size: %d free: %d",
1634 	      g_sectionSegmentPool.getSize(),
1635 	      g_sectionSegmentPool.getNoOfFree());
1636   }
1637 
1638   if (dumpState->args[0] == DumpStateOrd::DumpPageMemory)
1639   {
1640     const Uint32 len = signal->getLength();
1641     if (len == 1)
1642     {
1643       // Start dumping resource limits
1644       signal->theData[1] = 0;
1645       signal->theData[2] = ~0;
1646       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 3, JBB);
1647 
1648       // Dump data and index memory
1649       reportDMUsage(signal, 0);
1650       reportIMUsage(signal, 0);
1651       return;
1652     }
1653 
1654     if (len == 2)
1655     {
1656       // Dump data and index memory to specific ref
1657       Uint32 result_ref = signal->theData[1];
1658       reportDMUsage(signal, 0, result_ref);
1659       reportIMUsage(signal, 0, result_ref);
1660       return;
1661     }
1662 
1663     Uint32 id = signal->theData[1];
1664     Resource_limit rl;
1665     if (m_ctx.m_mm.get_resource_limit(id, rl))
1666     {
1667       if (rl.m_min || rl.m_curr || rl.m_max)
1668       {
1669         infoEvent("Resource %d min: %d max: %d curr: %d",
1670                   id, rl.m_min, rl.m_max, rl.m_curr);
1671       }
1672 
1673       signal->theData[0] = 1000;
1674       signal->theData[1] = id+1;
1675       signal->theData[2] = ~0;
1676       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 3, JBB);
1677     }
1678     return;
1679   }
1680   if (arg == DumpStateOrd::CmvmiSchedulerExecutionTimer)
1681   {
1682     Uint32 exec_time = signal->theData[1];
1683     globalEmulatorData.theConfiguration->schedulerExecutionTimer(exec_time);
1684   }
1685   if (arg == DumpStateOrd::CmvmiSchedulerSpinTimer)
1686   {
1687     Uint32 spin_time = signal->theData[1];
1688     globalEmulatorData.theConfiguration->schedulerSpinTimer(spin_time);
1689   }
1690   if (arg == DumpStateOrd::CmvmiRealtimeScheduler)
1691   {
1692     bool realtime_on = signal->theData[1];
1693     globalEmulatorData.theConfiguration->realtimeScheduler(realtime_on);
1694   }
1695   if (arg == DumpStateOrd::CmvmiExecuteLockCPU)
1696   {
1697   }
1698   if (arg == DumpStateOrd::CmvmiMaintLockCPU)
1699   {
1700   }
1701   if (arg == DumpStateOrd::CmvmiSetRestartOnErrorInsert)
1702   {
1703     if(signal->getLength() == 1)
1704     {
1705       Uint32 val = (Uint32)NRT_NoStart_Restart;
1706       const ndb_mgm_configuration_iterator * p =
1707 	m_ctx.m_config.getOwnConfigIterator();
1708       ndbrequire(p != 0);
1709 
1710       if(!ndb_mgm_get_int_parameter(p, CFG_DB_STOP_ON_ERROR_INSERT, &val))
1711       {
1712         m_ctx.m_config.setRestartOnErrorInsert(val);
1713       }
1714     }
1715     else
1716     {
1717       m_ctx.m_config.setRestartOnErrorInsert(signal->theData[1]);
1718     }
1719   }
1720 
1721   if (arg == DumpStateOrd::CmvmiTestLongSigWithDelay) {
1722     unsigned i;
1723     Uint32 testType = dumpState->args[1];
1724     Uint32 loopCount = dumpState->args[2];
1725     Uint32 print = dumpState->args[3];
1726     const unsigned len0 = 11;
1727     const unsigned len1 = 123;
1728     Uint32 sec0[len0];
1729     Uint32 sec1[len1];
1730     for (i = 0; i < len0; i++)
1731       sec0[i] = i;
1732     for (i = 0; i < len1; i++)
1733       sec1[i] = 16 * i;
1734     Uint32* sig = signal->getDataPtrSend();
1735     sig[0] = reference();
1736     sig[1] = testType;
1737     sig[2] = 0;
1738     sig[3] = print;
1739     sig[4] = loopCount;
1740     sig[5] = len0;
1741     sig[6] = len1;
1742     sig[7] = 0;
1743     LinearSectionPtr ptr[3];
1744     ptr[0].p = sec0;
1745     ptr[0].sz = len0;
1746     ptr[1].p = sec1;
1747     ptr[1].sz = len1;
1748     sendSignal(reference(), GSN_TESTSIG, signal, 8, JBB, ptr, 2);
1749   }
1750 
1751   if (arg == DumpStateOrd::DumpEventLog)
1752   {
1753     Uint32 result_ref = signal->theData[1];
1754     m_saved_event_buffer.startScan();
1755     SavedEvent s;
1756     Uint32 cnt = 0;
1757     EventReport * rep = CAST_PTR(EventReport, signal->getDataPtrSend());
1758     rep->setEventType(NDB_LE_SavedEvent);
1759     rep->setNodeId(getOwnNodeId());
1760     while (m_saved_event_buffer.scan(&s, 0))
1761     {
1762       jam();
1763       cnt++;
1764       signal->theData[1] = s.m_len;
1765       signal->theData[2] = s.m_seq;
1766       signal->theData[3] = s.m_time;
1767       if (s.m_len <= 21)
1768       {
1769         jam();
1770         memcpy(signal->theData+4, s.m_data, 4*s.m_len);
1771         sendSignal(result_ref, GSN_EVENT_REP, signal, 4 + s.m_len, JBB);
1772       }
1773       else
1774       {
1775         jam();
1776         LinearSectionPtr ptr[3];
1777         ptr[0].p = s.m_data;
1778         ptr[0].sz = s.m_len;
1779         sendSignal(result_ref, GSN_EVENT_REP, signal, 4, JBB, ptr, 1);
1780       }
1781     }
1782     signal->theData[1] = 0; // end of stream
1783     sendSignal(result_ref, GSN_EVENT_REP, signal, 2, JBB);
1784     return;
1785   }
1786 
1787   if (arg == DumpStateOrd::CmvmiTestLongSig)
1788   {
1789     /* Forward as GSN_TESTSIG to self */
1790     Uint32 numArgs= signal->length() - 1;
1791     memmove(signal->getDataPtrSend(),
1792             signal->getDataPtrSend() + 1,
1793             numArgs << 2);
1794     sendSignal(reference(), GSN_TESTSIG, signal, numArgs, JBB);
1795   }
1796 
1797 #ifdef ERROR_INSERT
1798   if (arg == 9000 || arg == 9002)
1799   {
1800     SET_ERROR_INSERT_VALUE(arg);
1801     for (Uint32 i = 1; i<signal->getLength(); i++)
1802       c_error_9000_nodes_mask.set(signal->theData[i]);
1803   }
1804 
1805   if (arg == 9001)
1806   {
1807     CLEAR_ERROR_INSERT_VALUE;
1808     if (signal->getLength() == 1 || signal->theData[1])
1809     {
1810       for (Uint32 i = 0; i<MAX_NODES; i++)
1811       {
1812 	if (c_error_9000_nodes_mask.get(i))
1813 	{
1814 	  signal->theData[0] = 0;
1815 	  signal->theData[1] = i;
1816 	  EXECUTE_DIRECT(CMVMI, GSN_OPEN_COMREQ, signal, 2);
1817 	}
1818       }
1819     }
1820     c_error_9000_nodes_mask.clear();
1821   }
1822 
1823   if (arg == 9004 && signal->getLength() == 2)
1824   {
1825     SET_ERROR_INSERT_VALUE(9004);
1826     c_error_9000_nodes_mask.clear();
1827     c_error_9000_nodes_mask.set(signal->theData[1]);
1828   }
1829 
1830   if (arg == 9004 && signal->getLength() == 2)
1831   {
1832     SET_ERROR_INSERT_VALUE(9004);
1833     c_error_9000_nodes_mask.clear();
1834     c_error_9000_nodes_mask.set(signal->theData[1]);
1835   }
1836 #endif
1837 
1838 #ifdef VM_TRACE
1839 #if 0
1840   {
1841     SafeCounterManager mgr(* this); mgr.setSize(1);
1842     SafeCounterHandle handle;
1843 
1844     {
1845       SafeCounter tmp(mgr, handle);
1846       tmp.init<RefSignalTest>(CMVMI, GSN_TESTSIG, /* senderData */ 13);
1847       tmp.setWaitingFor(3);
1848       ndbrequire(!tmp.done());
1849       ndbout_c("Allocted");
1850     }
1851     ndbrequire(!handle.done());
1852     {
1853       SafeCounter tmp(mgr, handle);
1854       tmp.clearWaitingFor(3);
1855       ndbrequire(tmp.done());
1856       ndbout_c("Deallocted");
1857     }
1858     ndbrequire(handle.done());
1859   }
1860 #endif
1861 #endif
1862 
1863 #ifdef ERROR_INSERT
1864   /* <Target NodeId> dump 9992 <NodeId list>
1865    * On Target NodeId, block receiving signals from NodeId list
1866    *
1867    * <Target NodeId> dump 9993 <NodeId list>
1868    * On Target NodeId, resume receiving signals from NodeId list
1869    *
1870    * <Target NodeId> dump 9991
1871    * On Target NodeId, resume receiving signals from any blocked node
1872    *
1873    *
1874    * See also code in QMGR for blocking receive from nodes based
1875    * on HB roles.
1876    *
1877    */
1878   if((arg == 9993) ||  /* Unblock recv from nodeid */
1879      (arg == 9992))    /* Block recv from nodeid */
1880   {
1881     bool block = (arg == 9992);
1882     for (Uint32 n = 1; n < signal->getLength(); n++)
1883     {
1884       Uint32 nodeId = signal->theData[n];
1885 
1886       if ((nodeId > 0) &&
1887           (nodeId < MAX_NODES))
1888       {
1889         if (block)
1890         {
1891           ndbout_c("CMVMI : Blocking receive from node %u", nodeId);
1892 
1893           globalTransporterRegistry.blockReceive(nodeId);
1894         }
1895         else
1896         {
1897           ndbout_c("CMVMI : Unblocking receive from node %u", nodeId);
1898 
1899           globalTransporterRegistry.unblockReceive(nodeId);
1900         }
1901       }
1902       else
1903       {
1904         ndbout_c("CMVMI : Ignoring dump %u for node %u",
1905                  arg, nodeId);
1906       }
1907     }
1908   }
1909   if (arg == 9990) /* Block recv from all ndbd matching pattern */
1910   {
1911     Uint32 pattern = 0;
1912     if (signal->getLength() > 1)
1913     {
1914       pattern = signal->theData[1];
1915       ndbout_c("CMVMI : Blocking receive from all ndbds matching pattern -%s-",
1916                ((pattern == 1)? "Other side":"Unknown"));
1917     }
1918 
1919     for (Uint32 node = 1; node < MAX_NDB_NODES; node++)
1920     {
1921       if (globalTransporterRegistry.is_connected(node))
1922       {
1923         if (getNodeInfo(node).m_type == NodeInfo::DB)
1924         {
1925           if (!globalTransporterRegistry.isBlocked(node))
1926           {
1927             switch (pattern)
1928             {
1929             case 1:
1930             {
1931               /* Match if given node is on 'other side' of
1932                * 2-replica cluster
1933                */
1934               if ((getOwnNodeId() & 1) != (node & 1))
1935               {
1936                 /* Node is on the 'other side', match */
1937                 break;
1938               }
1939               /* Node is on 'my side', don't match */
1940               continue;
1941             }
1942             default:
1943               break;
1944             }
1945             ndbout_c("CMVMI : Blocking receive from node %u", node);
1946             globalTransporterRegistry.blockReceive(node);
1947           }
1948         }
1949       }
1950     }
1951   }
1952   if (arg == 9991) /* Unblock recv from all blocked */
1953   {
1954     for (Uint32 node = 0; node < MAX_NODES; node++)
1955     {
1956       if (globalTransporterRegistry.isBlocked(node))
1957       {
1958         ndbout_c("CMVMI : Unblocking receive from node %u", node);
1959         globalTransporterRegistry.unblockReceive(node);
1960       }
1961     }
1962   }
1963 #endif
1964 
1965   if (arg == 9999)
1966   {
1967     Uint32 delay = 1000;
1968     switch(signal->getLength()){
1969     case 1:
1970       break;
1971     case 2:
1972       delay = signal->theData[1];
1973       break;
1974     default:{
1975       Uint32 dmin = signal->theData[1];
1976       Uint32 dmax = signal->theData[2];
1977       delay = dmin + (rand() % (dmax - dmin));
1978       break;
1979     }
1980     }
1981 
1982     signal->theData[0] = 9999;
1983     if (delay == 0)
1984     {
1985       execNDB_TAMPER(signal);
1986     }
1987     else if (delay < 10)
1988     {
1989       sendSignal(reference(), GSN_NDB_TAMPER, signal, 1, JBB);
1990     }
1991     else
1992     {
1993       sendSignalWithDelay(reference(), GSN_NDB_TAMPER, signal, delay, 1);
1994     }
1995   }
1996 
1997   if (signal->theData[0] == 666)
1998   {
1999     jam();
2000     Uint32 mb = 100;
2001     if (signal->getLength() > 1)
2002       mb = signal->theData[1];
2003 
2004     Uint64 bytes = Uint64(mb) * 1024 * 1024;
2005     AllocMemReq * req = CAST_PTR(AllocMemReq, signal->getDataPtrSend());
2006     req->senderData = 666;
2007     req->senderRef = reference();
2008     req->requestInfo = AllocMemReq::RT_EXTEND;
2009     req->bytes_hi = Uint32(bytes >> 32);
2010     req->bytes_lo = Uint32(bytes);
2011     sendSignal(NDBFS_REF, GSN_ALLOC_MEM_REQ, signal,
2012                AllocMemReq::SignalLength, JBB);
2013   }
2014 }//Cmvmi::execDUMP_STATE_ORD()
2015 
2016 void
execALLOC_MEM_REF(Signal * signal)2017 Cmvmi::execALLOC_MEM_REF(Signal* signal)
2018 {
2019   jamEntry();
2020   const AllocMemRef * ref = CAST_CONSTPTR(AllocMemRef, signal->getDataPtr());
2021 
2022   if (ref->senderData == 0)
2023   {
2024     jam();
2025     ndbrequire(false);
2026   }
2027 }
2028 
2029 void
execALLOC_MEM_CONF(Signal * signal)2030 Cmvmi::execALLOC_MEM_CONF(Signal* signal)
2031 {
2032   jamEntry();
2033   const AllocMemConf * conf = CAST_CONSTPTR(AllocMemConf, signal->getDataPtr());
2034 
2035   if (conf->senderData == 0)
2036   {
2037     jam();
2038 
2039     init_global_page_pool();
2040 
2041     ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
2042     conf->senderRef = reference();
2043     conf->senderData = f_read_config_data;
2044     sendSignal(f_read_config_ref, GSN_READ_CONFIG_CONF, signal,
2045                ReadConfigConf::SignalLength, JBB);
2046     return;
2047   }
2048 }
2049 
execDBINFO_SCANREQ(Signal * signal)2050 void Cmvmi::execDBINFO_SCANREQ(Signal *signal)
2051 {
2052   DbinfoScanReq req= *(DbinfoScanReq*)signal->theData;
2053   const Ndbinfo::ScanCursor* cursor =
2054     CAST_CONSTPTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtr(&req));
2055   Ndbinfo::Ratelimit rl;
2056 
2057   jamEntry();
2058 
2059   switch(req.tableId){
2060   case Ndbinfo::TRANSPORTERS_TABLEID:
2061   {
2062     jam();
2063     Uint32 rnode = cursor->data[0];
2064     if (rnode == 0)
2065       rnode++; // Skip node 0
2066 
2067     while(rnode < MAX_NODES)
2068     {
2069       switch(getNodeInfo(rnode).m_type)
2070       {
2071       default:
2072       {
2073         jam();
2074         Ndbinfo::Row row(signal, req);
2075         row.write_uint32(getOwnNodeId()); // Node id
2076         row.write_uint32(rnode); // Remote node id
2077         row.write_uint32(globalTransporterRegistry.getPerformState(rnode)); // State
2078         ndbinfo_send_row(signal, req, row, rl);
2079        break;
2080       }
2081 
2082       case NodeInfo::INVALID:
2083         jam();
2084        break;
2085       }
2086 
2087       rnode++;
2088       if (rl.need_break(req))
2089       {
2090         jam();
2091         ndbinfo_send_scan_break(signal, req, rl, rnode);
2092         return;
2093       }
2094     }
2095     break;
2096   }
2097 
2098   case Ndbinfo::RESOURCES_TABLEID:
2099   {
2100     jam();
2101     Uint32 resource_id = cursor->data[0];
2102     Resource_limit resource_limit;
2103 
2104     while(m_ctx.m_mm.get_resource_limit(resource_id, resource_limit))
2105     {
2106       jam();
2107       Ndbinfo::Row row(signal, req);
2108       row.write_uint32(getOwnNodeId()); // Node id
2109       row.write_uint32(resource_id);
2110 
2111       row.write_uint32(resource_limit.m_min);
2112       row.write_uint32(resource_limit.m_curr);
2113       row.write_uint32(resource_limit.m_max);
2114       row.write_uint32(0); //TODO
2115       ndbinfo_send_row(signal, req, row, rl);
2116       resource_id++;
2117 
2118       if (rl.need_break(req))
2119       {
2120         jam();
2121         ndbinfo_send_scan_break(signal, req, rl, resource_id);
2122         return;
2123       }
2124     }
2125     break;
2126   }
2127 
2128   case Ndbinfo::NODES_TABLEID:
2129   {
2130     jam();
2131     const NodeState& nodeState = getNodeState();
2132     const Uint32 start_level = nodeState.startLevel;
2133     const NDB_TICKS uptime = (NdbTick_CurrentMillisecond()/1000) - m_start_time;
2134     Uint32 generation = m_ctx.m_config.get_config_generation();
2135 
2136     Ndbinfo::Row row(signal, req);
2137     row.write_uint32(getOwnNodeId()); // Node id
2138 
2139     row.write_uint64(uptime);         // seconds
2140     row.write_uint32(start_level);
2141     row.write_uint32(start_level == NodeState::SL_STARTING ?
2142                      nodeState.starting.startPhase : 0);
2143     row.write_uint32(generation);
2144     ndbinfo_send_row(signal, req, row, rl);
2145     break;
2146   }
2147 
2148   case Ndbinfo::POOLS_TABLEID:
2149   {
2150     jam();
2151 
2152     Resource_limit res_limit;
2153     m_ctx.m_mm.get_resource_limit(RG_DATAMEM, res_limit);
2154 
2155     const Uint32 tup_pages_used = res_limit.m_curr - f_accpages;
2156     const Uint32 tup_pages_total = res_limit.m_min - f_accpages;
2157 
2158     Ndbinfo::pool_entry pools[] =
2159     {
2160       { "Data memory",
2161         tup_pages_used,
2162         tup_pages_total,
2163         sizeof(GlobalPage),
2164         0,
2165         { CFG_DB_DATA_MEM,0,0,0 }},
2166       { NULL, 0,0,0,0,{ 0,0,0,0 }}
2167     };
2168 
2169     static const size_t num_config_params =
2170       sizeof(pools[0].config_params)/sizeof(pools[0].config_params[0]);
2171     Uint32 pool = cursor->data[0];
2172     BlockNumber bn = blockToMain(number());
2173     while(pools[pool].poolname)
2174     {
2175       jam();
2176       Ndbinfo::Row row(signal, req);
2177       row.write_uint32(getOwnNodeId());
2178       row.write_uint32(bn);           // block number
2179       row.write_uint32(instance());   // block instance
2180       row.write_string(pools[pool].poolname);
2181 
2182       row.write_uint64(pools[pool].used);
2183       row.write_uint64(pools[pool].total);
2184       row.write_uint64(pools[pool].used_hi);
2185       row.write_uint64(pools[pool].entry_size);
2186       for (size_t i = 0; i < num_config_params; i++)
2187         row.write_uint32(pools[pool].config_params[i]);
2188       ndbinfo_send_row(signal, req, row, rl);
2189       pool++;
2190       if (rl.need_break(req))
2191       {
2192         jam();
2193         ndbinfo_send_scan_break(signal, req, rl, pool);
2194         return;
2195       }
2196     }
2197   }
2198 
2199   default:
2200     break;
2201   }
2202 
2203   ndbinfo_send_scan_conf(signal, req, rl);
2204 }
2205 
2206 
2207 void
execNODE_START_REP(Signal * signal)2208 Cmvmi::execNODE_START_REP(Signal* signal)
2209 {
2210 #ifdef ERROR_INSERT
2211   if (ERROR_INSERTED(9002) && signal->theData[0] == getOwnNodeId())
2212   {
2213     signal->theData[0] = 9001;
2214     execDUMP_STATE_ORD(signal);
2215   }
2216 #endif
2217 }
2218 
BLOCK_FUNCTIONS(Cmvmi)2219 BLOCK_FUNCTIONS(Cmvmi)
2220 
2221 void
2222 Cmvmi::startFragmentedSend(Signal* signal,
2223                            Uint32 variant,
2224                            Uint32 numSigs,
2225                            NodeReceiverGroup rg)
2226 {
2227   Uint32* sigData = signal->getDataPtrSend();
2228   const Uint32 sigLength = 6;
2229   const Uint32 sectionWords = 240;
2230   Uint32 sectionData[ sectionWords ];
2231 
2232   for (Uint32 i = 0; i < sectionWords; i++)
2233     sectionData[ i ] = i;
2234 
2235   const Uint32 secCount = 1;
2236   LinearSectionPtr ptr[3];
2237   ptr[0].sz = sectionWords;
2238   ptr[0].p = &sectionData[0];
2239 
2240   for (Uint32 i = 0; i < numSigs; i++)
2241   {
2242     sigData[0] = variant;
2243     sigData[1] = 31;
2244     sigData[2] = 0;
2245     sigData[3] = 1; // print
2246     sigData[4] = 0;
2247     sigData[5] = sectionWords;
2248 
2249     if ((i & 1) == 0)
2250     {
2251       DEBUG("Starting linear fragmented send (" << i + 1
2252             << "/" << numSigs << ")");
2253 
2254       /* Linear send */
2255       /* Todo : Avoid reading from invalid stackptr in CONTINUEB */
2256       sendFragmentedSignal(rg,
2257                            GSN_TESTSIG,
2258                            signal,
2259                            sigLength,
2260                            JBB,
2261                            ptr,
2262                            secCount,
2263                            TheEmptyCallback,
2264                            90); // messageSize
2265     }
2266     else
2267     {
2268       /* Segmented send */
2269       DEBUG("Starting segmented fragmented send (" << i + 1
2270             << "/" << numSigs << ")");
2271       Ptr<SectionSegment> segPtr;
2272       ndbrequire(import(segPtr, sectionData, sectionWords));
2273       SectionHandle handle(this, segPtr.i);
2274 
2275       sendFragmentedSignal(rg,
2276                            GSN_TESTSIG,
2277                            signal,
2278                            sigLength,
2279                            JBB,
2280                            &handle,
2281                            TheEmptyCallback,
2282                            90); // messageSize
2283     }
2284   }
2285 }
2286 
2287 void
testNodeFailureCleanupCallback(Signal * signal,Uint32 data,Uint32 elementsCleaned)2288 Cmvmi::testNodeFailureCleanupCallback(Signal* signal, Uint32 data, Uint32 elementsCleaned)
2289 {
2290   DEBUG("testNodeFailureCleanupCallback");
2291   DEBUG("Data : " << data
2292         << " elementsCleaned : " << elementsCleaned);
2293 
2294   debugPrintFragmentCounts();
2295 
2296   Uint32 variant = data & 0xffff;
2297   Uint32 testType = (data >> 16) & 0xffff;
2298 
2299   DEBUG("Sending trigger(" << testType
2300         << ") variant " << variant
2301         << " to self to cleanup any fragments that arrived "
2302         << "before send was cancelled");
2303 
2304   Uint32* sigData = signal->getDataPtrSend();
2305   sigData[0] = variant;
2306   sigData[1] = testType;
2307   sendSignal(reference(), GSN_TESTSIG, signal, 2, JBB);
2308 
2309   return;
2310 }
2311 
2312 void
testFragmentedCleanup(Signal * signal,SectionHandle * handle,Uint32 testType,Uint32 variant)2313 Cmvmi::testFragmentedCleanup(Signal* signal, SectionHandle* handle, Uint32 testType, Uint32 variant)
2314 {
2315   DEBUG("TestType " << testType << " variant " << variant);
2316   debugPrintFragmentCounts();
2317 
2318   /* Variants :
2319    *     Local fragmented send   Multicast fragmented send
2320    * 0 : Immediate cleanup       Immediate cleanup
2321    * 1 : Continued cleanup       Immediate cleanup
2322    * 2 : Immediate cleanup       Continued cleanup
2323    * 3 : Continued cleanup       Continued cleanup
2324    */
2325   const Uint32 NUM_VARIANTS = 4;
2326   if (variant >= NUM_VARIANTS)
2327   {
2328     DEBUG("Unsupported variant");
2329     releaseSections(*handle);
2330     return;
2331   }
2332 
2333   /* Test from ndb_mgm with
2334    * <node(s)> DUMP 2605 0 30
2335    *
2336    * Use
2337    * <node(s)> DUMP 2605 0 39 to get fragment resource usage counts
2338    * Use
2339    * <node(s)> DUMP 2601 to get segment usage counts in clusterlog
2340    */
2341   if (testType == 30)
2342   {
2343     /* Send the first fragment of a fragmented signal to self
2344      * Receiver will allocate assembly hash entries
2345      * which must be freed when node failure cleanup
2346      * executes later
2347      */
2348     const Uint32 sectionWords = 240;
2349     Uint32 sectionData[ sectionWords ];
2350 
2351     for (Uint32 i = 0; i < sectionWords; i++)
2352       sectionData[ i ] = i;
2353 
2354     const Uint32 secCount = 1;
2355     LinearSectionPtr ptr[3];
2356     ptr[0].sz = sectionWords;
2357     ptr[0].p = &sectionData[0];
2358 
2359     /* Send signal with testType == 31 */
2360     NodeReceiverGroup me(reference());
2361     Uint32* sigData = signal->getDataPtrSend();
2362     const Uint32 sigLength = 6;
2363     const Uint32 numPartialSigs = 4;
2364     /* Not too many as CMVMI's fragInfo hash is limited size */
2365     // TODO : Consider making it debug-larger to get
2366     // more coverage on CONTINUEB path
2367 
2368     for (Uint32 i = 0; i < numPartialSigs; i++)
2369     {
2370       /* Fill in messy TESTSIG format */
2371       sigData[0] = variant;
2372       sigData[1] = 31;
2373       sigData[2] = 0;
2374       sigData[3] = 0; // print
2375       sigData[4] = 0;
2376       sigData[5] = sectionWords;
2377 
2378       FragmentSendInfo fsi;
2379 
2380       DEBUG("Sending first fragment to self");
2381       sendFirstFragment(fsi,
2382                         me,
2383                         GSN_TESTSIG,
2384                         signal,
2385                         sigLength,
2386                         JBB,
2387                         ptr,
2388                         secCount,
2389                         90); // FragmentLength
2390 
2391       DEBUG("Cancelling remainder to free internal section");
2392       fsi.m_status = FragmentSendInfo::SendCancelled;
2393       sendNextLinearFragment(signal, fsi);
2394     };
2395 
2396     /* Ok, now send short signal with testType == 32
2397      * to trigger 'remote-side' actions in middle of
2398      * multiple fragment assembly
2399      */
2400     sigData[0] = variant;
2401     sigData[1] = 32;
2402 
2403     DEBUG("Sending node fail trigger to self");
2404     sendSignal(me, GSN_TESTSIG, signal, 2, JBB);
2405     return;
2406   }
2407 
2408   if (testType == 31)
2409   {
2410     /* Just release sections - execTESTSIG() has shown sections received */
2411     releaseSections(*handle);
2412     return;
2413   }
2414 
2415   if (testType == 32)
2416   {
2417     /* 'Remote side' trigger to clean up fragmented signal resources */
2418     BlockReference senderRef = signal->getSendersBlockRef();
2419     Uint32 sendingNode = refToNode(senderRef);
2420 
2421     /* Start sending some linear and fragmented responses to the
2422      * sender, to exercise frag-send cleanup code when we execute
2423      * node-failure later
2424      */
2425     DEBUG("Starting fragmented send using continueB back to self");
2426 
2427     NodeReceiverGroup sender(senderRef);
2428     startFragmentedSend(signal, variant, 6, sender);
2429 
2430     debugPrintFragmentCounts();
2431 
2432     Uint32 cbData= (((Uint32) 33) << 16) | variant;
2433     Callback cb = { safe_cast(&Cmvmi::testNodeFailureCleanupCallback),
2434                     cbData };
2435 
2436     Callback* cbPtr = NULL;
2437 
2438     bool passCallback = variant & 1;
2439 
2440     if (passCallback)
2441     {
2442       DEBUG("Running simBlock failure code WITH CALLBACK for node "
2443             << sendingNode);
2444       cbPtr = &cb;
2445     }
2446     else
2447     {
2448       DEBUG("Running simBlock failure code IMMEDIATELY (no callback) for node "
2449             << sendingNode);
2450       cbPtr = &TheEmptyCallback;
2451     }
2452 
2453     Uint32 elementsCleaned = simBlockNodeFailure(signal, sendingNode, *cbPtr);
2454 
2455     DEBUG("Elements cleaned by call : " << elementsCleaned);
2456 
2457     debugPrintFragmentCounts();
2458 
2459     if (! passCallback)
2460     {
2461       DEBUG("Variant " << variant << " manually executing callback");
2462       /* We call the callback inline here to continue processing */
2463       testNodeFailureCleanupCallback(signal,
2464                                      cbData,
2465                                      elementsCleaned);
2466     }
2467 
2468     return;
2469   }
2470 
2471   if (testType == 33)
2472   {
2473     /* Original side - receive cleanup trigger from 'remote' side
2474      * after node failure cleanup performed there.  We may have
2475      * fragments it managed to send before the cleanup completed
2476      * so we'll get rid of them.
2477      * This would not be necessary in reality as this node would
2478      * be failed
2479      */
2480     Uint32 sendingNode = refToNode(signal->getSendersBlockRef());
2481     DEBUG("Running simBlock failure code for node " << sendingNode);
2482 
2483     Uint32 elementsCleaned = simBlockNodeFailure(signal, sendingNode);
2484 
2485     DEBUG("Elements cleaned : " << elementsCleaned);
2486 
2487     /* Should have no fragment resources in use now */
2488     ndbrequire(debugPrintFragmentCounts() == 0);
2489 
2490     /* Now use ReceiverGroup to multicast a fragmented signal to
2491      * all database nodes
2492      */
2493     DEBUG("Starting to send fragmented continueB to all nodes inc. self : ");
2494     NodeReceiverGroup allNodes(CMVMI, c_dbNodes);
2495 
2496     unsigned nodeId = 0;
2497     while((nodeId = c_dbNodes.find(nodeId+1)) != BitmaskImpl::NotFound)
2498     {
2499       DEBUG("Node " << nodeId);
2500     }
2501 
2502     startFragmentedSend(signal, variant, 8, allNodes);
2503 
2504     debugPrintFragmentCounts();
2505 
2506     Uint32 cbData= (((Uint32) 34) << 16) | variant;
2507     Callback cb = { safe_cast(&Cmvmi::testNodeFailureCleanupCallback),
2508                     cbData };
2509 
2510     Callback* cbPtr = NULL;
2511 
2512     bool passCallback = variant & 2;
2513 
2514     if (passCallback)
2515     {
2516       DEBUG("Running simBlock failure code for self WITH CALLBACK ("
2517             << getOwnNodeId() << ")");
2518       cbPtr= &cb;
2519     }
2520     else
2521     {
2522       DEBUG("Running simBlock failure code for self IMMEDIATELY (no callback) ("
2523             << getOwnNodeId() << ")");
2524       cbPtr= &TheEmptyCallback;
2525     }
2526 
2527 
2528     /* Fragmented signals being sent will have this node removed
2529      * from their receiver group, but will keep sending to the
2530      * other node(s).
2531      * Other node(s) should therefore receive the complete signals.
2532      * We will then receive only the first fragment of each of
2533      * the signals which must be removed later.
2534      */
2535     elementsCleaned = simBlockNodeFailure(signal, getOwnNodeId(), *cbPtr);
2536 
2537     DEBUG("Elements cleaned : " << elementsCleaned);
2538 
2539     debugPrintFragmentCounts();
2540 
2541     /* Callback will send a signal to self to clean up fragments that
2542      * were sent to self before the send was cancelled.
2543      * (Again, unnecessary in a 'real' situation
2544      */
2545     if (!passCallback)
2546     {
2547       DEBUG("Variant " << variant << " manually executing callback");
2548 
2549       testNodeFailureCleanupCallback(signal,
2550                                      cbData,
2551                                      elementsCleaned);
2552     }
2553 
2554     return;
2555   }
2556 
2557   if (testType == 34)
2558   {
2559     /* Cleanup fragments which were sent before send was cancelled. */
2560     Uint32 elementsCleaned = simBlockNodeFailure(signal, getOwnNodeId());
2561 
2562     DEBUG("Elements cleaned " << elementsCleaned);
2563 
2564     /* All FragInfo should be clear, may still be sending some
2565      * to other node(s)
2566      */
2567     debugPrintFragmentCounts();
2568 
2569     DEBUG("Variant " << variant << " completed.");
2570 
2571     if (++variant < NUM_VARIANTS)
2572     {
2573       DEBUG("Re-executing with variant " << variant);
2574       Uint32* sigData = signal->getDataPtrSend();
2575       sigData[0] = variant;
2576       sigData[1] = 30;
2577       sendSignal(reference(), GSN_TESTSIG, signal, 2, JBB);
2578     }
2579 //    else
2580 //    {
2581 //      // Infinite loop to test for leaks
2582 //       DEBUG("Back to zero");
2583 //       Uint32* sigData = signal->getDataPtrSend();
2584 //       sigData[0] = 0;
2585 //       sigData[1] = 30;
2586 //       sendSignal(reference(), GSN_TESTSIG, signal, 2, JBB);
2587 //    }
2588   }
2589 }
2590 
2591 static Uint32 g_print;
2592 static LinearSectionPtr g_test[3];
2593 
2594 /* See above for how to generate TESTSIG using DUMP 2603
2595  * (e.g. : <All/NodeId> DUMP 2603 <TestId> <LoopCount> <Print>
2596  *   LoopCount : How many times test should loop (0-n)
2597  *   Print : Whether signals should be printed : 0=no 1=yes
2598  *
2599  * TestIds
2600  *   20 : Test sendDelayed with 1 milli delay, LoopCount times
2601  *   1-16 : See vm/testLongSig.cpp
2602  */
2603 void
execTESTSIG(Signal * signal)2604 Cmvmi::execTESTSIG(Signal* signal){
2605   Uint32 i;
2606   /**
2607    * Test of SafeCounter
2608    */
2609   jamEntry();
2610 
2611   if(!assembleFragments(signal)){
2612     jam();
2613     return;
2614   }
2615 
2616   Uint32 ref = signal->theData[0];
2617   Uint32 testType = signal->theData[1];
2618   Uint32 fragmentLength = signal->theData[2];
2619   g_print = signal->theData[3];
2620 //  Uint32 returnCount = signal->theData[4];
2621   Uint32 * secSizes = &signal->theData[5];
2622 
2623   SectionHandle handle(this, signal);
2624 
2625   if(g_print){
2626     SignalLoggerManager::printSignalHeader(stdout,
2627 					   signal->header,
2628 					   0,
2629 					   getOwnNodeId(),
2630 					   true);
2631     ndbout_c("-- Fixed section --");
2632     for(i = 0; i<signal->length(); i++){
2633       fprintf(stdout, "H'0x%.8x ", signal->theData[i]);
2634       if(((i + 1) % 6) == 0)
2635 	fprintf(stdout, "\n");
2636     }
2637     fprintf(stdout, "\n");
2638 
2639     for(i = 0; i<handle.m_cnt; i++){
2640       SegmentedSectionPtr ptr(0,0,0);
2641       ndbout_c("-- Section %d --", i);
2642       handle.getSection(ptr, i);
2643       ndbrequire(ptr.p != 0);
2644       print(ptr, stdout);
2645       ndbrequire(ptr.sz == secSizes[i]);
2646     }
2647   }
2648 
2649   /**
2650    * Validate length:s
2651    */
2652   for(i = 0; i<handle.m_cnt; i++){
2653     SegmentedSectionPtr ptr;
2654     handle.getSection(ptr, i);
2655     ndbrequire(ptr.p != 0);
2656     ndbrequire(ptr.sz == secSizes[i]);
2657   }
2658 
2659   /**
2660    * Testing send with delay.
2661    */
2662   if (testType == 20) {
2663     if (signal->theData[4] == 0) {
2664       releaseSections(handle);
2665       return;
2666     }
2667     signal->theData[4]--;
2668     sendSignalWithDelay(reference(), GSN_TESTSIG, signal, 100, 8, &handle);
2669     return;
2670   }
2671 
2672   if (g_print)
2673     ndbout_c("TestType=%u signal->theData[4]=%u, sendersBlockRef=%u ref=%u\n",
2674              testType, signal->theData[4], signal->getSendersBlockRef(), ref);
2675 
2676   NodeReceiverGroup rg(CMVMI, c_dbNodes);
2677 
2678   /**
2679    * Testing SimulatedBlock fragment assembly cleanup
2680    */
2681   if ((testType >= 30) &&
2682       (testType < 40))
2683   {
2684     testFragmentedCleanup(signal, &handle, testType, ref);
2685     return;
2686   }
2687 
2688   if(signal->getSendersBlockRef() == ref){
2689     /**
2690      * Signal from API (not via NodeReceiverGroup)
2691      */
2692     if((testType % 2) == 1){
2693       signal->theData[4] = 1; // No further signals after this
2694     } else {
2695       // Change testType to UniCast, and set loopCount to the
2696       // number of nodes.
2697       signal->theData[1] --;
2698       signal->theData[4] = rg.m_nodes.count();
2699     }
2700   }
2701 
2702   switch(testType){
2703   case 1:
2704     /* Unicast to self */
2705     sendSignal(ref, GSN_TESTSIG,  signal, signal->length(), JBB,
2706 	       &handle);
2707     break;
2708   case 2:
2709     /* Multicast to all nodes */
2710     sendSignal(rg, GSN_TESTSIG,  signal, signal->length(), JBB,
2711 	       &handle);
2712     break;
2713   case 3:
2714   case 4:{
2715     LinearSectionPtr ptr[3];
2716     const Uint32 secs = handle.m_cnt;
2717     for(i = 0; i<secs; i++){
2718       SegmentedSectionPtr sptr(0,0,0);
2719       handle.getSection(sptr, i);
2720       ptr[i].sz = sptr.sz;
2721       ptr[i].p = new Uint32[sptr.sz];
2722       copy(ptr[i].p, sptr);
2723     }
2724 
2725     if(testType == 3){
2726       /* Unicast linear sections to self */
2727       sendSignal(ref, GSN_TESTSIG, signal, signal->length(), JBB, ptr, secs);
2728     } else {
2729       /* Boradcast linear sections to all nodes */
2730       sendSignal(rg, GSN_TESTSIG, signal, signal->length(), JBB, ptr, secs);
2731     }
2732     for(Uint32 i = 0; i<secs; i++){
2733       delete[] ptr[i].p;
2734     }
2735     releaseSections(handle);
2736     break;
2737   }
2738   /* Send fragmented segmented sections direct send */
2739   case 5:
2740   case 6:{
2741 
2742     NodeReceiverGroup tmp;
2743     if(testType == 5){
2744       /* Unicast */
2745       tmp  = ref;
2746     } else {
2747       /* Multicast */
2748       tmp = rg;
2749     }
2750 
2751     FragmentSendInfo fragSend;
2752     sendFirstFragment(fragSend,
2753 		      tmp,
2754 		      GSN_TESTSIG,
2755 		      signal,
2756 		      signal->length(),
2757 		      JBB,
2758 		      &handle,
2759 		      false, // Release sections on send
2760                       fragmentLength);
2761 
2762     int count = 1;
2763     while(fragSend.m_status != FragmentSendInfo::SendComplete){
2764       count++;
2765       if(g_print)
2766 	ndbout_c("Sending fragment %d", count);
2767       sendNextSegmentedFragment(signal, fragSend);
2768     }
2769     break;
2770   }
2771   /* Send fragmented linear sections direct send */
2772   case 7:
2773   case 8:{
2774     LinearSectionPtr ptr[3];
2775     const Uint32 secs = handle.m_cnt;
2776     for(i = 0; i<secs; i++){
2777       SegmentedSectionPtr sptr(0,0,0);
2778       handle.getSection(sptr, i);
2779       ptr[i].sz = sptr.sz;
2780       ptr[i].p = new Uint32[sptr.sz];
2781       copy(ptr[i].p, sptr);
2782     }
2783 
2784     NodeReceiverGroup tmp;
2785     if(testType == 7){
2786       /* Unicast */
2787       tmp  = ref;
2788     } else {
2789       /* Multicast */
2790       tmp = rg;
2791     }
2792 
2793     FragmentSendInfo fragSend;
2794     sendFirstFragment(fragSend,
2795 		      tmp,
2796 		      GSN_TESTSIG,
2797 		      signal,
2798 		      signal->length(),
2799 		      JBB,
2800 		      ptr,
2801 		      secs,
2802 		      fragmentLength);
2803 
2804     int count = 1;
2805     while(fragSend.m_status != FragmentSendInfo::SendComplete){
2806       count++;
2807       if(g_print)
2808 	ndbout_c("Sending fragment %d", count);
2809       sendNextLinearFragment(signal, fragSend);
2810     }
2811 
2812     for(i = 0; i<secs; i++){
2813       delete[] ptr[i].p;
2814     }
2815     releaseSections(handle);
2816     break;
2817   }
2818   /* Test fragmented segmented send with callback */
2819   case 9:
2820   case 10:{
2821 
2822     Callback m_callBack;
2823     m_callBack.m_callbackFunction =
2824       safe_cast(&Cmvmi::sendFragmentedComplete);
2825 
2826     if(testType == 9){
2827       /* Unicast */
2828       m_callBack.m_callbackData = 9;
2829       sendFragmentedSignal(ref,
2830 			   GSN_TESTSIG, signal, signal->length(), JBB,
2831 			   &handle,
2832 			   m_callBack,
2833 			   fragmentLength);
2834     } else {
2835       /* Multicast */
2836       m_callBack.m_callbackData = 10;
2837       sendFragmentedSignal(rg,
2838 			   GSN_TESTSIG, signal, signal->length(), JBB,
2839 			   &handle,
2840 			   m_callBack,
2841 			   fragmentLength);
2842     }
2843     break;
2844   }
2845   /* Test fragmented linear send with callback */
2846   case 11:
2847   case 12:{
2848 
2849     const Uint32 secs = handle.m_cnt;
2850     memset(g_test, 0, sizeof(g_test));
2851     for(i = 0; i<secs; i++){
2852       SegmentedSectionPtr sptr(0,0,0);
2853       handle.getSection(sptr, i);
2854       g_test[i].sz = sptr.sz;
2855       g_test[i].p = new Uint32[sptr.sz];
2856       copy(g_test[i].p, sptr);
2857     }
2858 
2859     releaseSections(handle);
2860 
2861     Callback m_callBack;
2862     m_callBack.m_callbackFunction =
2863       safe_cast(&Cmvmi::sendFragmentedComplete);
2864 
2865     if(testType == 11){
2866       /* Unicast */
2867       m_callBack.m_callbackData = 11;
2868       sendFragmentedSignal(ref,
2869 			   GSN_TESTSIG, signal, signal->length(), JBB,
2870 			   g_test, secs,
2871 			   m_callBack,
2872 			   fragmentLength);
2873     } else {
2874       /* Multicast */
2875       m_callBack.m_callbackData = 12;
2876       sendFragmentedSignal(rg,
2877 			   GSN_TESTSIG, signal, signal->length(), JBB,
2878 			   g_test, secs,
2879 			   m_callBack,
2880 			   fragmentLength);
2881     }
2882     break;
2883   }
2884   /* Send fragmented segmented sections direct send no-release */
2885   case 13:
2886   case 14:{
2887     NodeReceiverGroup tmp;
2888     if(testType == 13){
2889       /* Unicast */
2890       tmp  = ref;
2891     } else {
2892       /* Multicast */
2893       tmp = rg;
2894     }
2895 
2896     FragmentSendInfo fragSend;
2897     sendFirstFragment(fragSend,
2898 		      tmp,
2899 		      GSN_TESTSIG,
2900 		      signal,
2901 		      signal->length(),
2902 		      JBB,
2903 		      &handle,
2904 		      true, // Don't release sections
2905                       fragmentLength);
2906 
2907     int count = 1;
2908     while(fragSend.m_status != FragmentSendInfo::SendComplete){
2909       count++;
2910       if(g_print)
2911 	ndbout_c("Sending fragment %d", count);
2912       sendNextSegmentedFragment(signal, fragSend);
2913     }
2914 
2915     if (g_print)
2916       ndbout_c("Free sections : %u\n", g_sectionSegmentPool.getNoOfFree());
2917     releaseSections(handle);
2918     //handle.clear(); // Use instead of releaseSections to Leak sections
2919     break;
2920   }
2921   /* Loop decrementing signal->theData[9] */
2922   case 15:{
2923     releaseSections(handle);
2924     ndbrequire(signal->getNoOfSections() == 0);
2925     Uint32 loop = signal->theData[9];
2926     if(loop > 0){
2927       signal->theData[9] --;
2928       sendSignal(CMVMI_REF, GSN_TESTSIG, signal, signal->length(), JBB);
2929       return;
2930     }
2931     sendSignal(ref, GSN_TESTSIG, signal, signal->length(), JBB);
2932     return;
2933   }
2934   case 16:{
2935     releaseSections(handle);
2936     Uint32 count = signal->theData[8];
2937     signal->theData[10] = count * rg.m_nodes.count();
2938     for(i = 0; i<count; i++){
2939       sendSignal(rg, GSN_TESTSIG, signal, signal->length(), JBB);
2940     }
2941     return;
2942   }
2943 
2944   default:
2945     ndbrequire(false);
2946   }
2947   return;
2948 }
2949 
2950 void
sendFragmentedComplete(Signal * signal,Uint32 data,Uint32 returnCode)2951 Cmvmi::sendFragmentedComplete(Signal* signal, Uint32 data, Uint32 returnCode){
2952   if(g_print)
2953     ndbout_c("sendFragmentedComplete: %d", data);
2954   if(data == 11 || data == 12){
2955     for(Uint32 i = 0; i<3; i++){
2956       if(g_test[i].p != 0)
2957 	delete[] g_test[i].p;
2958     }
2959   }
2960 }
2961 
2962 
2963 static Uint32
calc_percent(Uint32 used,Uint32 total)2964 calc_percent(Uint32 used, Uint32 total)
2965 {
2966   return (total ? (used * 100)/total : 0);
2967 }
2968 
2969 
2970 static Uint32
sum_array(const Uint32 array[],unsigned sz)2971 sum_array(const Uint32 array[], unsigned sz)
2972 {
2973   Uint32 sum = 0;
2974   for (unsigned i = 0; i < sz; i++)
2975     sum += array[i];
2976   return sum;
2977 }
2978 
2979 
2980 /*
2981   Check if any of the given thresholds has been
2982   passed since last
2983 
2984   Returns:
2985    -1       no threshold passed
2986    0 - 100  threshold passed
2987 */
2988 
2989 static int
check_threshold(Uint32 last,Uint32 now)2990 check_threshold(Uint32 last, Uint32 now)
2991 {
2992   assert(last <= 100 && now <= 100);
2993 
2994   static const Uint32 thresholds[] = { 100, 99, 90, 80, 0 };
2995 
2996   Uint32 passed;
2997   for (size_t i = 0; i < NDB_ARRAY_SIZE(thresholds); i++)
2998   {
2999     if (now >= thresholds[i])
3000     {
3001       passed = thresholds[i];
3002       break;
3003     }
3004   }
3005   assert(passed <= 100);
3006 
3007   if (passed == last)
3008     return -1; // Already reported this level
3009 
3010   return passed;
3011 }
3012 
3013 
3014 void
execCONTINUEB(Signal * signal)3015 Cmvmi::execCONTINUEB(Signal* signal)
3016 {
3017   switch(signal->theData[0]){
3018   case ZREPORT_MEMORY_USAGE:
3019   {
3020     jam();
3021     Uint32 cnt = signal->theData[1];
3022     Uint32 tup_percent_last = signal->theData[2];
3023     Uint32 acc_percent_last = signal->theData[3];
3024 
3025     {
3026       // Data memory threshold
3027       Resource_limit rl;
3028       m_ctx.m_mm.get_resource_limit(RG_DATAMEM, rl);
3029 
3030       const Uint32 tup_pages_used = rl.m_curr - f_accpages;
3031       const Uint32 tup_pages_total = rl.m_min - f_accpages;
3032       const Uint32 tup_percent_now = calc_percent(tup_pages_used,
3033                                                   tup_pages_total);
3034 
3035       int passed;
3036       if ((passed = check_threshold(tup_percent_last, tup_percent_now)) != -1)
3037       {
3038         jam();
3039         reportDMUsage(signal, tup_percent_now >= tup_percent_last ? 1 : -1);
3040         tup_percent_last = passed;
3041       }
3042     }
3043 
3044     {
3045       // Index memory threshold
3046       const Uint32 acc_pages_used =
3047         sum_array(g_acc_pages_used, NDB_ARRAY_SIZE(g_acc_pages_used));
3048       const Uint32 acc_pages_total = f_accpages * 4;
3049       const Uint32 acc_percent_now = calc_percent(acc_pages_used,
3050                                                   acc_pages_total);
3051 
3052       int passed;
3053       if ((passed = check_threshold(acc_percent_last, acc_percent_now)) != -1)
3054       {
3055         jam();
3056         reportIMUsage(signal, acc_percent_now >= acc_percent_last ? 1 : -1);
3057         acc_percent_last = passed;
3058       }
3059     }
3060 
3061     // Index and data memory report frequency
3062     if(c_memusage_report_frequency &&
3063        cnt + 1 == c_memusage_report_frequency)
3064     {
3065       jam();
3066       reportDMUsage(signal, 0);
3067       reportIMUsage(signal, 0);
3068       cnt = 0;
3069     }
3070     else
3071     {
3072       jam();
3073       cnt++;
3074     }
3075     signal->theData[0] = ZREPORT_MEMORY_USAGE;
3076     signal->theData[1] = cnt; // seconds since last report
3077     signal->theData[2] = tup_percent_last; // last reported threshold for TUP
3078     signal->theData[3] = acc_percent_last; // last reported threshold for ACC
3079     sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 1000, 4);
3080     return;
3081   }
3082   }
3083 }
3084 
3085 void
reportDMUsage(Signal * signal,int incDec,BlockReference ref)3086 Cmvmi::reportDMUsage(Signal* signal, int incDec, BlockReference ref)
3087 {
3088   Resource_limit rl;
3089   m_ctx.m_mm.get_resource_limit(RG_DATAMEM, rl);
3090 
3091   const Uint32 tup_pages_used = rl.m_curr - f_accpages;
3092   const Uint32 tup_pages_total = rl.m_min - f_accpages;
3093 
3094   signal->theData[0] = NDB_LE_MemoryUsage;
3095   signal->theData[1] = incDec;
3096   signal->theData[2] = sizeof(GlobalPage);
3097   signal->theData[3] = tup_pages_used;
3098   signal->theData[4] = tup_pages_total;
3099   signal->theData[5] = DBTUP;
3100   sendSignal(ref, GSN_EVENT_REP, signal, 6, JBB);
3101 }
3102 
3103 
3104 void
reportIMUsage(Signal * signal,int incDec,BlockReference ref)3105 Cmvmi::reportIMUsage(Signal* signal, int incDec, BlockReference ref)
3106 {
3107   const Uint32 acc_pages_used =
3108     sum_array(g_acc_pages_used, NDB_ARRAY_SIZE(g_acc_pages_used));
3109 
3110   signal->theData[0] = NDB_LE_MemoryUsage;
3111   signal->theData[1] = incDec;
3112   signal->theData[2] = 8192;
3113   signal->theData[3] = acc_pages_used;
3114   signal->theData[4] = f_accpages * 4;
3115   signal->theData[5] = DBACC;
3116   sendSignal(ref, GSN_EVENT_REP, signal, 6, JBB);
3117 }
3118 
3119 
3120 /**
3121  * execROUTE_ORD
3122  * Allows other blocks to route signals as if they
3123  * came from Cmvmi
3124  * Useful in ndbmtd for synchronising signals w.r.t
3125  * external signals received from other nodes which
3126  * arrive from the same thread that runs CMVMI.
3127  */
3128 void
execROUTE_ORD(Signal * signal)3129 Cmvmi::execROUTE_ORD(Signal* signal)
3130 {
3131   jamEntry();
3132   if(!assembleFragments(signal)){
3133     jam();
3134     return;
3135   }
3136 
3137   SectionHandle handle(this, signal);
3138 
3139   RouteOrd* ord = (RouteOrd*)signal->getDataPtr();
3140   Uint32 dstRef = ord->dstRef;
3141   Uint32 srcRef = ord->srcRef;
3142   Uint32 gsn = ord->gsn;
3143   /* ord->cnt ignored */
3144 
3145   Uint32 nodeId = refToNode(dstRef);
3146 
3147   if (likely((nodeId == 0) ||
3148              getNodeInfo(nodeId).m_connected))
3149   {
3150     jam();
3151     Uint32 secCount = handle.m_cnt;
3152     ndbrequire(secCount >= 1 && secCount <= 3);
3153 
3154     jamLine(secCount);
3155 
3156     /**
3157      * Put section 0 in signal->theData
3158      */
3159     Uint32 sigLen = handle.m_ptr[0].sz;
3160     ndbrequire(sigLen <= 25);
3161     copy(signal->theData, handle.m_ptr[0]);
3162 
3163     SegmentedSectionPtr save = handle.m_ptr[0];
3164     for (Uint32 i = 0; i < secCount - 1; i++)
3165       handle.m_ptr[i] = handle.m_ptr[i+1];
3166     handle.m_cnt--;
3167 
3168     sendSignal(dstRef, gsn, signal, sigLen, JBB, &handle);
3169 
3170     handle.m_cnt = 1;
3171     handle.m_ptr[0] = save;
3172     releaseSections(handle);
3173     return ;
3174   }
3175 
3176   releaseSections(handle);
3177   warningEvent("Unable to route GSN: %d from %x to %x",
3178 	       gsn, srcRef, dstRef);
3179 }
3180 
3181 
execGET_CONFIG_REQ(Signal * signal)3182 void Cmvmi::execGET_CONFIG_REQ(Signal *signal)
3183 {
3184   jamEntry();
3185   const GetConfigReq* const req = (const GetConfigReq *)signal->getDataPtr();
3186 
3187   Uint32 error = 0;
3188   Uint32 retRef = req->senderRef; // mgm servers ref
3189 
3190   if (retRef != signal->header.theSendersBlockRef)
3191   {
3192     error = GetConfigRef::WrongSender;
3193   }
3194 
3195   if (req->nodeId != getOwnNodeId())
3196   {
3197     error = GetConfigRef::WrongNodeId;
3198   }
3199 
3200   const Uint32 config_length = m_ctx.m_config.m_clusterConfigPacked.length();
3201   if (config_length == 0)
3202   {
3203     error = GetConfigRef::NoConfig;
3204   }
3205 
3206   if (error)
3207   {
3208     warningEvent("execGET_CONFIG_REQ: failed %u", error);
3209     GetConfigRef *ref = (GetConfigRef *)signal->getDataPtrSend();
3210     ref->error = error;
3211     sendSignal(retRef, GSN_GET_CONFIG_REF, signal,
3212                GetConfigRef::SignalLength, JBB);
3213     return;
3214   }
3215 
3216   const Uint32 nSections= 1;
3217   LinearSectionPtr ptr[3];
3218   ptr[0].p = (Uint32*)(m_ctx.m_config.m_clusterConfigPacked.get_data());
3219   ptr[0].sz = (config_length + 3) / 4;
3220 
3221   GetConfigConf *conf = (GetConfigConf *)signal->getDataPtrSend();
3222 
3223   conf->configLength = config_length;
3224 
3225   sendFragmentedSignal(retRef,
3226                        GSN_GET_CONFIG_CONF,
3227                        signal,
3228                        GetConfigConf::SignalLength,
3229                        JBB,
3230                        ptr,
3231                        nSections,
3232                        TheEmptyCallback);
3233 }
3234