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