Drizzled Public API Documentation

loader.cc
1 /* Copyright (C) 2005 MySQL AB
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include <config.h>
17 
18 #include <dlfcn.h>
19 
20 #include <cstdio>
21 #include <string>
22 #include <vector>
23 #include <map>
24 #include <algorithm>
25 #include <iostream>
26 
27 #include <boost/program_options.hpp>
28 
29 #include <drizzled/option.h>
30 #include <drizzled/internal/m_string.h>
31 
32 #include <drizzled/plugin.h>
33 #include <drizzled/module/load_list.h>
34 #include <drizzled/module/library.h>
35 #include <drizzled/module/registry.h>
37 #include <drizzled/sql_parse.h>
38 #include <drizzled/show.h>
39 #include <drizzled/cursor.h>
40 #include <drizzled/set_var.h>
41 #include <drizzled/session.h>
42 #include <drizzled/item/null.h>
43 #include <drizzled/error.h>
44 #include <drizzled/gettext.h>
45 #include <drizzled/errmsg_print.h>
46 #include <drizzled/pthread_globals.h>
47 #include <drizzled/util/tokenize.h>
48 #include <drizzled/system_variables.h>
49 
50 #include <boost/foreach.hpp>
51 
52 /* FreeBSD 2.2.2 does not define RTLD_NOW) */
53 #ifndef RTLD_NOW
54 #define RTLD_NOW 1
55 #endif
56 
57 namespace po=boost::program_options;
58 
59 using namespace std;
60 
62 typedef drizzled::module::Manifest drizzled_builtin_list[];
63 extern drizzled_builtin_list PANDORA_BUILTIN_SYMBOLS_LIST;
64 extern drizzled_builtin_list PANDORA_BUILTIN_LOAD_SYMBOLS_LIST;
65 drizzled::module::Manifest *drizzled_builtins[]=
66 {
67  PANDORA_BUILTIN_SYMBOLS_LIST, NULL
68 };
69 drizzled::module::Manifest *drizzled_load_builtins[]=
70 {
71  PANDORA_BUILTIN_LOAD_SYMBOLS_LIST, NULL
72 };
73 
74 namespace drizzled {
75 
76 
77 typedef vector<string> PluginOptions;
78 static PluginOptions opt_plugin_load;
79 static PluginOptions opt_plugin_add;
80 static PluginOptions opt_plugin_remove;
81 const char *builtin_plugins= PANDORA_BUILTIN_LIST;
82 const char *builtin_load_plugins= PANDORA_BUILTIN_LOAD_LIST;
83 
84 /* Note that 'int version' must be the first field of every plugin
85  sub-structure (plugin->info).
86 */
87 
88 static bool initialized= false;
89 
90 
91 static bool reap_needed= false;
92 
93 /*
94  write-lock on LOCK_system_variables_hash is required before modifying
95  the following variables/structures
96 */
97 static memory::Root plugin_mem_root(4096);
98 static uint32_t global_variables_dynamic_size= 0;
99 
100 
101 /*
102  hidden part of opaque value passed to variable check functions.
103  Used to provide a object-like structure to non C++ consumers.
104 */
106 {
107  Item *item;
108 };
109 
110 /* prototypes */
111 static void plugin_prune_list(vector<string> &plugin_list, const vector<string> &plugins_to_remove);
112 static bool plugin_load_list(module::Registry &registry,
113  memory::Root *tmp_root,
114  const set<string> &plugin_list,
115  po::options_description &long_options,
116  bool builtin= false);
117 static int test_plugin_options(memory::Root*, module::Module*, po::options_description&long_options);
118 static void unlock_variables(Session *session, drizzle_system_variables *vars);
119 static void cleanup_variables(drizzle_system_variables *vars);
120 
121 
122 /****************************************************************************
123  Plugin support code
124 ****************************************************************************/
125 
126 
127 
128 
129 /*
130  NOTE
131  Requires that a write-lock is held on LOCK_system_variables_hash
132 */
133 static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
134  module::Library *library,
135  po::options_description &long_options)
136 {
137  if (! initialized)
138  return true;
139 
140  if (registry.find(library->getName()))
141  {
142  errmsg_printf(error::WARN, ER(ER_PLUGIN_EXISTS),
143  library->getName().c_str());
144  return false;
145  }
146 
147  /* Find plugin by name */
148  const module::Manifest *manifest= library->getManifest();
149 
150  if (registry.find(manifest->name))
151  {
152  errmsg_printf(error::ERROR,
153  _("Plugin '%s' contains the name '%s' in its manifest, which "
154  "has already been registered.\n"),
155  library->getName().c_str(),
156  manifest->name);
157  return true;
158  }
159 
160  module::Module* tmp= new module::Module(manifest, library);
161 
162  if (!test_plugin_options(tmp_root, tmp, long_options))
163  {
164  registry.add(tmp);
165  return false;
166  }
167  errmsg_printf(error::ERROR, ER(ER_CANT_FIND_DL_ENTRY),
168  library->getName().c_str());
169  return true;
170 }
171 
172 
173 static void reap_plugins(module::Registry &registry)
174 {
175  BOOST_FOREACH(module::Registry::ModuleMap::const_reference module, registry.getModulesMap())
176  delete module.second;
177 }
178 
179 
180 static bool plugin_initialize(module::Registry &registry,
181  module::Module *module)
182 {
183  assert(module->isInited == false);
184 
185  module::Context loading_context(registry, module);
186  if (module->getManifest().init)
187  {
188  if (module->getManifest().init(loading_context))
189  {
190  errmsg_printf(error::ERROR,
191  _("Plugin '%s' init function returned error.\n"),
192  module->getName().c_str());
193  return true;
194  }
195  }
196  module->isInited= true;
197  return false;
198 }
199 
200 static void compose_plugin_options(vector<string> &target,
201  vector<string> options)
202 {
203  BOOST_FOREACH(vector<string>::reference it, options)
204  tokenize(it, target, ",", true);
205  BOOST_FOREACH(vector<string>::reference it, target)
206  std::replace(it.begin(), it.end(), '-', '_');
207 }
208 
209 void compose_plugin_add(const vector<string>& options)
210 {
211  compose_plugin_options(opt_plugin_add, options);
212 }
213 
214 void compose_plugin_remove(const vector<string>& options)
215 {
216  compose_plugin_options(opt_plugin_remove, options);
217 }
218 
219 void notify_plugin_load(const string& in_plugin_load)
220 {
221  tokenize(in_plugin_load, opt_plugin_load, ",", true);
222 }
223 
224 /*
225  The logic is that we first load and initialize all compiled in plugins.
226  From there we load up the dynamic types (assuming we have not been told to
227  skip this part).
228 
229  Finally we initialize everything, aka the dynamic that have yet to initialize.
230 */
231 bool plugin_init(module::Registry &registry,
232  po::options_description &long_options)
233 {
234  if (initialized)
235  return false;
236 
237  initialized= true;
238 
239  PluginOptions builtin_load_list;
240  tokenize(builtin_load_plugins, builtin_load_list, ",", true);
241 
242  PluginOptions builtin_list;
243  tokenize(builtin_plugins, builtin_list, ",", true);
244 
245  bool load_failed= false;
246 
247  if (opt_plugin_add.size() > 0)
248  {
249  for (PluginOptions::iterator iter= opt_plugin_add.begin();
250  iter != opt_plugin_add.end();
251  ++iter)
252  {
253  if (find(builtin_list.begin(),
254  builtin_list.end(), *iter) != builtin_list.end())
255  {
256  builtin_load_list.push_back(*iter);
257  }
258  else
259  {
260  opt_plugin_load.push_back(*iter);
261  }
262  }
263  }
264 
265  if (opt_plugin_remove.size() > 0)
266  {
267  plugin_prune_list(opt_plugin_load, opt_plugin_remove);
268  plugin_prune_list(builtin_load_list, opt_plugin_remove);
269  }
270 
271  memory::Root tmp_root(4096);
272  /*
273  First we register builtin plugins
274  */
275  const set<string> builtin_list_set(builtin_load_list.begin(),
276  builtin_load_list.end());
277  load_failed= plugin_load_list(registry, &tmp_root,
278  builtin_list_set, long_options, true);
279  if (load_failed)
280  {
281  tmp_root.free_root(MYF(0));
282  return true;
283  }
284 
285  /* Uniquify the list */
286  const set<string> plugin_list_set(opt_plugin_load.begin(),
287  opt_plugin_load.end());
288 
289  /* Register all dynamic plugins */
290  load_failed= plugin_load_list(registry, &tmp_root,
291  plugin_list_set, long_options);
292  if (load_failed)
293  {
294  tmp_root.free_root(MYF(0));
295  return true;
296  }
297 
298  tmp_root.free_root(MYF(0));
299 
300  return false;
301 }
302 
303 bool plugin_finalize(module::Registry &registry)
304 {
305  /*
306  Now we initialize all remaining plugins
307  */
308  BOOST_FOREACH(module::Registry::ModuleList::const_reference module, registry.getList())
309  {
310  if (not module->isInited && plugin_initialize(registry, module))
311  {
312  registry.remove(module);
313  delete module;
314  return true;
315  }
316  }
317  BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
318  {
319  value.second->prime();
320  }
321  return false;
322 }
323 
324 /*
325  Window of opportunity for plugins to issue any queries with the database up and running but with no user's connected.
326 */
327 void plugin_startup_window(module::Registry &registry, drizzled::Session &session)
328 {
329  BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
330  {
331  value.second->startup(session);
332  }
333 }
334 
335 class PrunePlugin :
336  public unary_function<string, bool>
337 {
338  const string to_match;
339 public:
340  explicit PrunePlugin(const string &match_in) :
341  to_match(match_in)
342  { }
343 
344  result_type operator()(const string &match_against)
345  {
346  return match_against == to_match;
347  }
348 };
349 
350 static void plugin_prune_list(vector<string> &plugin_list,
351  const vector<string> &plugins_to_remove)
352 {
353  for (vector<string>::const_iterator iter= plugins_to_remove.begin();
354  iter != plugins_to_remove.end();
355  ++iter)
356  {
357  plugin_list.erase(remove_if(plugin_list.begin(),
358  plugin_list.end(),
359  PrunePlugin(*iter)),
360  plugin_list.end());
361  }
362 }
363 
364 /*
365  called only by plugin_init()
366 */
367 static bool plugin_load_list(module::Registry &registry,
368  memory::Root *tmp_root,
369  const set<string> &plugin_list,
370  po::options_description &long_options,
371  bool builtin)
372 {
373  BOOST_FOREACH(const string& plugin_name, plugin_list)
374  {
375  module::Library* library= registry.addLibrary(plugin_name, builtin);
376  if (library == NULL)
377  {
378  errmsg_printf(error::ERROR,
379  _("Couldn't load plugin library named '%s'.\n"),
380  plugin_name.c_str());
381  return true;
382  }
383 
384  tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
385  if (plugin_add(registry, tmp_root, library, long_options))
386  {
387  registry.removeLibrary(plugin_name);
388  errmsg_printf(error::ERROR,
389  _("Couldn't load plugin named '%s'.\n"),
390  plugin_name.c_str());
391  return true;
392  }
393  }
394  return false;
395 }
396 
397 void module_shutdown(module::Registry &registry)
398 {
399  if (initialized)
400  {
401  reap_needed= true;
402 
403  reap_plugins(registry);
404  unlock_variables(NULL, &global_system_variables);
405  unlock_variables(NULL, &max_system_variables);
406 
407  cleanup_variables(&global_system_variables);
408  cleanup_variables(&max_system_variables);
409 
410  initialized= 0;
411  }
412 
413  /* Dispose of the memory */
414  plugin_mem_root.free_root(MYF(0));
415 
416  global_variables_dynamic_size= 0;
417 }
418 
419 
420 /****************************************************************************
421  System Variables support
422 ****************************************************************************/
423 
424 
425 
426 void plugin_sessionvar_init(Session *session)
427 {
428  session->variables.storage_engine= NULL;
429  cleanup_variables(&session->variables);
430 
431  session->variables= global_system_variables;
432  session->variables.storage_engine= NULL;
433 
434  /* we are going to allocate these lazily */
435  session->variables.dynamic_variables_version= 0;
436  session->variables.dynamic_variables_size= 0;
437  session->variables.dynamic_variables_ptr= 0;
438 
439  session->variables.storage_engine= global_system_variables.storage_engine;
440 }
441 
442 
443 /*
444  Unlocks all system variables which hold a reference
445 */
446 static void unlock_variables(Session *, struct drizzle_system_variables *vars)
447 {
448  vars->storage_engine= NULL;
449 }
450 
451 
452 /*
453  Frees memory used by system variables
454 
455  Unlike plugin_vars_free_values() it frees all variables of all plugins,
456  it's used on shutdown.
457 */
458 static void cleanup_variables(drizzle_system_variables *vars)
459 {
460  assert(vars->storage_engine == NULL);
461 
462  free(vars->dynamic_variables_ptr);
463  vars->dynamic_variables_ptr= NULL;
464  vars->dynamic_variables_size= 0;
465  vars->dynamic_variables_version= 0;
466 }
467 
468 
469 void plugin_sessionvar_cleanup(Session *session)
470 {
471  unlock_variables(session, &session->variables);
472  cleanup_variables(&session->variables);
473 }
474 
475 
476 
477 /*
478  SYNOPSIS
479  test_plugin_options()
480  tmp_root temporary scratch space
481  plugin internal plugin structure
482  default_enabled default plugin enable status
483  RETURNS:
484  0 SUCCESS - plugin should be enabled/loaded
485  NOTE:
486  Requires that a write-lock is held on LOCK_system_variables_hash
487 */
488 static int test_plugin_options(memory::Root *,
489  module::Module *test_module,
490  po::options_description &long_options)
491 {
492 
493  if (test_module->getManifest().init_options != NULL)
494  {
495  string plugin_section_title("Options used by ");
496  plugin_section_title.append(test_module->getName());
497  po::options_description module_options(plugin_section_title);
498  module::option_context opt_ctx(test_module->getName(),
499  module_options.add_options());
500  test_module->getManifest().init_options(opt_ctx);
501  long_options.add(module_options);
502  }
503 
504  return 0;
505 }
506 
507 
508 /****************************************************************************
509  Help Verbose text with Plugin System Variables
510 ****************************************************************************/
511 
513 {
514 public:
515  bool operator() (const option &a, const option &b)
516  {
517  return my_charset_utf8_general_ci.strcasecmp(a.name, b.name);
518  }
519 };
520 
521 
523 {
524  module::Registry &registry= module::Registry::singleton();
525  vector<option> all_options;
526  memory::Root mem_root(4096);
527 
528 
529  if (initialized)
530  {
531  std::map<std::string, module::Module *>::const_iterator modules=
532  registry.getModulesMap().begin();
533 
534  while (modules != registry.getModulesMap().end())
535  {
536  module::Module *p= (*modules).second;
537  ++modules;
538 
539  /* If we have an init_options function, we are registering
540  commmand line options that way, so don't do them this way */
541  if (p->getManifest().init_options != NULL)
542  continue;
543 
544  }
545  }
546 
547  for (;main_options->id; main_options++)
548  {
549  if (main_options->comment)
550  {
551  all_options.push_back(*main_options);
552  }
553  }
554 
561  /* main_options now points to the empty option terminator */
562  all_options.push_back(*main_options);
563 
564  my_print_help(&*(all_options.begin()));
565 
566  mem_root.free_root(MYF(0));
567 }
568 
569 } /* namespace drizzled */
570 
571 
TODO: Rename this file - func.h is stupid.
An Proxy Wrapper around options_description_easy_init.
void my_print_help_inc_plugins(option *main_options)
Definition: loader.cc:522
void free_root(myf MyFLAGS)
Deallocate everything used by alloc_root or just move used blocks to free list if called with MY_USED...
Definition: root.cc:288