Drizzled Public API Documentation

loader.cc
00001 /* Copyright (C) 2005 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #include <config.h>
00017 
00018 #include <dlfcn.h>
00019 
00020 #include <cstdio>
00021 #include <string>
00022 #include <vector>
00023 #include <map>
00024 #include <algorithm>
00025 #include <iostream>
00026 
00027 #include <boost/program_options.hpp>
00028 
00029 #include <drizzled/option.h>
00030 #include <drizzled/internal/m_string.h>
00031 
00032 #include <drizzled/plugin.h>
00033 #include <drizzled/module/load_list.h>
00034 #include <drizzled/module/library.h>
00035 #include <drizzled/module/registry.h>
00036 #include <drizzled/module/option_context.h>
00037 #include <drizzled/sql_parse.h>
00038 #include <drizzled/show.h>
00039 #include <drizzled/cursor.h>
00040 #include <drizzled/set_var.h>
00041 #include <drizzled/session.h>
00042 #include <drizzled/item/null.h>
00043 #include <drizzled/error.h>
00044 #include <drizzled/gettext.h>
00045 #include <drizzled/errmsg_print.h>
00046 #include <drizzled/pthread_globals.h>
00047 #include <drizzled/util/tokenize.h>
00048 #include <drizzled/system_variables.h>
00049 
00050 #include <boost/foreach.hpp>
00051 
00052 /* FreeBSD 2.2.2 does not define RTLD_NOW) */
00053 #ifndef RTLD_NOW
00054 #define RTLD_NOW 1
00055 #endif
00056 
00057 namespace po=boost::program_options;
00058 
00059 using namespace std;
00060 
00062 typedef drizzled::module::Manifest drizzled_builtin_list[];
00063 extern drizzled_builtin_list PANDORA_BUILTIN_SYMBOLS_LIST;
00064 extern drizzled_builtin_list PANDORA_BUILTIN_LOAD_SYMBOLS_LIST;
00065 drizzled::module::Manifest *drizzled_builtins[]=
00066 {
00067   PANDORA_BUILTIN_SYMBOLS_LIST, NULL
00068 };
00069 drizzled::module::Manifest *drizzled_load_builtins[]=
00070 {
00071   PANDORA_BUILTIN_LOAD_SYMBOLS_LIST, NULL
00072 };
00073 
00074 namespace drizzled {
00075  
00076 
00077 typedef vector<string> PluginOptions;
00078 static PluginOptions opt_plugin_load;
00079 static PluginOptions opt_plugin_add;
00080 static PluginOptions opt_plugin_remove;
00081 const char *builtin_plugins= PANDORA_BUILTIN_LIST;
00082 const char *builtin_load_plugins= PANDORA_BUILTIN_LOAD_LIST;
00083 
00084 /* Note that 'int version' must be the first field of every plugin
00085    sub-structure (plugin->info).
00086 */
00087 
00088 static bool initialized= false;
00089 
00090 
00091 static bool reap_needed= false;
00092 
00093 /*
00094   write-lock on LOCK_system_variables_hash is required before modifying
00095   the following variables/structures
00096 */
00097 static memory::Root plugin_mem_root(4096);
00098 static uint32_t global_variables_dynamic_size= 0;
00099 
00100 
00101 /*
00102   hidden part of opaque value passed to variable check functions.
00103   Used to provide a object-like structure to non C++ consumers.
00104 */
00105 struct st_item_value_holder : public drizzle_value
00106 {
00107   Item *item;
00108 };
00109 
00110 /* prototypes */
00111 static void plugin_prune_list(vector<string> &plugin_list, const vector<string> &plugins_to_remove);
00112 static bool plugin_load_list(module::Registry &registry,
00113                              memory::Root *tmp_root,
00114                              const set<string> &plugin_list,
00115                              po::options_description &long_options,
00116                              bool builtin= false);
00117 static int test_plugin_options(memory::Root*, module::Module*, po::options_description&long_options);
00118 static void unlock_variables(Session *session, drizzle_system_variables *vars);
00119 static void cleanup_variables(drizzle_system_variables *vars);
00120 
00121 
00122 /****************************************************************************
00123   Plugin support code
00124 ****************************************************************************/
00125 
00126 
00127 
00128 
00129 /*
00130   NOTE
00131     Requires that a write-lock is held on LOCK_system_variables_hash
00132 */
00133 static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
00134                        module::Library *library,
00135                        po::options_description &long_options)
00136 {
00137   if (! initialized)
00138     return true;
00139 
00140   if (registry.find(library->getName()))
00141   {
00142     errmsg_printf(error::WARN, ER(ER_PLUGIN_EXISTS),
00143                   library->getName().c_str());
00144     return false;
00145   }
00146 
00147   /* Find plugin by name */
00148   const module::Manifest *manifest= library->getManifest();
00149 
00150   if (registry.find(manifest->name))
00151   {
00152     errmsg_printf(error::ERROR, 
00153                   _("Plugin '%s' contains the name '%s' in its manifest, which "
00154                     "has already been registered.\n"),
00155                   library->getName().c_str(),
00156                   manifest->name);
00157     return true;
00158   }
00159 
00160   module::Module* tmp= new module::Module(manifest, library);
00161 
00162   if (!test_plugin_options(tmp_root, tmp, long_options))
00163   {
00164     registry.add(tmp);
00165     return false;
00166   }
00167   errmsg_printf(error::ERROR, ER(ER_CANT_FIND_DL_ENTRY),
00168                 library->getName().c_str());
00169   return true;
00170 }
00171 
00172 
00173 static void reap_plugins(module::Registry &registry)
00174 {
00175   BOOST_FOREACH(module::Registry::ModuleMap::const_reference module, registry.getModulesMap())
00176     delete module.second;
00177 }
00178 
00179 
00180 static bool plugin_initialize(module::Registry &registry,
00181                               module::Module *module)
00182 {
00183   assert(module->isInited == false);
00184 
00185   module::Context loading_context(registry, module);
00186   if (module->getManifest().init)
00187   {
00188     if (module->getManifest().init(loading_context))
00189     {
00190       errmsg_printf(error::ERROR,
00191                     _("Plugin '%s' init function returned error.\n"),
00192                     module->getName().c_str());
00193       return true;
00194     }
00195   }
00196   module->isInited= true;
00197   return false;
00198 }
00199 
00200 static void compose_plugin_options(vector<string> &target,
00201                                    vector<string> options)
00202 {
00203   BOOST_FOREACH(vector<string>::reference it, options)
00204     tokenize(it, target, ",", true);
00205   BOOST_FOREACH(vector<string>::reference it, target)
00206     std::replace(it.begin(), it.end(), '-', '_');
00207 }
00208 
00209 void compose_plugin_add(const vector<string>& options)
00210 {
00211   compose_plugin_options(opt_plugin_add, options);
00212 }
00213 
00214 void compose_plugin_remove(const vector<string>& options)
00215 {
00216   compose_plugin_options(opt_plugin_remove, options);
00217 }
00218 
00219 void notify_plugin_load(const string& in_plugin_load)
00220 {
00221   tokenize(in_plugin_load, opt_plugin_load, ",", true);
00222 }
00223 
00224 /*
00225   The logic is that we first load and initialize all compiled in plugins.
00226   From there we load up the dynamic types (assuming we have not been told to
00227   skip this part).
00228 
00229   Finally we initialize everything, aka the dynamic that have yet to initialize.
00230 */
00231 bool plugin_init(module::Registry &registry,
00232                  po::options_description &long_options)
00233 {
00234   if (initialized)
00235     return false;
00236 
00237   initialized= true;
00238 
00239   PluginOptions builtin_load_list;
00240   tokenize(builtin_load_plugins, builtin_load_list, ",", true);
00241 
00242   PluginOptions builtin_list;
00243   tokenize(builtin_plugins, builtin_list, ",", true);
00244 
00245   bool load_failed= false;
00246 
00247   if (opt_plugin_add.size() > 0)
00248   {
00249     for (PluginOptions::iterator iter= opt_plugin_add.begin();
00250          iter != opt_plugin_add.end();
00251          ++iter)
00252     {
00253       if (find(builtin_list.begin(),
00254                builtin_list.end(), *iter) != builtin_list.end())
00255       {
00256         builtin_load_list.push_back(*iter);
00257       }
00258       else
00259       {
00260         opt_plugin_load.push_back(*iter);
00261       }
00262     }
00263   }
00264 
00265   if (opt_plugin_remove.size() > 0)
00266   {
00267     plugin_prune_list(opt_plugin_load, opt_plugin_remove);
00268     plugin_prune_list(builtin_load_list, opt_plugin_remove);
00269   }
00270 
00271   memory::Root tmp_root(4096);
00272   /*
00273     First we register builtin plugins
00274   */
00275   const set<string> builtin_list_set(builtin_load_list.begin(),
00276                                      builtin_load_list.end());
00277   load_failed= plugin_load_list(registry, &tmp_root,
00278                                 builtin_list_set, long_options, true);
00279   if (load_failed)
00280   {
00281     tmp_root.free_root(MYF(0));
00282     return true;
00283   }
00284 
00285   /* Uniquify the list */
00286   const set<string> plugin_list_set(opt_plugin_load.begin(),
00287                                     opt_plugin_load.end());
00288   
00289   /* Register all dynamic plugins */
00290   load_failed= plugin_load_list(registry, &tmp_root,
00291                                 plugin_list_set, long_options);
00292   if (load_failed)
00293   {
00294     tmp_root.free_root(MYF(0));
00295     return true;
00296   }
00297 
00298   tmp_root.free_root(MYF(0));
00299 
00300   return false;
00301 }
00302 
00303 bool plugin_finalize(module::Registry &registry)
00304 {
00305   /*
00306     Now we initialize all remaining plugins
00307   */
00308   BOOST_FOREACH(module::Registry::ModuleList::const_reference module, registry.getList())
00309   {
00310     if (not module->isInited && plugin_initialize(registry, module))
00311     {
00312       registry.remove(module);
00313       delete module;
00314       return true;
00315     }
00316   }
00317   BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
00318   {
00319     value.second->prime();
00320   }
00321   return false;
00322 }
00323 
00324 /*
00325   Window of opportunity for plugins to issue any queries with the database up and running but with no user's connected.
00326 */
00327 void plugin_startup_window(module::Registry &registry, drizzled::Session &session)
00328 {
00329   BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
00330   {
00331     value.second->startup(session);
00332   }
00333 }
00334 
00335 class PrunePlugin :
00336   public unary_function<string, bool>
00337 {
00338   const string to_match;
00339 public:
00340   explicit PrunePlugin(const string &match_in) :
00341     to_match(match_in)
00342   { }
00343 
00344   result_type operator()(const string &match_against)
00345   {
00346     return match_against == to_match;
00347   }
00348 };
00349 
00350 static void plugin_prune_list(vector<string> &plugin_list,
00351                               const vector<string> &plugins_to_remove)
00352 {
00353   for (vector<string>::const_iterator iter= plugins_to_remove.begin();
00354        iter != plugins_to_remove.end();
00355        ++iter)
00356   {
00357     plugin_list.erase(remove_if(plugin_list.begin(),
00358                                 plugin_list.end(),
00359                                 PrunePlugin(*iter)),
00360                       plugin_list.end());
00361   }
00362 }
00363 
00364 /*
00365   called only by plugin_init()
00366 */
00367 static bool plugin_load_list(module::Registry &registry,
00368                              memory::Root *tmp_root,
00369                              const set<string> &plugin_list,
00370                              po::options_description &long_options,
00371                              bool builtin)
00372 {
00373   BOOST_FOREACH(const string& plugin_name, plugin_list)
00374   {
00375     module::Library* library= registry.addLibrary(plugin_name, builtin);
00376     if (library == NULL)
00377     {
00378       errmsg_printf(error::ERROR,
00379                     _("Couldn't load plugin library named '%s'.\n"),
00380                     plugin_name.c_str());
00381       return true;
00382     }
00383 
00384     tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
00385     if (plugin_add(registry, tmp_root, library, long_options))
00386     {
00387       registry.removeLibrary(plugin_name);
00388       errmsg_printf(error::ERROR,
00389                     _("Couldn't load plugin named '%s'.\n"),
00390                     plugin_name.c_str());
00391       return true;
00392     }
00393   }
00394   return false;
00395 }
00396 
00397 void module_shutdown(module::Registry &registry)
00398 {
00399   if (initialized)
00400   {
00401     reap_needed= true;
00402 
00403     reap_plugins(registry);
00404     unlock_variables(NULL, &global_system_variables);
00405     unlock_variables(NULL, &max_system_variables);
00406 
00407     cleanup_variables(&global_system_variables);
00408     cleanup_variables(&max_system_variables);
00409 
00410     initialized= 0;
00411   }
00412 
00413   /* Dispose of the memory */
00414   plugin_mem_root.free_root(MYF(0));
00415 
00416   global_variables_dynamic_size= 0;
00417 }
00418 
00419 
00420 /****************************************************************************
00421   System Variables support
00422 ****************************************************************************/
00423 
00424 
00425 
00426 void plugin_sessionvar_init(Session *session)
00427 {
00428   session->variables.storage_engine= NULL;
00429   cleanup_variables(&session->variables);
00430 
00431   session->variables= global_system_variables;
00432   session->variables.storage_engine= NULL;
00433 
00434   /* we are going to allocate these lazily */
00435   session->variables.dynamic_variables_version= 0;
00436   session->variables.dynamic_variables_size= 0;
00437   session->variables.dynamic_variables_ptr= 0;
00438 
00439   session->variables.storage_engine= global_system_variables.storage_engine;
00440 }
00441 
00442 
00443 /*
00444   Unlocks all system variables which hold a reference
00445 */
00446 static void unlock_variables(Session *, struct drizzle_system_variables *vars)
00447 {
00448   vars->storage_engine= NULL;
00449 }
00450 
00451 
00452 /*
00453   Frees memory used by system variables
00454 
00455   Unlike plugin_vars_free_values() it frees all variables of all plugins,
00456   it's used on shutdown.
00457 */
00458 static void cleanup_variables(drizzle_system_variables *vars)
00459 {
00460   assert(vars->storage_engine == NULL);
00461 
00462   free(vars->dynamic_variables_ptr);
00463   vars->dynamic_variables_ptr= NULL;
00464   vars->dynamic_variables_size= 0;
00465   vars->dynamic_variables_version= 0;
00466 }
00467 
00468 
00469 void plugin_sessionvar_cleanup(Session *session)
00470 {
00471   unlock_variables(session, &session->variables);
00472   cleanup_variables(&session->variables);
00473 }
00474 
00475 
00476 
00477 /*
00478   SYNOPSIS
00479     test_plugin_options()
00480     tmp_root                    temporary scratch space
00481     plugin                      internal plugin structure
00482     default_enabled             default plugin enable status
00483   RETURNS:
00484     0 SUCCESS - plugin should be enabled/loaded
00485   NOTE:
00486     Requires that a write-lock is held on LOCK_system_variables_hash
00487 */
00488 static int test_plugin_options(memory::Root *,
00489                                module::Module *test_module,
00490                                po::options_description &long_options)
00491 {
00492 
00493   if (test_module->getManifest().init_options != NULL)
00494   {
00495     string plugin_section_title("Options used by ");
00496     plugin_section_title.append(test_module->getName());
00497     po::options_description module_options(plugin_section_title);
00498     module::option_context opt_ctx(test_module->getName(),
00499                                    module_options.add_options());
00500     test_module->getManifest().init_options(opt_ctx);
00501     long_options.add(module_options);
00502   }
00503 
00504   return 0;
00505 }
00506 
00507 
00508 /****************************************************************************
00509   Help Verbose text with Plugin System Variables
00510 ****************************************************************************/
00511 
00512 class OptionCmp
00513 {
00514 public:
00515   bool operator() (const option &a, const option &b)
00516   {
00517     return my_charset_utf8_general_ci.strcasecmp(a.name, b.name);
00518   }
00519 };
00520 
00521 
00522 void my_print_help_inc_plugins(option *main_options)
00523 {
00524   module::Registry &registry= module::Registry::singleton();
00525   vector<option> all_options;
00526   memory::Root mem_root(4096);
00527 
00528 
00529   if (initialized)
00530   {
00531     std::map<std::string, module::Module *>::const_iterator modules=
00532       registry.getModulesMap().begin();
00533     
00534     while (modules != registry.getModulesMap().end())
00535     {
00536       module::Module *p= (*modules).second;
00537       ++modules;
00538 
00539       /* If we have an init_options function, we are registering
00540          commmand line options that way, so don't do them this way */
00541       if (p->getManifest().init_options != NULL)
00542         continue;
00543 
00544     }
00545   }
00546 
00547   for (;main_options->id; main_options++)
00548   {
00549     if (main_options->comment)
00550     {
00551       all_options.push_back(*main_options);
00552     }
00553   }
00554 
00561   /* main_options now points to the empty option terminator */
00562   all_options.push_back(*main_options);
00563 
00564   my_print_help(&*(all_options.begin()));
00565 
00566   mem_root.free_root(MYF(0));
00567 }
00568 
00569 } /* namespace drizzled */
00570 
00571