~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/main.cc

This patch completes the first step in the splitting of
the XA resource manager API from the storage engine API,
as outlined in the specification here:

http://drizzle.org/wiki/XaStorageEngine

* Splits plugin::StorageEngine into a base StorageEngine
  class and two derived classes, TransactionalStorageEngine
  and XaStorageEngine.  XaStorageEngine derives from
  TransactionalStorageEngine and creates the XA Resource
  Manager API for storage engines.

  - The methods moved from StorageEngine to TransactionalStorageEngine
    include releaseTemporaryLatches(), startConsistentSnapshot(), 
    commit(), rollback(), setSavepoint(), releaseSavepoint(),
    rollbackToSavepoint() and hasTwoPhaseCommit()
  - The methods moved from StorageEngine to XaStorageEngine
    include recover(), commitXid(), rollbackXid(), and prepare()

* Places all static "EngineVector"s into their proper
  namespaces (typedefs belong in header files, not implementation files)
  and places all static methods corresponding
  to either only transactional engines or only XA engines
  into their respective files in /drizzled/plugin/

* Modifies the InnoDB "handler" files to extend plugin::XaStorageEngine
  and not plugin::StorageEngine

The next step, as outlined in the wiki spec page above, is to isolate
the XA Resource Manager API into its own plugin class and modify
plugin::XaStorageEngine to implement plugin::XaResourceManager via
composition.  This is necessary to enable building plugins which can
participate in an XA transaction *without having to have that plugin
implement the entire storage engine API*

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