~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.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
 
/* 
2
 
   Copyright (C) 2011 Brian Aker
3
 
   Copyright (C) 2006 MySQL AB
 
1
/* Copyright (C) 2006 MySQL AB
4
2
 
5
3
   This program is free software; you can redistribute it and/or modify
6
4
   it under the terms of the GNU General Public License as published by
15
13
   along with this program; if not, write to the Free Software
16
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
17
15
 
18
 
#include <config.h>
19
 
 
 
16
#include "config.h"
20
17
#include <drizzled/gettext.h>
21
18
#include <drizzled/error.h>
22
19
#include <drizzled/unireg.h>
23
20
#include <drizzled/plugin/storage_engine.h>
24
 
#include <drizzled/pthread_globals.h>
25
 
#include <drizzled/internal/my_pthread.h>
26
 
#include <drizzled/internal/my_sys.h>
27
 
#include <drizzled/plugin/daemon.h>
28
 
#include <drizzled/signal_handler.h>
29
 
 
30
 
#include <drizzled/session.h>
31
 
#include <drizzled/session/cache.h>
32
 
 
33
 
#include <drizzled/debug.h>
34
 
 
35
 
#include <drizzled/drizzled.h>
36
 
 
37
 
#include <drizzled/refresh_version.h>
38
 
 
39
 
#include <boost/thread/thread.hpp>
40
 
#include <boost/filesystem.hpp>
 
21
#include <drizzled/cursor.h> /* for refresh_version */
 
22
#include "drizzled/pthread_globals.h"
 
23
#include "drizzled/internal/my_pthread.h"
 
24
#include "drizzled/internal/my_sys.h"
41
25
 
42
26
#include <sys/stat.h>
43
27
#include <fcntl.h>
44
28
 
45
29
 
46
30
static bool kill_in_progress= false;
47
 
void signal_hand(void);
 
31
static bool volatile signal_thread_in_use= false;
 
32
extern "C" pthread_handler_t signal_hand(void *);
48
33
 
49
34
namespace drizzled
50
35
{
51
36
extern int cleanup_done;
52
37
extern bool volatile abort_loop;
53
38
extern bool volatile shutdown_in_progress;
54
 
extern boost::filesystem::path pid_file;
 
39
extern char pidfile_name[FN_REFLEN];
55
40
/* Prototypes -> all of these should be factored out into a propper shutdown */
56
41
extern void close_connections(void);
 
42
extern std::bitset<12> test_flags;
57
43
}
58
44
 
59
45
using namespace drizzled;
60
46
 
61
47
 
62
48
 
63
 
 
64
49
/**
65
50
  Force server down. Kill all connections and threads and exit.
66
51
 
72
57
    or stop, we just want to kill the server.
73
58
*/
74
59
 
75
 
static void kill_server(int sig)
 
