00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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 }
00190
00191 DRIZZLE_PLUGIN(drizzle_plugin::init, NULL, drizzle_plugin::init_options);
00192