~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/main.cc

  • Committer: Stewart Smith
  • Date: 2009-06-16 00:46:49 UTC
  • mto: (1119.2.6 merge)
  • mto: This revision was merged to the branch mainline in revision 1124.
  • Revision ID: stewart@flamingspork.com-20090616004649-k2qt6b31sorpi6am
make type_blob test not leave tables behind

Show diffs side-by-side

added added

removed removed

Lines of Context:
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/tztime.h>
67
 
#include <drizzled/unireg.h>
68
 
#include <drizzled/util/backtrace.h>
69
 
 
70
 
extern "C" int daemonize(int nochdir, int noclose, int wait_sigusr1);
71
 
extern "C" int daemon_is_ready(void);
72
 
 
73
 
using namespace drizzled;
74
 
using namespace std;
75
 
namespace fs=boost::filesystem;
76
 
 
77
 
static pthread_t select_thread;
78
 
static uint32_t thr_kill_signal;
79
 
 
80
 
extern bool opt_daemon;
81
 
 
82
 
 
83
 
/**
84
 
  All global error messages are sent here where the first one is stored
85
 
  for the client.
86
 
*/
87
 
static void my_message_sql(drizzled::error_t error, const char *str, myf MyFlags)
88
 
{
89
 
  Session *session;
90
 
  /*
91
 
    Put here following assertion when situation with EE_* error codes
92
 
    will be fixed
93
 
  */
94
 
  if ((session= current_session))
95
 
  {
96
 
    if (MyFlags & ME_FATALERROR)
97
 
      session->is_fatal_error= 1;
98
 
 
99
 
    /*
100
 
      @TODO There are two exceptions mechanism (Session and sp_rcontext),
101
 
      this could be improved by having a common stack of handlers.
102
 
    */
103
 
    if (session->handle_error(error, str, DRIZZLE_ERROR::WARN_LEVEL_ERROR))
104
 
      return;
105
 
 
106
 
    /*
107
 
      session->lex->current_select == 0 if lex structure is not inited
108
 
      (not query command (COM_QUERY))
109
 
    */
110
 
    if (! (session->lex->current_select &&
111
 
           session->lex->current_select->no_error && !session->is_fatal_error))
112
 
    {
113
 
      if (! session->main_da.is_error())            // Return only first message
114
 
      {
115
 
        if (error == EE_OK)
116
 
          error= ER_UNKNOWN_ERROR;
117
 
 
118
 
        if (str == NULL)
119
 
          str= ER(error);
120
 
 
121
 
        session->main_da.set_error_status(error, str);
122
 
      }
123
 
    }
124
 
 
125
 
    if (!session->no_warnings_for_error && !session->is_fatal_error)
126
 
    {
127
 
      /*
128
 
        Suppress infinite recursion if there a memory allocation error
129
 
        inside push_warning.
130
 
      */
131
 
      session->no_warnings_for_error= true;
132
 
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error, str);
133
 
      session->no_warnings_for_error= false;
134
 
    }
135
 
  }
136
 
 
137
 
  if (not session || MyFlags & ME_NOREFRESH)
138
 
  {
139
 
    errmsg_printf(error::ERROR, "%s: %s",internal::my_progname,str);
140
 
  }
141
 
}
142
 
 
143
 
static void init_signals(void)
144
 
