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 
84 
89 static void my_message_sql(drizzled::error_t error, const char *str, myf MyFlags)
90 {
91  Session* session= current_session;
92  /*
93  Put here following assertion when situation with EE_* error codes
94  will be fixed
95  */
96  if (session)
97  {
98  if (MyFlags & ME_FATALERROR)
99  {
100  session->is_fatal_error= 1;
101  }
102 
103  /*
104  @TODO There are two exceptions mechanism (Session and sp_rcontext),
105  this could be improved by having a common stack of handlers.
106 
107  if (session->handle_error(error, str, DRIZZLE_ERROR::WARN_LEVEL_ERROR))
108  return;
109  */
110 
111  /*
112  session->lex().current_select == 0 if lex structure is not inited
113  (not query command (COM_QUERY))
114  */
115  if (! (session->lex().current_select &&
116  session->lex().current_select->no_error && !session->is_fatal_error))
117  {
118  if (! session->main_da().is_error()) // Return only first message
119  {
120  if (error == EE_OK)
121  error= ER_UNKNOWN_ERROR;
122 
123  if (str == NULL)
124  str= ER(error);
125 
126  session->main_da().set_error_status(error, str);
127  }
128  }
129 
130  if (!session->no_warnings_for_error && !session->is_fatal_error)
131  {
132  /*
133  Suppress infinite recursion if there a memory allocation error
134  inside push_warning.
135  */
136  session->no_warnings_for_error= true;
137  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error, str);
138  session->no_warnings_for_error= false;
139  }
140  }
141 
142  if (not session || MyFlags & ME_NOREFRESH)
143  {
144  errmsg_printf(error::ERROR, "%s: %s",internal::my_progname,str);
145  }
146 }
147 
148 static void init_signals(void)
149 {
150  sigset_t set;
151  struct sigaction sa;
152 
153  if (not (getDebug().test(debug::NO_STACKTRACE) ||
154  getDebug().test(debug::CORE_ON_SIGNAL)))
155  {
156  sa.sa_flags = SA_RESETHAND | SA_NODEFER;
157  sigemptyset(&sa.sa_mask);
158  sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
159 
160  sa.sa_handler= drizzled_handle_segfault;
161  sigaction(SIGSEGV, &sa, NULL);
162  sigaction(SIGABRT, &sa, NULL);
163 #ifdef SIGBUS
164  sigaction(SIGBUS, &sa, NULL);
165 #endif
166  sigaction(SIGILL, &sa, NULL);
167  sigaction(SIGFPE, &sa, NULL);
168  }
169 
170  if (getDebug().test(debug::CORE_ON_SIGNAL))
171  {
172  /* Change limits so that we will get a core file */
173  struct rlimit rl;
174  rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
175  if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
176  errmsg_printf(error::WARN,
177  _("setrlimit could not change the size of core files "
178  "to 'infinity'; We may not be able to generate a "
179  "core file on signals"));
180  }
181  (void) sigemptyset(&set);
182  ignore_signal(SIGPIPE);
183  sigaddset(&set,SIGPIPE);
184 #ifndef IGNORE_SIGHUP_SIGQUIT
185  sigaddset(&set,SIGQUIT);
186  sigaddset(&set,SIGHUP);
187 #endif
188  sigaddset(&set,SIGTERM);
189 
190  /* Fix signals if blocked by parents (can happen on Mac OS X) */
191  sigemptyset(&sa.sa_mask);
192  sa.sa_flags = 0;
193  sa.sa_handler = drizzled_print_signal_warning;
194  sigaction(SIGTERM, &sa, NULL);
195  sa.sa_flags = 0;
196  sa.sa_handler = drizzled_print_signal_warning;
197  sigaction(SIGHUP, &sa, NULL);
198 #ifdef SIGTSTP
199  sigaddset(&set,SIGTSTP);
200 #endif
201  if (getDebug().test(debug::ALLOW_SIGINT))
202  {
203  sa.sa_flags= 0;
204  sa.sa_handler= drizzled_end_thread_signal;
205  sigaction(thr_kill_signal, &sa, NULL);
206 
207  // May be SIGINT
208  sigdelset(&set, thr_kill_signal);
209  }
210  else
211  {
212  sigaddset(&set,SIGINT);
213  }
214  sigprocmask(SIG_SETMASK,&set,NULL);
215  pthread_sigmask(SIG_SETMASK,&set,NULL);
216 
217  (void) sigemptyset(&set);
218  sigaddset(&set,SIGTSTP);
219  sigaddset(&set,SIGINT);
220  sigprocmask(SIG_UNBLOCK,&set,NULL);
221  pthread_sigmask(SIG_UNBLOCK,&set,NULL);
222 
223  sa.sa_handler = drizzled_sigint_handler;
224  sigaction(SIGINT,&sa,NULL);
225 
226  return;
227 }
228 
229 
230 
231 static void GoogleProtoErrorThrower(google::protobuf::LogLevel level,
232  const char* ,
233  int, const string& ) throw(const char *)
234 {
235  switch(level)
236  {
237  case google::protobuf::LOGLEVEL_INFO:
238  break;
239  case google::protobuf::LOGLEVEL_WARNING:
240  case google::protobuf::LOGLEVEL_ERROR:
241  case google::protobuf::LOGLEVEL_FATAL:
242  default:
243  throw("error in google protocol buffer parsing");
244  }
245 }
246 
247 int main(int argc, char **argv)
248 {
249 #if defined(ENABLE_NLS)
250 # if defined(HAVE_LOCALE_H)
251  setlocale(LC_ALL, "");
252 # endif
253  bindtextdomain("drizzle", LOCALEDIR);
254  textdomain("drizzle");
255 #endif
256 
257  module::Registry &modules= module::Registry::singleton();
258 
259  drizzled::internal::my_progname= argv[0];
260  drizzled::internal::my_init();
261 
262  /* nothing should come before this line ^^^ */
263 
264  /* Set signal used to kill Drizzle */
265  thr_kill_signal= SIGINT;
266 
267  google::protobuf::SetLogHandler(&GoogleProtoErrorThrower);
268 
269  /* Function generates error messages before abort */
270  error_handler_hook= my_message_sql;
271 
272  /* init_common_variables must get basic settings such as data_home_dir and plugin_load_list. */
273  if (init_variables_before_daemonizing(argc, argv) == false)
274  {
275  unireg_abort << "init_variables_before_daemonizing() failed"; // Will do exit
276  }
277 
278  if (opt_daemon and was_help_requested() == false)
279  {
280  if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
281  {
282  perror("Failed to ignore SIGHUP");
283  }
284 
285  if (daemonize())
286  {
287  unireg_abort << "--daemon failed";
288  }
289  }
290 
291  if (init_variables_after_daemonizing(modules) == false)
292  {
293  unireg_abort << "init_variables_after_daemonizing() failed"; // Will do exit
294  }
295 
296  /*
297  init signals & alarm
298  After this we can't quit by a simple unireg_abort
299  */
300 
301  init_signals();
302 
303  select_thread= pthread_self();
304  select_thread_in_use=1;
305 
306  if (was_help_requested() == false)
307  {
308  if (chdir(getDataHome().file_string().c_str()))
309  {
310  unireg_abort << "Data directory " << getDataHome().file_string() << " does not exist";
311  }
312 
313  ifstream old_uuid_file ("server.uuid");
314  if (old_uuid_file.is_open())
315  {
316  getline(old_uuid_file, server_uuid);
317  old_uuid_file.close();
318  }
319  else
320  {
321  uuid_t uu;
322  char uuid_string[37];
323  uuid_generate_random(uu);
324  uuid_unparse(uu, uuid_string);
325  ofstream new_uuid_file ("server.uuid");
326  new_uuid_file << uuid_string;
327  new_uuid_file.close();
328  server_uuid= string(uuid_string);
329  }
330 
331  if (mkdir("local", 0700) == -1)
332  {
333  switch (errno)
334  {
335  case EEXIST:
336  break;
337 
338  case EACCES:
339  {
340  char cwd[1024];
341  unireg_abort << "Could not create local catalog, permission denied in directory:" << getcwd(cwd, sizeof(cwd));
342  }
343 
344  default:
345  {
346  char cwd[1024];
347  unireg_abort << "Could not create local catalog, in directory:" << getcwd(cwd, sizeof(cwd)) << " system error was:" << strerror(errno);
348  }
349  }
350  }
351 
352  setFullDataHome(boost::filesystem::system_complete(getDataHome()));
353  errmsg_printf(error::INFO, "Data Home directory is : %s", getFullDataHome().native_file_string().c_str());
354  }
355 
356  if (server_id == 0)
357  {
358  server_id= 1;
359  }
360 
361  try
362  {
363  init_server_components(modules);
364  }
365  catch (abort_exception& ex)
366  {
367 #if defined(DEBUG)
368  cout << _("Drizzle has receieved an abort event.") << endl;
369  cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
370  cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
371  cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
372 #endif
373  unireg_abort << "init_server_components() failed";
374  }
375 
376 
389 
390  if (plugin::Listen::setup())
391  {
392  unireg_abort << "Failed plugin::Listen::setup()";
393  }
394 
395  assert(plugin::num_trx_monitored_objects > 0);
396  drizzle_rm_tmp_tables();
397  errmsg_printf(error::INFO, _(ER(ER_STARTUP)), internal::my_progname, PANDORA_RELEASE_VERSION, COMPILATION_COMMENT);
398 
399  /* Send server startup event */
400  {
401  Session::shared_ptr session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local());
402  setCurrentSession(session.get());
404  plugin_startup_window(modules, *session.get());
405  }
406 
407  if (opt_daemon)
408  {
409  daemon_is_ready();
410  }
411 
412 
413  errmsg_printf(error::INFO, "Drizzle startup complete, listening for connections will now begin.");
414 
415  /*
416  Listen for new connections and start new session for each connection
417  accepted. The listen.getClient() method will return NULL when the server
418  should be shutdown.
419  */
420  while (plugin::Client* client= plugin::Listen::getClient())
421  {
422  Session::shared_ptr session= Session::make_shared(client, client->catalog());
423 
424  /* If we error on creation we drop the connection and delete the session. */
425  if (Session::schedule(session))
426  {
427  Session::unlink(session);
428  }
429  }
430 
431  /* Send server shutdown event */
432  {
433  Session::shared_ptr session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local());
434  setCurrentSession(session.get());
436  }
437 
438  {
439  boost::mutex::scoped_lock scopedLock(session::Cache::mutex());
440  select_thread_in_use= false; // For close_connections
441  }
442  COND_thread_count.notify_all();
443 
444  /* Wait until cleanup is done */
445  session::Cache::shutdownSecond();
446 
447  clean_up(1);
448  module::Registry::shutdown();
449  internal::my_end();
450 
451  errmsg_printf(error::INFO, "Drizzle is now shutting down");
452 
453  return 0;
454 }
455 
static bool sendStartupEvent(Session &)
static bool sendShutdownEvent(Session &)
static plugin::Client * getClient()
Definition: listen.cc:107
bool is_fatal_error
Definition: session.h:540
static bool setup(void)
Definition: listen.cc:60
static plugin::Client * getNullClient()
Definition: listen.cc:151
bool no_warnings_for_error
Definition: session.h:565
void set_error_status(drizzled::error_t sql_errno_arg, const char *message_arg)