1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 
27 #include "Configuration.hpp"
28 #include <ErrorHandlingMacros.hpp>
29 #include "GlobalData.hpp"
30 
31 #include <ConfigRetriever.hpp>
32 #include <IPCConfig.hpp>
33 #include <ndb_version.h>
34 #include <NdbMem.h>
35 #include <NdbOut.hpp>
36 #include <WatchDog.hpp>
37 #include <NdbConfig.h>
38 
39 #include <mgmapi_configuration.hpp>
40 #include <kernel_config_parameters.h>
41 
42 #include <util/ConfigValues.hpp>
43 #include <NdbEnv.h>
44 
45 #include <ndbapi_limits.h>
46 #include "mt.hpp"
47 
48 #include <EventLogger.hpp>
49 extern EventLogger * g_eventLogger;
50 
51 extern Uint32 g_start_type;
52 
53 bool
init(int _no_start,int _initial,int _initialstart)54 Configuration::init(int _no_start, int _initial,
55                     int _initialstart)
56 {
57   // Check the start flag
58   if (_no_start)
59     globalData.theRestartFlag = initial_state;
60   else
61     globalData.theRestartFlag = perform_start;
62 
63   // Check the initial flag
64   if (_initial)
65     _initialStart = true;
66 
67   globalData.ownId= 0;
68 
69   if (_initialstart)
70   {
71     _initialStart = true;
72     g_start_type |= (1 << NodeState::ST_INITIAL_START);
73   }
74 
75   threadIdMutex = NdbMutex_Create();
76   if (!threadIdMutex)
77   {
78     g_eventLogger->error("Failed to create threadIdMutex");
79     return false;
80   }
81   initThreadArray();
82   return true;
83 }
84 
Configuration()85 Configuration::Configuration()
86 {
87   _fsPath = 0;
88   _backupPath = 0;
89   _initialStart = false;
90   m_config_retriever= 0;
91   m_clusterConfig= 0;
92   m_clusterConfigIter= 0;
93   m_logLevel= 0;
94 }
95 
~Configuration()96 Configuration::~Configuration(){
97 
98   if(_fsPath != NULL)
99     free(_fsPath);
100 
101   if(_backupPath != NULL)
102     free(_backupPath);
103 
104   if (m_config_retriever) {
105     delete m_config_retriever;
106   }
107 
108   if(m_logLevel) {
109     delete m_logLevel;
110   }
111 }
112 
113 void
closeConfiguration(bool end_session)114 Configuration::closeConfiguration(bool end_session){
115   m_config_retriever->end_session(end_session);
116   if (m_config_retriever) {
117     delete m_config_retriever;
118   }
119   m_config_retriever= 0;
120 }
121 
122 void
fetch_configuration(const char * _connect_string,int force_nodeid,const char * _bind_address,NodeId allocated_nodeid)123 Configuration::fetch_configuration(const char* _connect_string,
124                                    int force_nodeid,
125                                    const char* _bind_address,
126                                    NodeId allocated_nodeid)
127 {
128   /**
129    * Fetch configuration from management server
130    */
131   if (m_config_retriever) {
132     delete m_config_retriever;
133   }
134 
135   m_config_retriever= new ConfigRetriever(_connect_string,
136                                           force_nodeid,
137                                           NDB_VERSION,
138                                           NDB_MGM_NODE_TYPE_NDB,
139 					  _bind_address);
140   if (!m_config_retriever)
141   {
142     ERROR_SET(fatal, NDBD_EXIT_MEMALLOC,
143               "Failed to create ConfigRetriever", "");
144   }
145 
146   if (m_config_retriever->hasError())
147   {
148     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
149 	      "Could not initialize handle to management server",
150 	      m_config_retriever->getErrorString());
151   }
152 
153   if(m_config_retriever->do_connect(12,5,1) == -1){
154     const char * s = m_config_retriever->getErrorString();
155     if(s == 0)
156       s = "No error given!";
157     /* Set stop on error to true otherwise NDB will
158        go into an restart loop...
159     */
160     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Could not connect to ndb_mgmd", s);
161   }
162 
163   ConfigRetriever &cr= *m_config_retriever;
164 
165   if (allocated_nodeid)
166   {
167     // The angel has already allocated the nodeid, no need to
168     // allocate it
169     globalData.ownId = allocated_nodeid;
170   }
171   else
172   {
173 
174     const int alloc_retries = 2;
175     const int alloc_delay = 3;
176     globalData.ownId = cr.allocNodeId(alloc_retries, alloc_delay);
177     if(globalData.ownId == 0)
178     {
179       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
180                 "Unable to alloc node id",
181                 m_config_retriever->getErrorString());
182     }
183   }
184   assert(globalData.ownId);
185 
186   ndb_mgm_configuration * p = cr.getConfig(globalData.ownId);
187   if(p == 0){
188     const char * s = cr.getErrorString();
189     if(s == 0)
190       s = "No error given!";
191 
192     /* Set stop on error to true otherwise NDB will
193        go into an restart loop...
194     */
195 
196     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Could not fetch configuration"
197 	      "/invalid configuration", s);
198   }
199   if(m_clusterConfig)
200     free(m_clusterConfig);
201 
202   m_clusterConfig = p;
203 
204   const ConfigValues * cfg = (ConfigValues*)m_clusterConfig;
205   cfg->pack(m_clusterConfigPacked);
206 
207   {
208     Uint32 generation;
209     ndb_mgm_configuration_iterator sys_iter(*p, CFG_SECTION_SYSTEM);
210     if (sys_iter.get(CFG_SYS_CONFIG_GENERATION, &generation))
211     {
212       g_eventLogger->info("Configuration fetched from '%s:%d', unknown generation!! (likely older ndb_mgmd)",
213                           m_config_retriever->get_mgmd_host(),
214                           m_config_retriever->get_mgmd_port());
215     }
216     else
217     {
218       g_eventLogger->info("Configuration fetched from '%s:%d', generation: %d",
219                           m_config_retriever->get_mgmd_host(),
220                           m_config_retriever->get_mgmd_port(),
221                           generation);
222     }
223   }
224 
225   ndb_mgm_configuration_iterator iter(* p, CFG_SECTION_NODE);
226   if (iter.find(CFG_NODE_ID, globalData.ownId)){
227     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "DB missing");
228   }
229 
230   if(iter.get(CFG_DB_STOP_ON_ERROR, &_stopOnError)){
231     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
232 	      "StopOnError missing");
233   }
234 
235   const char * datadir;
236   if(iter.get(CFG_NODE_DATADIR, &datadir)){
237     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
238 	      "DataDir missing");
239   }
240   NdbConfig_SetPath(datadir);
241 
242 }
243 
get_and_validate_path(ndb_mgm_configuration_iterator & iter,Uint32 param,const char * param_string)244 static char * get_and_validate_path(ndb_mgm_configuration_iterator &iter,
245 				    Uint32 param, const char *param_string)
246 {
247   const char* path = NULL;
248   if(iter.get(param, &path)){
249     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched missing ",
250 	      param_string);
251   }
252 
253   if(path == 0 || strlen(path) == 0){
254     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
255 	      "Invalid configuration fetched. Configuration does not contain valid ",
256 	      param_string);
257   }
258 
259   // check that it is pointing on a valid directory
260   //
261   char buf2[PATH_MAX];
262   memset(buf2, 0,sizeof(buf2));
263 #ifdef NDB_WIN32
264   char* szFilePart;
265   if(!GetFullPathName(path, sizeof(buf2), buf2, &szFilePart) ||
266      (GetFileAttributes(buf2) & FILE_ATTRIBUTE_READONLY))
267 #else
268   if((::realpath(path, buf2) == NULL)||
269        (::access(buf2, W_OK) != 0))
270 #endif
271   {
272     ERROR_SET(fatal, NDBD_EXIT_AFS_INVALIDPATH, path, param_string);
273   }
274 
275   if (strcmp(&buf2[strlen(buf2) - 1], DIR_SEPARATOR))
276     strcat(buf2, DIR_SEPARATOR);
277 
278   return strdup(buf2);
279 }
280 
281 #include "../../common/util/parse_mask.hpp"
282 
283 void
setupConfiguration()284 Configuration::setupConfiguration(){
285 
286   DBUG_ENTER("Configuration::setupConfiguration");
287 
288   ndb_mgm_configuration * p = m_clusterConfig;
289 
290   /**
291    * Configure transporters
292    */
293   if (!globalTransporterRegistry.init(globalData.ownId))
294   {
295     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
296               "Invalid configuration fetched",
297               "Could not init transporter registry");
298   }
299 
300   if (!IPCConfig::configureTransporters(globalData.ownId,
301                                         * p,
302                                         globalTransporterRegistry))
303   {
304     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
305               "Invalid configuration fetched",
306               "Could not configure transporters");
307   }
308 
309   /**
310    * Setup cluster configuration data
311    */
312   ndb_mgm_configuration_iterator iter(* p, CFG_SECTION_NODE);
313   if (iter.find(CFG_NODE_ID, globalData.ownId)){
314     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "DB missing");
315   }
316 
317   unsigned type;
318   if(!(iter.get(CFG_TYPE_OF_SECTION, &type) == 0 && type == NODE_TYPE_DB)){
319     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
320 	      "I'm wrong type of node");
321   }
322 
323   Uint32 total_send_buffer = 0;
324   iter.get(CFG_TOTAL_SEND_BUFFER_MEMORY, &total_send_buffer);
325   globalTransporterRegistry.allocate_send_buffers(total_send_buffer);
326 
327   if(iter.get(CFG_DB_NO_SAVE_MSGS, &_maxErrorLogs)){
328     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
329 	      "MaxNoOfSavedMessages missing");
330   }
331 
332   if(iter.get(CFG_DB_MEMLOCK, &_lockPagesInMainMemory)){
333     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
334 	      "LockPagesInMainMemory missing");
335   }
336 
337   if(iter.get(CFG_DB_WATCHDOG_INTERVAL, &_timeBetweenWatchDogCheck)){
338     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
339 	      "TimeBetweenWatchDogCheck missing");
340   }
341 
342   _schedulerExecutionTimer = 50;
343   iter.get(CFG_DB_SCHED_EXEC_TIME, &_schedulerExecutionTimer);
344 
345   _schedulerSpinTimer = 0;
346   iter.get(CFG_DB_SCHED_SPIN_TIME, &_schedulerSpinTimer);
347 
348   _realtimeScheduler = 0;
349   iter.get(CFG_DB_REALTIME_SCHEDULER, &_realtimeScheduler);
350 
351   if(iter.get(CFG_DB_WATCHDOG_INTERVAL_INITIAL,
352               &_timeBetweenWatchDogCheckInitial)){
353     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
354 	      "TimeBetweenWatchDogCheckInitial missing");
355   }
356 
357   /**
358    * Get paths
359    */
360   if (_fsPath)
361     free(_fsPath);
362   _fsPath= get_and_validate_path(iter, CFG_DB_FILESYSTEM_PATH, "FileSystemPath");
363   if (_backupPath)
364     free(_backupPath);
365   _backupPath= get_and_validate_path(iter, CFG_DB_BACKUP_DATADIR, "BackupDataDir");
366 
367   if(iter.get(CFG_DB_STOP_ON_ERROR_INSERT, &m_restartOnErrorInsert)){
368     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
369 	      "RestartOnErrorInsert missing");
370   }
371 
372   /**
373    * Create the watch dog thread
374    */
375   {
376     if (_timeBetweenWatchDogCheckInitial < _timeBetweenWatchDogCheck)
377       _timeBetweenWatchDogCheckInitial = _timeBetweenWatchDogCheck;
378 
379     Uint32 t = _timeBetweenWatchDogCheckInitial;
380     t = globalEmulatorData.theWatchDog ->setCheckInterval(t);
381     _timeBetweenWatchDogCheckInitial = t;
382   }
383 
384   const char * lockmask = 0;
385   {
386     if (iter.get(CFG_DB_EXECUTE_LOCK_CPU, &lockmask) == 0)
387     {
388       int res = m_thr_config.setLockExecuteThreadToCPU(lockmask);
389       if (res < 0)
390       {
391         // Could not parse LockExecuteThreadToCPU mask
392         g_eventLogger->warning("Failed to parse 'LockExecuteThreadToCPU=%s' "
393                                "(error: %d), ignoring it!",
394                                lockmask, res);
395       }
396     }
397   }
398 
399   {
400     Uint32 maintCPU = NO_LOCK_CPU;
401     iter.get(CFG_DB_MAINT_LOCK_CPU, &maintCPU);
402     if (maintCPU == 65535)
403       maintCPU = NO_LOCK_CPU; // Ignore old default(may come from old mgmd)
404     if (maintCPU != NO_LOCK_CPU)
405       m_thr_config.setLockIoThreadsToCPU(maintCPU);
406   }
407 
408   const char * thrconfigstring = NdbEnv_GetEnv("NDB_MT_THREAD_CONFIG",
409                                                (char*)0, 0);
410   if (thrconfigstring ||
411       iter.get(CFG_DB_MT_THREAD_CONFIG, &thrconfigstring) == 0)
412   {
413     int res = m_thr_config.do_parse(thrconfigstring);
414     if (res != 0)
415     {
416       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
417                 "Invalid configuration fetched, invalid ThreadConfig",
418                 m_thr_config.getErrorMessage());
419     }
420   }
421   else
422   {
423     Uint32 mtthreads = 0;
424     iter.get(CFG_DB_MT_THREADS, &mtthreads);
425 
426     Uint32 classic = 0;
427     iter.get(CFG_NDBMT_CLASSIC, &classic);
428     const char* p = NdbEnv_GetEnv("NDB_MT_LQH", (char*)0, 0);
429     if (p != 0)
430     {
431       if (strstr(p, "NOPLEASE") != 0)
432         classic = 1;
433     }
434 
435     Uint32 lqhthreads = 0;
436     iter.get(CFG_NDBMT_LQH_THREADS, &lqhthreads);
437 
438     int res = m_thr_config.do_parse(mtthreads, lqhthreads, classic);
439     if (res != 0)
440     {
441       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG,
442                 "Invalid configuration fetched, invalid thread configuration",
443                 m_thr_config.getErrorMessage());
444     }
445   }
446   if (thrconfigstring)
447   {
448     ndbout_c("ThreadConfig: input: %s LockExecuteThreadToCPU: %s => parsed: %s",
449              thrconfigstring,
450              lockmask ? lockmask : "",
451              m_thr_config.getConfigString());
452   }
453   else
454   {
455     ndbout_c("ThreadConfig (old ndb_mgmd) LockExecuteThreadToCPU: %s => parsed: %s",
456              lockmask ? lockmask : "",
457              m_thr_config.getConfigString());
458   }
459 
460   ConfigValues* cf = ConfigValuesFactory::extractCurrentSection(iter.m_config);
461 
462   if(m_clusterConfigIter)
463     ndb_mgm_destroy_iterator(m_clusterConfigIter);
464   m_clusterConfigIter = ndb_mgm_create_configuration_iterator
465     (p, CFG_SECTION_NODE);
466 
467   calcSizeAlt(cf);
468 
469   DBUG_VOID_RETURN;
470 }
471 
472 Uint32
lockPagesInMainMemory() const473 Configuration::lockPagesInMainMemory() const {
474   return _lockPagesInMainMemory;
475 }
476 
477 int
schedulerExecutionTimer() const478 Configuration::schedulerExecutionTimer() const {
479   return _schedulerExecutionTimer;
480 }
481 
482 void
schedulerExecutionTimer(int value)483 Configuration::schedulerExecutionTimer(int value) {
484   if (value < 11000)
485     _schedulerExecutionTimer = value;
486 }
487 
488 int
schedulerSpinTimer() const489 Configuration::schedulerSpinTimer() const {
490   return _schedulerSpinTimer;
491 }
492 
493 void
schedulerSpinTimer(int value)494 Configuration::schedulerSpinTimer(int value) {
495   if (value < 500)
496     value = 500;
497   _schedulerSpinTimer = value;
498 }
499 
500 bool
realtimeScheduler() const501 Configuration::realtimeScheduler() const
502 {
503   return (bool)_realtimeScheduler;
504 }
505 
506 void
realtimeScheduler(bool realtime_on)507 Configuration::realtimeScheduler(bool realtime_on)
508 {
509    bool old_value = (bool)_realtimeScheduler;
510   _realtimeScheduler = (Uint32)realtime_on;
511   if (old_value != realtime_on)
512     setAllRealtimeScheduler();
513 }
514 
515 int
timeBetweenWatchDogCheck() const516 Configuration::timeBetweenWatchDogCheck() const {
517   return _timeBetweenWatchDogCheck;
518 }
519 
520 void
timeBetweenWatchDogCheck(int value)521 Configuration::timeBetweenWatchDogCheck(int value) {
522   _timeBetweenWatchDogCheck = value;
523 }
524 
525 int
maxNoOfErrorLogs() const526 Configuration::maxNoOfErrorLogs() const {
527   return _maxErrorLogs;
528 }
529 
530 void
maxNoOfErrorLogs(int val)531 Configuration::maxNoOfErrorLogs(int val){
532   _maxErrorLogs = val;
533 }
534 
535 bool
stopOnError() const536 Configuration::stopOnError() const {
537   return _stopOnError;
538 }
539 
540 void
stopOnError(bool val)541 Configuration::stopOnError(bool val){
542   _stopOnError = val;
543 }
544 
545 int
getRestartOnErrorInsert() const546 Configuration::getRestartOnErrorInsert() const {
547   return m_restartOnErrorInsert;
548 }
549 
550 void
setRestartOnErrorInsert(int i)551 Configuration::setRestartOnErrorInsert(int i){
552   m_restartOnErrorInsert = i;
553 }
554 
555 const ndb_mgm_configuration_iterator *
getOwnConfigIterator() const556 Configuration::getOwnConfigIterator() const {
557   return m_ownConfigIterator;
558 }
559 
560 ndb_mgm_configuration_iterator *
getClusterConfigIterator() const561 Configuration::getClusterConfigIterator() const {
562   return m_clusterConfigIter;
563 }
564 
565 Uint32
get_config_generation() const566 Configuration::get_config_generation() const {
567   Uint32 generation = ~0;
568   ndb_mgm_configuration_iterator sys_iter(*m_clusterConfig,
569                                           CFG_SECTION_SYSTEM);
570   sys_iter.get(CFG_SYS_CONFIG_GENERATION, &generation);
571   return generation;
572 }
573 
574 
575 void
calcSizeAlt(ConfigValues * ownConfig)576 Configuration::calcSizeAlt(ConfigValues * ownConfig){
577   const char * msg = "Invalid configuration fetched";
578   char buf[255];
579 
580   unsigned int noOfTables = 0;
581   unsigned int noOfUniqueHashIndexes = 0;
582   unsigned int noOfOrderedIndexes = 0;
583   unsigned int noOfTriggers = 0;
584   unsigned int noOfReplicas = 0;
585   unsigned int noOfDBNodes = 0;
586   unsigned int noOfAPINodes = 0;
587   unsigned int noOfMGMNodes = 0;
588   unsigned int noOfNodes = 0;
589   unsigned int noOfAttributes = 0;
590   unsigned int noOfOperations = 0;
591   unsigned int noOfLocalOperations = 0;
592   unsigned int noOfTransactions = 0;
593   unsigned int noOfIndexPages = 0;
594   unsigned int noOfDataPages = 0;
595   unsigned int noOfScanRecords = 0;
596   unsigned int noOfLocalScanRecords = 0;
597   unsigned int noBatchSize = 0;
598   m_logLevel = new LogLevel();
599   if (!m_logLevel)
600   {
601     ERROR_SET(fatal, NDBD_EXIT_MEMALLOC, "Failed to create LogLevel", "");
602   }
603 
604   struct AttribStorage { int paramId; Uint32 * storage; bool computable; };
605   AttribStorage tmp[] = {
606     { CFG_DB_NO_SCANS, &noOfScanRecords, false },
607     { CFG_DB_NO_LOCAL_SCANS, &noOfLocalScanRecords, true },
608     { CFG_DB_BATCH_SIZE, &noBatchSize, false },
609     { CFG_DB_NO_TABLES, &noOfTables, false },
610     { CFG_DB_NO_ORDERED_INDEXES, &noOfOrderedIndexes, false },
611     { CFG_DB_NO_UNIQUE_HASH_INDEXES, &noOfUniqueHashIndexes, false },
612     { CFG_DB_NO_TRIGGERS, &noOfTriggers, true },
613     { CFG_DB_NO_REPLICAS, &noOfReplicas, false },
614     { CFG_DB_NO_ATTRIBUTES, &noOfAttributes, false },
615     { CFG_DB_NO_OPS, &noOfOperations, false },
616     { CFG_DB_NO_LOCAL_OPS, &noOfLocalOperations, true },
617     { CFG_DB_NO_TRANSACTIONS, &noOfTransactions, false }
618   };
619 
620   ndb_mgm_configuration_iterator db(*(ndb_mgm_configuration*)ownConfig, 0);
621 
622   const int sz = sizeof(tmp)/sizeof(AttribStorage);
623   for(int i = 0; i<sz; i++){
624     if(ndb_mgm_get_int_parameter(&db, tmp[i].paramId, tmp[i].storage)){
625       if (tmp[i].computable) {
626         *tmp[i].storage = 0;
627       } else {
628         BaseString::snprintf(buf, sizeof(buf),"ConfigParam: %d not found", tmp[i].paramId);
629         ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
630       }
631     }
632   }
633 
634   Uint32 lqhInstances = 1;
635   if (globalData.isNdbMtLqh)
636   {
637     lqhInstances = globalData.ndbMtLqhWorkers;
638   }
639 
640   Uint64 indexMem = 0, dataMem = 0;
641   ndb_mgm_get_int64_parameter(&db, CFG_DB_DATA_MEM, &dataMem);
642   ndb_mgm_get_int64_parameter(&db, CFG_DB_INDEX_MEM, &indexMem);
643   if(dataMem == 0){
644     BaseString::snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_DATA_MEM);
645     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
646   }
647 
648   if(indexMem == 0){
649     BaseString::snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_INDEX_MEM);
650     ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
651   }
652 
653 #define DO_DIV(x,y) (((x) + (y - 1)) / (y))
654 
655   noOfDataPages = (Uint32)(dataMem / 32768);
656   noOfIndexPages = (Uint32)(indexMem / 8192);
657   noOfIndexPages = DO_DIV(noOfIndexPages, lqhInstances);
658 
659   for(unsigned j = 0; j<LogLevel::LOGLEVEL_CATEGORIES; j++){
660     Uint32 tmp;
661     if(!ndb_mgm_get_int_parameter(&db, CFG_MIN_LOGLEVEL+j, &tmp)){
662       m_logLevel->setLogLevel((LogLevel::EventCategory)j, tmp);
663     }
664   }
665 
666   // tmp
667   ndb_mgm_configuration_iterator * p = m_clusterConfigIter;
668 
669   Uint32 nodeNo = noOfNodes = 0;
670   NodeBitmask nodes;
671   for(ndb_mgm_first(p); ndb_mgm_valid(p); ndb_mgm_next(p), nodeNo++){
672 
673     Uint32 nodeId;
674     Uint32 nodeType;
675 
676     if(ndb_mgm_get_int_parameter(p, CFG_NODE_ID, &nodeId)){
677       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data (Id) missing");
678     }
679 
680     if(ndb_mgm_get_int_parameter(p, CFG_TYPE_OF_SECTION, &nodeType)){
681       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data (Type) missing");
682     }
683 
684     if(nodeId > MAX_NODES || nodeId == 0){
685       BaseString::snprintf(buf, sizeof(buf),
686 	       "Invalid node id: %d", nodeId);
687       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
688     }
689 
690     if(nodes.get(nodeId)){
691       BaseString::snprintf(buf, sizeof(buf), "Two node can not have the same node id: %d",
692 	       nodeId);
693       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
694     }
695     nodes.set(nodeId);
696 
697     switch(nodeType){
698     case NODE_TYPE_DB:
699       noOfDBNodes++; // No of NDB processes
700 
701       if(nodeId > MAX_NDB_NODES){
702 		  BaseString::snprintf(buf, sizeof(buf), "Maximum node id for a ndb node is: %d",
703 		 MAX_NDB_NODES);
704 	ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
705       }
706       break;
707     case NODE_TYPE_API:
708       noOfAPINodes++; // No of API processes
709       break;
710     case NODE_TYPE_MGM:
711       noOfMGMNodes++; // No of MGM processes
712       break;
713     default:
714       BaseString::snprintf(buf, sizeof(buf), "Unknown node type: %d", nodeType);
715       ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf);
716     }
717   }
718   noOfNodes = nodeNo;
719 
720   noOfTables+= 2; // Add System tables
721   noOfAttributes += 9;  // Add System table attributes
722 
723   ConfigValues::Iterator it2(*ownConfig, db.m_config);
724   it2.set(CFG_DB_NO_TABLES, noOfTables);
725   it2.set(CFG_DB_NO_ATTRIBUTES, noOfAttributes);
726   {
727     Uint32 neededNoOfTriggers =   /* types: Insert/Update/Delete/Custom */
728       3 * noOfUniqueHashIndexes + /* for unique hash indexes, I/U/D */
729       3 * NDB_MAX_ACTIVE_EVENTS + /* for events in suma, I/U/D */
730       3 * noOfTables +            /* for backup, I/U/D */
731       noOfOrderedIndexes;         /* for ordered indexes, C */
732     if (noOfTriggers < neededNoOfTriggers)
733     {
734       noOfTriggers= neededNoOfTriggers;
735       it2.set(CFG_DB_NO_TRIGGERS, noOfTriggers);
736     }
737   }
738 
739   /**
740    * Do size calculations
741    */
742   ConfigValuesFactory cfg(ownConfig);
743 
744   Uint32 noOfMetaTables= noOfTables + noOfOrderedIndexes +
745                            noOfUniqueHashIndexes;
746   Uint32 noOfMetaTablesDict= noOfMetaTables;
747   if (noOfMetaTablesDict > NDB_MAX_TABLES)
748     noOfMetaTablesDict= NDB_MAX_TABLES;
749 
750   {
751     /**
752      * Dict Size Alt values
753      */
754     cfg.put(CFG_DICT_ATTRIBUTE,
755 	    noOfAttributes);
756 
757     cfg.put(CFG_DICT_TABLE,
758 	    noOfMetaTablesDict);
759   }
760 
761 
762   if (noOfLocalScanRecords == 0) {
763 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
764     noOfLocalScanRecords = (noOfDBNodes * noOfScanRecords) +
765 #else
766     noOfLocalScanRecords = 4 * (noOfDBNodes * noOfScanRecords) +
767 #endif
768       1 /* NR */ +
769       1 /* LCP */;
770   }
771   if (noOfLocalOperations == 0) {
772     noOfLocalOperations= (11 * noOfOperations) / 10;
773   }
774 
775   Uint32 noOfTCScanRecords = noOfScanRecords;
776   Uint32 noOfTCLocalScanRecords = noOfLocalScanRecords;
777 
778   noOfLocalOperations = DO_DIV(noOfLocalOperations, lqhInstances);
779   noOfLocalScanRecords = DO_DIV(noOfLocalScanRecords, lqhInstances);
780 
781   {
782     Uint32 noOfAccTables= noOfMetaTables/*noOfTables+noOfUniqueHashIndexes*/;
783     /**
784      * Acc Size Alt values
785      */
786     // Can keep 65536 pages (= 0.5 GByte)
787     cfg.put(CFG_ACC_DIR_RANGE,
788 	    2 * NO_OF_FRAG_PER_NODE * noOfAccTables* noOfReplicas);
789 
790     cfg.put(CFG_ACC_DIR_ARRAY,
791 	    (noOfIndexPages >> 8) +
792 	    2 * NO_OF_FRAG_PER_NODE * noOfAccTables* noOfReplicas);
793 
794     cfg.put(CFG_ACC_FRAGMENT,
795 	    NO_OF_FRAG_PER_NODE * noOfAccTables* noOfReplicas);
796 
797     /*-----------------------------------------------------------------------*/
798     // The extra operation records added are used by the scan and node
799     // recovery process.
800     // Node recovery process will have its operations dedicated to ensure
801     // that they never have a problem with allocation of the operation record.
802     // The remainder are allowed for use by the scan processes.
803     /*-----------------------------------------------------------------------*/
804     cfg.put(CFG_ACC_OP_RECS,
805 	    (noOfLocalOperations + 50) +
806 	    (noOfLocalScanRecords * noBatchSize) +
807 	    NODE_RECOVERY_SCAN_OP_RECORDS);
808 
809     cfg.put(CFG_ACC_OVERFLOW_RECS,
810 	    noOfIndexPages +
811 	    NO_OF_FRAG_PER_NODE * noOfAccTables* noOfReplicas);
812 
813     cfg.put(CFG_ACC_PAGE8,
814 	    noOfIndexPages + 32);
815 
816     cfg.put(CFG_ACC_TABLE, noOfAccTables);
817 
818     cfg.put(CFG_ACC_SCAN, noOfLocalScanRecords);
819   }
820 
821   {
822     /**
823      * Dih Size Alt values
824      */
825     cfg.put(CFG_DIH_API_CONNECT,
826 	    2 * noOfTransactions);
827 
828     Uint32 noFragPerTable= (((noOfDBNodes * lqhInstances) +
829                              NO_OF_FRAGS_PER_CHUNK - 1) >>
830                             LOG_NO_OF_FRAGS_PER_CHUNK) <<
831       LOG_NO_OF_FRAGS_PER_CHUNK;
832 
833     cfg.put(CFG_DIH_FRAG_CONNECT,
834 	    noFragPerTable *  noOfMetaTables);
835 
836     cfg.put(CFG_DIH_REPLICAS,
837 	    NO_OF_FRAG_PER_NODE * noOfMetaTables *
838 	    noOfDBNodes * noOfReplicas * lqhInstances);
839 
840     cfg.put(CFG_DIH_TABLE,
841 	    noOfMetaTables);
842   }
843 
844   {
845     /**
846      * Lqh Size Alt values
847      */
848     cfg.put(CFG_LQH_FRAG,
849 	    NO_OF_FRAG_PER_NODE * noOfMetaTables * noOfReplicas);
850 
851     cfg.put(CFG_LQH_TABLE,
852 	    noOfMetaTables);
853 
854     cfg.put(CFG_LQH_TC_CONNECT,
855 	    noOfLocalOperations + 50);
856 
857     cfg.put(CFG_LQH_SCAN,
858 	    noOfLocalScanRecords);
859   }
860 
861   {
862     /**
863      * Tc Size Alt values
864      */
865     cfg.put(CFG_TC_API_CONNECT,
866 	    3 * noOfTransactions);
867 
868     cfg.put(CFG_TC_TC_CONNECT,
869 	    (2 * noOfOperations) + 16 + noOfTransactions);
870 
871     cfg.put(CFG_TC_TABLE,
872 	    noOfMetaTables);
873 
874     cfg.put(CFG_TC_LOCAL_SCAN,
875 	    noOfTCLocalScanRecords);
876 
877     cfg.put(CFG_TC_SCAN,
878 	    noOfTCScanRecords);
879   }
880 
881   {
882     /**
883      * Tup Size Alt values
884      */
885     cfg.put(CFG_TUP_FRAG,
886 	    NO_OF_FRAG_PER_NODE * noOfMetaTables* noOfReplicas);
887 
888     cfg.put(CFG_TUP_OP_RECS,
889 	    noOfLocalOperations + 50);
890 
891     cfg.put(CFG_TUP_PAGE,
892 	    noOfDataPages);
893 
894     cfg.put(CFG_TUP_TABLE,
895 	    noOfMetaTables);
896 
897     cfg.put(CFG_TUP_STORED_PROC,
898 	    noOfLocalScanRecords);
899   }
900 
901   {
902     /**
903      * Tux Size Alt values
904      */
905     cfg.put(CFG_TUX_INDEX,
906 	    noOfMetaTables /*noOfOrderedIndexes*/);
907 
908     cfg.put(CFG_TUX_FRAGMENT,
909 	    NO_OF_FRAG_PER_NODE * noOfOrderedIndexes * noOfReplicas);
910 
911     cfg.put(CFG_TUX_ATTRIBUTE,
912 	    noOfOrderedIndexes * 4);
913 
914     cfg.put(CFG_TUX_SCAN_OP, noOfLocalScanRecords);
915   }
916 
917   m_ownConfig = (ndb_mgm_configuration*)cfg.getConfigValues();
918   m_ownConfigIterator = ndb_mgm_create_configuration_iterator
919     (m_ownConfig, 0);
920 }
921 
922 void
setAllRealtimeScheduler()923 Configuration::setAllRealtimeScheduler()
924 {
925   Uint32 i;
926   for (i = 0; i < threadInfo.size(); i++)
927   {
928     if (threadInfo[i].type != NotInUse)
929     {
930       if (setRealtimeScheduler(threadInfo[i].pThread,
931                                threadInfo[i].type,
932                                _realtimeScheduler,
933                                FALSE))
934         return;
935     }
936   }
937 }
938 
939 void
setAllLockCPU(bool exec_thread)940 Configuration::setAllLockCPU(bool exec_thread)
941 {
942   Uint32 i;
943   for (i = 0; i < threadInfo.size(); i++)
944   {
945     if (threadInfo[i].type == NotInUse)
946       continue;
947 
948     bool run =
949       (exec_thread && threadInfo[i].type == MainThread) ||
950       (!exec_thread && threadInfo[i].type != MainThread);
951 
952     if (run)
953     {
954       setLockCPU(threadInfo[i].pThread, threadInfo[i].type);
955     }
956   }
957 }
958 
959 int
setRealtimeScheduler(NdbThread * pThread,enum ThreadTypes type,bool real_time,bool init)960 Configuration::setRealtimeScheduler(NdbThread* pThread,
961                                     enum ThreadTypes type,
962                                     bool real_time,
963                                     bool init)
964 {
965   /*
966     We ignore thread characteristics on platforms where we cannot
967     determine the thread id.
968   */
969   if (!init || real_time)
970   {
971     int error_no;
972     if ((error_no = NdbThread_SetScheduler(pThread, real_time,
973                                            (type != MainThread))))
974     {
975       //Warning, no permission to set scheduler
976       return 1;
977     }
978   }
979   return 0;
980 }
981 
982 int
setLockCPU(NdbThread * pThread,enum ThreadTypes type)983 Configuration::setLockCPU(NdbThread * pThread,
984                           enum ThreadTypes type)
985 {
986   int res = 0;
987   if (type != MainThread)
988   {
989     res = m_thr_config.do_bind_io(pThread);
990   }
991   else if (!NdbIsMultiThreaded())
992   {
993     BlockNumber list[] = { CMVMI };
994     res = m_thr_config.do_bind(pThread, list, 1);
995   }
996 
997   if (res != 0)
998   {
999     if (res > 0)
1000     {
1001       ndbout << "Locked to CPU ok" << endl;
1002       return 0;
1003     }
1004     else
1005     {
1006       ndbout << "Failed to lock CPU, error_no = " << (-res) << endl;
1007       return 1;
1008     }
1009   }
1010 
1011   return 0;
1012 }
1013 
1014 Uint32
addThread(struct NdbThread * pThread,enum ThreadTypes type)1015 Configuration::addThread(struct NdbThread* pThread, enum ThreadTypes type)
1016 {
1017   Uint32 i;
1018   NdbMutex_Lock(threadIdMutex);
1019   for (i = 0; i < threadInfo.size(); i++)
1020   {
1021     if (threadInfo[i].type == NotInUse)
1022       break;
1023   }
1024   if (i == threadInfo.size())
1025   {
1026     struct ThreadInfo tmp;
1027     threadInfo.push_back(tmp);
1028   }
1029   threadInfo[i].pThread = pThread;
1030   threadInfo[i].type = type;
1031   NdbMutex_Unlock(threadIdMutex);
1032   setRealtimeScheduler(pThread, type, _realtimeScheduler, TRUE);
1033   if (type != MainThread)
1034   {
1035     /**
1036      * main threads are set in ThreadConfig::ipControlLoop
1037      * as it's handled differently with mt
1038      */
1039     setLockCPU(pThread, type);
1040   }
1041   return i;
1042 }
1043 
1044 void
removeThreadId(Uint32 index)1045 Configuration::removeThreadId(Uint32 index)
1046 {
1047   NdbMutex_Lock(threadIdMutex);
1048   threadInfo[index].pThread = 0;
1049   threadInfo[index].type = NotInUse;
1050   NdbMutex_Unlock(threadIdMutex);
1051 }
1052 
1053 void
yield_main(Uint32 index,bool start)1054 Configuration::yield_main(Uint32 index, bool start)
1055 {
1056   if (_realtimeScheduler)
1057   {
1058     if (start)
1059       setRealtimeScheduler(threadInfo[index].pThread,
1060                            threadInfo[index].type,
1061                            FALSE,
1062                            FALSE);
1063     else
1064       setRealtimeScheduler(threadInfo[index].pThread,
1065                            threadInfo[index].type,
1066                            TRUE,
1067                            FALSE);
1068   }
1069 }
1070 
1071 void
initThreadArray()1072 Configuration::initThreadArray()
1073 {
1074   NdbMutex_Lock(threadIdMutex);
1075   for (Uint32 i = 0; i < threadInfo.size(); i++)
1076   {
1077     threadInfo[i].pThread = 0;
1078     threadInfo[i].type = NotInUse;
1079   }
1080   NdbMutex_Unlock(threadIdMutex);
1081 }
1082 
1083 template class Vector<struct ThreadInfo>;
1084 
1085