{
145
 
  sigset_t set;
146
 
  struct sigaction sa;
147
 
 
148
 
  if (not (getDebug().test(debug::NO_STACKTRACE) || 
149
 
        getDebug().test(debug::CORE_ON_SIGNAL)))
150
 
  {
151
 
    sa.sa_flags = SA_RESETHAND | SA_NODEFER;
152
 
    sigemptyset(&sa.sa_mask);
153
 
    sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
154
 
 
155
 
    sa.sa_handler= drizzled_handle_segfault;
156
 
    sigaction(SIGSEGV, &sa, NULL);
157
 
    sigaction(SIGABRT, &sa, NULL);
158
 
#ifdef SIGBUS
159
 
    sigaction(SIGBUS, &sa, NULL);
160
 
#endif
161
 
    sigaction(SIGILL, &sa, NULL);
162
 
    sigaction(SIGFPE, &sa, NULL);
163
 
  }
164
 
 
165
 
  if (getDebug().test(debug::CORE_ON_SIGNAL))
166
 
  {
167
 
    /* Change limits so that we will get a core file */
168
 
    struct rlimit rl;
169
 
    rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
170
 
    if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
171
 
        errmsg_printf(error::WARN,
172
 
                      _("setrlimit could not change the size of core files "
173
 
                        "to 'infinity';  We may not be able to generate a "
174
 
                        "core file on signals"));
175
 
  }
176
 
  (void) sigemptyset(&set);
177
 
  ignore_signal(SIGPIPE);
178
 
  sigaddset(&set,SIGPIPE);
179
 
#ifndef IGNORE_SIGHUP_SIGQUIT
180
 
  sigaddset(&set,SIGQUIT);
181
 
  sigaddset(&set,SIGHUP);
182
 
#endif
183
 
  sigaddset(&set,SIGTERM);
184
 
 
185
 
  /* Fix signals if blocked by parents (can happen on Mac OS X) */
186
 
  sigemptyset(&sa.sa_mask);
187
 
  sa.sa_flags = 0;
188
 
  sa.sa_handler = drizzled_print_signal_warning;
189
 
  sigaction(SIGTERM, &sa, NULL);
190
 
  sa.sa_flags = 0;
191
 
  sa.sa_handler = drizzled_print_signal_warning;
192
 
  sigaction(SIGHUP, &sa, NULL);
193
 
#ifdef SIGTSTP
194
 
  sigaddset(&set,SIGTSTP);
195
 
#endif
196
 
  if (getDebug().test(debug::ALLOW_SIGINT))
197
 
  {
198
 
    sa.sa_flags= 0;
199
 
    sa.sa_handler= drizzled_end_thread_signal;
200
 
    sigaction(thr_kill_signal, &sa, NULL);
201
 
 
202
 
    // May be SIGINT
203
 
    sigdelset(&set, thr_kill_signal);
204
 
  }
205
 
  else
206
 
  {
207
 
    sigaddset(&set,SIGINT);
208
 
  }
209
 
  sigprocmask(SIG_SETMASK,&set,NULL);
210
 
  pthread_sigmask(SIG_SETMASK,&set,NULL);
211
 
  return;
212
 
}
213
 
 
214
 
static void GoogleProtoErrorThrower(google::protobuf::LogLevel level,
215
 
                                    const char* ,
216
 
                                    int, const string& ) throw(const char *)
217
 
{
218
 
  switch(level)
219
 
  {
220
 
  case google::protobuf::LOGLEVEL_INFO:
221
 
    break;
222
 
  case google::protobuf::LOGLEVEL_WARNING:
223
 
  case google::protobuf::LOGLEVEL_ERROR:
224
 
  case google::protobuf::LOGLEVEL_FATAL:
225
 
  default:
226
 
    throw("error in google protocol buffer parsing");
227
 
  }
228
 
}
229
 
 
230
 
int main(int argc, char **argv)
231
 
