~thomir-deactivatedaccount/drizzle/drizzle-fix-bug653747

« back to all changes in this revision

Viewing changes to plugin/pool_of_threads/pool_of_threads.cc

  • Committer: Brian Aker
  • Date: 2010-10-10 02:07:52 UTC
  • mfrom: (1827.2.3 staging)
  • Revision ID: brian@tangent.org-20101010020752-ktv73isay5dxtvp3
Merge in switch on table_share_instance inheritance.

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) 2006 MySQL AB
 
5
 * Copyright (C) 2009 Sun Microsystems
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; version 2 of the License.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
#include <fcntl.h>
 
23
#include <plugin/pool_of_threads/pool_of_threads.h>
 
24
#include "drizzled/pthread_globals.h"
 
25
#include "drizzled/internal/my_pthread.h"
 
26
#include <boost/program_options.hpp>
 
27
#include <drizzled/module/option_map.h>
 
28
 
 
29
#include <boost/thread/thread.hpp>
 
30
#include <boost/bind.hpp>
 
31
 
 
32
namespace po= boost::program_options;
 
33
using namespace std;
 
34
using namespace drizzled;
 
35
 
 
36
/* Global's (TBR) */
 
37
 
 
38
/**
 
39
 * Set this to true to trigger killing of all threads in the pool
 
40
 */
 
41
static volatile bool kill_pool_threads= false;
 
42
 
 
43
static volatile uint32_t created_threads= 0;
 
44
 
 
45
static struct event session_add_event;
 
46
static struct event session_kill_event;
 
47
 
 
48
 
 
49
static int session_add_pipe[2]; /* pipe to signal add a connection to libevent*/
 
50
static int session_kill_pipe[2]; /* pipe to signal kill a connection in libevent */
 
51
 
 
52
 
 
53
static bool libevent_needs_immediate_processing(Session *session);
 
54
static void libevent_connection_close(Session *session);
 
55
void libevent_session_add(Session* session);
 
56
bool libevent_should_close_connection(Session* session);
 
57
void libevent_thread_proc(PoolOfThreadsScheduler *pot_scheduler);
 
58
extern "C" {
 
59
#if 0
 
60
  void *libevent_thread_proc(void *arg);
 
61
#endif
 
62
  void libevent_io_callback(int Fd, short Operation, void *ctx);
 
63
  void libevent_add_session_callback(int Fd, short Operation, void *ctx);
 
64
  void libevent_kill_session_callback(int Fd, short Operation, void *ctx);
 
65
}
 
66
 
 
67
static uint32_t pool_size;
 
68
 
 
69
/**
 
70
 * @brief 
 
71
 *  Create a pipe and set to non-blocking. 
 
72
 * @return 
 
73
 *  True if there is an error.
 
74
 */
 
75
static bool init_pipe(int pipe_fds[])
 
76
{
 
77
  int flags;
 
78
  return pipe(pipe_fds) < 0 ||
 
79
          (flags= fcntl(pipe_fds[0], F_GETFL)) == -1 ||
 
80
          fcntl(pipe_fds[0], F_SETFL, flags | O_NONBLOCK) == -1 ||
 
81
          (flags= fcntl(pipe_fds[1], F_GETFL)) == -1 ||
 
82
          fcntl(pipe_fds[1], F_SETFL, flags | O_NONBLOCK) == -1;
 
83
}
 
84
 
 
85
 
 
86
 
 
87
 
 
88
 
 
89
/**
 
90
 * @brief
 
91
 *  This is called when data is ready on the socket.
 
92
 *
 
93
 * @details
 
94
 *  This is only called by the thread that owns LOCK_event_loop.
 
95
 *
 
96
 *  We add the session that got the data to sessions_need_processing, and
 
97
 *  cause the libevent event_loop() to terminate. Then this same thread will
 
98
 *  return from event_loop and pick the session value back up for
 
99
 *  processing.
 
100
 */
 
101
void libevent_io_callback(int, short, void *ctx)
 
102
{
 
103
  Session *session= reinterpret_cast<Session*>(ctx);
 
104
  session_scheduler *sched= static_cast<session_scheduler *>(session->scheduler_arg);
 
105
  assert(sched);
 
106
  PoolOfThreadsScheduler *pot_scheduler= static_cast<PoolOfThreadsScheduler *>(session->scheduler);
 
107
  pot_scheduler->doIO(sched);
 
108
}
 
