Drizzled Public API Documentation

rabbitmq_log.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Marcus Eriksson
00005  *
00006  *  Authors:
00007  *
00008  *  Marcus Eriksson <krummas@gmail.com>
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00023  */
00024 
00025 #include <config.h>
00026 #include "rabbitmq_log.h"
00027 #include <drizzled/message/transaction.pb.h>
00028 #include <google/protobuf/io/coded_stream.h>
00029 #include <stdio.h>
00030 #include <drizzled/module/registry.h>
00031 #include <drizzled/plugin.h>
00032 #include <stdint.h>
00033 #include "rabbitmq_handler.h"
00034 #include <boost/program_options.hpp>
00035 #include <drizzled/module/option_map.h>
00036 
00037 namespace po= boost::program_options;
00038 
00039 using namespace std;
00040 using namespace drizzled;
00041 using namespace google;
00042 
00043 namespace drizzle_plugin
00044 {
00045 
00049 static port_constraint sysvar_rabbitmq_port;
00050 
00051 
00052 RabbitMQLog::RabbitMQLog(const string &name, 
00053                          RabbitMQHandler* mqHandler) :
00054   plugin::TransactionApplier(name),
00055   _rabbitMQHandler(mqHandler)
00056 { }
00057 
00058 RabbitMQLog::~RabbitMQLog() 
00059 { 
00060   _rabbitMQHandler->disconnect();
00061   delete _rabbitMQHandler;
00062 }
00063 
00064 plugin::ReplicationReturnCode
00065 RabbitMQLog::apply(Session &, const message::Transaction &to_apply)
00066 {
00067   size_t message_byte_length= to_apply.ByteSize();
00068   uint8_t* buffer= new uint8_t[message_byte_length];
00069   if(buffer == NULL)
00070   {
00071     errmsg_printf(error::ERROR, _("Failed to allocate enough memory to transaction message\n"));
00072     deactivate();
00073     return plugin::UNKNOWN_ERROR;
00074   }
00075 
00076   to_apply.SerializeWithCachedSizesToArray(buffer);
00077   short tries = 3;
00078   bool sent = false;
00079   while (!sent && tries > 0) {
00080     tries--;
00081     try
00082     {
00083       _rabbitMQHandler->publish(buffer, int(message_byte_length));
00084       sent = true;
00085     } 
00086     catch(exception& e)
00087     {
00088       errmsg_printf(error::ERROR, _(e.what()));
00089       try {
00090     _rabbitMQHandler->reconnect();
00091       } catch(exception &e) {
00092     errmsg_printf(error::ERROR, _("Could not reconnect, trying again.. - waiting 10 seconds for server to come back"));
00093     sleep(10);
00094       } // 
00095     }
00096   }
00097 
00098   delete[] buffer;
00099   if(sent) return plugin::SUCCESS;
00100   errmsg_printf(error::ERROR, _("RabbitMQ server has disappeared, failing transaction."));
00101   deactivate();
00102   return plugin::UNKNOWN_ERROR;
00103 }
00104 
00105 static RabbitMQLog *rabbitmqLogger; 
00106 static RabbitMQHandler* rabbitmqHandler; 
00107 
00108 
00114 static int init(drizzled::module::Context &context)
00115 {
00116   const module::option_map &vm= context.getOptions();
00117   
00118   try 
00119   {
00120     rabbitmqHandler= new RabbitMQHandler(vm["host"].as<string>(),
00121                                          sysvar_rabbitmq_port, 
00122                                          vm["username"].as<string>(), 
00123                                          vm["password"].as<string>(), 
00124                                          vm["virtualhost"].as<string>(),
00125            vm["exchange"].as<string>(),
00126            vm["routingkey"].as<string>());
00127   } 
00128   catch (exception& e) 
00129   {
00130     errmsg_printf(error::ERROR, _("Failed to allocate the RabbitMQHandler.  Got error: %s\n"),
00131                   e.what());
00132     return 1;
00133   }
00134   try 
00135   {
00136     rabbitmqLogger= new RabbitMQLog("rabbit_log_applier",
00137                                     rabbitmqHandler);
00138   } 
00139   catch (exception& e) 
00140   {
00141     errmsg_printf(error::ERROR, _("Failed to allocate the RabbitMQLog instance.  Got error: %s\n"), 
00142                   e.what());
00143     return 1;
00144   }
00145 
00146   context.add(rabbitmqLogger);
00147   ReplicationServices::attachApplier(rabbitmqLogger, vm["use-replicator"].as<string>());
00148 
00149   context.registerVariable(new sys_var_const_string_val("host", vm["host"].as<string>()));
00150   context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", sysvar_rabbitmq_port));
00151   context.registerVariable(new sys_var_const_string_val("username", vm["username"].as<string>()));
00152   context.registerVariable(new sys_var_const_string_val("password", vm["password"].as<string>()));
00153   context.registerVariable(new sys_var_const_string_val("virtualhost", vm["virtualhost"].as<string>()));
00154   context.registerVariable(new sys_var_const_string_val("exchange", vm["exchange"].as<string>()));
00155   context.registerVariable(new sys_var_const_string_val("routingkey", vm["routingkey"].as<string>()));
00156 
00157   return 0;
00158 }
00159 
00160 
00161 static void init_options(drizzled::module::option_context &context)
00162 {
00163   context("host", 
00164           po::value<string>()->default_value("localhost"),
00165           _("Host name to connect to"));
00166   context("port",
00167           po::value<port_constraint>(&sysvar_rabbitmq_port)->default_value(5672),
00168           _("Port to connect to"));
00169   context("virtualhost",
00170           po::value<string>()->default_value("/"),
00171           _("RabbitMQ virtualhost"));
00172   context("username",
00173           po::value<string>()->default_value("guest"),
00174           _("RabbitMQ username"));
00175   context("password",
00176           po::value<string>()->default_value("guest"),
00177           _("RabbitMQ password"));
00178   context("use-replicator",
00179           po::value<string>()->default_value("default_replicator"),
00180           _("Name of the replicator plugin to use (default='default_replicator')"));
00181   context("exchange",
00182           po::value<string>()->default_value("ReplicationExchange"),
00183           _("Name of RabbitMQ exchange to publish to"));
00184   context("routingkey",
00185           po::value<string>()->default_value("ReplicationRoutingKey"),
00186           _("Name of RabbitMQ routing key to use"));
00187 }
00188 
00189 } /* namespace drizzle_plugin */
00190 
00191 DRIZZLE_PLUGIN(drizzle_plugin::init, NULL, drizzle_plugin::init_options);
00192