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 = §ionData[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 = §ionData[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