109
 
 
110
void PoolOfThreadsScheduler::doIO(session_scheduler *sched)
 
111
{
 
112
  safe_mutex_assert_owner(&LOCK_event_loop);
 
113
  sessions_waiting_for_io.erase(sched->session);
 
114
  sessions_need_processing.push(sched->session);
 
115
}
 
116
/**
 
117
 * @brief
 
118
 *  This is called when we have a thread we want to be killed.
 
119
 *
 
120
 * @details
 
121
 *  This is only called by the thread that owns LOCK_event_loop.
 
122
 */
 
123
void libevent_kill_session_callback(int Fd, short, void *ctx)
 
124
{
 
125
  PoolOfThreadsScheduler *pot_scheduler=
 
126
    reinterpret_cast<PoolOfThreadsScheduler *>(ctx);
 
127
 
 
128
  pot_scheduler->killSession(Fd);
 
129
}
 
130
 
 
131
void PoolOfThreadsScheduler::killSession(int Fd)
 
132
{
 
133
  safe_mutex_assert_owner(&LOCK_event_loop);
 
134
  /*
 
135
   For pending events clearing
 
136
  */
 
137
  char c;
 
138
  int count= 0;
 
139
 
 
140
  LOCK_session_kill.lock();
 
141
  while (! sessions_to_be_killed.empty())
 
142
  {
 
143
 
 
144
    /*
 
145
     Fetch a session from the queue
 
146
    */
 
147
    Session* session= sessions_to_be_killed.front();
 
148
    LOCK_session_kill.unlock();
 
149
 
 
150
    session_scheduler *sched= static_cast<session_scheduler *>(session->scheduler_arg);
 
151
    assert(sched);
 
152
 
 
153
    /*
 
154
     Delete from libevent and add to the processing queue.
 
155
    */
 
156
    event_del(&sched->io_event);
 
157
    /*
 
158
     Remove from the sessions_waiting_for_io set
 
159
    */
 
160
    sessions_waiting_for_io.erase(session);
 
161
    /*
 
162
     Push into the sessions_need_processing; the kill action will be
 
163
     performed out of the event loop
 
164
    */
 
165
    sessions_need_processing.push(sched->session);
 
166
 
 
167
    LOCK_session_kill.lock();
 
168
    /*
 
169
     Pop until this session is already processed
 
170
    */
 
171
    sessions_to_be_killed.pop();
 
172
  }
 
173
  
 
174
  /*
 
175
   Clear the pending events 
 
176
   One and only one charactor should be in the pipe
 
177
  */
 
178
  while (read(Fd, &c, sizeof(c)) == sizeof(c))
 
179
  {
 
180
    count++;
 
181
  }
 
182
  assert(count == 1);
 
183
  LOCK_session_kill.unlock();
 
184
}
 
185
 
 
186
 
 
187
/**
 
188
 * @brief
 
189
 *  This is used to add connections to the pool. This callback is invoked
 
190
 *  from the libevent event_loop() call whenever the session_add_pipe[1]
 
191
 *  pipe has a byte written to it.
 
192
 *
 
193
 * @details
 
194
 *  This is only called by the thread that owns LOCK_event_loop.
 
195
 */
 
196
void libevent_add_session_callback(int Fd, short, void *ctx)
 
197
{
 
198
  PoolOfThreadsScheduler *pot_scheduler=
 
199
    reinterpret_cast<PoolOfThreadsScheduler *>(ctx);
 
200
  pot_scheduler->addSession(Fd);
 
201
}
 
202
 
 
203
void PoolOfThreadsScheduler::addSession(int Fd)
 
