1 /* Copyright (c) 2008, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 #include "Dbinfo.hpp"
24 
25 #include <signaldata/NodeFailRep.hpp>
26 #include <signaldata/ReadNodesConf.hpp>
27 
28 #include <signaldata/DumpStateOrd.hpp>
29 #include <signaldata/DbinfoScan.hpp>
30 #include <signaldata/TransIdAI.hpp>
31 
32 //#define DBINFO_SCAN_TRACE
33 #ifdef DBINFO_SCAN_TRACE
34 #include <debugger/DebuggerNames.hpp>
35 #endif
36 
37 #define JAM_FILE_ID 455
38 
39 
40 Uint32 dbinfo_blocks[] = { DBACC, DBTUP, BACKUP, DBTC, SUMA, DBUTIL,
41                            TRIX, DBTUX, DBDICT, CMVMI, DBLQH, LGMAN,
42                            PGMAN, DBSPJ, THRMAN, TRPMAN, QMGR, DBDIH, 0};
43 
Dbinfo(Block_context & ctx)44 Dbinfo::Dbinfo(Block_context& ctx) :
45   SimulatedBlock(DBINFO, ctx)
46 {
47   BLOCK_CONSTRUCTOR(Dbinfo);
48 
49   STATIC_ASSERT(sizeof(DbinfoScanCursor) == sizeof(Ndbinfo::ScanCursor));
50 
51   /* Add Received Signals */
52   addRecSignal(GSN_STTOR, &Dbinfo::execSTTOR);
53   addRecSignal(GSN_DUMP_STATE_ORD, &Dbinfo::execDUMP_STATE_ORD);
54   addRecSignal(GSN_READ_CONFIG_REQ, &Dbinfo::execREAD_CONFIG_REQ, true);
55 
56   addRecSignal(GSN_DBINFO_SCANREQ, &Dbinfo::execDBINFO_SCANREQ);
57   addRecSignal(GSN_DBINFO_SCANCONF, &Dbinfo::execDBINFO_SCANCONF);
58 
59   addRecSignal(GSN_NODE_FAILREP, &Dbinfo::execNODE_FAILREP);
60   addRecSignal(GSN_INCL_NODEREQ, &Dbinfo::execINCL_NODEREQ);
61 
62 }
63 
~Dbinfo()64 Dbinfo::~Dbinfo()
65 {
66 }
67 
BLOCK_FUNCTIONS(Dbinfo)68 BLOCK_FUNCTIONS(Dbinfo)
69 
70 void Dbinfo::execSTTOR(Signal *signal)
71 {
72   jamEntry();
73   sendSTTORRY(signal);
74   return;
75 }
76 
execREAD_CONFIG_REQ(Signal * signal)77 void Dbinfo::execREAD_CONFIG_REQ(Signal *signal)
78 {
79   jamEntry();
80   const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
81   Uint32 ref = req->senderRef;
82   Uint32 senderData = req->senderData;
83 
84   /* In the future, do something sensible here. */
85 
86   ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
87   conf->senderRef = reference();
88   conf->senderData = senderData;
89   sendSignal(ref, GSN_READ_CONFIG_CONF, signal,
90 	     ReadConfigConf::SignalLength, JBB);
91 }
92 
sendSTTORRY(Signal * signal)93 void Dbinfo::sendSTTORRY(Signal* signal)
94 {
95   signal->theData[0] = 0;
96   signal->theData[3] = 1;
97   signal->theData[4] = 255; // No more start phases from missra
98   sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 5, JBB);
99 }
100 
execDUMP_STATE_ORD(Signal * signal)101 void Dbinfo::execDUMP_STATE_ORD(Signal* signal)
102 {
103   jamEntry();
104 
105   switch(signal->theData[0])
106   {
107   case DumpStateOrd::DbinfoListTables:
108     jam();
109     ndbout_c("--- BEGIN NDB$INFO.TABLES ---");
110     for(int i = 0; i < Ndbinfo::getNumTables(); i++)
111     {
112       const Ndbinfo::Table& tab = Ndbinfo::getTable(i);
113       ndbout_c("%d,%s", i, tab.m.name);
114     }
115     ndbout_c("--- END NDB$INFO.TABLES ---");
116     break;
117 
118   case DumpStateOrd::DbinfoListColumns:
119     jam();
120     ndbout_c("--- BEGIN NDB$INFO.COLUMNS ---");
121     for(int i = 0; i < Ndbinfo::getNumTables(); i++)
122     {
123       const Ndbinfo::Table& tab = Ndbinfo::getTable(i);
124 
125       for(int j = 0; j < tab.m.ncols; j++)
126         ndbout_c("%d,%d,%s,%d", i, j,
127                  tab.col[j].name, tab.col[j].coltype);
128     }
129     ndbout_c("--- END NDB$INFO.COLUMNS ---");
130     break;
131 
132   };
133 }
134 
135 
find_next_block(Uint32 block) const136 Uint32 Dbinfo::find_next_block(Uint32 block) const
137 {
138   int i = 0;
139   // Find current blocks position
140   while (dbinfo_blocks[i] != block &&
141          dbinfo_blocks[i] != 0)
142     i++;
143 
144   // Make sure current block was found
145   ndbrequire(dbinfo_blocks[i]);
146 
147   // Return the next block(which might be 0)
148   return dbinfo_blocks[++i];
149 }
150 
151 static Uint32
switchRef(Uint32 block,Uint32 node)152 switchRef(Uint32 block, Uint32 node)
153 {
154   const Uint32 ref = numberToRef(block, node);
155 #ifdef DBINFO_SCAN_TRACE
156   ndbout_c("Dbinfo: switching to %s in node %d, ref: 0x%.8x",
157            getBlockName(block, "<unknown>"), node, ref);
158 #endif
159   return ref;
160 }
161 
162 
find_next(Ndbinfo::ScanCursor * cursor) const163 bool Dbinfo::find_next(Ndbinfo::ScanCursor* cursor) const
164 {
165   Uint32 node = refToNode(cursor->currRef);
166   Uint32 block = refToBlock(cursor->currRef);
167   const Uint32 instance = refToInstance(cursor->currRef);
168   ndbrequire(instance == 0);
169 
170   if (node == 0)
171   {
172     jam();
173     // First 'find_next'
174     ndbrequire(block == 0);
175     cursor->currRef = switchRef(dbinfo_blocks[0], getOwnNodeId());
176     return true;
177   }
178 
179   if (block)
180   {
181     jam();
182     // Find next block
183     ndbrequire(node == getOwnNodeId());
184     block = find_next_block(block);
185     if (block)
186     {
187       jam();
188       cursor->currRef = switchRef(block, node);
189       return true;
190     }
191   }
192 
193   // Nothing more to scan
194   cursor->currRef = 0;
195   return false;
196 }
197 
execDBINFO_SCANREQ(Signal * signal)198 void Dbinfo::execDBINFO_SCANREQ(Signal *signal)
199 {
200   jamEntry();
201   DbinfoScanReq* req_ptr = (DbinfoScanReq*)signal->getDataPtrSend();
202   const Uint32 senderRef = signal->header.theSendersBlockRef;
203 
204   // Copy signal on stack
205   DbinfoScanReq req = *req_ptr;
206 
207   const Uint32 resultData = req.resultData;
208   const Uint32 transId0 = req.transId[0];
209   const Uint32 transId1 = req.transId[1];
210   const Uint32 resultRef = req.resultRef;
211 
212   // Validate tableId
213   const Uint32 tableId = req.tableId;
214   if (tableId >= (Uint32)Ndbinfo::getNumTables())
215   {
216     jam();
217     DbinfoScanRef *ref= (DbinfoScanRef*)signal->getDataPtrSend();
218     ref->resultData = resultData;
219     ref->transId[0] = transId0;
220     ref->transId[1] = transId1;
221     ref->resultRef = resultRef;
222     ref->errorCode= DbinfoScanRef::NoTable;
223     sendSignal(senderRef, GSN_DBINFO_SCANREF, signal,
224                DbinfoScanRef::SignalLength, JBB);
225     return;
226   }
227 
228   // TODO Check all scan parameters
229   Ndbinfo::ScanCursor* cursor =
230     CAST_PTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtrSend(&req));
231 
232   Uint32 signal_length = signal->getLength();
233   if (signal_length == DbinfoScanReq::SignalLength)
234   {
235     // Initialize cursor
236     jam();
237     cursor->senderRef = senderRef;
238     cursor->saveSenderRef = 0;
239     cursor->currRef = 0;
240     cursor->saveCurrRef = 0;
241     // Reset all data holders
242     memset(cursor->data, 0, sizeof(cursor->data));
243     cursor->flags = 0;
244     cursor->totalRows = 0;
245     cursor->totalBytes = 0;
246     req.cursor_sz = Ndbinfo::ScanCursor::Length;
247     signal_length += req.cursor_sz;
248   }
249   ndbrequire(signal_length ==
250              DbinfoScanReq::SignalLength + Ndbinfo::ScanCursor::Length);
251   ndbrequire(req.cursor_sz == Ndbinfo::ScanCursor::Length);
252 
253   switch(tableId)
254   {
255   case Ndbinfo::TABLES_TABLEID:
256   {
257     jam();
258 
259     Ndbinfo::Ratelimit rl;
260     Uint32 tableId = cursor->data[0];
261 
262     while(tableId < (Uint32)Ndbinfo::getNumTables())
263     {
264       jam();
265       const Ndbinfo::Table& tab = Ndbinfo::getTable(tableId);
266       Ndbinfo::Row row(signal, req);
267       row.write_uint32(tableId);
268       row.write_string(tab.m.name);
269       row.write_string(tab.m.comment);
270       ndbinfo_send_row(signal, req, row, rl);
271 
272       tableId++;
273 
274       if (rl.need_break(req))
275       {
276         jam();
277         ndbinfo_send_scan_break(signal, req, rl, tableId);
278         return;
279       }
280     }
281 
282     // All tables sent
283     req.cursor_sz = 0; // Close cursor
284     ndbinfo_send_scan_conf(signal, req, rl);
285     return;
286 
287     break;
288   }
289 
290   case Ndbinfo::COLUMNS_TABLEID:
291   {
292     jam();
293 
294     Ndbinfo::Ratelimit rl;
295     Uint32 tableId = cursor->data[0];
296     Uint32 columnId = cursor->data[1];
297 
298     while(tableId < (Uint32)Ndbinfo::getNumTables())
299     {
300       jam();
301       const Ndbinfo::Table& tab = Ndbinfo::getTable(tableId);
302       while(columnId < (Uint32)tab.m.ncols)
303       {
304         jam();
305         Ndbinfo::Row row(signal, req);
306         row.write_uint32(tableId);
307         row.write_uint32(columnId);
308         row.write_string(tab.col[columnId].name);
309         row.write_uint32(tab.col[columnId].coltype);
310         row.write_string(tab.col[columnId].comment);
311         ndbinfo_send_row(signal, req, row, rl);
312 
313         assert(columnId < 256);
314         columnId++;
315 
316         if(rl.need_break(req))
317         {
318           jam();
319           ndbinfo_send_scan_break(signal, req, rl, tableId, columnId);
320           return;
321         }
322       }
323       columnId = 0;
324       tableId++;
325     }
326 
327     // All tables and columns sent
328     req.cursor_sz = 0; // Close cursor
329     ndbinfo_send_scan_conf(signal, req, rl);
330 
331     break;
332   }
333 
334   default:
335   {
336     jam();
337 
338     ndbassert(tableId > 1);
339 
340     //printSignalHeader(stdout, signal->header, 99, 98, true);
341     //printDBINFO_SCAN(stdout, signal->theData, signal->getLength(), 0);
342 
343     if (Ndbinfo::ScanCursor::getHasMoreData(cursor->flags) ||
344         find_next(cursor))
345     {
346       jam();
347       ndbrequire(cursor->currRef);
348 
349       // CONF or REF should be sent back here
350       cursor->senderRef = reference();
351 
352       // Send SCANREQ
353       MEMCOPY_NO_WORDS(req_ptr,
354                        &req, signal_length);
355       sendSignal(cursor->currRef,
356                  GSN_DBINFO_SCANREQ,
357                  signal, signal_length, JBB);
358     }
359     else
360     {
361       // Scan is done, send SCANCONF back to caller
362       jam();
363       DbinfoScanConf *apiconf= (DbinfoScanConf*)signal->getDataPtrSend();
364       MEMCOPY_NO_WORDS(apiconf, &req, DbinfoScanConf::SignalLength);
365       // Set cursor_sz back to 0 to indicate end of scan
366       apiconf->cursor_sz = 0;
367       sendSignal(resultRef, GSN_DBINFO_SCANCONF, signal,
368                  DbinfoScanConf::SignalLength, JBB);
369     }
370     break;
371   }
372   }
373 }
374 
execDBINFO_SCANCONF(Signal * signal)375 void Dbinfo::execDBINFO_SCANCONF(Signal *signal)
376 {
377   const DbinfoScanConf* conf_ptr= (const DbinfoScanConf*)signal->getDataPtr();
378   // Copy signal on stack
379   DbinfoScanConf conf= *conf_ptr;
380 
381   jamEntry();
382 
383   //printDBINFO_SCAN(stdout, signal->theData, signal->getLength(), 0);
384 
385   Uint32 signal_length = signal->getLength();
386   ndbrequire(signal_length ==
387              DbinfoScanReq::SignalLength+Ndbinfo::ScanCursor::Length);
388   ndbrequire(conf.cursor_sz == Ndbinfo::ScanCursor::Length);
389 
390   // Validate tableId
391   ndbassert(conf.tableId < (Uint32)Ndbinfo::getNumTables());
392 
393   const Uint32 resultRef = conf.resultRef;
394 
395   // Copy cursor on stack
396   ndbrequire(conf.cursor_sz);
397   Ndbinfo::ScanCursor* cursor =
398     CAST_PTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtrSend(&conf));
399 
400   if (Ndbinfo::ScanCursor::getHasMoreData(cursor->flags) || conf.returnedRows)
401   {
402     // Rate limit break, pass through to API
403     jam();
404     ndbrequire(cursor->currRef);
405     DbinfoScanConf *apiconf = (DbinfoScanConf*) signal->getDataPtrSend();
406     MEMCOPY_NO_WORDS(apiconf, &conf, signal_length);
407     sendSignal(resultRef, GSN_DBINFO_SCANCONF, signal, signal_length, JBB);
408     return;
409   }
410 
411   if (find_next(cursor))
412   {
413     jam();
414     ndbrequire(cursor->currRef);
415 
416     // CONF or REF should be sent back here
417     cursor->senderRef = reference();
418 
419     // Send SCANREQ
420     MEMCOPY_NO_WORDS(signal->getDataPtrSend(),
421                      &conf, signal_length);
422     sendSignal(cursor->currRef,
423                GSN_DBINFO_SCANREQ,
424                signal, signal_length, JBB);
425     return;
426   }
427 
428   // Scan is done, send SCANCONF back to caller
429   jam();
430   DbinfoScanConf *apiconf = (DbinfoScanConf*) signal->getDataPtrSend();
431   MEMCOPY_NO_WORDS(apiconf, &conf, DbinfoScanConf::SignalLength);
432 
433   // Set cursor_sz back to 0 to indicate end of scan
434   apiconf->cursor_sz = 0;
435   sendSignal(resultRef, GSN_DBINFO_SCANCONF, signal,
436              DbinfoScanConf::SignalLength, JBB);
437   return;
438 }
439 
440 
execINCL_NODEREQ(Signal * signal)441 void Dbinfo::execINCL_NODEREQ(Signal* signal)
442 {
443   jamEntry();
444 
445   const Uint32 senderRef = signal->theData[0];
446   const Uint32 inclNode  = signal->theData[1];
447 
448   signal->theData[0] = inclNode;
449   signal->theData[1] = reference();
450   sendSignal(senderRef, GSN_INCL_NODECONF, signal, 2, JBB);
451 }
452 
execNODE_FAILREP(Signal * signal)453 void Dbinfo::execNODE_FAILREP(Signal* signal)
454 {
455   jamEntry();
456 
457   NodeFailRep * rep = (NodeFailRep*)signal->getDataPtr();
458 
459   Uint32 theFailedNodes[NdbNodeBitmask::Size];
460   for (Uint32 i = 0; i < NdbNodeBitmask::Size; i++)
461     theFailedNodes[i] = rep->theNodes[i];
462 
463   for (Uint32 i = 0; i < MAX_NDB_NODES; i++)
464   {
465     if (NdbNodeBitmask::get(theFailedNodes, i))
466     {
467       Uint32 elementsCleaned = simBlockNodeFailure(signal, i); // No callback
468       ndbassert(elementsCleaned == 0); // DbInfo should have no distributed frag signals
469       (void) elementsCleaned; // Remove compiler warning
470     }
471   }
472 }
473