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