204
{
 
205
  safe_mutex_assert_owner(&LOCK_event_loop);
 
206
  /*
 
207
   For pending events clearing
 
208
  */
 
209
  char c;
 
210
  int count= 0;
 
211
 
 
212
  LOCK_session_add.lock();
 
213
  while (! sessions_need_adding.empty())
 
214
  {
 
215
    /*
 
216
     Pop the first session off the queue 
 
217
    */
 
218
    Session* session= sessions_need_adding.front();
 
219
    LOCK_session_add.unlock();
 
220
 
 
221
    session_scheduler *sched= static_cast<session_scheduler *>(session->scheduler_arg);
 
222
    assert(sched);
 
223
 
 
224
 
 
225
    if (!sched->logged_in || libevent_should_close_connection(session))
 
226
    {
 
227
      /*
 
228
       Add session to sessions_need_processing queue. If it needs closing
 
229
       we'll close it outside of event_loop().
 
230
      */
 
231
      sessions_need_processing.push(sched->session);
 
232
    }
 
233
    else
 
234
    {
 
235
      /* Add to libevent */
 
236
      if (event_add(&sched->io_event, NULL))
 
237
      {
 
238
        errmsg_printf(ERRMSG_LVL_ERROR, _("event_add error in libevent_add_session_callback\n"));
 
239
        libevent_connection_close(session);
 
240
      }
 
241
      else
 
242
      {
 
243
        sessions_waiting_for_io.insert(sched->session);
 
244
      }
 
245
    }
 
246
 
 
247
    LOCK_session_add.lock();
 
248
    /*
 
249
     Pop until this session is already processed
 
250
    */
 
251
    sessions_need_adding.pop();
 
252
  }
 
253
 
 
254
  /*
 
255
   Clear the pending events 
 
256
   One and only one charactor should be in the pipe
 
257
  */
 
258
  while (read(Fd, &c, sizeof(c)) == sizeof(c))
 
259
  {
 
260
    count++;
 
261
  }
 
262
  assert(count == 1);
 
263
  LOCK_session_add.unlock();
 
264
}
 
265
 
 
266
/**
 
267
 * @brief 
 
268
 *  Close and delete a connection.
 
269
 */
 
270
static void libevent_connection_close(Session *session)
 
271
{
 
272
  session_scheduler *sched= (session_scheduler *)session->scheduler_arg;
 
273
  assert(sched);
 
274
  session->killed= Session::KILL_CONNECTION;    /* Avoid error messages */
 
275
 
 
276
  if (session->client->getFileDescriptor() >= 0) /* not already closed */
 
277
  {
 
278
    session->disconnect(0, true);
 
279
  }
 
280
  sched->thread_detach();
 
281
  
 
282
  delete sched;
 
283
  session->scheduler_arg= NULL;
 
284
 
 
285
  Session::unlink(session);   /* locks LOCK_thread_count and deletes session */
 
286
 
 
287
  return;
 
288
}
 
289
 
 
290
 
 
291
/**
 
292
 * @brief 
 
293
 *  Checks if a session should be closed.
 
294
 *  
 
295
 * @retval true this session should be closed.  
 
296
 * @retval false not to be closed.
 
297
 */
 
298
bool libevent_should_close_connection(Session* session)
 
299
{
 
300
  return session->client->haveError() ||
 
301
         session->killed == Session::KILL_CONNECTION;
 
302
}
 
303
 
 
304
 
 
305
/**
 
306
 * @brief
 
307
 *  libevent_thread_proc is the outer loop of each thread in the thread pool.
 
308
 *  These procs only return/terminate on shutdown (kill_pool_threads ==
 
309
 *  true).
 
310
 */
 
311
void libevent_thread_proc(PoolOfThreadsScheduler *pot_scheduler)
 
312
{
 
313
  if (internal::my_thread_init())
 
314
  {
 
315
    internal::my_thread_global_end();
 
316
    errmsg_printf(ERRMSG_LVL_ERROR, _("libevent_thread_proc: internal::my_thread_init() failed\n"));
 
317
    exit(1);
 
318
  }
 
319
 
 
320
  (void)pot_scheduler->mainLoop();
 
321
}
 
322
 
 
323
void *PoolOfThreadsScheduler::mainLoop()
 
