Drizzled Public API Documentation

replication_slave.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2011 David Shrewsbury
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 #include <plugin/slave/replication_slave.h>
00023 #include <drizzled/errmsg_print.h>
00024 #include <drizzled/program_options/config_file.h>
00025 #include <boost/lexical_cast.hpp>
00026 #include <boost/program_options.hpp>
00027 #include <fstream>
00028 #include <drizzled/plugin.h>
00029 
00030 using namespace std;
00031 using namespace drizzled;
00032 
00033 namespace po= boost::program_options;
00034 
00035 namespace slave
00036 {
00037 
00038 void ReplicationSlave::startup(Session &session)
00039 {
00040   (void)session;
00041   if (not initWithConfig())
00042   {
00043     errmsg_printf(error::ERROR, _("Could not start slave services: %s\n"),
00044                   _error.c_str());
00045   }
00046   else
00047   {
00048     /* Start the IO threads */
00049     boost::unordered_map<uint32_t, Master *>::const_iterator it;
00050     for (it= _masters.begin(); it != _masters.end(); ++it)
00051     {
00052       it->second->start();
00053       /* Consumer must know server IDs */
00054       _consumer.addMasterId(it->first);
00055     }
00056 
00057     _consumer_thread= boost::thread(&QueueConsumer::run, &_consumer);
00058   }
00059 }
00060 
00061 bool ReplicationSlave::initWithConfig()
00062 {
00063   po::variables_map vm;
00064   po::options_description slave_options("Options for the slave plugin");
00065 
00066   /* Common options */
00067   slave_options.add_options()
00068     ("seconds-between-reconnects", po::value<uint32_t>()->default_value(30))
00069     ("io-thread-sleep", po::value<uint32_t>()->default_value(5))
00070     ("applier-thread-sleep", po::value<uint32_t>()->default_value(5))
00071     ("ignore-errors", po::value<bool>()->default_value(false)->zero_tokens());
00072 
00073   /* Master defining options */
00074   for (size_t num= 1; num <= 10; num++)
00075   {
00076     string section("master");
00077     section.append(boost::lexical_cast<string>(num));
00078     slave_options.add_options()
00079       ((section + ".master-host").c_str(), po::value<string>()->default_value(""))
00080       ((section + ".master-port").c_str(), po::value<uint16_t>()->default_value(3306))
00081       ((section + ".master-user").c_str(), po::value<string>()->default_value(""))
00082       ((section + ".master-pass").c_str(), po::value<string>()->default_value(""))
00083       ((section + ".max-reconnects").c_str(), po::value<uint32_t>()->default_value(10))
00084       ((section + ".max-commit-id").c_str(), po::value<uint64_t>());
00085    }
00086 
00087   ifstream cf_stream(_config_file.c_str());
00088 
00089   if (not cf_stream.is_open())
00090   {
00091     _error= "Unable to open file ";
00092     _error.append(_config_file);
00093     return false;
00094   }
00095 
00096   po::store(drizzled::program_options::parse_config_file(cf_stream, slave_options), vm);
00097 
00098   po::notify(vm);
00099 
00100   /*
00101    * We will support 10 masters. This loope effectively creates the Master
00102    * objects as they are referenced.
00103    *
00104    * @todo Support a variable number of master hosts.
00105    */
00106   for (size_t num= 1; num <= 10; num++)
00107   {
00108     string section("master");
00109     section.append(boost::lexical_cast<string>(num));
00110 
00111     /* WARNING! Hack!
00112      * We need to be able to determine when a master host is actually defined
00113      * by the user vs. we are just using defaults. So if the hostname is ever
00114      * the default value of "", then we'll assume that this section was not
00115      * user defined.
00116      */
00117     if (vm[section + ".master-host"].as<string>() == "")
00118       continue;
00119 
00120     _masters[num]= new (std::nothrow) Master(num);
00121 
00122     if (vm.count(section + ".master-host"))
00123       master(num).producer().setMasterHost(vm[section + ".master-host"].as<string>());
00124 
00125     if (vm.count(section + ".master-port"))
00126       master(num).producer().setMasterPort(vm[section + ".master-port"].as<uint16_t>());
00127 
00128     if (vm.count(section + ".master-user"))
00129       master(num).producer().setMasterUser(vm[section + ".master-user"].as<string>());
00130 
00131     if (vm.count(section + ".master-pass"))
00132       master(num).producer().setMasterPassword(vm[section + ".master-pass"].as<string>());
00133 
00134     if (vm.count(section + ".max-commit-id"))
00135       master(num).producer().setCachedMaxCommitId(vm[section + ".max-commit-id"].as<uint64_t>());
00136   }
00137 
00138   boost::unordered_map<uint32_t, Master *>::const_iterator it;
00139 
00140   for (it= _masters.begin(); it != _masters.end(); ++it)
00141   {
00142     if (vm.count("max-reconnects"))
00143       it->second->producer().setMaxReconnectAttempts(vm["max-reconnects"].as<uint32_t>());
00144 
00145     if (vm.count("seconds-between-reconnects"))
00146       it->second->producer().setSecondsBetweenReconnects(vm["seconds-between-reconnects"].as<uint32_t>());
00147 
00148     if (vm.count("io-thread-sleep"))
00149       it->second->producer().setSleepInterval(vm["io-thread-sleep"].as<uint32_t>());
00150   }
00151 
00152   if (vm.count("applier-thread-sleep"))
00153     _consumer.setSleepInterval(vm["applier-thread-sleep"].as<uint32_t>());
00154   if (vm.count("ignore-errors"))
00155     _consumer.setIgnoreErrors(vm["ignore-errors"].as<bool>());
00156 
00157   /* setup schema and tables */
00158   ReplicationSchema rs;
00159   if (not rs.create())
00160   {
00161     _error= rs.getErrorMessage();
00162     return false;
00163   }
00164 
00165   for (it= _masters.begin(); it != _masters.end(); ++it)
00166   {
00167     /* make certain a row exists for each master */
00168     rs.createInitialApplierRow(it->first);
00169     rs.createInitialIORow(it->first);
00170 
00171     uint64_t cachedValue= it->second->producer().cachedMaxCommitId();
00172     if (cachedValue)
00173     {
00174       if (not rs.setInitialMaxCommitId(it->first, cachedValue))
00175       {
00176         _error= rs.getErrorMessage();
00177         return false;
00178       }
00179     }
00180   }
00181 
00182   return true;
00183 }
00184 
00185 } /* namespace slave */