60
static void kill_server(void *sig_ptr)
76
61
{
 
62
  int sig=(int) (long) sig_ptr;                 // This is passed a int
77
63
  // if there is a signal during the kill in progress, ignore the other
78
64
  if (kill_in_progress)                         // Safety
79
65
    return;
80
66
  kill_in_progress=true;
81
67
  abort_loop=1;                                 // This should be set
82
68
  if (sig != 0) // 0 is not a valid signal number
83
 
    ignore_signal(sig);                    /* purify inspected */
 
69
    my_sigset(sig, SIG_IGN);                    /* purify inspected */
84
70
  if (sig == SIGTERM || sig == 0)
85
 
    errmsg_printf(error::INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
 
71
    errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
86
72
  else
87
 
    errmsg_printf(error::ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
 
73
    errmsg_printf(ERRMSG_LVL_ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
88
74
 
89
75
  close_connections();
90
 
  clean_up(1);
 
76
  if (sig != SIGTERM && sig != 0)
 
77
    unireg_abort(1);
 
78
  else
 
79
    unireg_end();
91
80
}
92
81
 
93
82
/**
98
87
  int file;
99
88
  char buff[1024];
100
89
 
101
 
  if ((file = open(pid_file.file_string().c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
 
90
  assert(pidfile_name[0]);
 
91
  if ((file = open(pidfile_name, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
102
92
  {
103
93
    int length;
104
94
 
111
101
    }
112
102
    (void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
113
103
  }
114
 
  memset(buff, 0, sizeof(buff));
115
 
  snprintf(buff, sizeof(buff)-1, "Can't start server: can't create PID file (%s)", pid_file.file_string().c_str());
 
104
  snprintf(buff, 1024, "Can't start server: can't create PID file (%s)", pidfile_name);
116
105
  sql_perror(buff);
117
106
  exit(1);
118
107
}
119
108
 
120
109
 
121
110
/** This threads handles all signals and alarms. */
122
 
void signal_hand()
 
111
pthread_handler_t signal_hand(void *)
123
112
{
124
113
  sigset_t set;
125
114
  int sig;
126
115
  internal::my_thread_init();                           // Init new thread
127
 
  boost::this_thread::at_thread_exit(&internal::my_thread_end);
128
116
  signal_thread_in_use= true;
129
117
 
130
 
  if ((drizzled::getDebug().test(drizzled::debug::ALLOW_SIGINT)))
 
118
  if (internal::thd_lib_detected != THD_LIB_LT && 
 
119
      (test_flags.test(TEST_SIGINT)))
131
120
  {
132
121
    (void) sigemptyset(&set);                   // Setup up SIGINT for debug
133
122
    (void) sigaddset(&set,SIGINT);              // For debugging
134
 
    (void) pthread_sigmask(SIG_UNBLOCK, &set, NULL);
 
123
    (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
135
124
  }
136
125
  (void) sigemptyset(&set);                     // Setup up SIGINT for debug
137
126
#ifndef IGNORE_SIGHUP_SIGQUIT
138
 
  if (sigaddset(&set,SIGQUIT))
139
 
  {
140
 
    std::cerr << "failed setting sigaddset() with SIGQUIT\n";
141
 
  }
142
 
  if (sigaddset(&set,SIGHUP))
143
 
  {
144
 
    std::cerr << "failed setting sigaddset() with SIGHUP\n";
145
 
  }
 
127
  (void) sigaddset(&set,SIGQUIT);
 
128
  (void) sigaddset(&set,SIGHUP);
146
129
#endif
147
 
  if (sigaddset(&set,SIGTERM))
148
 
  {
149
 
    std::cerr << "failed setting sigaddset() with SIGTERM\n";
150
 
  }
151
 
  if (sigaddset(&set,SIGTSTP))
152
 
  {
153
 
    std::cerr << "failed setting sigaddset() with SIGTSTP\n";
154
 
  }
 
130
  (void) sigaddset(&set,SIGTERM);
 
131
  (void) sigaddset(&set,SIGTSTP);
155
132
 
156
133
  /* Save pid to this process (or thread on Linux) */
157
134
  create_pid_file();
158
135
 
 
136
#ifdef HAVE_STACK_TRACE_ON_SEGV
 
137
  if (opt_do_pstack)
 
138
  {
 
139
    sprintf(pstack_file_name,"drizzled-%lu-%%d-%%d.backtrace", (uint32_t)getpid());
 
140
    pstack_install_segv_action(pstack_file_name);
 
141
  }
 
142
#endif /* HAVE_STACK_TRACE_ON_SEGV */
 
143
 
159
144
  /*
160
145
    signal to init that we are ready
161
146
    This works by waiting for init to free mutex,
168
153
    (Asked MontyW over the phone about this.) -Brian
169
154
 
170
155
  */
171
 
  session::Cache::singleton().mutex().lock();
172
 
  session::Cache::singleton().mutex().unlock();
173
 
  COND_thread_count.notify_all();
174
 
 
175
 
  if (pthread_sigmask(SIG_BLOCK, &set, NULL))
176
 
  {
177
 
    std::cerr << "Failed to set pthread_sigmask() in signal handler\n";
178
 
  }
179
 
 
 
156
  if (pthread_mutex_lock(&LOCK_thread_count) == 0)
 
157
    (void) pthread_mutex_unlock(&LOCK_thread_count);
 
158
  (void) pthread_cond_broadcast(&COND_thread_count);
 
159
 
 
160
  (void) pthread_sigmask(SIG_BLOCK,&set,NULL);
180
161
  for (;;)
181
162
  {
182
163
    int error;                                  // Used when debugging
183
 
 
184
164
    if (shutdown_in_progress && !abort_loop)
185
165
    {
186
166
      sig= SIGTERM;
187
167
      error=0;
188
168
    }
189
169
    else
190
 
    {
191
 
      while ((error= sigwait(&set, &sig)) == EINTR) ;
192
 
    }
193
 
 
 
170
      while ((error= sigwait(&set,&sig)) == EINTR) ;
194
171
    if (cleanup_done)
195
172
    {
 
173
      internal::my_thread_end();
196
174
      signal_thread_in_use= false;
197
175
 
198
 
      return;
 
176
      return NULL;
199
177
    }
200
178
    switch (sig) {
201
179
    case SIGTERM:
202
180
    case SIGQUIT:
203
181
    case SIGKILL:
204
 
    case SIGTSTP:
205
182
      /* switch to the old log message processing */
206
183
      if (!abort_loop)
207
184
      {
208
185
        abort_loop=1;                           // mark abort for threads
209
 
        kill_server(sig);               // MIT THREAD has a alarm thread
 
186
        kill_server((void*) sig);       // MIT THREAD has a alarm thread
210
187
      }
211
188
      break;
212
189
    case SIGHUP:
222
199
  }
223
200
}
224
201
 
225
 
class SignalHandler :
226
 
  public drizzled::plugin::Daemon
227
 
{
228
 
  SignalHandler(const SignalHandler &);
229
 
  SignalHandler& operator=(const SignalHandler &);
230
 
  boost::thread thread;
231
 
 
232
 
public:
233
 
  SignalHandler() :
234
 
    drizzled::plugin::Daemon("Signal Handler")
235
 
  {
236
 
    // @todo fix spurious wakeup issue
237
 
    boost::mutex::scoped_lock scopedLock(session::Cache::singleton().mutex());
238
 
    thread= boost::thread(signal_hand);
239
 
    signal_thread= thread.native_handle();
240
 
    COND_thread_count.wait(scopedLock);
241
 
  }
242
 
 
243
 
  /**
244
 
    This is mainly needed when running with purify, but it's still nice to
245
 
    know that all child threads have died when drizzled exits.
246
 
  */
247
 
  ~SignalHandler()
248
 
  {
249
 
    /*
250
 
      Wait up to 100000 micro-seconds for signal thread to die. We use this mainly to
251
 
      avoid getting warnings that internal::my_thread_end has not been called
252
 
    */
253
 
    bool completed= false;
254
 
    /*
255
 
     * We send SIGTERM and then do a timed join. If that fails we will on
256
 
     * the last pthread_kill() call SIGTSTP. OSX (and FreeBSD) seem to
257
 
     * prefer this. -Brian
258
 
   */
259
 
    uint32_t count= 2; // How many times to try join and see if the caller died.
260
 
    while (not completed and count--)
261
 
    {
262
 
      int error;
263
 
      int signal= count == 1 ? SIGTSTP : SIGTERM;
264
 
      
265
 
      if ((error= pthread_kill(thread.native_handle(), signal)))
266
 
      {
267
 
        char buffer[1024]; // No reason for number;
268
 
        strerror_r(error, buffer, sizeof(buffer));
269
 
        std::cerr << "pthread_kill() error on shutdown of signal thread (" << buffer << ")\n";
270
 
        break;
271
 
      }
272
 
      else
273
 
      {
274
 
        boost::posix_time::milliseconds duration(100);
275
 
        completed= thread.timed_join(duration);
276
 
      }
277
 
    }
278
 
  }
 
202
 
 
203
static int init(drizzled::plugin::Registry&)
 
204
{
 
205
  int error;
 
206
  pthread_attr_t thr_attr;
 
207
  size_t my_thread_stack_size= 65536;
 
208
 
 
209
  (void) pthread_attr_init(&thr_attr);
 
210
  pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM);
 
211
  (void) pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
 
212
  {
 
213
    struct sched_param tmp_sched_param;
 
214
 
 
215
    memset(&tmp_sched_param, 0, sizeof(tmp_sched_param));
 
216
    tmp_sched_param.sched_priority= INTERRUPT_PRIOR;
 
217
    (void)pthread_attr_setschedparam(&thr_attr, &tmp_sched_param);
 
218
  }
 
219
#if defined(__ia64__) || defined(__ia64)
 
220
  /*
 
221
    Peculiar things with ia64 platforms - it seems we only have half the
 
222
    stack size in reality, so we have to double it here
 
223
  */
 
224
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size*2);
 
225
# else
 
226
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size);
 
227
#endif
 
228
 
 
229
  (void) pthread_mutex_lock(&LOCK_thread_count);
 
230
  if ((error=pthread_create(&signal_thread, &thr_attr, signal_hand, 0)))
 
231
  {
 
232
      errmsg_printf(ERRMSG_LVL_ERROR, _("Can't create interrupt-thread (error %d, errno: %d)"),
 
233
                    error,errno);
 
234
    exit(1);
 
235
  }
 
236
  (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
 
237
  pthread_mutex_unlock(&LOCK_thread_count);
 
238
 
 
239
  (void) pthread_attr_destroy(&thr_attr);
 
240
 
 
241
  return 0;
 
242
}
 
243
 
 
244
/**
 
245
  This is mainly needed when running with purify, but it's still nice to
 
246
  know that all child threads have died when drizzled exits.
 
247
*/
 
248
static int deinit(drizzled::plugin::Registry&)
 
249
{
 
250
  uint32_t i;
 
251
  /*
 
252
    Wait up to 10 seconds for signal thread to die. We use this mainly to
 
253
    avoid getting warnings that internal::my_thread_end has not been called
 
254
  */
 
255
  for (i= 0 ; i < 100 && signal_thread_in_use; i++)
 
256
  {
 
257
    if (pthread_kill(signal_thread, SIGTERM) != ESRCH)
 
258
      break;
 
259
    usleep(100);                                // Give it time to die
 
260
  }
 
261
 
 
262
  return 0;
 
263
}
 
264
 
 
265
static drizzle_sys_var* system_variables[]= {
 
266
  NULL
279
267
};
280
268
 
281
 
static int init(drizzled::module::Context& context)
282
 
{
283
 
  context.add(new SignalHandler);
284
 
 
285
 
  return 0;
286
 
}
287
 
 
288
 
 
289
269
DRIZZLE_DECLARE_PLUGIN
290
270
{
291
271
  DRIZZLE_VERSION_ID,
295
275
  "Default Signal Handler",
296
276
  PLUGIN_LICENSE_GPL,
297
277
  init, /* Plugin Init */
298
 
  NULL,   /* depends */
 
278
  deinit, /* Plugin Deinit */
 
279
  NULL,   /* status variables */
 
280
  system_variables,   /* system variables */
299
281
  NULL    /* config options */
300
282
}
301
283
DRIZZLE_DECLARE_PLUGIN_END;