324
{
 
325
  /*
 
326
   Signal libevent_init() when all threads has been created and are ready
 
327
   to receive events.
 
328
  */
 
329
  (void) LOCK_thread_count.lock();
 
330
  created_threads++;
 
331
  if (created_threads == pool_size)
 
332
    COND_thread_count.notify_one();
 
333
 
 
334
  (void) LOCK_thread_count.unlock();
 
335
 
 
336
  for (;;)
 
337
  {
 
338
    Session *session= NULL;
 
339
    LOCK_event_loop.lock();
 
340
 
 
341
    /* get session(s) to process */
 
342
    while (sessions_need_processing.empty())
 
343
    {
 
344
      if (kill_pool_threads)
 
345
      {
 
346
        /* the flag that we should die has been set */
 
347
        LOCK_event_loop.unlock();
 
348
        goto thread_exit;
 
349
      }
 
350
      event_loop(EVLOOP_ONCE);
 
351
    }
 
352
 
 
353
    /* pop the first session off the queue */
 
354
    session= sessions_need_processing.front();
 
355
    sessions_need_processing.pop();
 
356
    session_scheduler *sched= (session_scheduler *)session->scheduler_arg;
 
357
 
 
358
    LOCK_event_loop.lock();
 
359
 
 
360
    /* now we process the connection (session) */
 
361
 
 
362
    /* set up the session<->thread links. */
 
363
    session->thread_stack= (char*) &session;
 
364
 
 
365
    if (sched->thread_attach())
 
366
    {
 
367
      libevent_connection_close(session);
 
368
      continue;
 
369
    }
 
370
 
 
371
    /* is the connection logged in yet? */
 
372
    if (!sched->logged_in)
 
373
    {
 
374
      if (session->authenticate())
 
375
      {
 
376
        /* Failed to log in */
 
377
        libevent_connection_close(session);
 
378
        continue;
 
379
      }
 
380
      else
 
381
      {
 
382
        /* login successful */
 
383
        sched->logged_in= true;
 
384
        session->prepareForQueries();
 
385
        if (!libevent_needs_immediate_processing(session))
 
386
          continue; /* New connection is now waiting for data in libevent*/
 
387
      }
 
388
    }
 
389
 
 
390
    do
 
391
    {
 
392
      /* Process a query */
 
393
      if (! session->executeStatement())
 
394
      {
 
395
        libevent_connection_close(session);
 
396
        break;
 
397
      }
 
398
    } while (libevent_needs_immediate_processing(session));
 
399
 
 
400
    if (kill_pool_threads) /* the flag that we should die has been set */
 
401
      goto thread_exit;
 
402
  }
 
403
 
 
404
thread_exit:
 
405
  (void) LOCK_thread_count.lock();
 
406
  created_threads--;
 
407
  COND_thread_count.notify_all();
 
408
  (void) LOCK_thread_count.unlock();
 
409
  internal::my_thread_end();
 
410
  pthread_exit(0);
 
411
 
 
412
  return NULL;                               /* purify: deadcode */
 
413
}
 
414
 
 
415
 
 
416
/**
 
417
 * @brief
 
418
 *  Checks if a session needs immediate processing
 
419
 *
 
420
 * @retval true the session needs immediate processing 
 
421
 * @retval false if not, and is detached from the thread waiting for another
 
422
 * adding. The naming of the function is misleading in this case; it
 
423
 * actually does more than just checking if immediate processing is needed.
 
424
 */
 
425
static bool libevent_needs_immediate_processing(Session *session)
 
426
{
 
427
  session_scheduler *sched= (session_scheduler *)session->scheduler_arg;
 
428
 
 
429
  if (libevent_should_close_connection(session))
 
430
  {
 
431
    libevent_connection_close(session);
 
432
    return false;
 
433
  }
 
434
  /*
 
435
   If more data in the socket buffer, return true to process another command.
 
436
  
 
437
   Note: we cannot add for event processing because the whole request
 
438
   might already be buffered and we wouldn't receive an event. This is
 
439
   indeed the root of the reason of low performace. Need to be changed
 
440
   when nonblocking Protocol is finished.
 
441
  */
 
442
  if (session->client->haveMoreData())
 
443
    return true;
 
444
 
 
445
  sched->thread_detach();
 
446
  libevent_session_add(session);
 
447
 
 
448
  return false;
 
449
}
 
450
 
 
451
 
 
452
/**
 
453
 * @brief 
 
454
 *  Adds a Session to queued for libevent processing.
 
455
 * 
 
456
 * @details
 
457
 *  This call does not actually register the event with libevent.
 
458
 *  Instead, it places the Session onto a queue and signals libevent by writing
 
459
 *  a byte into session_add_pipe, which will cause our libevent_add_session_callback to
 
460
 *  be invoked which will find the Session on the queue and add it to libevent.
 
461
 */
 
