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/unireg.h>
00067 #include <drizzled/util/backtrace.h>
00068 #include <drizzled/current_session.h>
00069 #include <drizzled/daemon.h>
00070 #include <drizzled/diagnostics_area.h>
00071 #include <drizzled/sql_base.h>
00072 #include <drizzled/sql_lex.h>
00073 #include <drizzled/system_variables.h>
00074 
00075 using namespace drizzled;
00076 using namespace std;
00077 
00078 static pthread_t select_thread;
00079 static uint32_t thr_kill_signal;
00080 
00081 extern bool opt_daemon;
00082 
00083 
00088 static void my_message_sql(drizzled::error_t error, const char *str, myf MyFlags)
00089 {
00090   Session* session= current_session;
00091   /*
00092     Put here following assertion when situation with EE_* error codes
00093     will be fixed
00094   */
00095   if (session)
00096   {
00097     if (MyFlags & ME_FATALERROR)
00098     {
00099       session->is_fatal_error= 1;
00100     }
00101 
00102     /*
00103       @TODO There are two exceptions mechanism (Session and sp_rcontext),
00104       this could be improved by having a common stack of handlers.
00105 
00106     if (session->handle_error(error, str, DRIZZLE_ERROR::WARN_LEVEL_ERROR))
00107       return;
00108     */
00109 
00110     /*
00111       session->lex().current_select == 0 if lex structure is not inited
00112       (not query command (COM_QUERY))
00113     */
00114     if (! (session->lex().current_select &&
00115            session->lex().current_select->no_error && !session->is_fatal_error))
00116     {
00117       if (! session->main_da().is_error())            // Return only first message
00118       {
00119         if (error == EE_OK)
00120           error= ER_UNKNOWN_ERROR;
00121 
00122         if (str == NULL)
00123           str= ER(error);
00124 
00125         session->main_da().set_error_status(error, str);
00126       }
00127     }
00128 
00129     if (!session->no_warnings_for_error && !session->is_fatal_error)
00130     {
00131       /*
00132         Suppress infinite recursion if there a memory allocation error
00133         inside push_warning.
00134       */
00135       session->no_warnings_for_error= true;
00136       push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error, str);
00137       session->no_warnings_for_error= false;
00138     }
00139   }
00140 
00141   if (not session || MyFlags & ME_NOREFRESH)
00142   {
00143     errmsg_printf(error::ERROR, "%s: %s",internal::my_progname,str);
00144   }
00145 }
00146 
00147 static void init_signals(void)
00148 {
00149   sigset_t set;
00150   struct sigaction sa;
00151 
00152   if (not (getDebug().test(debug::NO_STACKTRACE) ||
00153         getDebug().test(debug::CORE_ON_SIGNAL)))
00154   {
00155     sa.sa_flags = SA_RESETHAND | SA_NODEFER;
00156     sigemptyset(&sa.sa_mask);
00157     sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
00158 
00159     sa.sa_handler= drizzled_handle_segfault;
00160     sigaction(SIGSEGV, &sa, NULL);
00161     sigaction(SIGABRT, &sa, NULL);
00162 #ifdef SIGBUS
00163     sigaction(SIGBUS, &sa, NULL);
00164 #endif
00165     sigaction(SIGILL, &sa, NULL);
00166     sigaction(SIGFPE, &sa, NULL);
00167   }
00168 
00169   if (getDebug().test(debug::CORE_ON_SIGNAL))
00170   {
00171     /* Change limits so that we will get a core file */
00172     struct rlimit rl;
00173     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
00174     if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
00175         errmsg_printf(error::WARN,
00176                       _("setrlimit could not change the size of core files "
00177                         "to 'infinity';  We may not be able to generate a "
00178                         "core file on signals"));
00179   }
00180   (void) sigemptyset(&set);
00181   ignore_signal(SIGPIPE);
00182   sigaddset(&set,SIGPIPE);
00183 #ifndef IGNORE_SIGHUP_SIGQUIT
00184   sigaddset(&set,SIGQUIT);
00185   sigaddset(&set,SIGHUP);
00186 #endif
00187   sigaddset(&set,SIGTERM);
00188 
00189   /* Fix signals if blocked by parents (can happen on Mac OS X) */
00190   sigemptyset(&sa.sa_mask);
00191   sa.sa_flags = 0;
00192   sa.sa_handler = drizzled_print_signal_warning;
00193   sigaction(SIGTERM, &sa, NULL);
00194   sa.sa_flags = 0;
00195   sa.sa_handler = drizzled_print_signal_warning;
00196   sigaction(SIGHUP, &sa, NULL);
00197 #ifdef SIGTSTP
00198   sigaddset(&set,SIGTSTP);
00199 #endif
00200   if (getDebug().test(debug::ALLOW_SIGINT))
00201   {
00202     sa.sa_flags= 0;
00203     sa.sa_handler= drizzled_end_thread_signal;
00204     sigaction(thr_kill_signal, &sa, NULL);
00205 
00206     // May be SIGINT
00207     sigdelset(&set, thr_kill_signal);
00208   }
00209   else
00210   {
00211     sigaddset(&set,SIGINT);
00212   }
00213   sigprocmask(SIG_SETMASK,&set,NULL);
00214   pthread_sigmask(SIG_SETMASK,&set,NULL);
00215   return;
00216 }
00217 
00218 static void GoogleProtoErrorThrower(google::protobuf::LogLevel level,
00219                                     const char* ,
00220                                     int, const string& ) throw(const char *)
00221 {
00222   switch(level)
00223   {
00224   case google::protobuf::LOGLEVEL_INFO:
00225     break;
00226   case google::protobuf::LOGLEVEL_WARNING:
00227   case google::protobuf::LOGLEVEL_ERROR:
00228   case google::protobuf::LOGLEVEL_FATAL:
00229   default:
00230     throw("error in google protocol buffer parsing");
00231   }
00232 }
00233 
00234 int main(int argc, char **argv)
00235 {
00236 #if defined(ENABLE_NLS)
00237 # if defined(HAVE_LOCALE_H)
00238   setlocale(LC_ALL, "");
00239 # endif
00240   bindtextdomain("drizzle7", LOCALEDIR);
00241   textdomain("drizzle7");
00242 #endif
00243 
00244   module::Registry &modules= module::Registry::singleton();
00245 
00246   drizzled::internal::my_progname= argv[0]; 
00247   drizzled::internal::my_init();
00248 
00249   /* nothing should come before this line ^^^ */
00250 
00251   /* Set signal used to kill Drizzle */
00252   thr_kill_signal= SIGINT;
00253 
00254   google::protobuf::SetLogHandler(&GoogleProtoErrorThrower);
00255 
00256   /* Function generates error messages before abort */
00257   error_handler_hook= my_message_sql;
00258 
00259   /* init_common_variables must get basic settings such as data_home_dir and plugin_load_list. */
00260   if (not init_variables_before_daemonizing(argc, argv))
00261   {
00262     unireg_abort << "init_variables_before_daemonizing() failed";       // Will do exit
00263   }
00264 
00265   if (opt_daemon and was_help_requested() == false)
00266   {
00267     if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
00268     {
00269       perror("Failed to ignore SIGHUP");
00270     }
00271     if (daemonize())
00272     {
00273       unireg_abort << "--daemon failed";
00274     }
00275   }
00276 
00277   if (not init_variables_after_daemonizing(modules))
00278   {
00279     unireg_abort << "init_variables_after_daemonizing() failed";        // Will do exit
00280   }
00281 
00282 
00283   /*
00284     init signals & alarm
00285     After this we can't quit by a simple unireg_abort
00286   */
00287   init_signals();
00288 
00289 
00290   select_thread= pthread_self();
00291   select_thread_in_use=1;
00292 
00293   if (was_help_requested() == false)
00294   {
00295     if (chdir(getDataHome().file_string().c_str()))
00296     {
00297       unireg_abort << "Data directory " << getDataHome().file_string() << " does not exist";
00298     }
00299 
00300     ifstream old_uuid_file ("server.uuid");
00301     if (old_uuid_file.is_open())
00302     {
00303       getline(old_uuid_file, server_uuid);
00304       old_uuid_file.close();
00305     } 
00306     else 
00307     {
00308       uuid_t uu;
00309       char uuid_string[37];
00310       uuid_generate_random(uu);
00311       uuid_unparse(uu, uuid_string);
00312       ofstream new_uuid_file ("server.uuid");
00313       new_uuid_file << uuid_string;
00314       new_uuid_file.close();
00315       server_uuid= string(uuid_string);
00316     }
00317 
00318     if (mkdir("local", 0700) == -1)
00319     {
00320       switch (errno)
00321       {
00322       case EEXIST:
00323         break;
00324 
00325       case EACCES:
00326         {
00327           char cwd[1024];
00328           unireg_abort << "Could not create local catalog, permission denied in directory:" << getcwd(cwd, sizeof(cwd));
00329         }
00330 
00331       default:
00332         {
00333           char cwd[1024];
00334           unireg_abort << "Could not create local catalog, in directory:" << getcwd(cwd, sizeof(cwd)) << " system error was:" << strerror(errno);
00335         }
00336       }
00337     }
00338 
00339     if (chdir("local") == -1)
00340     {
00341       unireg_abort << "Local catalog does not exist, was unable to chdir() to " << getDataHome().file_string();
00342     }
00343 
00344     setFullDataHome(boost::filesystem::system_complete(getDataHome()));
00345     errmsg_printf(error::INFO, "Data Home directory is : %s", getFullDataHome().native_file_string().c_str());
00346   }
00347 
00348   if (server_id == 0)
00349   {
00350     server_id= 1;
00351   }
00352 
00353   try
00354   {
00355     init_server_components(modules);
00356   }
00357   catch (abort_exception& ex)
00358   {
00359 #if defined(DEBUG)
00360     cout << _("Drizzle has receieved an abort event.") << endl;
00361     cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
00362     cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
00363     cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
00364 #endif
00365     unireg_abort << "init_server_components() failed";
00366   }
00367 
00368 
00380   (void) ReplicationServices::evaluateRegisteredPlugins();
00381 
00382   if (plugin::Listen::setup())
00383   {
00384     unireg_abort << "Failed plugin::Listen::setup()";
00385   }
00386 
00387   assert(plugin::num_trx_monitored_objects > 0);
00388   drizzle_rm_tmp_tables();
00389   errmsg_printf(error::INFO, _(ER(ER_STARTUP)), internal::my_progname, PANDORA_RELEASE_VERSION, COMPILATION_COMMENT);
00390 
00391   /* Send server startup event */
00392   {
00393     Session::shared_ptr session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local());
00394     setCurrentSession(session.get());
00395     TransactionServices::sendStartupEvent(*session);
00396     plugin_startup_window(modules, *session.get());
00397   }
00398 
00399   if (opt_daemon)
00400   {
00401     daemon_is_ready();
00402   }
00403 
00404 
00405   errmsg_printf(error::INFO, "Drizzle startup complete, listening for connections will now begin.");
00406 
00407   /*
00408     Listen for new connections and start new session for each connection
00409      accepted. The listen.getClient() method will return NULL when the server
00410      should be shutdown.
00411    */
00412   while (plugin::Client* client= plugin::Listen::getClient())
00413   {
00414     Session::shared_ptr session= Session::make_shared(client, client->catalog());
00415 
00416     /* If we error on creation we drop the connection and delete the session. */
00417     if (Session::schedule(session))
00418       Session::unlink(session);
00419   }
00420 
00421   /* Send server shutdown event */
00422   {
00423     Session::shared_ptr session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local());
00424     setCurrentSession(session.get());
00425     TransactionServices::sendShutdownEvent(*session.get());
00426   }
00427 
00428   {
00429     boost::mutex::scoped_lock scopedLock(session::Cache::mutex());
00430     select_thread_in_use= false;      // For close_connections
00431   }
00432   COND_thread_count.notify_all();
00433 
00434   /* Wait until cleanup is done */
00435   session::Cache::shutdownSecond();
00436 
00437   clean_up(1);
00438   module::Registry::shutdown();
00439   internal::my_end();
00440 
00441   errmsg_printf(error::INFO, "Drizzle is now shutting down");
00442 
00443   return 0;
00444 }
00445