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