462
void libevent_session_add(Session* session)
 
463
{
 
464
  session_scheduler *sched= (session_scheduler *)session->scheduler_arg;
 
465
  assert(sched);
 
466
  PoolOfThreadsScheduler *pot_scheduler=
 
467
    static_cast<PoolOfThreadsScheduler *>(session->scheduler);
 
468
  pot_scheduler->sessionAddToQueue(sched);
 
469
}
 
470
 
 
471
void PoolOfThreadsScheduler::sessionAddToQueue(session_scheduler *sched)
 
472
{
 
473
  char c= 0;
 
474
  boost::mutex::scoped_lock scopedLock(LOCK_session_add);
 
475
  if (sessions_need_adding.empty())
 
476
  {
 
477
    /* notify libevent */
 
478
    size_t written= write(session_add_pipe[1], &c, sizeof(c));
 
479
    assert(written == sizeof(c));
 
480
  }
 
481
  /* queue for libevent */
 
482
  sessions_need_adding.push(sched->session);
 
483
}
 
484
 
 
485
 
 
486
PoolOfThreadsScheduler::PoolOfThreadsScheduler(const char *name_arg)
 
487
  : Scheduler(name_arg), sessions_need_adding(), sessions_to_be_killed(),
 
488
    sessions_need_processing(), sessions_waiting_for_io()
 
489
{
 
490
  /* Setup attribute parameter for session threads. */
 
491
  (void) pthread_attr_init(&attr);
 
492
  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
493
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
 
494
}
 
495
 
 
496
 
 
497
PoolOfThreadsScheduler::~PoolOfThreadsScheduler()
 
498
{
 
499
  (void) LOCK_thread_count.lock();
 
500
 
 
501
  kill_pool_threads= true;
 
502
  while (created_threads)
 
503
  {
 
504
    /*
 
505
     * Wake up the event loop
 
506
     */
 
507
    char c= 0;
 
508
    size_t written= write(session_add_pipe[1], &c, sizeof(c));
 
509
    assert(written == sizeof(c));
 
510
 
 
511
    pthread_cond_wait(COND_thread_count.native_handle(), LOCK_thread_count.native_handle());
 
512
  }
 
513
  (void) LOCK_thread_count.unlock();
 
514
 
 
515
  event_del(&session_add_event);
 
516
  close(session_add_pipe[0]);
 
517
  close(session_add_pipe[1]);
 
518
  event_del(&session_kill_event);
 
519
  close(session_kill_pipe[0]);
 
520
  close(session_kill_pipe[1]);
 
521
 
 
522
  (void) pthread_attr_destroy(&attr);
 
523
}
 
524
 
 
525
 
 
526
bool PoolOfThreadsScheduler::addSession(Session *session)
 
527
{
 
528
  assert(session->scheduler_arg == NULL);
 
529
  session_scheduler *sched= new session_scheduler(session);
 
530
 
 
531
  if (sched == NULL)
 
532
    return true;
 
533
 
 
534
  session->scheduler_arg= (void *)sched;
 
535
 
 
536
  libevent_session_add(session);
 
537
 
 
538
  return false;
 
539
}
 
540
 
 
541
 
 
542
void PoolOfThreadsScheduler::killSession(Session *session)
 
543
{
 
544
  char c= 0;
 
545
 
 
546
  boost::mutex::scoped_lock scopedLock(LOCK_session_kill);
 
547
 
 
548
  if (sessions_to_be_killed.empty())
 
549
  {
 
550
    /* 
 
551
      Notify libevent with the killing event if this's the first killing
 
552
      notification of the batch
 
553
    */
 
554
    size_t written= write(session_kill_pipe[1], &c, sizeof(c));
 
555
    assert(written == sizeof(c));
 
556
  }
 
557
 
 
558
  /*
 
559
    Push into the sessions_to_be_killed queue
 
560
  */
 
561
  sessions_to_be_killed.push(session);
 
562
}
 
563
 
 
564
 
 
565
bool PoolOfThreadsScheduler::libevent_init(void)
 