{
232
 
#if defined(ENABLE_NLS)
233
 
# if defined(HAVE_LOCALE_H)
234
 
  setlocale(LC_ALL, "");
235
 
# endif
236
 
  bindtextdomain("drizzle7", LOCALEDIR);
237
 
  textdomain("drizzle7");
238
 
#endif
239
 
 
240
 
  module::Registry &modules= module::Registry::singleton();
241
 
 
242
 
  MY_INIT(argv[0]);             // init my_sys library & pthreads
243
 
  /* nothing should come before this line ^^^ */
244
 
 
245
 
  /* Set signal used to kill Drizzle */
246
 
  thr_kill_signal= SIGINT;
247
 
 
248
 
  google::protobuf::SetLogHandler(&GoogleProtoErrorThrower);
249
 
 
250
 
  /* Function generates error messages before abort */
251
 
  error_handler_hook= my_message_sql;
252
 
 
253
 
  /* init_common_variables must get basic settings such as data_home_dir
254
 
     and plugin_load_list. */
255
 
  if (init_basic_variables(argc, argv))
256
 
    unireg_abort(1);                            // Will do exit
257
 
 
258
 
  if (opt_daemon)
259
 
  {
260
 
    if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
261
 
    {
262
 
      perror("Failed to ignore SIGHUP");
263
 
    }
264
 
    if (daemonize(1, 1, 1) == -1)
265
 
    {
266
 
      fprintf(stderr, "failed to daemon() in order to daemonize\n");
267
 
      exit(EXIT_FAILURE);
268
 
    }
269
 
  }
270
 
 
271
 
  if (init_remaining_variables(modules))
272
 
    unireg_abort(1);                            // Will do exit
273
 
 
274
 
  /*
275
 
    init signals & alarm
276
 
    After this we can't quit by a simple unireg_abort
277
 
  */
278
 
  init_signals();
279
 
 
280
 
 
281
 
  select_thread=pthread_self();
282
 
  select_thread_in_use=1;
283
 
 
284
 
  if (not opt_help)
285
 
  {
286
 
    if (chdir(getDataHome().file_string().c_str()))
287
 
    {
288
 
      errmsg_printf(error::ERROR,
289
 
                    _("Data directory %s does not exist\n"),
290
 
                    getDataHome().file_string().c_str());
291
 
      unireg_abort(1);
292
 
    }
293
 
    if (mkdir("local", 0700))
294
 
    {
295
 
      /* We don't actually care */
296
 
    }
297
 
    if (chdir("local"))
298
 
    {
299
 
      errmsg_printf(error::ERROR,
300
 
                    _("Local catalog %s/local does not exist\n"),
301
 
                    getDataHome().file_string().c_str());
302
 
      unireg_abort(1);
303
 
    }
304
 
 
305
 
    fs::path &full_data_home= getFullDataHome();
306
 
    full_data_home= fs::system_complete(getDataHome());
307
 
    std::cerr << "home " << full_data_home << std::endl;
308
 
  }
309
 
 
310
 
 
311
 
 
312
 
  if (server_id == 0)
313
 
  {
314
 
    server_id= 1;
315
 
  }
316
 
 
317
 
  try
318
 
  {
319
 
    if (init_server_components(modules))
320
 
      DRIZZLE_ABORT;
321
 
  }
322
 
  catch (abort_exception& ex)
323
 
  {
324
 
#if defined(DEBUG)
325
 
    cout << _("Drizzle has receieved an abort event.") << endl;
326
 
    cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
327
 
    cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
328
 
    cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
329
 
#endif
330
 
    unireg_abort(1);
331
 
  }
332
 
 
333
 
 
334
 
  /**
335
 
   * This check must be done after init_server_components for now
336
 
   * because we don't yet have plugin dependency tracking...
337
 
   *
338
 
   * ReplicationServices::evaluateRegisteredPlugins() will print error messages to stderr
339
 
   * via errmsg_printf().
340
 
   *
341
 
   * @todo
342
 
   *
343
 
   * not checking return since unireg_abort() hangs
344
 
   */
345
 
  ReplicationServices &replication_services= ReplicationServices::singleton();
346
 
    (void) replication_services.evaluateRegisteredPlugins();
347
 
 
348
 
  if (plugin::Listen::setup())
349
 
    unireg_abort(1);
350
 
 
351
 
  assert(plugin::num_trx_monitored_objects > 0);
352
 
  if (drizzle_rm_tmp_tables() || my_tz_init((Session *)0, default_tz_name))
353
 
  {
354
 
    abort_loop= true;
355
 
    select_thread_in_use=0;
356
 
    (void) pthread_kill(signal_thread, SIGTERM);
357
 
 
358
 
    (void) unlink(pid_file.file_string().c_str());      // Not needed anymore
359
 
 
360
 
    unireg_abort(1);
361
 
  }
362
 
 
363
 
  errmsg_printf(error::INFO, _(ER(ER_STARTUP)), internal::my_progname,
364
 
                PANDORA_RELEASE_VERSION, COMPILATION_COMMENT);
365
 
 
366
 
 
367
 
  TransactionServices &transaction_services= TransactionServices::singleton();
368
 
 
369
 
  /* Send server startup event */
370
 
  {
371
 
    Session::shared_ptr session;
372
 
 
373
 
    if ((session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local())))
374
 
    {
375
 
      currentSession().release();
376
 
      currentSession().reset(session.get());
377
 
 
378
 
 
379
 
      transaction_services.sendStartupEvent(*session);
380
 
 
381
 
      plugin_startup_window(modules, *(session.get()));
382
 
    }
383
 
  }
384
 
 
385
 
  if (opt_daemon)
386
 
    daemon_is_ready();
387
 
 
388
 
  /* 
389
 
    Listen for new connections and start new session for each connection
390
 
     accepted. The listen.getClient() method will return NULL when the server
391
 
     should be shutdown.
392
 
   */
393
 
  plugin::Client *client;
394
 
  while ((client= plugin::Listen::getClient()) != NULL)
395
 
  {
396
 
    Session::shared_ptr session;
397
 
    session= Session::make_shared(client, client->catalog());
398
 
 
399
 
    if (not session)
400
 
    {
401
 
      delete client;
402
 
      continue;
403
 
    }
404
 
 
405
 
    /* If we error on creation we drop the connection and delete the session. */
406
 
    if (Session::schedule(session))
407
 
      Session::unlink(session);
408
 
  }
409
 
 
410
 
  /* Send server shutdown event */
411
 
  {
412
 
    Session::shared_ptr session;
413
 
 
414
 
    if ((session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local())))
415
 
    {
416
 
      currentSession().release();
417
 
      currentSession().reset(session.get());
418
 
      transaction_services.sendShutdownEvent(*session.get());
419
 
    }
420
 
  }
421
 
 
422
 
  {
423
 
    boost::mutex::scoped_lock scopedLock(session::Cache::singleton().mutex());
424
 
    select_thread_in_use= false;                        // For close_connections
425
 
  }
426
 
  COND_thread_count.notify_all();
427
 
 
428
 
  /* Wait until cleanup is done */
429
 
  session::Cache::singleton().shutdownSecond();
430
 
 
431
 
  clean_up(1);
432
 
  module::Registry::shutdown();
433
 
  internal::my_end();
434
 
 
435
 
  return 0;
436
 
}
437