Drizzled Public API Documentation

main.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2008 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 
22 #include <pthread.h>
23 #include <signal.h>
24 #include <sys/resource.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 
29 
30 #if TIME_WITH_SYS_TIME
31 # include <sys/time.h>
32 # include <time.h>
33 #else
34 # if HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 # else
37 # include <time.h>
38 # endif
39 #endif
40 
41 #if defined(HAVE_LOCALE_H)
42 # include <locale.h>
43 #endif
44 
45 #include <boost/filesystem.hpp>
46 
47 #include <drizzled/abort_exception.h>
48 #include <drizzled/catalog/local.h>
49 #include <drizzled/configmake.h>
50 #include <drizzled/data_home.h>
51 #include <drizzled/debug.h>
52 #include <drizzled/drizzled.h>
53 #include <drizzled/errmsg_print.h>
54 #include <drizzled/gettext.h>
55 #include <drizzled/internal/my_sys.h>
56 #include <drizzled/plugin.h>
57 #include <drizzled/plugin/client.h>
58 #include <drizzled/plugin/listen.h>
59 #include <drizzled/plugin/monitored_in_transaction.h>
60 #include <drizzled/pthread_globals.h>
61 #include <drizzled/replication_services.h>
62 #include <drizzled/session.h>
63 #include <drizzled/session/cache.h>
64 #include <drizzled/signal_handler.h>
65 #include <drizzled/transaction_services.h>
66 #include <drizzled/unireg.h>
67 #include <drizzled/util/backtrace.h>
68 #include <drizzled/current_session.h>
69 #include <drizzled/daemon.h>
70 #include <drizzled/diagnostics_area.h>
71 #include <drizzled/sql_base.h>
72 #include <drizzled/sql_lex.h>
73 #include <drizzled/system_variables.h>
74 
75 using namespace drizzled;
76 using namespace std;
77 
78 static pthread_t select_thread;
79 static uint32_t thr_kill_signal;
80 
81 extern bool opt_daemon;
82 
83 
88 static void my_message_sql(drizzled::error_t error, const char *str, myf MyFlags)
89 {
90  Session* session= current_session;
91  /*
92  Put here following assertion when situation with EE_* error codes
93  will be fixed
94  */
95  if (session)
96  {
97  if (MyFlags & ME_FATALERROR)
98  {
99  session->is_fatal_error= 1;
100  }
101 
102  /*
103  @TODO There are two exceptions mechanism (Session and sp_rcontext),
104  this could be improved by having a common stack of handlers.
105 
106  if (session->handle_error(error, str, DRIZZLE_ERROR::WARN_LEVEL_ERROR))
107  return;
108  */
109 
110  /*
111  session->lex().current_select == 0 if lex structure is not inited
112  (not query command (COM_QUERY))
113  */
114  if (! (session->lex().current_select &&
115  session->lex().current_select->no_error && !session->is_fatal_error))
116  {
117  if (! session->main_da().is_error()) // Return only first message
118  {
119  if (error == EE_OK)
120  error= ER_UNKNOWN_ERROR;
121 
122  if (str == NULL)
123  str= ER(error);
124 
125  session->main_da().set_error_status(error, str);
126  }
127  }
128 
129  if (!session->no_warnings_for_error && !session->is_fatal_error)
130  {
131  /*
132  Suppress infinite recursion if there a memory allocation error
133  inside push_warning.
134  */
135  session->no_warnings_for_error= true;
136  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error, str);
137  session->no_warnings_for_error= false;
138  }
139  }
140 
141  if (not session || MyFlags & ME_NOREFRESH)
142  {
143  errmsg_printf(error::ERROR, "%s: %s",internal::my_progname,str);
144  }
145 }
146 
147 static void init_signals(void)
148 {
149  sigset_t set;
150  struct sigaction sa;
151 
152  if (not (getDebug().test(debug::NO_STACKTRACE) ||
153  getDebug().test(debug::CORE_ON_SIGNAL)))
154  {
155  sa.sa_flags = SA_RESETHAND | SA_NODEFER;
156  sigemptyset(&sa.sa_mask);
157  sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
158 
159  sa.sa_handler= drizzled_handle_segfault;
160  sigaction(SIGSEGV, &sa, NULL);
161  sigaction(SIGABRT, &sa, NULL);
162 #ifdef SIGBUS
163  sigaction(SIGBUS, &sa, NULL);
164 #endif
165  sigaction(SIGILL, &sa, NULL);
166  sigaction(SIGFPE, &sa, NULL);
167  }
168 
169  if (getDebug().test(debug::CORE_ON_SIGNAL))
170  {
171  /* Change limits so that we will get a core file */
172  struct rlimit rl;
173  rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
174  if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
175  errmsg_printf(error::WARN,
176  _("setrlimit could not change the size of core files "
177  "to 'infinity'; We may not be able to generate a "
178  "core file on signals"));
179  }
180  (void) sigemptyset(&set);
181  ignore_signal(SIGPIPE);
182  sigaddset(&set,SIGPIPE);
183 #ifndef IGNORE_SIGHUP_SIGQUIT
184  sigaddset(&set,SIGQUIT);
185  sigaddset(&set,SIGHUP);
186 #endif
187  sigaddset(&set,SIGTERM);
188 
189  /* Fix signals if blocked by parents (can happen on Mac OS X) */
190  sigemptyset(&sa.sa_mask);
191  sa.sa_flags = 0;
192  sa.sa_handler = drizzled_print_signal_warning;
193  sigaction(SIGTERM, &sa, NULL);
194  sa.sa_flags = 0;
195  sa.sa_handler = drizzled_print_signal_warning;
196  sigaction(SIGHUP, &sa, NULL);
197 #ifdef SIGTSTP
198  sigaddset(&set,SIGTSTP);
199 #endif
200  if (getDebug().test(debug::ALLOW_SIGINT))
201  {
202  sa.sa_flags= 0;
203  sa.sa_handler= drizzled_end_thread_signal;
204  sigaction(thr_kill_signal, &sa, NULL);
205 
206  // May be SIGINT
207  sigdelset(&set, thr_kill_signal);
208  }
209  else
210  {
211  sigaddset(&set,SIGINT);
212  }
213  sigprocmask(SIG_SETMASK,&set,NULL);
214  pthread_sigmask(SIG_SETMASK,&set,NULL);
215  return;
216 }
217 
218 static void GoogleProtoErrorThrower(google::protobuf::LogLevel level,
219  const char* ,
220  int, const string& ) throw(const char *)
221 {
222  switch(level)
223  {
224  case google::protobuf::LOGLEVEL_INFO:
225  break;
226  case google::protobuf::LOGLEVEL_WARNING:
227  case google::protobuf::LOGLEVEL_ERROR:
228  case google::protobuf::LOGLEVEL_FATAL:
229  default:
230  throw("error in google protocol buffer parsing");
231  }
232 }
233 
234 int main(int argc, char **argv)
235 {
236 #if defined(ENABLE_NLS)
237 # if defined(HAVE_LOCALE_H)
238  setlocale(LC_ALL, "");
239 # endif
240  bindtextdomain("drizzle", LOCALEDIR);
241  textdomain("drizzle");
242 #endif
243 
244  module::Registry &modules= module::Registry::singleton();
245 
246  drizzled::internal::my_progname= argv[0];
247  drizzled::internal::my_init();
248 
249  /* nothing should come before this line ^^^ */
250 
251  /* Set signal used to kill Drizzle */
252  thr_kill_signal= SIGINT;
253 
254  google::protobuf::SetLogHandler(&GoogleProtoErrorThrower);
255 
256  /* Function generates error messages before abort */
257  error_handler_hook= my_message_sql;
258 
259  /* init_common_variables must get basic settings such as data_home_dir and plugin_load_list. */
260  if (init_variables_before_daemonizing(argc, argv) == false)
261  {
262  unireg_abort << "init_variables_before_daemonizing() failed"; // Will do exit
263  }
264 
265  if (opt_daemon and was_help_requested() == false)
266  {
267  if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
268  {
269  perror("Failed to ignore SIGHUP");
270  }
271 
272  if (daemonize())
273  {
274  unireg_abort << "--daemon failed";
275  }
276  }
277 
278  if (init_variables_after_daemonizing(modules) == false)
279  {
280  unireg_abort << "init_variables_after_daemonizing() failed"; // Will do exit
281  }
282 
283  /*
284  init signals & alarm
285  After this we can't quit by a simple unireg_abort
286  */
287  init_signals();
288 
289 
290  select_thread= pthread_self();
291  select_thread_in_use=1;
292 
293  if (was_help_requested() == false)
294  {
295  if (chdir(getDataHome().file_string().c_str()))
296  {
297  unireg_abort << "Data directory " << getDataHome().file_string() << " does not exist";
298  }
299 
300  ifstream old_uuid_file ("server.uuid");
301  if (old_uuid_file.is_open())
302  {
303  getline(old_uuid_file, server_uuid);
304  old_uuid_file.close();
305  }
306  else
307  {
308  uuid_t uu;
309  char uuid_string[37];
310  uuid_generate_random(uu);
311  uuid_unparse(uu, uuid_string);
312  ofstream new_uuid_file ("server.uuid");
313  new_uuid_file << uuid_string;
314  new_uuid_file.close();
315  server_uuid= string(uuid_string);
316  }
317 
318  if (mkdir("local", 0700) == -1)
319  {
320  switch (errno)
321  {
322  case EEXIST:
323  break;
324 
325  case EACCES:
326  {
327  char cwd[1024];
328  unireg_abort << "Could not create local catalog, permission denied in directory:" << getcwd(cwd, sizeof(cwd));
329  }
330 
331  default:
332  {
333  char cwd[1024];
334  unireg_abort << "Could not create local catalog, in directory:" << getcwd(cwd, sizeof(cwd)) << " system error was:" << strerror(errno);
335  }
336  }
337  }
338 
339  if (chdir("local") == -1)
340  {
341  unireg_abort << "Local catalog does not exist, was unable to chdir() to " << getDataHome().file_string();
342  }
343 
344  setFullDataHome(boost::filesystem::system_complete(getDataHome()));
345  errmsg_printf(error::INFO, "Data Home directory is : %s", getFullDataHome().native_file_string().c_str());
346  }
347 
348  if (server_id == 0)
349  {
350  server_id= 1;
351  }
352 
353  try
354  {
355  init_server_components(modules);
356  }
357  catch (abort_exception& ex)
358  {
359 #if defined(DEBUG)
360  cout << _("Drizzle has receieved an abort event.") << endl;
361  cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
362  cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
363  cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
364 #endif
365  unireg_abort << "init_server_components() failed";
366  }
367 
368 
381 
382  if (plugin::Listen::setup())
383  {
384  unireg_abort << "Failed plugin::Listen::setup()";
385  }
386 
387  assert(plugin::num_trx_monitored_objects > 0);
388  drizzle_rm_tmp_tables();
389  errmsg_printf(error::INFO, _(ER(ER_STARTUP)), internal::my_progname, PANDORA_RELEASE_VERSION, COMPILATION_COMMENT);
390 
391  /* Send server startup event */
392  {
393  Session::shared_ptr session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local());
394  setCurrentSession(session.get());
396  plugin_startup_window(modules, *session.get());
397  }
398 
399  if (opt_daemon)
400  {
401  daemon_is_ready();
402  }
403 
404 
405  errmsg_printf(error::INFO, "Drizzle startup complete, listening for connections will now begin.");
406 
407  /*
408  Listen for new connections and start new session for each connection
409  accepted. The listen.getClient() method will return NULL when the server
410  should be shutdown.
411  */
412  while (plugin::Client* client= plugin::Listen::getClient())
413  {
414  Session::shared_ptr session= Session::make_shared(client, client->catalog());
415 
416  /* If we error on creation we drop the connection and delete the session. */
417  if (Session::schedule(session))
418  {
419  Session::unlink(session);
420  }
421  }
422 
423  /* Send server shutdown event */
424  {
425  Session::shared_ptr session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local());
426  setCurrentSession(session.get());
428  }
429 
430  {
431  boost::mutex::scoped_lock scopedLock(session::Cache::mutex());
432  select_thread_in_use= false; // For close_connections
433  }
434  COND_thread_count.notify_all();
435 
436  /* Wait until cleanup is done */
437  session::Cache::shutdownSecond();
438 
439  clean_up(1);
440  module::Registry::shutdown();
441  internal::my_end();
442 
443  errmsg_printf(error::INFO, "Drizzle is now shutting down");
444 
445  return 0;
446 }
447