566
{
 
567
  event_init();
 
568
 
 
569
 
 
570
  /* Set up the pipe used to add new sessions to the event pool */
 
571
  if (init_pipe(session_add_pipe))
 
572
  {
 
573
    errmsg_printf(ERRMSG_LVL_ERROR,
 
574
                  _("init_pipe(session_add_pipe) error in libevent_init\n"));
 
575
    return true;
 
576
  }
 
577
  /* Set up the pipe used to kill sessions in the event queue */
 
578
  if (init_pipe(session_kill_pipe))
 
579
  {
 
580
    errmsg_printf(ERRMSG_LVL_ERROR,
 
581
                  _("init_pipe(session_kill_pipe) error in libevent_init\n"));
 
582
    close(session_add_pipe[0]);
 
583
    close(session_add_pipe[1]);
 
584
    return true;
 
585
  }
 
586
  event_set(&session_add_event, session_add_pipe[0], EV_READ|EV_PERSIST,
 
587
            libevent_add_session_callback, this);
 
588
  event_set(&session_kill_event, session_kill_pipe[0], EV_READ|EV_PERSIST,
 
589
            libevent_kill_session_callback, this);
 
590
 
 
591
  if (event_add(&session_add_event, NULL) || event_add(&session_kill_event, NULL))
 
592
  {
 
593
    errmsg_printf(ERRMSG_LVL_ERROR, _("session_add_event event_add error in libevent_init\n"));
 
594
    return true;
 
595
 
 
596
  }
 
597
  /* Set up the thread pool */
 
598
  boost::mutex::scoped_lock scopedLock(LOCK_thread_count);
 
599
 
 
600
  for (uint32_t x= 0; x < pool_size; x++)
 
601
  {
 
602
    if (not new boost::thread(boost::bind(libevent_thread_proc, this)))
 
603
    {
 
604
      errmsg_printf(ERRMSG_LVL_ERROR, _("Can't create completion port thread (error %d)"), 1);
 
605
      return true;
 
606
    }
 
607
  }
 
608
 
 
609
  /* Wait until all threads are created */
 
610
  while (created_threads != pool_size)
 
611
  {
 
612
    COND_thread_count.wait(scopedLock);
 
613
  }
 
614
 
 
615
  return false;
 
616
}
 
617
 
 
618
 
 
619
/**
 
620
 * @brief
 
621
 *  Called to initialize the pool of threads scheduler plugin
 
622
 * 
 
623
 * @param[in] registry holding the record of the plugins
 
624
 */
 
625
static int init(drizzled::module::Context &context)
 
626
{
 
627
  const module::option_map &vm= context.getOptions();
 
628
 
 
629
  if (vm.count("size"))
 
630
  {
 
631
    if (pool_size > 1024 || pool_size < 1)
 
632
    {
 
633
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for size\n"));
 
634
      exit(-1);
 
635
    }
 
636
  }
 
637
 
 
638
  assert(pool_size != 0);
 
639
 
 
640
  context.add(new PoolOfThreadsScheduler("pool_of_threads"));
 
641
 
 
642
  return 0;
 
643
}
 
644
 
 
645
/*
 
646
 The defaults here were picked based on what I see (aka Brian). They should
 
647
 be vetted across a larger audience.
 
648
*/
 
649
static DRIZZLE_SYSVAR_UINT(size, pool_size,
 
650
                           PLUGIN_VAR_RQCMDARG,
 
651
                           N_("Size of Pool."),
 
652
                           NULL, NULL, 8, 1, 1024, 0);
 
653
 
 
654
static void init_options(drizzled::module::option_context &context)
 
655
{
 
656
  context("size",
 
657
          po::value<uint32_t>(&pool_size)->default_value(8),
 
658
          N_("Size of Pool."));
 
659
}
 
660
 
 
661
static drizzle_sys_var* sys_variables[]= {
 
662
  DRIZZLE_SYSVAR(size),
 
663
  NULL,
 
664
};
 
665
 
 
666
DRIZZLE_DECLARE_PLUGIN
 
667
{
 
668
  DRIZZLE_VERSION_ID,
 
669
  "pool_of_threads",
 
670
  "0.1",
 
671
  "Brian Aker",
 
672
  "Pool of Threads Scheduler",
 
673
  PLUGIN_LICENSE_GPL,
 
674
  init, /* Plugin Init */
 
675
  sys_variables,   /* system variables */
 
676
  init_options    /* config options */
 
677
}
 
678
DRIZZLE_DECLARE_PLUGIN_END;