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