Drizzled Public API Documentation

main.cc

00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <pthread.h>
00023 #include <signal.h>
00024 #include <sys/resource.h>
00025 #include <unistd.h>
00026 #include <sys/stat.h>
00027 #include <sys/types.h>
00028 
00029 
00030 #if TIME_WITH_SYS_TIME
00031 # include <sys/time.h>
00032 # include <time.h>
00033 #else
00034 # if HAVE_SYS_TIME_H
00035 #  include <sys/time.h>
00036 # else
00037 #  include <time.h>
00038 # endif
00039 #endif
00040 
00041 #if defined(HAVE_LOCALE_H)
00042 # include <locale.h>
00043 #endif
00044 
00045 #include <boost/filesystem.hpp>
00046 
00047 #include <drizzled/abort_exception.h>
00048 #include <drizzled/catalog/local.h>
00049 #include <drizzled/configmake.h>
00050 #include <drizzled/data_home.h>
00051 #include <drizzled/debug.h>
00052 #include <drizzled/drizzled.h>
00053 #include <drizzled/errmsg_print.h>
00054 #include <drizzled/gettext.h>
00055 #include <drizzled/internal/my_sys.h>
00056 #include <drizzled/plugin.h>
00057 #include <drizzled/plugin/client.h>
00058 #include <drizzled/plugin/listen.h>
00059 #include <drizzled/plugin/monitored_in_transaction.h>
00060 #include <drizzled/pthread_globals.h>
00061 #include <drizzled/replication_services.h>
00062 #include <drizzled/session.h>
00063 #include <drizzled/session/cache.h>
00064 #include <drizzled/signal_handler.h>
00065 #include <drizzled/transaction_services.h>
00066 #include <drizzled/tztime.h>
00067 #include <drizzled/unireg.h>
00068 #include <drizzled/util/backtrace.h>
00069 #include <drizzled/current_session.h>
00070 #include <drizzled/daemon.h>
00071 #include <drizzled/sql_base.h>
00072 #include <drizzled/sql_lex.h>
00073 
00074 using namespace drizzled;
00075 using namespace std;
00076 
00077 static pthread_t select_thread;
00078 static uint32_t thr_kill_signal;
00079 
00080 extern bool opt_daemon;
00081 
00082 
00087 static void my_message_sql(drizzled::error_t error, const char *str, myf MyFlags)
00088 {
00089   Session *session;
00090   /*
00091     Put here following assertion when situation with EE_* error codes
00092     will be fixed
00093   */
00094   if ((session= current_session))
00095   {
00096     if (MyFlags & ME_FATALERROR)
00097       session->is_fatal_error= 1;
00098 
00099     /*
00100       @TODO There are two exceptions mechanism (Session and sp_rcontext),
00101       this could be improved by having a common stack of handlers.
00102     */
00103     if (session->handle_error(error, str, DRIZZLE_ERROR::WARN_LEVEL_ERROR))
00104       return;
00105 
00106     /*
00107       session->lex().current_select == 0 if lex structure is not inited
00108       (not query command (COM_QUERY))
00109     */
00110     if (! (session->lex().current_select &&
00111            session->lex().current_select->no_error && !session->is_fatal_error))
00112     {
00113       if (! session->main_da.is_error())            // Return only first message
00114       {
00115         if (error == EE_OK)
00116           error= ER_UNKNOWN_ERROR;
00117 
00118         if (str == NULL)
00119           str= ER(error);
00120 
00121         session->main_da.set_error_status(error, str);
00122       }
00123     }
00124 
00125     if (!session->no_warnings_for_error && !session->is_fatal_error)
00126     {
00127       /*
00128         Suppress infinite recursion if there a memory allocation error
00129         inside push_warning.
00130       */
00131       session->no_warnings_for_error= true;
00132       push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error, str);
00133       session->no_warnings_for_error= false;
00134     }
00135   }
00136 
00137   if (not session || MyFlags & ME_NOREFRESH)
00138   {
00139     errmsg_printf(error::ERROR, "%s: %s",internal::my_progname,str);
00140   }
00141 }
00142 
00143 static void init_signals(void)
00144 {
00145   sigset_t set;
00146   struct sigaction sa;
00147 
00148   if (not (getDebug().test(debug::NO_STACKTRACE) ||
00149         getDebug().test(debug::CORE_ON_SIGNAL)))
00150   {
00151     sa.sa_flags = SA_RESETHAND | SA_NODEFER;
00152     sigemptyset(&sa.sa_mask);
00153     sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
00154 
00155     sa.sa_handler= drizzled_handle_segfault;
00156     sigaction(SIGSEGV, &sa, NULL);
00157     sigaction(SIGABRT, &sa, NULL);
00158 #ifdef SIGBUS
00159     sigaction(SIGBUS, &sa, NULL);
00160 #endif
00161     sigaction(SIGILL, &sa, NULL);
00162     sigaction(SIGFPE, &sa, NULL);
00163   }
00164 
00165   if (getDebug().test(debug::CORE_ON_SIGNAL))
00166   {
00167     /* Change limits so that we will get a core file */
00168     struct rlimit rl;
00169     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
00170     if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
00171         errmsg_printf(error::WARN,
00172                       _("setrlimit could not change the size of core files "
00173                         "to 'infinity';  We may not be able to generate a "
00174                         "core file on signals"));
00175   }
00176   (void) sigemptyset(&set);
00177   ignore_signal(SIGPIPE);
00178   sigaddset(&set,SIGPIPE);
00179 #ifndef IGNORE_SIGHUP_SIGQUIT
00180   sigaddset(&set,SIGQUIT);
00181   sigaddset(&set,SIGHUP);
00182 #endif
00183   sigaddset(&set,SIGTERM);
00184 
00185   /* Fix signals if blocked by parents (can happen on Mac OS X) */
00186   sigemptyset(&sa.sa_mask);
00187   sa.sa_flags = 0;
00188   sa.sa_handler = drizzled_print_signal_warning;
00189   sigaction(SIGTERM, &sa, NULL);
00190   sa.sa_flags = 0;
00191   sa.sa_handler = drizzled_print_signal_warning;
00192   sigaction(SIGHUP, &sa, NULL);
00193 #ifdef SIGTSTP
00194   sigaddset(&set,SIGTSTP);
00195 #endif
00196   if (getDebug().test(debug::ALLOW_SIGINT))
00197   {
00198     sa.sa_flags= 0;
00199     sa.sa_handler= drizzled_end_thread_signal;
00200     sigaction(thr_kill_signal, &sa, NULL);
00201 
00202     // May be SIGINT
00203     sigdelset(&set, thr_kill_signal);
00204   }
00205   else
00206   {
00207     sigaddset(&set,SIGINT);
00208   }
00209   sigprocmask(SIG_SETMASK,&set,NULL);
00210   pthread_sigmask(SIG_SETMASK,&set,NULL);
00211   return;
00212 }
00213 
00214 static void GoogleProtoErrorThrower(google::protobuf::LogLevel level,
00215                                     const char* ,
00216                                     int, const string& ) throw(const char *)
00217 {
00218   switch(level)
00219   {
00220   case google::protobuf::LOGLEVEL_INFO:
00221     break;
00222   case google::protobuf::LOGLEVEL_WARNING:
00223   case google::protobuf::LOGLEVEL_ERROR:
00224   case google::protobuf::LOGLEVEL_FATAL:
00225   default:
00226     throw("error in google protocol buffer parsing");
00227   }
00228 }
00229 
00230 int main(int argc, char **argv)
00231 {
00232 #if defined(ENABLE_NLS)
00233 # if defined(HAVE_LOCALE_H)
00234   setlocale(LC_ALL, "");
00235 # endif
00236   bindtextdomain("drizzle7", LOCALEDIR);
00237   textdomain("drizzle7");
00238 #endif
00239 
00240   module::Registry &modules= module::Registry::singleton();
00241 
00242   MY_INIT(argv[0]);   // init my_sys library & pthreads
00243   /* nothing should come before this line ^^^ */
00244 
00245   /* Set signal used to kill Drizzle */
00246   thr_kill_signal= SIGINT;
00247 
00248   google::protobuf::SetLogHandler(&GoogleProtoErrorThrower);
00249 
00250   /* Function generates error messages before abort */
00251   error_handler_hook= my_message_sql;
00252 
00253   /* init_common_variables must get basic settings such as data_home_dir
00254      and plugin_load_list. */
00255   if (init_basic_variables(argc, argv))
00256     unireg_abort(1);        // Will do exit
00257 
00258   if (opt_daemon)
00259   {
00260     if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
00261     {
00262       perror("Failed to ignore SIGHUP");
00263     }
00264     if (daemonize())
00265     {
00266       fprintf(stderr, "failed to daemon() in order to daemonize\n");
00267       exit(EXIT_FAILURE);
00268     }
00269   }
00270 
00271   if (init_remaining_variables(modules))
00272     unireg_abort(1);        // Will do exit
00273 
00274   /*
00275     init signals & alarm
00276     After this we can't quit by a simple unireg_abort
00277   */
00278   init_signals();
00279 
00280 
00281   select_thread=pthread_self();
00282   select_thread_in_use=1;
00283 
00284   if (not opt_help)
00285   {
00286     if (chdir(getDataHome().file_string().c_str()))
00287     {
00288       errmsg_printf(error::ERROR,
00289                     _("Data directory %s does not exist\n"),
00290                     getDataHome().file_string().c_str());
00291       unireg_abort(1);
00292     }
00293     if (mkdir("local", 0700))
00294     {
00295       /* We don't actually care */
00296     }
00297     if (chdir("local"))
00298     {
00299       errmsg_printf(error::ERROR,
00300                     _("Local catalog %s/local does not exist\n"),
00301                     getDataHome().file_string().c_str());
00302       unireg_abort(1);
00303     }
00304 
00305     boost::filesystem::path &full_data_home= getFullDataHome();
00306     full_data_home= boost::filesystem::system_complete(getDataHome());
00307     errmsg_printf(error::INFO, "Data Home directory is : %s", full_data_home.native_file_string().c_str());
00308   }
00309 
00310 
00311 
00312   if (server_id == 0)
00313   {
00314     server_id= 1;
00315   }
00316 
00317   try
00318   {
00319     if (init_server_components(modules))
00320       DRIZZLE_ABORT;
00321   }
00322   catch (abort_exception& ex)
00323   {
00324 #if defined(DEBUG)
00325     cout << _("Drizzle has receieved an abort event.") << endl;
00326     cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
00327     cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
00328     cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
00329 #endif
00330     unireg_abort(1);
00331   }
00332 
00333 
00345   ReplicationServices &replication_services= ReplicationServices::singleton();
00346     (void) replication_services.evaluateRegisteredPlugins();
00347 
00348   if (plugin::Listen::setup())
00349     unireg_abort(1);
00350 
00351   assert(plugin::num_trx_monitored_objects > 0);
00352   if (drizzle_rm_tmp_tables())
00353   {
00354     abort_loop= true;
00355     select_thread_in_use=0;
00356     (void) pthread_kill(signal_thread, SIGTERM);
00357 
00358     (void) unlink(pid_file.file_string().c_str());  // Not needed anymore
00359 
00360     unireg_abort(1);
00361   }
00362 
00363   errmsg_printf(error::INFO, _(ER(ER_STARTUP)), internal::my_progname,
00364                 PANDORA_RELEASE_VERSION, COMPILATION_COMMENT);
00365 
00366 
00367   TransactionServices &transaction_services= TransactionServices::singleton();
00368 
00369   /* Send server startup event */
00370   {
00371     Session::shared_ptr session;
00372 
00373     if ((session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local())))
00374     {
00375       currentSession().release();
00376       currentSession().reset(session.get());
00377 
00378 
00379       transaction_services.sendStartupEvent(*session);
00380 
00381       plugin_startup_window(modules, *(session.get()));
00382     }
00383   }
00384 
00385   if (opt_daemon)
00386     daemon_is_ready();
00387 
00388   /*
00389     Listen for new connections and start new session for each connection
00390      accepted. The listen.getClient() method will return NULL when the server
00391      should be shutdown.
00392    */
00393   plugin::Client *client;
00394   while ((client= plugin::Listen::getClient()) != NULL)
00395   {
00396     Session::shared_ptr session;
00397     session= Session::make_shared(client, client->catalog());
00398 
00399     if (not session)
00400     {
00401       delete client;
00402       continue;
00403     }
00404 
00405     /* If we error on creation we drop the connection and delete the session. */
00406     if (Session::schedule(session))
00407       Session::unlink(session);
00408   }
00409 
00410   /* Send server shutdown event */
00411   {
00412     Session::shared_ptr session;
00413 
00414     if ((session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local())))
00415     {
00416       currentSession().release();
00417       currentSession().reset(session.get());
00418       transaction_services.sendShutdownEvent(*session.get());
00419     }
00420   }
00421 
00422   {
00423     boost::mutex::scoped_lock scopedLock(session::Cache::singleton().mutex());
00424     select_thread_in_use= false;      // For close_connections
00425   }
00426   COND_thread_count.notify_all();
00427 
00428   /* Wait until cleanup is done */
00429   session::Cache::singleton().shutdownSecond();
00430 
00431   clean_up(1);
00432   module::Registry::shutdown();
00433   internal::my_end();
00434 
00435   return 0;
00436 }
00437